<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Can Ceylan</title>
    <description>The latest articles on DEV Community by Can Ceylan (@canceylan1988).</description>
    <link>https://dev.to/canceylan1988</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3861469%2F5a1153d6-d767-404d-8731-acf1033c9807.png</url>
      <title>DEV Community: Can Ceylan</title>
      <link>https://dev.to/canceylan1988</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/canceylan1988"/>
    <language>en</language>
    <item>
      <title>Automation Was Always Possible. AI Just Made It Everyone's Problem to Ignore</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Wed, 15 Jul 2026 06:29:58 +0000</pubDate>
      <link>https://dev.to/canceylan1988/automation-was-always-possible-ai-just-made-it-everyones-problem-to-ignore-kf1</link>
      <guid>https://dev.to/canceylan1988/automation-was-always-possible-ai-just-made-it-everyones-problem-to-ignore-kf1</guid>
      <description>&lt;h2&gt;
  
  
  This article answers:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is actually the difference between automation and agentic AI?&lt;/li&gt;
&lt;li&gt;Is agentic AI really that expensive, and when does cost become a problem?&lt;/li&gt;
&lt;li&gt;Can you automate business operations without building full AI agents?&lt;/li&gt;
&lt;li&gt;How do you reduce API costs when using LLM-based workflows?&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Every second LinkedIn post right now is about AI agents. Agents that book your meetings, write your emails, manage your calendar, run your customer support. The pitch is always the same: the future of work is autonomous, and if you are not building agents, you are already behind.&lt;/p&gt;

&lt;p&gt;I find this a little funny, because we were building automation at Foodora back in 2018 using Zapier. No agents. No LLMs. Just a trigger, an action, and a team of young professionals with the tools of a highly funded start-up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;The conflation of automation and agentic AI is not just a semantic problem. It leads people to over-engineer solutions, overspend on API calls, and completely miss the fact that a large portion of what they want to automate does not require an agent at all.&lt;/p&gt;

&lt;p&gt;At the same time, the people who do understand the difference are quietly getting a compounding advantage. Because what AI actually changed is not whether automation is possible. It changed who can do it, and how fast.&lt;/p&gt;

&lt;p&gt;That is worth sitting with for a moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the difference between automation and agentic AI?
&lt;/h2&gt;

&lt;p&gt;Automation, in the classic sense, is rule-based. If this happens, do that. It is deterministic. You define every step, every branch, every output format. Tools like Zapier made this accessible to non-developers in the early 2010s, though Zapier in 2018 was still quite technical to use properly and definitely assumed you had a certain level of digital literacy. Tools like Make (formerly Integromat) and n8n pushed this further, allowing more complex multi-step flows, direct API integrations, and significantly more flexibility without requiring you to write code from scratch. That space has matured a lot.&lt;/p&gt;

&lt;p&gt;Agentic AI is something different. An agent does not just follow a fixed decision tree. It reasons. It takes a goal, breaks it into steps, decides how to proceed at each step, uses tools (APIs, browsers, files, code execution), and adapts when something unexpected happens. The defining quality of an agent is autonomous decision-making across a sequence of actions, not just task execution.&lt;/p&gt;

&lt;p&gt;Here is the honest version: most of what businesses want to automate right now is not agentic. It is deterministic workflows that happen to involve a language model at one or two steps. Writing a summary, classifying an email, generating a draft response. That is not an agent. That is automation with an LLM node inside it.&lt;/p&gt;

&lt;p&gt;Calling that an agent is a bit like calling a calculator an AI because it computes things faster than a human.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is agentic AI actually expensive?
&lt;/h2&gt;

&lt;p&gt;It depends entirely on what you are asking the agent to do, and how often.&lt;/p&gt;

&lt;p&gt;Text-based tasks are cheap. A well-structured prompt to GPT-4o or Claude for summarising a document, extracting structured data, or generating a short output costs fractions of a cent. At scale that adds up, but it is manageable if you are thoughtful about it.&lt;/p&gt;

&lt;p&gt;The cost climbs when you introduce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long context windows with lots of history passed on every call&lt;/li&gt;
&lt;li&gt;Audio or video transcription as part of the workflow&lt;/li&gt;
&lt;li&gt;Multi-step agent loops where the model calls itself repeatedly to reason through a problem&lt;/li&gt;
&lt;li&gt;Vision tasks where images need to be analysed at each step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the question is not "is agentic AI expensive" in the abstract. The question is whether you have designed your workflow with cost in mind from the start.&lt;/p&gt;

&lt;p&gt;A few things that actually help: build a memory layer so you are not re-passing the same context on every API call. Ask yourself whether a written summary of a meeting is sufficient, or whether you genuinely need to transcribe and analyse the full audio. Minimise API outreach by caching results where possible. Text is cheaper than audio, audio is cheaper than video. Work with that hierarchy.&lt;/p&gt;

&lt;p&gt;This is operational efficiency, and it applies to AI workflows exactly the same way it applies to logistics or product operations. You design for throughput and cost at the same time, not as an afterthought.&lt;/p&gt;

&lt;h2&gt;
  
  
  What most people get wrong
&lt;/h2&gt;

&lt;p&gt;The dominant narrative positions agents as a democratisation of intelligence. And that is partly true. But the real democratisation that happened is in automation itself.&lt;/p&gt;

&lt;p&gt;Before LLMs, setting up a non-trivial automation required either a developer, a very patient non-technical person who was willing to spend weeks figuring out webhooks and API authentication, or a significant SaaS budget. Most small businesses and solo operators skipped it entirely because the barrier was too high.&lt;/p&gt;

&lt;p&gt;What changed with AI is not that agents replaced automation. What changed is that a domain expert, someone who deeply understands their own customer journey and internal processes, can now describe what they want in plain language, get a working draft of the logic, and implement it themselves. The technical ceiling dropped dramatically.&lt;/p&gt;

&lt;p&gt;But here is the catch: you still need to understand your own processes. The LLM cannot do that part for you. If you do not know what happens between a customer placing an order and that order being fulfilled, no agent in the world will automate it well. The map has to exist in your head first.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Automation was never the hard part. Understanding your own processes well enough to automate them was.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have seen this at both ends. In logistics operations, the processes that got automated well were the ones someone had already documented and lived with for years. The ones that failed were handed off to a developer with a vague brief and a tight deadline.&lt;/p&gt;

&lt;p&gt;AI lowers the technical barrier. It does not lower the thinking requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to actually do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audit before you automate.&lt;/strong&gt; Map out one complete internal or customer-facing workflow end to end before touching any tool. Every handoff, every decision point, every place where a human currently applies judgement. That map is the thing you are automating, not the tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with classic automation, not agents.&lt;/strong&gt; If your workflow is deterministic, use n8n, Make, or even a simple script. Bring an LLM in only at the steps where language understanding or generation is genuinely needed. This keeps costs down and makes debugging much easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a memory layer early.&lt;/strong&gt; If your agent or workflow needs context about a user, a project, or a product, store that context in a database and retrieve it selectively. Do not dump everything into the prompt every time. Your API bill will thank you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text first, always.&lt;/strong&gt; Before deciding to transcribe audio, extract from video, or analyse images, ask whether a written alternative exists or could be created upstream. The cost difference is not trivial at volume.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understand where agents actually earn their complexity.&lt;/strong&gt; Agents make sense when the task requires real-time decision making across multiple unknown steps, when exceptions are common and unpredictable, or when the workflow cannot be fully specified in advance. That is a narrower set of use cases than the current hype suggests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you are early and cost-sensitive, start with free tiers and open-source models.&lt;/strong&gt; n8n self-hosted is free. Local models via Ollama cost nothing per call. You can build and validate a lot of logic before spending meaningful money on frontier model APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I write more about working with AI tools practically and the product thinking behind them in the Tech &amp;amp; AI section. And if you are thinking about where automation connects to building a business around your own expertise, that thread runs through a lot of what I think about with Fleamio.&lt;/p&gt;

&lt;p&gt;Agents are not magic. They are just automation that can think a little. The thinking part is impressive. But the automation part was always there, waiting for someone who understood their own work well enough to use it.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>AI Tools Worth Knowing in 2026: What I Picked Up at a Workshop in Vienna</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Tue, 14 Jul 2026 07:21:55 +0000</pubDate>
      <link>https://dev.to/canceylan1988/ai-tools-worth-knowing-in-2025-what-i-picked-up-at-a-workshop-in-vienna-hgc</link>
      <guid>https://dev.to/canceylan1988/ai-tools-worth-knowing-in-2025-what-i-picked-up-at-a-workshop-in-vienna-hgc</guid>
      <description>&lt;h2&gt;
  
  
  This article answers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What are the best AI tools for entrepreneurs and builders right now?&lt;/li&gt;
&lt;li&gt;How do you run a local LLM to keep your data private?&lt;/li&gt;
&lt;li&gt;Which AI tools actually lead in video, image, voice, and music generation?&lt;/li&gt;
&lt;li&gt;What is the European shift away from US AI providers really about?&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I spent a day at a KI Workshop at the UGP in Vienna this week. A room with practitioners, founders, and curious generalists, all arguing about the same thing: which tools are actually useful, and which ones just look good in a demo.&lt;/p&gt;

&lt;p&gt;I took notes. Here is what stayed with me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;The AI conversation has split into two very different rooms. One room is still debating whether AI is overhyped. The other room is quietly rebuilding workflows, cutting costs, and shipping faster. The gap between those rooms is growing every quarter.&lt;/p&gt;

&lt;p&gt;What struck me at this workshop was not the tools themselves. It was the attitude in the room. Less FOMO, more selectivity. People are starting to ask better questions: not "have you tried this?" but "does this actually solve anything?"&lt;/p&gt;

&lt;p&gt;That is a sign of a maturing space. And it means the tools that survive will be the ones that solve a real, repeatable problem, not just the ones with the best product hunt launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which LLM should you actually use?
&lt;/h2&gt;

&lt;p&gt;The honest answer: it depends, and the people in this room were split.&lt;/p&gt;

&lt;p&gt;For general use, the debate was spread across Gemini, Claude, and OpenAI. No single winner. Each has a different personality and different strengths. Claude tends to write better. Gemini integrates tightly with Google's ecosystem. OpenAI has the widest tool surface.&lt;/p&gt;

&lt;p&gt;What was more interesting to me was the names that came up as alternatives: Hermes, Mistral, and, perhaps most surprisingly for a European room, Qwen, a Chinese provider from Alibaba. The fact that Qwen was being discussed seriously, without the reflexive suspicion that would have greeted it a year ago, says something about how the geopolitical mood is shifting.&lt;/p&gt;

&lt;p&gt;There is a growing sentiment in Austria, and I would guess across the EU broadly, that US Big Tech is no longer a neutral choice. The combination of the AI Act tensions, concerns about the US Cloud Act giving American authorities access to data stored on US-operated infrastructure regardless of physical location, and a general political discomfort with the direction of some major tech players, is pushing people to look elsewhere. This is not fringe thinking anymore. It came up naturally, without anyone making a speech about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to run a local LLM for privacy and cost control
&lt;/h2&gt;

&lt;p&gt;This one matters practically, so let me be direct about what the workshop covered and what the facts actually support.&lt;/p&gt;

&lt;p&gt;The argument for running a local LLM has two legs: data privacy and long-term cost. Both are real, but they come with trade-offs worth understanding.&lt;/p&gt;

&lt;p&gt;On privacy: if you run a model locally, your prompts and outputs never leave your machine. For anyone handling client data, internal documents, or anything that falls under GDPR scrutiny, this is not a paranoid preference, it is a compliance consideration. The Cloud Act concern is legitimate: US-based cloud providers can be compelled to hand over data stored on their infrastructure under US law, even if that data belongs to an EU user. Running locally sidesteps that entirely.&lt;/p&gt;

&lt;p&gt;On cost: the upfront compute investment can be real, especially for heavier models. But for high-volume users, the marginal cost of API calls adds up. Local models eliminate that recurring cost once you have the hardware.&lt;/p&gt;

&lt;p&gt;The dominant tools mentioned for desktop use were &lt;strong&gt;Ollama&lt;/strong&gt; and &lt;strong&gt;LM Studio&lt;/strong&gt;. Both let you pull and run open-source models locally without needing to write code. Ollama is more developer-friendly and runs cleanly from the terminal. LM Studio offers a graphical interface that makes it accessible to non-technical users. For mobile, &lt;strong&gt;Pocket Pal&lt;/strong&gt; was the name that came up, an app that runs smaller models directly on your phone.&lt;/p&gt;

&lt;p&gt;The honest caveat: local models are still behind the frontier models on raw capability. You are making a trade-off between privacy and performance. For sensitive internal work, that trade-off is often worth it. For complex reasoning tasks, you may still reach for the cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the best AI tools by category right now?
&lt;/h2&gt;

&lt;p&gt;Here is the practical breakdown from the workshop, with my own read layered in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Video transcription and summarisation:&lt;/strong&gt; Google Gemini's NotebookLM came up as the clear leader for turning long content into structured summaries. Whisper (the open-source transcription model from OpenAI) handles audio-to-text well and can be run locally. CapCut got a mention for lighter video editing workflows with AI-assisted captioning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Voice cloning and imitation:&lt;/strong&gt; ElevenLabs was the perceived leader. It was not contested much. If you are building any kind of audio content workflow, it is the first stop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logo creation:&lt;/strong&gt; Ideogram was recommended, especially for entrepreneurs in early stages. I want to be straight about something here though. A live test at the workshop showed the same limitation that plagues most image generators: the first draft can be surprisingly good, but adjustability is limited. And critically, outputs are not served as vector files. A logo that lives only as a raster image is a logo that will cause you problems the moment you need to resize it for a pitch deck, a banner, or a print run.&lt;/p&gt;

&lt;p&gt;My take: until someone builds a one-stop solution that goes from prompt to editable vector, logo generation tools are still a starting point, not a finish line. You will end up in Adobe Illustrator anyway. If anyone pitches you a logo service, ask one question before anything else: do you deliver an editable vector file? If the answer is no, save your time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Presentations and pitch decks:&lt;/strong&gt; Still unsettled. Canva and Gamma were discussed but the room was not convinced. This feels like a gap that has not been filled cleanly yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Website and product UI drafting:&lt;/strong&gt; I found &lt;strong&gt;Google Stitch&lt;/strong&gt; genuinely useful for first-draft website layouts in a product development context. It is not a builder, it is a thinking tool. For getting a rough structure out of your head and onto a screen quickly, it holds up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image and video generation:&lt;/strong&gt; &lt;strong&gt;Higgsfield&lt;/strong&gt; was cited as the best starting point for AI video generation. For creating a digital avatar of yourself with your own voice, &lt;strong&gt;HeyGen&lt;/strong&gt; and &lt;strong&gt;Synthesia&lt;/strong&gt; were the two names mentioned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Music and sound:&lt;/strong&gt; &lt;strong&gt;Suno&lt;/strong&gt; is the perceived leader for AI-generated music. The one that genuinely caught my attention was &lt;strong&gt;Magenta-RT&lt;/strong&gt;, which generates an infinite AI radio station from a text prompt. I have not tested it yet, but the concept is immediately interesting, especially for fitness instructors, content creators, or anyone who needs background audio without licensing headaches. I will report back.&lt;/p&gt;

&lt;h2&gt;
  
  
  What most people get wrong about AI adoption
&lt;/h2&gt;

&lt;p&gt;The biggest mistake I see is treating AI adoption as a one-time decision. People either go all-in on one provider and ignore the rest, or they try everything and master nothing.&lt;/p&gt;

&lt;p&gt;The better frame: think in layers. One general-purpose LLM you use daily and know deeply. One privacy-respecting local option for sensitive work. One or two specialist tools for the specific workflows that matter in your business.&lt;/p&gt;

&lt;p&gt;The other thing worth saying out loud: we are still early. Most of the people in that room, smart, engaged, genuinely curious practitioners, are still mostly using basic LLMs. No category has a dominant winner yet. Most workflows are still being figured out. That is not a reason to panic. That is actually a reason to breathe.&lt;/p&gt;

&lt;p&gt;The window where showing up and learning is enough is still open. It will not be forever.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most people are still using AI like a slightly smarter search engine. The gap between that and what is actually possible is where the next five years will be decided.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What to actually do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pick one LLM and go deep.&lt;/strong&gt; Use it for 30 days across real work. Do not switch. The compounding comes from fluency, not from sampling every new release.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you handle client or company data, set up Ollama or LM Studio now.&lt;/strong&gt; Even if you only use it occasionally, having a local option removes a category of risk entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit your logo and brand assets.&lt;/strong&gt; If you have used an AI tool and do not have editable vector files, fix that before you need to scale anything. The problem always shows up at the worst moment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Follow people who filter for you.&lt;/strong&gt; Matthew Berman, Matt Wolfe, Andreas Horn, and Sasha Pallenberg were all mentioned as reliable signal in a noisy space. Let them do the scanning, you focus on applying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Magenta-RT if you create audio-heavy content.&lt;/strong&gt; I have not yet, but an infinite prompt-driven radio station sounds worth an hour of exploration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch the Will Smith eating spaghetti compilation from 2023 to today.&lt;/strong&gt; It is the most honest visual timeline of how far AI video generation has come. Better than any trend report.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The European alternatives to US AI providers are still catching up on usability. But the direction is clear and the funding is following. If you are building in that space, the tailwind is real, and an EU-first positioning is already a differentiator even before the product is competitive on pure capability.&lt;/p&gt;

&lt;p&gt;Stay curious. Stay selective. And if someone tries to sell you urgency about any single tool right now, they are probably selling the tool.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>AI Is the Most Equalising Force Tech Has Ever Seen, Especially for Women</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Thu, 04 Jun 2026 14:48:54 +0000</pubDate>
      <link>https://dev.to/canceylan1988/ai-is-the-most-equalising-force-tech-has-ever-seen-especially-for-women-15dk</link>
      <guid>https://dev.to/canceylan1988/ai-is-the-most-equalising-force-tech-has-ever-seen-especially-for-women-15dk</guid>
      <description>&lt;h2&gt;
  
  
  AI Is the Most Equalising Force Tech Has Ever Seen, Especially for Women
&lt;/h2&gt;

&lt;p&gt;I spent a day at an AI coding conference. Not as a speaker. Just as someone building something, paying attention, and occasionally wondering whether I was the least technical person in the room. The conversations were sharp. Some were uncomfortable. But one thread kept pulling at me, and it was not the one everyone expected.&lt;/p&gt;

&lt;p&gt;Nobody had clean answers. And that was actually useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Let me be honest about what most AI-in-tech conversations look like from the outside. Confident takes. Either the robots are coming for everything, or nothing is really changing and you should relax. The conference was not like that. It was full of people actively building things, actively unsure, and actively debating. That felt closer to reality.&lt;/p&gt;

&lt;p&gt;What I took away is not a prediction. It is more of a reframe. The question is not whether AI will change the job market. It obviously will. The more interesting question is who it changes things &lt;em&gt;for&lt;/em&gt;, and in which direction.&lt;/p&gt;

&lt;p&gt;The answer that kept coming back to me: the people who have historically been locked out. And at the top of that list, women.&lt;/p&gt;

&lt;h2&gt;
  
  
  Will AI replace software developers?
&lt;/h2&gt;

&lt;p&gt;Short answer: not the ones paying attention.&lt;/p&gt;

&lt;p&gt;The longer version is genuinely complicated. The role of Junior developers got some airtime at this conference, and not in a reassuring way. Some argue that entry-level roles will shrink because AI can now handle the scaffolding work that used to train those people. Others argue the opposite: that juniors who embrace AI tooling are actually more valuable right now, because they arrive without years of habits to unlearn and with a genuine appetite for the new workflow.&lt;/p&gt;

&lt;p&gt;Both arguments are probably true in different contexts. What seems less debatable is that the shape of the job is changing faster than job descriptions are. About 80% of enterprise AI projects reportedly fail, and the most cited reason is not the technology. It is people inside organisations who are not willing to leave their comfort zone, including, maybe especially, in leadership positions. The bottleneck is human, not algorithmic.&lt;/p&gt;

&lt;p&gt;So the developer who learns to work &lt;em&gt;with&lt;/em&gt; AI is not being replaced. They are being promoted past everyone who refused to adjust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can you build real things with AI if you are not a developer?
&lt;/h2&gt;

&lt;p&gt;This is the one that kept me up a little.&lt;/p&gt;

&lt;p&gt;Vibe coding, the practice of building working software through natural language prompts without writing traditional code, is not a gimmick anymore. It is clumsy in places, and I would not hand it a critical infrastructure project tomorrow. But the distance between an idea and a working prototype has collapsed. Significantly.&lt;/p&gt;

&lt;p&gt;What surprised me at the conference was who was least threatened by this. The coding bootcamps, the certification platforms, the learn-to-code institutions. You might expect them to be nervous. Most were not. Their argument: understanding the fundamentals still matters, because when the AI gets it wrong, you need to know what wrong looks like. The tool accelerates. It does not replace the need for judgment.&lt;/p&gt;

&lt;p&gt;I am not fully convinced, but I am not dismissing it either. I'll keep watching that space and report back.&lt;/p&gt;

&lt;h2&gt;
  
  
  What most people get wrong
&lt;/h2&gt;

&lt;p&gt;Everyone is framing this as a loss. Job cuts. Skill obsolescence. Industry disruption. That framing is real, but it is not the whole picture, and it is suspiciously centred on people who already had the advantage.&lt;/p&gt;

&lt;p&gt;The conversation that landed hardest for me was about women in tech. The argument, and I think it is a strong one, is that AI is one of the most significant equalising forces the industry has ever seen. Women have historically been underrepresented in tech roles, partly because of gatekeeping, partly because of credentials culture, partly because of how networking and sponsorship work in deeply homogenous industries. AI disrupts all three simultaneously.&lt;/p&gt;

&lt;p&gt;When the barrier to building something is no longer five years of computer science, but curiosity and the ability to ask the right questions, the landscape changes. The same logic applies to migrants, to people without elite degrees, to people in regions that were never close to a Silicon Valley pipeline.&lt;/p&gt;

&lt;p&gt;Globally, women hold around 26% of tech jobs, a number that has barely moved in a decade. The gender pay gap in tech sits somewhere between 16 and 28% depending on the market. Those are stubborn numbers. But when the tools change, the gatekeepers lose some of their leverage.&lt;/p&gt;

&lt;p&gt;This is worth sitting with. The technical debt that kept most people on the outside of the digital economy, the years of learning, the access to the right networks, the cost of entry, is being vaporised. Not completely. Not overnight. But faster than any previous shift in computing.&lt;/p&gt;

&lt;p&gt;And here is the asymmetry that nobody talks about enough: individuals can adapt faster than organisations. A person can learn a new tool this weekend. A corporation with legacy infrastructure, internal politics, and a middle management layer that is quietly terrified has to navigate all of that before it can even run a proper pilot. That is a structural advantage that currently sits with small teams, independent builders, and people who have nothing to unlearn.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every structural advantage that kept people out of tech is slowly becoming a software problem, and AI just shipped the patch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A note on Fleamio
&lt;/h2&gt;

&lt;p&gt;One thing I can speak to directly is what this shift looks like in practice for a small team. At Fleamio, we are a lean operation. We are not a legacy enterprise. We do not have layers of internal politics slowing down every experiment. When a new AI tool lands, we can pick it up, test it against a real problem, and decide within days whether it belongs in the workflow. That agility is not incidental. It is one of the few genuine structural advantages a small team holds over a funded competitor right now. The window where moving fast actually matters is open. We are using it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to actually do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If you are early in your career:&lt;/strong&gt; do not wait for clarity. The people debating whether to learn AI tooling are already behind the people using it. Pick one tool, build one real thing with it, understand where it breaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you have been out of tech or never felt like it was for you:&lt;/strong&gt; this is the most genuinely open window in a generation. The qualification inflation that kept the door closed for years is losing its grip. The entry cost has never been lower.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you are inside a large organisation:&lt;/strong&gt; the 80% failure rate on AI projects is almost certainly downstream of culture, not capability. The question to push internally is not "what tools are we buying" but "what are we actually willing to change about how decisions get made."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you are building something independently:&lt;/strong&gt; your advantage over incumbents is real right now, but it is time-limited. Organisations are slow, but they are not asleep. The window where a small team can move 10x faster than a funded competitor is open. Act accordingly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On the pay gap question:&lt;/strong&gt; if you are a woman, a migrant, or anyone who has been told the cost of entry into tech was too high, it is worth genuinely reassessing that right now. The tools changed. The old map is not reliable anymore.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>Do not build masks from translucent polygons</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Sat, 30 May 2026 04:51:37 +0000</pubDate>
      <link>https://dev.to/canceylan1988/do-not-build-masks-from-translucent-polygons-1ee0</link>
      <guid>https://dev.to/canceylan1988/do-not-build-masks-from-translucent-polygons-1ee0</guid>
      <description>&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;A map needed a fog-of-war effect: areas with data should feel visible, and areas without data should stay dark.&lt;/p&gt;

&lt;p&gt;The first implementation used circular buffer polygons around every data point. Each buffer had soft transition rings with different opacities. In isolation, one buffer looked reasonable.&lt;/p&gt;

&lt;p&gt;But once multiple data points were close together, the map turned into a mess of dark circular bands. The visual effect looked like stacked shadows instead of explored territory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root cause
&lt;/h2&gt;

&lt;p&gt;The mistake was using many translucent polygons for a masking problem.&lt;/p&gt;

&lt;p&gt;Map renderers blend every semi-transparent shape independently. If three rings overlap, their opacity stacks. If ten rings overlap, the area becomes much darker than intended.&lt;/p&gt;

&lt;p&gt;The system was technically doing the right thing. The model was wrong.&lt;/p&gt;

&lt;p&gt;A fog effect should answer one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How visible should this pixel be?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The polygon approach answered a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How many semi-transparent shapes happen to cover this pixel?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are not equivalent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it was non-obvious
&lt;/h2&gt;

&lt;p&gt;The bug hides because the first few test cases look fine.&lt;/p&gt;

&lt;p&gt;One circle creates a nice transition. Two circles still seem acceptable. Then real data arrives, nearby buffers overlap, and the renderer starts accumulating darkness in unpredictable-looking bands.&lt;/p&gt;

&lt;p&gt;This is especially easy to miss in AI-assisted UI work because the proposed solution sounds geospatially correct: "create buffer zones around covered areas." But the desired output was not a geographic fact. It was a visual effect.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix
&lt;/h2&gt;

&lt;p&gt;Use a single composited mask.&lt;/p&gt;

&lt;p&gt;The corrected implementation used a canvas layer above the map:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Draw one dark rectangle over the whole viewport.&lt;/li&gt;
&lt;li&gt;For each covered area, subtract a soft radial gradient from that dark layer.&lt;/li&gt;
&lt;li&gt;Redraw the canvas when the map moves, zooms, resizes, or receives new data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now overlaps reveal more of the map instead of adding more darkness.&lt;/p&gt;

&lt;p&gt;The important change was not canvas itself. It was changing the mental model:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One mask, many cutouts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Many transparent overlays.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Reusable rule
&lt;/h2&gt;

&lt;p&gt;Use map polygons for geographic facts.&lt;/p&gt;

&lt;p&gt;Use canvas, WebGL, or another compositing layer for visual masks.&lt;/p&gt;

&lt;p&gt;Good uses for polygons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;boundaries&lt;/li&gt;
&lt;li&gt;regions&lt;/li&gt;
&lt;li&gt;hex cells&lt;/li&gt;
&lt;li&gt;selected areas&lt;/li&gt;
&lt;li&gt;measured buffers that represent real spatial meaning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bad use for overlapping translucent polygons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fog-of-war&lt;/li&gt;
&lt;li&gt;spotlight effects&lt;/li&gt;
&lt;li&gt;progressive reveal&lt;/li&gt;
&lt;li&gt;darkness/lightness masks&lt;/li&gt;
&lt;li&gt;any effect where opacity should not depend on shape count&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the overlay is supposed to behave like a mask, build a mask. Do not approximate it with many semi-transparent geometries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical test
&lt;/h2&gt;

&lt;p&gt;Before shipping a visual map overlay, test it with clustered data.&lt;/p&gt;

&lt;p&gt;Sparse points can hide blending bugs. Dense points reveal whether the effect is truly composited or just stacked.&lt;/p&gt;

&lt;p&gt;If adding more data makes the overlay darker, louder, or ring-shaped, the rendering model is wrong.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Claude Is Overhyped. Codex Is Underrated. Here Is What Actually Happened When I Built Real Products With Both.</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Fri, 29 May 2026 20:55:46 +0000</pubDate>
      <link>https://dev.to/canceylan1988/claude-is-overhyped-codex-is-underrated-here-is-what-actually-happened-when-i-built-real-products-33bb</link>
      <guid>https://dev.to/canceylan1988/claude-is-overhyped-codex-is-underrated-here-is-what-actually-happened-when-i-built-real-products-33bb</guid>
      <description>&lt;h2&gt;
  
  
  The picture looks different now
&lt;/h2&gt;

&lt;p&gt;A few months ago I &lt;a href="https://dev.toLINK_TO_ORIGINAL"&gt;wrote about hiring two AI developers&lt;/a&gt; and the surprisingly human feeling of having to manage them. At the time I was still figuring out the dynamic. Now I have actually shipped products with both of them running in parallel, and the picture looks different. Not worse. Just sharper.&lt;/p&gt;

&lt;p&gt;This is not a Claude takedown. I want to be clear about that from the start. Claude is the reason I broke through a years-long wall of having ideas with no real way to implement them. That matters to me personally. But after running both agents through real production cycles, I have some honest things to say about where each one earns its money and where the hype does not hold up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters if you are building as a solo founder or small team
&lt;/h2&gt;

&lt;p&gt;Most AI coding conversations are still about single-agent setups. Someone opens Cursor or Claude, asks it to build something, and judges the tool by what comes out. That is a fine place to start. But once you are building products with actual users, real infrastructure, and moving parts that interact with each other, the single-agent model starts to show its limits.&lt;/p&gt;

&lt;p&gt;The moment I started treating these two tools as roles rather than alternatives, everything got faster and more stable. The question is not "which AI is better." The question is: better at what, and at which stage?&lt;/p&gt;

&lt;h2&gt;
  
  
  How does Claude perform for building real products?
&lt;/h2&gt;

&lt;p&gt;Still exceptional for the right tasks. Claude is my frontend developer and UX partner, full stop. Its design instincts are genuinely younger and fresher than anything Codex produces. When I give it a layout brief or a component to build, what comes back tends to feel modern, clean, and considered. It does not need much direction on visual hierarchy.&lt;/p&gt;

&lt;p&gt;For heavy implementation work, especially in the middle phases of building an MVP, Claude handles multitasking well. You can hand it several things at once and it manages them with decent coherence. Speed is real. If I need a working prototype that looks like a product rather than a proof of concept, Claude gets me there faster than anything else I have used.&lt;/p&gt;

&lt;p&gt;But here is the honest limitation. Claude is not great at knowing what it does not know. When something breaks at the deployment layer or the server behaves unexpectedly, Claude reasons from the code rather than from observed behaviour. It guesses intelligently, but it is still guessing. For debugging live environments, that gap becomes expensive quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does Codex actually do better than Claude?
&lt;/h2&gt;

&lt;p&gt;More than people give it credit for, particularly at the stages most developers skip or rush.&lt;/p&gt;

&lt;p&gt;I now start every project with Codex, not Claude. The planning and architecture phase is where it genuinely surprises me. It thinks like a product manager and a solutions architect at the same time, identifies edge cases before they exist, maps dependencies, and produces infrastructure decisions that hold up later. The plans need very little correction mid-build. That saves an enormous amount of back-and-forth downstream.&lt;/p&gt;

&lt;p&gt;The second place Codex outperforms is testing and deployment. This is the capability that I think is most underrated in public discussion. Codex can actually observe what is happening on a live server. It takes screenshots. It checks whether the implementation works in production, not just whether the code looks correct. That is a fundamentally different kind of intelligence for debugging. Claude tells you what the code says. Codex tells you what the product is actually doing.&lt;/p&gt;

&lt;p&gt;Codex also thinks more carefully about legal and compliance dimensions of code. Not perfectly, but noticeably. For anyone building in regulated contexts or even just thinking about data handling, it flags things that Claude would sail past without comment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What most people get wrong about dual AI workflows
&lt;/h2&gt;

&lt;p&gt;They treat it as a competition. They pick a side, defend it, and miss the point entirely.&lt;/p&gt;

&lt;p&gt;The workflow that is actually working for me looks like this: Codex plans and architects, Claude builds the frontend and implements the core product, both review each other's work (yes, I run cross-reviews deliberately, the 360-degree perspective catches things neither would catch alone), and then Codex takes the lead again for testing, deployment, and server-side debugging.&lt;/p&gt;

&lt;p&gt;The uncomfortable truth is that neither agent is dominant across the full stack. Claude is not the rocket I called it in the original article, it is more like a brilliant junior frontend architect. Codex is not just the wiring-checker, it is closer to a senior engineer who works more slowly but breaks fewer things in production.&lt;/p&gt;

&lt;p&gt;The hype around Claude specifically tends to come from people who are building prototypes and demos. Which is valid. Claude is exceptional at that. But once you are building something real, the production reliability of Codex starts to matter in ways that demo culture does not reward.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best AI workflow is not about picking a winner. It is about knowing which problem each agent was actually built to solve.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am still testing things here, including some newer capabilities I have heard about but not fully explored yet, particularly around how Codex handles longer-context architectural reasoning across large codebases. That is next on my list and I will keep people posted as the stack evolves.&lt;/p&gt;

&lt;p&gt;I also write about the product thinking side of building with AI tools. If you are interested in how the solo builder mindset connects to product strategy, that territory overlaps with what I cover in my notes on AI and product development.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to actually do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start every build with Codex, not Claude.&lt;/strong&gt; Use it to define your architecture, plan your data model, and map your infrastructure before a single line of code is written. The time you spend here is recovered threefold later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hand the frontend and MVP implementation to Claude.&lt;/strong&gt; Give it the vision that Codex defined and let it build fast. Do not micromanage the design decisions, it has better instincts there than you expect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run cross-reviews deliberately.&lt;/strong&gt; Let Claude review Codex's plans. Let Codex review Claude's implementation. The friction between the two agents surfaces things you would not find alone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return to Codex at deployment.&lt;/strong&gt; Do not try to debug live server behaviour with Claude. It is not built for that. Codex can observe the running product, not just the codebase, and that distinction matters when something is wrong in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resist the urge to pick one tool.&lt;/strong&gt; The efficiency gain from a dual setup is not marginal. It is structural. The two agents cover genuinely different parts of the software development lifecycle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat the workflow as a living thing.&lt;/strong&gt; Both tools are updating regularly. What is true about their relative strengths at the time of writing this may shift. Build the habit of re-evaluating, not just defending the setup that worked last month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The solo builder era is real. But it works best when you stop thinking about AI tools as replacements for a dev team and start thinking about them as a dev team with distinct roles that you actually have to manage.&lt;/p&gt;

</description>
      <category>techai</category>
    </item>
    <item>
      <title>Use a working-memory file as the handoff layer between AI coding sessions</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Fri, 22 May 2026 07:58:00 +0000</pubDate>
      <link>https://dev.to/canceylan1988/use-a-working-memory-file-as-the-handoff-layer-between-ai-coding-sessions-5cl7</link>
      <guid>https://dev.to/canceylan1988/use-a-working-memory-file-as-the-handoff-layer-between-ai-coding-sessions-5cl7</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;AI coding assistants are powerful — but stateless. Every new session starts cold. The agent doesn't know what was decided yesterday, why a particular approach was chosen, or what not to touch while something else is in progress.&lt;/p&gt;

&lt;p&gt;This creates invisible risk: the same wrong decision gets made twice, context gets re-explained from scratch every session, and two agents working in parallel can silently collide on the same files.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern
&lt;/h2&gt;

&lt;p&gt;Keep a &lt;code&gt;docs/working-memory.md&lt;/code&gt; file in the project root. It is not documentation. It is not a changelog. It is the shared, current-state brain of the project — meant to be read at the start of every session before any code is written.&lt;/p&gt;

&lt;p&gt;The file answers four questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What is the current architecture?&lt;/strong&gt; — the decisions that must not be undone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is in progress right now?&lt;/strong&gt; — the protected work that should not be touched&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is next?&lt;/strong&gt; — the agreed next step, not a wishlist&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What changed recently and why?&lt;/strong&gt; — enough context to reconstruct the reasoning
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Current Architecture&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Articles stored in Vercel KV via lib/content-db.ts
&lt;span class="p"&gt;-&lt;/span&gt; Git is the source of truth for code, not for content

&lt;span class="gu"&gt;## Next 2 Steps&lt;/span&gt;

&lt;span class="gu"&gt;### 1. Surface asset readiness in the existing UI&lt;/span&gt;
What to do: show distributionState.assets in article editor cards
What not to touch: do not replace the Articles tab structure

&lt;span class="gu"&gt;### 2. Extend provider fallback to remaining generation routes&lt;/span&gt;
What not to touch: do not add per-run ceremony

&lt;span class="gu"&gt;## Recent Decisions&lt;/span&gt;

&lt;span class="gu"&gt;### 2026-04-24&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; distributionState is now the per-article workflow record in KV
&lt;span class="p"&gt;-&lt;/span&gt; Lazy backfill: if missing, it is built on first read from socialPosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The update rule
&lt;/h2&gt;

&lt;p&gt;The file only works if it stays current. The rule is simple: whenever a non-trivial decision is made, it gets written here in the same session — before the session ends.&lt;/p&gt;

&lt;p&gt;Prefer facts over plans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what changed&lt;/li&gt;
&lt;li&gt;why it changed&lt;/li&gt;
&lt;li&gt;what must not be broken next time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid aspirational entries. If something was decided but not yet built, it belongs in a backlog, not here.&lt;/p&gt;

&lt;h2&gt;
  
  
  For multi-agent workflows
&lt;/h2&gt;

&lt;p&gt;When two agents (or a human and an agent) are working on the same codebase simultaneously, the working-memory file becomes a coordination layer.&lt;/p&gt;

&lt;p&gt;Designate a &lt;strong&gt;protected lane&lt;/strong&gt; — files and contracts that only one agent touches at a time. List what the other agent should not touch. This prevents merge collisions without requiring real-time communication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Parallel Lane For Claude&lt;/span&gt;

Claude can work on these areas while Codex works on the protected lane:
&lt;span class="p"&gt;1.&lt;/span&gt; test coverage
&lt;span class="p"&gt;2.&lt;/span&gt; documentation hygiene
&lt;span class="p"&gt;3.&lt;/span&gt; UI copy polish

Claude should not touch:
&lt;span class="p"&gt;-&lt;/span&gt; app/admin/page.tsx workflow rendering rewires
&lt;span class="p"&gt;-&lt;/span&gt; shared distributionState contract changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The working-memory file is where both agents agree on the boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a flat file beats a ticket system for this
&lt;/h2&gt;

&lt;p&gt;Ticket systems are great for task tracking. They are poor at preserving architectural reasoning in a form that an AI agent can read at the start of a session with zero additional context.&lt;/p&gt;

&lt;p&gt;A flat Markdown file in the repo has three advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is always co-located with the code — no separate system to open&lt;/li&gt;
&lt;li&gt;It can be read by an AI agent as part of the first tool call of a session&lt;/li&gt;
&lt;li&gt;It can be committed alongside code changes, making the decision and the implementation visible in the same diff&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The file does not replace PRs, commit messages, or decision logs. It is the short-term working memory that keeps sessions coherent until decisions stabilize into those longer-lived artifacts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anti-patterns to avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Making it too long.&lt;/strong&gt; Once it exceeds ~200 lines, agents start missing the critical parts. Keep it scannable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using it as a changelog.&lt;/strong&gt; Recent decisions should drop off after they are no longer at risk of being undone. Rotate old entries out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skipping the update.&lt;/strong&gt; The file is worthless if it is three sessions out of date. The update rule must be treated as non-negotiable, not optional.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>aitools</category>
    </item>
    <item>
      <title>Sequential vs Parallel Execution: when faster is the wrong answer</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Fri, 22 May 2026 07:57:43 +0000</pubDate>
      <link>https://dev.to/canceylan1988/sequential-vs-parallel-execution-when-faster-is-the-wrong-answer-2p1h</link>
      <guid>https://dev.to/canceylan1988/sequential-vs-parallel-execution-when-faster-is-the-wrong-answer-2p1h</guid>
      <description>&lt;p&gt;Every developer's first instinct when they see a loop is: &lt;em&gt;can I run this in parallel?&lt;/em&gt; Parallel means faster. And faster is better. Right?&lt;/p&gt;

&lt;p&gt;Not always.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the terms actually mean
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sequential execution&lt;/strong&gt; means tasks run one after another — task B starts only when task A finishes. Think of a single cashier at a supermarket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parallel execution&lt;/strong&gt; means tasks run simultaneously — A and B both run at the same time. Think of ten cashiers working at once.&lt;/p&gt;

&lt;p&gt;Parallel is faster. Sequential is safer and more predictable. Choosing between them is a tradeoff, not a free upgrade.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hidden cost of parallel
&lt;/h2&gt;

&lt;p&gt;When you run things in parallel, you introduce a new problem: &lt;strong&gt;shared state&lt;/strong&gt;. What happens when two tasks try to write to the same database row at the same time? What happens when two requests share the same session cookie?&lt;/p&gt;

&lt;p&gt;The short answer: unpredictable things. Race conditions. Corrupted data. Bans.&lt;/p&gt;

&lt;p&gt;This isn't theoretical. When building a price monitoring tool for a European consumer marketplace, the temptation was to parallelize keyword requests — hit 10 searches at once instead of one every 3 seconds. It would have been 10x faster. It also would have triggered the platform's anti-bot system within minutes.&lt;/p&gt;

&lt;p&gt;Most large European consumer platforms use bot-detection layers that monitor for non-human traffic patterns. A human browsing a marketplace would never fire 10 requests per second. The moment your code does, you're flagged.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule
&lt;/h2&gt;

&lt;p&gt;Sequential is the right default when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're hitting an &lt;strong&gt;external service with rate limiting or anti-bot&lt;/strong&gt; (most scrapers, payment APIs, social APIs)&lt;/li&gt;
&lt;li&gt;Tasks &lt;strong&gt;share a stateful session&lt;/strong&gt; — cookies, auth tokens, database connections&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Order matters&lt;/strong&gt; — step 2 depends on the result of step 1&lt;/li&gt;
&lt;li&gt;You're writing to a resource that &lt;strong&gt;doesn't support concurrent writes&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Parallel is the right choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tasks are &lt;strong&gt;truly independent&lt;/strong&gt; with no shared state&lt;/li&gt;
&lt;li&gt;You're hitting &lt;strong&gt;services you control&lt;/strong&gt; (your own API, your own database)&lt;/li&gt;
&lt;li&gt;The service &lt;strong&gt;explicitly supports high concurrency&lt;/strong&gt; (most cloud APIs with documented rate limits)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput is the priority&lt;/strong&gt; and you've verified safety&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  In practice
&lt;/h2&gt;

&lt;p&gt;A scraper that respects these rules runs sequentially with a fixed pause between requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;searches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;scrape_keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keyword&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;save_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# politeness delay
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;asyncio.gather()&lt;/code&gt;. No &lt;code&gt;ThreadPoolExecutor&lt;/code&gt;. The delay is the feature, not a bug.&lt;/p&gt;

&lt;p&gt;If the platform starts returning errors, the fix is to &lt;em&gt;increase&lt;/em&gt; the delay — not to add clever workarounds or reduce it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The professional term
&lt;/h2&gt;

&lt;p&gt;This tradeoff is often called the &lt;strong&gt;throughput vs. safety tradeoff&lt;/strong&gt; in distributed systems. In scraping contexts, the pause between requests is called a &lt;strong&gt;politeness delay&lt;/strong&gt; or &lt;strong&gt;request throttling&lt;/strong&gt;. The broader pattern of slowing requests to avoid detection is &lt;strong&gt;rate limiting&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you see these terms in documentation, they're telling you: this service expects you to be sequential.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>architecture</category>
    </item>
    <item>
      <title>The data isolation audit: every endpoint must be scoped to the requesting user</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Fri, 22 May 2026 07:57:26 +0000</pubDate>
      <link>https://dev.to/canceylan1988/the-data-isolation-audit-every-endpoint-must-be-scoped-to-the-requesting-user-370k</link>
      <guid>https://dev.to/canceylan1988/the-data-isolation-audit-every-endpoint-must-be-scoped-to-the-requesting-user-370k</guid>
      <description>&lt;h2&gt;
  
  
  The bug that's easy to miss in review
&lt;/h2&gt;

&lt;p&gt;You're building a multi-tenant application. A user can see their own data, not anyone else's.&lt;/p&gt;

&lt;p&gt;You add a new endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@router.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/searches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_searches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM searches WHERE active = 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You test it. It returns your searches. Works correctly — for you, because you're the only user in development.&lt;/p&gt;

&lt;p&gt;In production, with multiple users, it returns everyone's searches to everyone. The &lt;code&gt;user_id&lt;/code&gt; filter is missing. You have a data isolation breach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this happens
&lt;/h2&gt;

&lt;p&gt;Data isolation failures are rarely intentional. They happen because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The developer tested with a single user account and didn't observe the failure&lt;/li&gt;
&lt;li&gt;The filter was present in some query functions and assumed in others&lt;/li&gt;
&lt;li&gt;A refactor removed the filter accidentally&lt;/li&gt;
&lt;li&gt;The endpoint was copied from a public-data endpoint and the filter wasn't added&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Code review catches many bugs, but data isolation failures are hard to spot unless the reviewer is specifically looking for missing &lt;code&gt;user_id&lt;/code&gt; clauses on every query.&lt;/p&gt;

&lt;h2&gt;
  
  
  The systematic audit
&lt;/h2&gt;

&lt;p&gt;Before shipping any feature, audit every endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;For each endpoint that returns data:
  □ Does the query include WHERE user_id = current_user.id?
  □ OR is this data intentionally public? (document why)
  □ OR is this an admin endpoint? (require admin role check, not just auth)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For admin bypass, the filter must be explicit, not omitted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Wrong: admin bypass by omitting the filter
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM searches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM searches WHERE user_id = ?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Right: explicit bypass with documentation
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Admin can see all searches for support purposes
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM searches ORDER BY created_at DESC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The distinction matters for auditing. An omitted filter is invisible. An explicit &lt;code&gt;# Admin can see all&lt;/code&gt; comment is visible and intentional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing negative tests
&lt;/h2&gt;

&lt;p&gt;For each scoped endpoint, write a test that verifies cross-user access is blocked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_user_cannot_see_other_users_searches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# user_b creates a search
&lt;/span&gt;    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/searches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keyword&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_b&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# user_a fetches searches — should not see user_b's search
&lt;/span&gt;    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/searches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;slugs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keyword&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;slugs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This test fails immediately if the &lt;code&gt;user_id&lt;/code&gt; filter is missing. It cannot be accidentally removed during a refactor without breaking the test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Geolocation and sensitive fields: negative tests for field presence
&lt;/h2&gt;

&lt;p&gt;Some data isolation isn't about users — it's about which fields should never appear in any response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_api_response_contains_no_location_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location_lat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location_lng&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seller_address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These negative tests verify that sensitive fields are absent from the response. They're easy to write and catch the "I added a new field to the model and forgot to exclude it from the serialiser" class of bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule
&lt;/h2&gt;

&lt;p&gt;Every query that touches user data has &lt;code&gt;user_id = current_user.id&lt;/code&gt; in its WHERE clause, or a documented, tested reason why it doesn't. There is no middle ground.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>backend</category>
    </item>
    <item>
      <title>The Stock Market Feels Like Crypto Now. Here Is What I Am Actually Doing About It.</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Fri, 22 May 2026 07:53:17 +0000</pubDate>
      <link>https://dev.to/canceylan1988/the-stock-market-feels-like-crypto-now-here-is-what-i-am-actually-doing-about-it-5aac</link>
      <guid>https://dev.to/canceylan1988/the-stock-market-feels-like-crypto-now-here-is-what-i-am-actually-doing-about-it-5aac</guid>
      <description>&lt;p&gt;I have been avoiding this article for a few weeks.&lt;/p&gt;

&lt;p&gt;Not because I do not have thoughts on it. Because after my burnout, I made a deliberate choice to stop obsessing over my portfolio. Long-term, slow, boring investing had always worked better for me than the anxious tab-switching of short-term trading. Letting it go a little felt healthy. It probably was.&lt;/p&gt;

&lt;p&gt;But Q1 numbers are in. And something is shifting in a way that is hard to ignore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters right now
&lt;/h2&gt;

&lt;p&gt;Here is the thing about Q1 2026 that does not quite add up on paper. GDP growth came in soft. Inflation stayed sticky in both the US and Europe. Consumer confidence was weak. Tariff noise from renewed escalations under the Trump administration rattled markets through January and February.&lt;/p&gt;

&lt;p&gt;And yet. Major indices hit all-time highs.&lt;/p&gt;

&lt;p&gt;That gap between the economic mood music and where markets actually landed is what I keep coming back to. Money is not sitting in broad indices waiting for macro conditions to improve. It is moving. Decisively. Into very specific corners of the market.&lt;/p&gt;

&lt;p&gt;The AI investment wave is doing something structurally similar to what crypto did to speculative appetite in 2017 and again in 2021. Except this time it is not retail traders buying tokens at 2am. It is sovereign wealth funds, pension allocators, and the largest infrastructure investors in the world redirecting capital at a speed I genuinely did not expect to see this decade.&lt;/p&gt;

&lt;p&gt;So I stopped asking "what is the market doing right now" and started asking "what are the structural shifts already in motion that will not reverse regardless of a short-term recession or rate cycle." That reframe helped me think more clearly.&lt;/p&gt;

&lt;p&gt;Here is where I landed. None of this is investment advice. These are my personal observations and the lens through which I am thinking about my own allocation. Do your own research, and talk to someone qualified before making any decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the money is actually going: three macro themes I am tracking
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Energy infrastructure
&lt;/h3&gt;

&lt;p&gt;This one feels almost unsexy compared to the AI hype. But the numbers are staggering. AI data centres and automation systems require orders of magnitude more energy than the digital infrastructure we built in the 2010s. We are not ready for that demand curve.&lt;/p&gt;

&lt;p&gt;Hydrogen, solar, wind, and grid infrastructure are seeing renewed interest from a completely different demand source than before. It is not just climate policy. It is raw computational appetite. And energy infrastructure does not go to zero when an AI model gets outcompeted. The electrons still need to flow.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The AI infrastructure stack
&lt;/h3&gt;

&lt;p&gt;Most of the market conversation is here, but there are really three distinct sub-themes worth separating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rare earths and critical materials.&lt;/strong&gt; The hardware required to build and run AI, chips, cooling systems, sensors, storage, depends on materials with genuinely constrained supply chains. Ongoing US-China trade tensions are creating strategic urgency around sourcing. Slow burn, but the structural case is real.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hardware and data centre infrastructure.&lt;/strong&gt; Chip production, rack density, power distribution, cooling. This is where the arms race is most visible. The infrastructure layer tends to be less volatile than the application layer because it services everyone, regardless of which AI model wins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A shifting top of the market.&lt;/strong&gt; OpenAI is reportedly exploring a public market path. Anthropic is a legitimate enterprise alternative with differentiated positioning. The composition of the most valuable AI companies in five years will probably look different from today, and that has real implications for where capital flows.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Robotics and autonomous systems
&lt;/h3&gt;

&lt;p&gt;The longest time horizon of the three, but the investment infrastructure is being built right now.&lt;/p&gt;

&lt;p&gt;The hardware stack is already in a full capital cycle: sensors and LiDAR, radar systems, precision localisation, connectivity infrastructure (V2X, 5G private networks), and edge compute. Tesla remains interesting because it is operating across the full stack. But the more durable plays might be component suppliers who benefit regardless of which platform wins the consumer-facing race.&lt;/p&gt;

&lt;p&gt;One thing worth watching: SpaceX IPO speculation has been circulating seriously. If and when that happens, it would be one of the largest public listings in years. Worth having a plan for in advance rather than reacting in real time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What most people get wrong
&lt;/h2&gt;

&lt;p&gt;They treat it as a short-term trade.&lt;/p&gt;

&lt;p&gt;The AI infrastructure buildout is a multi-decade capital cycle. The companies that win in 2026 are not necessarily the ones that win in 2032. If you are buying into these themes expecting a clean 18-month return, you will probably sell at the wrong moment.&lt;/p&gt;

&lt;p&gt;A genuine risk worth naming: a short-term recession or credit event is still entirely possible. The macro picture in Q1 2026 is genuinely uncertain, tariff volatility is not resolved, and consumer balance sheets in the US are more stretched than the headline numbers suggest. A long-term structural thesis does not immunise you from a painful drawdown along the way.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the market starts behaving like crypto, the question is not whether to panic. It is whether your allocation was built for a world that no longer exists.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What to actually do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audit your current holdings for real exposure.&lt;/strong&gt; Pull up the top 10 underlying positions in any fund you hold. You may be less diversified than the fund name implies. Adjust from the actual holdings, not the label.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Think in layers, not bets.&lt;/strong&gt; Energy infrastructure, AI hardware, and robotics components carry three different risk and time profiles. Size them accordingly. Infrastructure tends to be more stable. Growth stocks and application-layer plays carry more variance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a portion boring on purpose.&lt;/strong&gt; The reallocation I am describing is not a wholesale pivot. It is a considered addition to a base that stays slow and steady. Do not let macro excitement push you into over-rotation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch for liquidity events.&lt;/strong&gt; A potential OpenAI IPO, a potential SpaceX listing, and continued rare earth ETF development in European markets are moments worth planning for in advance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not mistake volatility for opportunity without a thesis.&lt;/strong&gt; Some growth stock charts right now look extraordinary. That is not a reason to buy. The question is whether you understand why they are moving and whether that reason holds over the period you intend to hold.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talk to someone qualified before acting on any of this.&lt;/strong&gt; Genuinely. I am thinking out loud about my own allocation, not giving you a roadmap for yours.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Are there themes I missed? Probably. Biotech, longevity tech, and defence and aerospace are all conversations worth having in a future piece.&lt;/p&gt;

&lt;p&gt;For now: long on structural disruption, honest about short-term risk, and no longer pretending that the allocation I built in a different macro environment is still the right one.&lt;/p&gt;

</description>
      <category>financeinvesting</category>
    </item>
    <item>
      <title>Lazy backfill: roll out new data shapes without a migration script</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Mon, 18 May 2026 04:24:07 +0000</pubDate>
      <link>https://dev.to/canceylan1988/lazy-backfill-roll-out-new-data-shapes-without-a-migration-script-16g5</link>
      <guid>https://dev.to/canceylan1988/lazy-backfill-roll-out-new-data-shapes-without-a-migration-script-16g5</guid>
      <description>&lt;h2&gt;
  
  
  The instinct: write a migration script
&lt;/h2&gt;

&lt;p&gt;You add a new field to a stored record type. Existing records don't have it. The straightforward fix is a migration script: fetch every record, add the field, write it back.&lt;/p&gt;

&lt;p&gt;Migration scripts are fine for relational databases with schema enforcement. For document stores, KV stores, and any system where records are read more often than they are written, they create unnecessary operational risk:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The migration runs once, at a moment you choose, and you have to be present for it&lt;/li&gt;
&lt;li&gt;If it fails halfway through, you have partial state&lt;/li&gt;
&lt;li&gt;You need to coordinate the migration with the deployment of the code that expects the new field&lt;/li&gt;
&lt;li&gt;For large record sets, the migration may time out or hit rate limits&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The alternative: normalize on read
&lt;/h2&gt;

&lt;p&gt;Instead of migrating upfront, detect missing fields on every read and fill them lazily.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;normalizeRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Article&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// New field: distributionState — missing on older records&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;distributionState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;distributionState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;distributionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;distributionState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildDistributionState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;distributionMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getDistributionMap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;socialPosts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socialPosts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// New field: publishedAt — recoverable from legacy signals&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;publishedAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;published&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;publishedAt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;inferLegacyPublishedAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;changed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;distributionState&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;distributionState&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;publishedAt&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;publishedAt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Only write if something actually changed — prevents infinite write loops&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;changed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;distributionState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;publishedAt&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recordKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pattern works in three phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First read:&lt;/strong&gt; the field is missing, so it gets computed and written back. One KV write.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every subsequent read:&lt;/strong&gt; the field is present. The &lt;code&gt;!changed&lt;/code&gt; guard returns early. Zero extra writes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollout complete:&lt;/strong&gt; after every record has been read at least once, all records are normalized. No migration script was needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The changed-guard is critical
&lt;/h2&gt;

&lt;p&gt;Without the &lt;code&gt;changed&lt;/code&gt; check, the normalize function writes on every read — even when nothing changed. This turns every GET into a GET + SET, multiplying write load and potentially triggering unnecessary index updates.&lt;/p&gt;

&lt;p&gt;Use reference equality (&lt;code&gt;!==&lt;/code&gt;) for object fields: if the field was already present and you didn't build a new object, the reference is unchanged, and &lt;code&gt;changed&lt;/code&gt; stays false.&lt;/p&gt;

&lt;p&gt;For primitive fields (strings, booleans), compare values directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use this pattern
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good fit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding optional or derivable fields to stored records&lt;/li&gt;
&lt;li&gt;Fields that can be inferred from other existing data (timestamps from logs, structured state from legacy flat data)&lt;/li&gt;
&lt;li&gt;Systems where reads are frequent and records are accessed regularly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Not a good fit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fields that are required immediately at write time and cannot be inferred from existing data&lt;/li&gt;
&lt;li&gt;Schema changes that alter how existing fields are interpreted (requires explicit migration)&lt;/li&gt;
&lt;li&gt;Relational databases with foreign key constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The "what not to rewrite" rule
&lt;/h2&gt;

&lt;p&gt;Lazy backfill can introduce a subtle bug: if the derivation logic changes after some records have already been normalized, early-normalized records will have the old shape while un-normalized records will get the new shape.&lt;/p&gt;

&lt;p&gt;The fix: only backfill when the field is completely absent. Never rewrite an existing field just because the derivation logic changed. If the logic needs to change for existing records, that is a deliberate migration decision, not a lazy normalization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✓ Only backfill when missing&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;distributionState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;distributionState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildDistributionState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ✗ Don't rewrite existing state just because the build logic changed&lt;/span&gt;
&lt;span class="c1"&gt;// record.distributionState = buildDistributionState(record); // always overwrites&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This rule ensures the backfill is idempotent and safe to run in production without supervision.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Test what the toast cannot prove</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Mon, 18 May 2026 04:23:42 +0000</pubDate>
      <link>https://dev.to/canceylan1988/test-what-the-toast-cannot-prove-3jh1</link>
      <guid>https://dev.to/canceylan1988/test-what-the-toast-cannot-prove-3jh1</guid>
      <description>&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;An event form looked healthy from the outside. The user changed fields, clicked save, and saw a success toast.&lt;/p&gt;

&lt;p&gt;But the saved data was not trustworthy. Address changes could keep the previous map coordinates. The edit form accepted weak input. The create form had validation state that could drift from the data being submitted. The test suite did not catch it because it mostly checked that the dialog closed or that a success screen appeared.&lt;/p&gt;

&lt;p&gt;That is the dangerous part: the UI told the truth about the request finishing, not about the data being correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root cause
&lt;/h2&gt;

&lt;p&gt;The tests were proving the wrong contract.&lt;/p&gt;

&lt;p&gt;They asserted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the form could be filled&lt;/li&gt;
&lt;li&gt;the save button could be clicked&lt;/li&gt;
&lt;li&gt;the success state appeared&lt;/li&gt;
&lt;li&gt;the dialog closed&lt;/li&gt;
&lt;li&gt;the updated title was visible somewhere on the page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are useful smoke checks, but they are not persistence checks.&lt;/p&gt;

&lt;p&gt;For a real create/edit flow, the contract is bigger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the browser selected the intended autocomplete result&lt;/li&gt;
&lt;li&gt;the payload included the derived fields&lt;/li&gt;
&lt;li&gt;the server accepted only valid input&lt;/li&gt;
&lt;li&gt;the database stored the intended values&lt;/li&gt;
&lt;li&gt;the next read returns those values&lt;/li&gt;
&lt;li&gt;stale client cache did not hide a failed save&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the E2E test stops at the toast, a broken save path can still pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it was non-obvious
&lt;/h2&gt;

&lt;p&gt;Forms often have derived state.&lt;/p&gt;

&lt;p&gt;An address field might populate city, postal code, region, latitude, and longitude. A date field might generate opening-hour rows. A login dialog might resume a draft submit. An edit form might start with existing coordinates, then accidentally keep them after the address text changes.&lt;/p&gt;

&lt;p&gt;The visible input is only one layer. The meaningful saved record is the combination of typed fields, derived fields, validation, API behavior, and refetch behavior.&lt;/p&gt;

&lt;p&gt;That is why "I saw the new text on the card" can be misleading. The card may be optimistic, partially refreshed, or showing only one field while the broken field remains hidden.&lt;/p&gt;

&lt;h2&gt;
  
  
  The better E2E rule
&lt;/h2&gt;

&lt;p&gt;For important forms, every save test should have a readback assertion.&lt;/p&gt;

&lt;p&gt;After create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/create/i&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;heading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/created/i&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/items/mine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;uniqueName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Selected Street 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeCloseTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;48.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openingHours&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toContain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;09:00-18:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After edit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/save/i&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/items/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedAddress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeCloseTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedLongitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important move is not the exact API path. It is the discipline: test the persisted record after the UI says success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make external services deterministic
&lt;/h2&gt;

&lt;p&gt;Autocomplete and geocoding are classic sources of flaky tests. Do not depend on a live map provider in a form-save regression test.&lt;/p&gt;

&lt;p&gt;Mock the search endpoint with a known result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;**/api/geocode/search?**&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fulfill&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;display_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Selected Street 1, City&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;48.2000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;16.3000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;road&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Selected Street&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;house_number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;City&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the test verifies your app logic: dropdown selection, derived fields, payload, persistence, and readback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reusable rule
&lt;/h2&gt;

&lt;p&gt;A toast proves that code reached a happy branch. It does not prove that the right data survived the round trip.&lt;/p&gt;

&lt;p&gt;For any create/edit form with derived fields, cache, or autocomplete, write at least one E2E test that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;uses deterministic external-service mocks&lt;/li&gt;
&lt;li&gt;submits through the real UI&lt;/li&gt;
&lt;li&gt;reads back through the API&lt;/li&gt;
&lt;li&gt;asserts the fields users cannot easily see&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hidden fields are where save bugs like to live.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>testing</category>
    </item>
    <item>
      <title>Swipe Right on This: Dating Apps and LLMs Are Running the Same Playbook</title>
      <dc:creator>Can Ceylan</dc:creator>
      <pubDate>Thu, 14 May 2026 17:29:42 +0000</pubDate>
      <link>https://dev.to/canceylan1988/swipe-right-on-this-dating-apps-and-llms-are-running-the-same-playbook-2al0</link>
      <guid>https://dev.to/canceylan1988/swipe-right-on-this-dating-apps-and-llms-are-running-the-same-playbook-2al0</guid>
      <description>&lt;h1&gt;
  
  
  Swipe Right on This: Dating Apps and LLMs Are Running the Same Playbook
&lt;/h1&gt;

&lt;p&gt;Somewhere between my third Claude session and my seventh Tinder swipe, I noticed something strange. Both had cut me off.&lt;/p&gt;

&lt;p&gt;Not in a dramatic way. Just that quiet wall. "You've reached your limit." The digital equivalent of a bouncer pointing at the velvet rope.&lt;/p&gt;

&lt;h2&gt;
  
  
  The surface similarity is almost too obvious
&lt;/h2&gt;

&lt;p&gt;Dating apps and LLMs both gate their core functionality behind usage limits. Hourly caps, daily caps, weekly caps. You can do the thing, just not too much of the thing. And if you want more, you can pay for it.&lt;/p&gt;

&lt;p&gt;The root causes are completely different, which is what makes the parallel interesting rather than trivial.&lt;/p&gt;

&lt;p&gt;For LLMs, the limit is mostly honest. Inference is expensive. Running GPT-4 or Claude Opus at scale costs real money per token, and until the supply side catches up with demand, platforms have to ration access or go broke. The limit is infrastructure. It is temporary, at least in theory.&lt;/p&gt;

&lt;p&gt;For dating apps, the limit is a business model. Tinder is not rationing swipes because their servers are struggling. They are rationing swipes because scarcity is the product. You feel the limit. You feel the pull to remove it. That tension is the conversion funnel.&lt;/p&gt;

&lt;p&gt;Two completely different problems. Identical UX solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the limit might actually be doing you a favour
&lt;/h2&gt;

&lt;p&gt;Here is the uncomfortable part: the limit is probably good for you, even when the motivation behind it is purely commercial.&lt;/p&gt;

&lt;p&gt;Imagine a version of Tinder with no constraints. Unlimited swipes, no cooldown, no friction. For most people, that would not feel like freedom. It would feel like a slot machine with an infinite pull lever and no payout ceiling. The dopamine loop would eat the rest of your evening and a portion of your self-esteem.&lt;/p&gt;

&lt;p&gt;The limit forces something like intention. You get fifty swipes, so you start reading profiles. You get three free Claude messages on the heavy model, so you think before you type.&lt;/p&gt;

&lt;p&gt;Scarcity creates attention. Which is maybe why meditation teachers have been saying it for centuries, just without the app store rating.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The limit is not there to protect the platform. It is there to protect you from yourself, and then charge you when protection stops working.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The algo paradox nobody talks about
&lt;/h2&gt;

&lt;p&gt;Here is where it gets genuinely strange. Dating apps penalise overuse.&lt;/p&gt;

&lt;p&gt;Swipe too fast, too indiscriminately, and the algorithm quietly deprioritises your profile. Your reach drops. Your matches slow down. The platform is simultaneously selling you unlimited swipes and punishing you for using them.&lt;/p&gt;

&lt;p&gt;That is a product contradiction so strange it almost sounds made up. The commercial incentive says "engage more, pay more." The algorithmic incentive says "slow down or we will slow you down."&lt;/p&gt;

&lt;p&gt;I would genuinely love to spend a few weeks inside a Match Group product meeting to understand how they hold that tension. It must be a fascinating conversation. Or a deeply uncomfortable one.&lt;/p&gt;

&lt;p&gt;The LLM side does not have this paradox yet, because the limits are supply-side, not behavioural. But the question worth sitting with is: what happens when AI supply overtakes demand? When inference gets cheap enough that limits become optional rather than necessary?&lt;/p&gt;

&lt;p&gt;Will Anthropic and OpenAI discover what Tinder already knows? That the limit was never really about the infrastructure. That the moment before the paywall is the most valuable real estate in the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gender statistics nobody wants to say out loud
&lt;/h2&gt;

&lt;p&gt;While we are here, there is a structural problem with dating apps that LLMs might actually help fix, and it is bigger than anyone in the industry wants to advertise.&lt;/p&gt;

&lt;p&gt;The gender ratio on most major dating platforms sits somewhere around 70 to 30, men to women. Some platforms skew even further. That demographic imbalance creates a market dynamic that has nothing to do with romance and everything to do with supply and demand. Men compete furiously for attention. Women filter from abundance. Neither situation is particularly healthy for either side, but the apps profit from the friction regardless.&lt;/p&gt;

&lt;p&gt;It is less like dating and more like an ecosystem where one species massively outnumbers the other. The Serengeti, but with push notifications.&lt;/p&gt;

&lt;p&gt;What I find genuinely hopeful is the current wave of vibe-coded, LLM-assisted apps being built by people outside the traditional VC-backed dating industry. When the barrier to building a dating product drops low enough, someone will eventually build one with different incentive structures. Fairer matching mechanics. Less weaponised scarcity. Behavioural science used to create connection rather than to extract subscription revenue. Maybe I'll tackle that one day, my ADHD Brain wants to start it right away, however I have to focus on my current focus. Creating a flea market ecosystem that is better than the current ones. More on that, hopefully soon.&lt;/p&gt;

&lt;p&gt;I do not know what that could look like exactly. But I would bet (or I hope) it gets built in the next three years by someone using AI tools to move fast and a social science background to think clearly. I am watching this space, and I will keep you posted. Likewise, if you need help on doing that, hit me up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd actually do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Treat usage limits as useful friction, not just annoyance.&lt;/strong&gt; When an LLM or app cuts you off, use the pause to ask whether you were being intentional or just scrolling on autopilot. The limit is information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn the algorithm before you try to beat it.&lt;/strong&gt; On dating apps, quality signals matter more than volume. On LLMs, prompt quality matters more than prompt frequency. The platforms reward users who engage with intention.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you are building anything in the dating or social app space, look at what LLM tools have made newly possible.&lt;/strong&gt; The infrastructure cost of launching a niche dating product has dropped dramatically. The interesting white space is in underserved communities and fairer matching models, not in replicating Tinder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch what happens to LLM pricing over the next two years.&lt;/strong&gt; If compute costs drop fast enough, the current usage limits will become a choice rather than a necessity. How OpenAI and Anthropic handle that moment will tell you a lot about whether they think like infrastructure companies or like consumer apps. This is my personal read on where things are heading, not financial advice of any kind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;And if you are on a dating app right now, this is your sign to slow down.&lt;/strong&gt; Not because the algorithm will punish you if you do not, though it might. But because the best thing about the limit is that it gives you a moment to ask whether you actually want what you are chasing, or whether you have just been conditioned to chase it. That question is worth more than another fifty swipes.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>techai</category>
    </item>
  </channel>
</rss>
