<?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: Ed</title>
    <description>The latest articles on DEV Community by Ed (@olegkoval).</description>
    <link>https://dev.to/olegkoval</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F157742%2Fd033bbdd-b7bd-4d4f-86d8-48cc3be7a4d3.jpeg</url>
      <title>DEV Community: Ed</title>
      <link>https://dev.to/olegkoval</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olegkoval"/>
    <language>en</language>
    <item>
      <title>Your Terminal Is an AI Workspace Now</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Tue, 17 Mar 2026 11:23:23 +0000</pubDate>
      <link>https://dev.to/olegkoval/your-terminal-is-an-ai-workspace-now-m1n</link>
      <guid>https://dev.to/olegkoval/your-terminal-is-an-ai-workspace-now-m1n</guid>
      <description>&lt;p&gt;In 2025, something quietly changed about the terminal. It didn’t happen all at once. Claude Code arrived, then Cursor’s terminal mode, then AI agents running as background workers, streaming output continuously. Token-saving proxies started intercepting shell commands. Suddenly the terminal wasn’t just where you typed commands - it was where AI lived.&lt;/p&gt;

&lt;p&gt;I’d been on iTerm2 since 2015. Back then, switching from Linux to macOS, it was the first thing every senior engineer told me to install. For a decade it was invisible infrastructure - just there, doing its job. I didn’t think about it.&lt;/p&gt;

&lt;p&gt;AI made me think about it again. The lags. The memory. The realization that I couldn’t script it properly. And then, in a move that felt almost too on-brand, I had Claude Code do the migration for me.&lt;/p&gt;

&lt;p&gt;This is that story - and what an AI-optimised terminal actually looks like.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olko.substack.com/subscribe?" rel="noopener noreferrer"&gt;Subscribe now&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2015: When iTerm2 Was Still The Answer
&lt;/h2&gt;

&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21VHoO%21%2Cw_1456%2Cc_limit%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F5b80be49-8580-4ebb-90c8-055743a22cfc_666x457.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21VHoO%21%2Cw_1456%2Cc_limit%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F5b80be49-8580-4ebb-90c8-055743a22cfc_666x457.jpeg" title="iTerm2 - Mac OS Terminal Replacement" alt="iTerm2 - Mac OS Terminal Replacement" width="666" height="457"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;](&lt;a href="https://substackcdn.com/image/fetch/$s_!VHoO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b80be49-8580-4ebb-90c8-055743a22cfc_666x457.jpeg" rel="noopener noreferrer"&gt;https://substackcdn.com/image/fetch/$s_!VHoO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b80be49-8580-4ebb-90c8-055743a22cfc_666x457.jpeg&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;When I made the jump from Linux to macOS in 2015, the terminal was the first thing I felt homesick about. Linux gave you a raw, fast shell. macOS’s default Terminal.app felt like a toy.&lt;/p&gt;

&lt;p&gt;iTerm2 fixed that. Split panes, saved profiles, a hotkey window that dropped down on a keystroke, shell integration that tracked your working directory across tabs. For a developer coming from Linux, it was a genuine power tool. I set it up once and stopped thinking about it. That’s the highest praise you can give infrastructure.&lt;/p&gt;

&lt;p&gt;It worked invisibly for nearly a decade. Then three things started going wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The terminal started lagging.&lt;/strong&gt; Long output - build logs, test runs, streaming responses - would cause the window to stutter. Scrolling froze for a beat. The cursor fell behind what I was typing. This wasn’t dramatic, just irritating - until I started running Claude Code sessions. AI generates output fast, and iTerm2’s CPU-based renderer couldn’t keep up. My laptop fans would spin up during what was supposed to be a quiet coding session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My machine got sluggish.&lt;/strong&gt; Nothing I could point to directly, just swap pressure, slower context switches, the general feeling of running out of headroom. When I looked more carefully, iTerm2 was quietly eating 300-400MB across my open panes - on top of Cursor, Claude Code, Docker, and a local Redis already competing for memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I couldn’t script it.&lt;/strong&gt; I wanted to automate my window layout, send commands programmatically from scripts, have AI tools interact with the terminal as an API rather than just a UI. iTerm2 has AppleScript. That’s its answer to programmability. No socket, no remote protocol, no way to open a tab from a shell script without writing brittle AppleScript glue.&lt;/p&gt;

&lt;p&gt;None of these were dealbreakers on their own. Together, they were death by a thousand cuts - and all three had the same root cause: AI had moved into my terminal, and iTerm2 wasn’t built for a roommate.&lt;/p&gt;

&lt;p&gt;It’s not that iTerm2 got worse. It’s that the job description changed. In 2015, a terminal needed to display text reliably, manage tabs and splits, and stay out of the way. In 2026, it also needs to handle continuous high-volume output without stuttering, run lean alongside a full AI toolchain, and expose enough programmability for AI tools to treat it as a first-class interface. iTerm2 was built for the first set of requirements. Kitty was built closer to the second.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Migration That Migrated Itself
&lt;/h2&gt;

&lt;p&gt;Here is the prompt I gave Claude Code: &lt;em&gt;“Install Kitty and set it up the same way I have iTerm2 set up. Make it default for all editors and the system.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That’s it. What happened next took under 10 minutes of AI execution time.&lt;/p&gt;

&lt;p&gt;Claude Code read my iTerm2 preferences using &lt;code&gt;defaults read&lt;/code&gt; - the macOS command that dumps application settings from their binary plist format. From that output it extracted my font (Monaco 12), my color scheme (a custom light theme), window dimensions, and every keybinding I had configured.&lt;/p&gt;

&lt;p&gt;It installed &lt;a href="https://sw.kovidgoyal.net/kitty/" rel="noopener noreferrer"&gt;Kitty&lt;/a&gt; via Homebrew and wrote a &lt;code&gt;kitty.conf&lt;/code&gt; from scratch - ported colors to Kitty’s plain text format, mapped my split-pane shortcuts (Cmd+D for vertical, Cmd+Shift+D for horizontal), carried over the visual bell, inactive pane dimming, the lot. Then it opened my VS Code and Cursor settings files, found &lt;code&gt;terminal.external.osxExec: "iTerm.app"&lt;/code&gt; in both, and changed them to &lt;code&gt;"kitty.app"&lt;/code&gt;. Finally it installed &lt;code&gt;duti&lt;/code&gt; and registered Kitty as the default handler for shell file types using its bundle ID (&lt;code&gt;net.kovidgoyal.kitty&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;A human doing this manually - reading iTerm2 documentation, decoding a binary plist, translating color values between two different config formats, hunting for the right &lt;code&gt;duti&lt;/code&gt; incantation - would spend an hour. Easily. I know because I’ve done similar migrations before.&lt;/p&gt;

&lt;p&gt;Config migration is exactly the kind of task AI handles better than humans: tedious, well-documented, error-prone, with no room for creativity. AI doesn’t get bored halfway through and start approximating. It does all ten steps the same way.&lt;/p&gt;

&lt;p&gt;The irony wasn’t lost on me. I was using AI to build a terminal optimised for AI. The ouroboros of developer tooling.&lt;/p&gt;




&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an AI-Optimised Terminal Looks Like in 2026
&lt;/h2&gt;

&lt;p&gt;The full config is &lt;a href="https://gist.github.com/oleg-koval/77ff6d4332ee3c382ab24003f519afca" rel="noopener noreferrer"&gt;here&lt;/a&gt;. What follows is the philosophy behind it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The emulator: Kitty&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kitty is GPU-accelerated. This matters more than it sounds. When Claude Code streams a long response, or a BullMQ worker dumps a thousand lines of agent output, the renderer doesn’t choke. CPU usage stays flat. The fans stay quiet. That was the first thing I noticed after switching.&lt;/p&gt;

&lt;p&gt;The second thing: Kitty has a remote control protocol. With &lt;code&gt;allow_remote_control yes&lt;/code&gt; and a unix socket, other processes can send commands to Kitty - open a tab, split a pane, send keystrokes - without any GUI automation. This is the terminal as an API, not just a UI. AI tools can drive it programmatically.&lt;/p&gt;

&lt;p&gt;The third thing, which turns out to matter most: the config is a plain text file. &lt;code&gt;~/.config/kitty/kitty.conf&lt;/code&gt;. One file. Human-readable. Version-controllable. And - this is the key - fully legible to AI tools. iTerm2’s configuration lives in a binary plist that’s opaque to everything except iTerm2 itself. Kitty’s config is just text with clear semantics. That’s what made the migration possible in the first place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The AI layer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On top of Kitty, I run RTK - a personal tool that acts as a transparent proxy between Claude Code and the shell, compressing command output before it hits the token counter. It saves 60-90% on tokens for routine dev operations, wired in via Claude Code hooks so it’s invisible in normal use.&lt;/p&gt;

&lt;p&gt;Claude Code runs with &lt;code&gt;shell_integration enabled&lt;/code&gt;, which gives it awareness of the terminal state - working directory, running processes, exit codes. Cursor and VS Code both point to Kitty as their external terminal. The BullMQ agent workers that run my AI simulation backend stream their output through Kitty’s GPU renderer.&lt;/p&gt;

&lt;p&gt;The most useful consequence of a plain text config: the terminal is now AI-maintained. Need a new keybinding? I describe it to Claude Code. Want to port a color scheme from another tool? It reads the source format and writes the Kitty equivalent. The config is a living document that gets better over time without me manually editing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The shell layer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My zsh setup - Powerlevel10k, fzf, Atuin for shell history, zsh-autosuggestions - moved from iTerm2 to Kitty unchanged. This layer is terminal-agnostic. It doesn’t care what’s rendering it.&lt;/p&gt;

&lt;p&gt;That’s the point of the whole stack: Kitty renders, zsh orchestrates, AI tools inhabit. Each layer is independently replaceable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tool That Disappears
&lt;/h2&gt;

&lt;p&gt;The best infrastructure is invisible. You don’t think about your database when you’re writing a query; you think about the data. You don’t think about your terminal when you’re working; you think about the code.&lt;/p&gt;

&lt;p&gt;iTerm2 was invisible for ten years. Then the work changed, and it became visible - in the lag, the memory pressure, the AppleScript dead ends. Kitty is invisible again.&lt;/p&gt;

&lt;p&gt;That said: Kitty is not a drop-in replacement for everyone. There’s no GUI preferences pane - you edit a text file. The macOS integration is less polished; some things that just work in iTerm2 require config tweaks in Kitty. If you rely heavily on tmux integration, iTerm2’s implementation is more mature. And if you’re not running AI agents, worker processes, or heavy streaming output in your terminal, you probably won’t feel the difference. iTerm2 is still excellent software.&lt;/p&gt;

&lt;p&gt;But if your terminal has become an AI workspace - and for a growing number of engineers it has, or soon will - it’s worth thinking about whether your emulator was built for that world.&lt;/p&gt;

&lt;p&gt;Your terminal is the last tool that should slow down your AI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olko.substack.com/?utm_source=substack&amp;amp;utm_medium=email&amp;amp;utm_content=share&amp;amp;action=share" rel="noopener noreferrer"&gt;Share Olko - Tech/Engineering&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cli</category>
      <category>productivity</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Your Prompts Don't Have Tests. That's a Problem.</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Fri, 27 Feb 2026 11:34:28 +0000</pubDate>
      <link>https://dev.to/olegkoval/your-prompts-dont-have-tests-thats-a-problem-25g6</link>
      <guid>https://dev.to/olegkoval/your-prompts-dont-have-tests-thats-a-problem-25g6</guid>
      <description>&lt;p&gt;Nobody knows when a prompt got worse.&lt;/p&gt;

&lt;p&gt;I mean that literally. A teammate tweaks a system prompt on Tuesday - removes a constraint, adds a sentence. By Thursday the AI assistant is giving shorter, vaguer answers. Support tickets go up. On Monday someone finally traces it back to that one edit.&lt;/p&gt;

&lt;p&gt;No diff. No test. No review. The prompt lived in a Google Doc, and someone changed it the way you’d change a wiki page.&lt;/p&gt;

&lt;p&gt;I keep hearing the same story from different teams, and it always plays out the same way.&lt;/p&gt;

&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompts drift. Nobody notices.
&lt;/h2&gt;

&lt;p&gt;Once LLM systems move from prototype to production, a specific failure mode kicks in. Prompts drift - not dramatically, but incrementally. Someone adjusts wording. Someone switches the model. Someone adds a paragraph of context. Each change seems fine on its own. Nobody measures the cumulative effect.&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnracdlfqftcpzu0fjeh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbnracdlfqftcpzu0fjeh.png" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;](&lt;a href="https://substackcdn.com/image/fetch/$s_!8tSM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7117c66-13dc-417d-b866-198a394bab9b_1456x816.png" rel="noopener noreferrer"&gt;https://substackcdn.com/image/fetch/$s_!8tSM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7117c66-13dc-417d-b866-198a394bab9b_1456x816.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This is the LLM equivalent of configuration drift. The prompt that worked last month might not work today, and without measurement, you won’t know until a user complains or your API bill spikes with no explanation.&lt;/p&gt;

&lt;p&gt;The deeper issue: prompt quality is treated as vibes. An engineer writes a prompt, eyeballs the output, decides it’s “good enough,” and ships. No baseline. No regression check. No way to compare version A against version B.&lt;/p&gt;

&lt;p&gt;For any other production component, we’d call that reckless.&lt;/p&gt;

&lt;h2&gt;
  
  
  How this started
&lt;/h2&gt;

&lt;p&gt;I kept writing the same prompt structure by hand - persona, task decomposition, constraints, output format - and I kept doing it badly. Inconsistently. Forgetting sections. So I built a CLI that takes a rough intent and produces a structured prompt. No LLM call - the engine is rule-based and deterministic. It classifies your intent into one of eleven task types and applies the right structure.&lt;/p&gt;

&lt;p&gt;Here’s what that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;promptctl create &lt;span class="s2"&gt;"review auth middleware for security issues"&lt;/span&gt;
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Generates a structured prompt with:
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;- Security engineer persona
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;- OWASP-aligned review checklist
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;- Specific output format &lt;span class="o"&gt;(&lt;/span&gt;findings table, severity, remediation&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;promptctl cost &lt;span class="nt"&gt;--compare&lt;/span&gt;
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Shows token cost across 10 models before you spend anything
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Claude Sonnet 4.5: ~&lt;span class="nv"&gt;$0&lt;/span&gt;.018
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;GPT-5: ~&lt;span class="nv"&gt;$0&lt;/span&gt;.022
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;DeepSeek V3: ~&lt;span class="nv"&gt;$0&lt;/span&gt;.003
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Llama 4 Maverick: ~&lt;span class="nv"&gt;$0&lt;/span&gt;.001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful, but the real problem showed up when I looked at cost patterns.&lt;/p&gt;

&lt;p&gt;Unstructured prompts waste money in ways that aren’t obvious. The model rambles because nothing constrains it. You send follow-ups because the first response missed the point. Each retry costs tokens. Structured prompts consistently cost 55-71% less across ten models - not because the model gets cheaper, but because you need fewer calls and get tighter output.&lt;/p&gt;

&lt;p&gt;What surprised me: showing engineers the cost before they hit send changed their behavior more than any other feature. People make different choices when the price tag is visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treating prompts like code
&lt;/h2&gt;

&lt;p&gt;The interesting shift happened when I started thinking about prompts the way I think about any other artifact that changes over time.&lt;/p&gt;

&lt;p&gt;Here’s the pipeline:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwy03jq00a984t5csemw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftwy03jq00a984t5csemw.png" width="800" height="111"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;](&lt;a href="https://substackcdn.com/image/fetch/$s_!0NDK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0eac20-5aaf-4dc6-aa13-8c7eeb97d9b1_5589x780.png" rel="noopener noreferrer"&gt;https://substackcdn.com/image/fetch/$s_!0NDK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0eac20-5aaf-4dc6-aa13-8c7eeb97d9b1_5589x780.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Versioning.&lt;/strong&gt; A prompt template is a YAML file with variables and metadata. When you change the body, you bump the version. Old versions stay. You can diff them, you can roll back. We do this with code. Almost nobody does it with prompts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quality scoring.&lt;/strong&gt; The &lt;code&gt;--score&lt;/code&gt; flag evaluates prompt structure on a 0-100 scale: does the prompt match the intent, does it have clear sections and constraints, are there common mistakes like duplicate instructions or vague asks. It’s not a replacement for judgment - but it catches obvious failures before you burn tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Baseline comparison.&lt;/strong&gt; This is where it starts to feel like actual engineering. Concrete example:&lt;/p&gt;

&lt;p&gt;You have a code review template. Version 1 scores 82. You tweak the constraints and persona - that’s version 2. Before shipping v2, you evaluate it against the v1 baseline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;promptctl score &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;code-review &lt;span class="nt"&gt;--baseline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v1
&lt;span class="go"&gt;
Template: code-review
Current (v2): 78/100
Baseline (v1): 82/100
Delta: -4

⚠ Regression detected. v2 scores lower than baseline.
  - Structural quality dropped (missing constraint section)
  - Fidelity unchanged

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;promptctl record &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;code-review
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Saves v2 score to benchmark &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Next comparison will use v2 as the new baseline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvg5yraachje3rsoab36u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvg5yraachje3rsoab36u.png" width="800" height="1849"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;](&lt;a href="https://substackcdn.com/image/fetch/$s_!oVfc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0d0bd8d-7f07-48c7-84e5-3fb3b4be1d11_1485x3433.png" rel="noopener noreferrer"&gt;https://substackcdn.com/image/fetch/$s_!oVfc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0d0bd8d-7f07-48c7-84e5-3fb3b4be1d11_1485x3433.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Wire that into CI and prompt changes get the same regression gate as code changes. A PR that degrades prompt quality fails the pipeline, same as a PR that breaks a test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tradeoffs are real.&lt;/strong&gt; Versioning adds overhead - you have to decide what counts as a “new version” versus a minor edit. Deterministic evaluation at temperature=0 gives reproducible results but won’t tell you how the prompt behaves at higher temperatures or across different models. CI gating creates friction - engineers push back on quality gates for something they consider subjective. My counter: if this prompt runs in production and affects user-facing output, it should meet a minimum bar. And that bar should be measurable.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually learned building this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Determinism beats cleverness.&lt;/strong&gt; Early versions tried multi-model scoring with fancy aggregation. Output was non-reproducible. I ripped it out. Simple, deterministic evaluation on one model. Less impressive on a slide deck, actually useful for catching regressions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The generation engine has to be deep.&lt;/strong&gt; First version produced skeleton prompts - a heading for “Expert role,” a heading for “Constraints,” some placeholder text. Useless. Anyone could write that in thirty seconds. I rewrote the engine with domain knowledge: when someone says “build a virtual football manager,” it needs to surface match simulation mechanics, player attribute models, transfer market economics, engagement loops. Not “Subject: virtual football manager.” The prompt has to know what the user needs but hasn’t thought to ask for yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pipe-anywhere was the right call.&lt;/strong&gt; Everything goes to stdout. Pipe to Claude CLI, OpenAI CLI, clipboard, file. Cost tracking and scores go to stderr so they don’t pollute the output stream. Basic Unix philosophy, but a lot of developer tools get this wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feature creep kills CLI tools.&lt;/strong&gt; I kept wanting to add dashboards, team management, analytics. None of it belonged in a CLI. The rule I settled on: if it doesn’t make the next prompt better or cheaper, it doesn’t ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;The current version handles prompt creation, cost comparison, and quality scoring. The next step is persistent benchmarks - tracking how prompt versions perform over time, not just at the moment of creation.&lt;/p&gt;

&lt;p&gt;But there’s a bigger shift happening that matters more than any feature.&lt;/p&gt;

&lt;p&gt;Prompt engineering is becoming operational. Two years ago prompts were a novelty. Today they’re load-bearing. A chatbot resolves support tickets. An assistant generates code that ships to production. A summarizer produces reports that executives act on. The prompt is often the single biggest factor in output quality, and it’s the least tested part of the stack.&lt;/p&gt;

&lt;p&gt;We’ve seen this pattern before. Early DevOps was deployment scripts in a shared folder. They worked - until they didn’t. The shift from “deployment scripts” to “deployment pipelines” wasn’t a tooling change. It was teams recognizing that something critical needed discipline, not ad-hoc management.&lt;/p&gt;

&lt;p&gt;Prompt workflows are at that same point. The work happening now is useful but fragile. No regression protection. No quality history. No review process for the thing that most directly controls what your LLM produces.&lt;/p&gt;

&lt;p&gt;That will change. Not because prompt engineering is exciting or trendy, but because the cost of not doing it keeps going up. Every production LLM system that ships without prompt quality tracking is accumulating risk the same way teams accumulated risk shipping without tests in 2008.&lt;/p&gt;

&lt;p&gt;The question isn’t whether your prompts need regression protection. It’s how expensive the next silent failure has to be before you add it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is the first in a series on applying engineering discipline to LLM workflows. Next up: what happens when you actually run prompt regression testing on a real codebase.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmmepkpr2modqcd4h10n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmmepkpr2modqcd4h10n.png" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;](&lt;a href="https://substackcdn.com/image/fetch/$s_!P-Yz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe461f7fc-6c25-4db5-b8e6-5cc0ad9b1e14_1200x628.png" rel="noopener noreferrer"&gt;https://substackcdn.com/image/fetch/$s_!P-Yz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe461f7fc-6c25-4db5-b8e6-5cc0ad9b1e14_1200x628.png&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;promptctl is a free CLI. Install via brew&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; oleg-koval/tap/promptctl 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;or grab it from &lt;a href="https://prompt-ctl.com" rel="noopener noreferrer"&gt;prompt-ctl.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>softwareengineering</category>
      <category>testing</category>
    </item>
    <item>
      <title>I built a Cursor Skill that ships code</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Sat, 24 Jan 2026 08:13:01 +0000</pubDate>
      <link>https://dev.to/olegkoval/i-built-a-cursor-skill-that-ships-code-fkb</link>
      <guid>https://dev.to/olegkoval/i-built-a-cursor-skill-that-ships-code-fkb</guid>
      <description>&lt;h2&gt;
  
  
  The Problem Every AI-Assisted Developer Knows
&lt;/h2&gt;

&lt;p&gt;Last month I asked Cursor to build a dashboard. Simple request: “Build me an analytics dashboard with auth.”&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nmp0ilm7qgnd2y21s0e.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nmp0ilm7qgnd2y21s0e.jpeg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;](&lt;a href="https://substackcdn.com/image/fetch/$s_!VJpD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c55afa8-3783-4ec3-af88-2bec92eb0360_4896x3264.jpeg" rel="noopener noreferrer"&gt;https://substackcdn.com/image/fetch/$s_!VJpD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c55afa8-3783-4ec3-af88-2bec92eb0360_4896x3264.jpeg&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;What I got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;“What framework would you prefer?”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“Should I include dark mode?”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“What authentication provider?”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“Do you want SSO support?”&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Four questions before a single line of code. By the time I finished the interrogation, I could have scaffolded the project myself.&lt;/p&gt;

&lt;p&gt;This isn’t a Cursor problem. It’s an LLM problem. Models are trained to be helpful, and “helpful” often means clarifying requirements before committing to implementation. In a chatbot context, that’s reasonable. In a code editor where you’re paying per request and context window is precious, it’s friction.&lt;/p&gt;

&lt;p&gt;I spent a week building a Cursor skill that flips this behavior. The result: describe what you want, get working code. No clarifying questions unless genuinely ambiguous.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Cursor 2.4 Actually Enables
&lt;/h2&gt;

&lt;p&gt;Cursor’s &lt;a href="https://cursor.com/changelog/2-4" rel="noopener noreferrer"&gt;January 2025 release&lt;/a&gt; introduced two features that make this possible:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subagents&lt;/strong&gt; : Independent agents that handle discrete subtasks in parallel. Each gets its own context window, custom prompts, and tool access. The main agent delegates to specialists instead of trying to do everything in one thread.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image generation&lt;/strong&gt; : Generate mockups and assets directly from prompts. Save to your project’s assets folder. Useful for visualizing before building.&lt;/p&gt;

&lt;p&gt;The subagent architecture is the key innovation. Instead of one overloaded context trying to be a UI expert, database architect, and test writer simultaneously, you get specialists that excel at their domain.&lt;/p&gt;

&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Skill Architecture
&lt;/h2&gt;

&lt;p&gt;The skill lives in &lt;code&gt;.cursor/rules/&lt;/code&gt; and &lt;code&gt;.cursor/agents/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.cursor/
├── rules/
│ └── imagine-builder.mdc # Core behavior rules
└── agents/
    ├── ui-designer.md # Tailwind, shadcn, animations
    ├── schema-architect.md # Prisma, indexes, relations
    ├── api-builder.md # Routes, validation, auth
    └── test-writer.md # Vitest, RTL, Playwright

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main rule file (&lt;code&gt;imagine-builder.mdc&lt;/code&gt;) establishes the core principle: &lt;strong&gt;build first, ask later&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
description: AI Product Builder - Build functional products through conversation
globs: "**/*"
alwaysApply: true
---

# AI Product Builder

## Core Principles

1. **Build real products, not prototypes** - Every output should be deployable
2. **Infer intent aggressively** - Don't ask unnecessary clarifying questions
3. **Ship fast** - Prioritize working code over perfect code

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The “infer intent aggressively” directive is doing the heavy lifting. It tells the model to make reasonable assumptions based on context rather than seeking explicit confirmation for every decision.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Subagents Matter
&lt;/h2&gt;

&lt;p&gt;Consider a request like “Build a SaaS dashboard with org management and billing.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without subagents&lt;/strong&gt; , the main agent tries to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Design the database schema&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create API routes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build React components&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wire up auth&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add Stripe integration&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By step 3, the context window is polluted with schema definitions the model no longer needs to reference. Quality degrades.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With subagents&lt;/strong&gt; , the main agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Plans the architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delegates schema design to &lt;code&gt;@schema-architect&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delegates API routes to &lt;code&gt;@api-builder&lt;/code&gt; (in parallel)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delegates UI components to &lt;code&gt;@ui-designer&lt;/code&gt; (in parallel)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Aggregates results&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each specialist operates with clean context focused on its domain. The schema architect isn’t thinking about button hover states. The UI designer isn’t worrying about database indexes.&lt;/p&gt;

&lt;p&gt;Here’s what the schema architect subagent looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Schema Architect Subagent

You are a specialized database architect focused on designing 
scalable, efficient data models.

## Schema Design Principles

### 1. Always Include Audit Fields
model BaseModel {
  id String @id @default(cuid())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

### 2. Use Proper ID Strategies
- cuid() for distributed systems (default)
- uuid() for high-security requirements
- autoincrement() only for analytics tables

### 3. Soft Deletes for User Data
model User {
  deletedAt DateTime?
  isActive Boolean @default(true)
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The subagent includes complete code patterns, not abstract principles. When it generates a schema, it follows these patterns automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Default Stack Decision
&lt;/h2&gt;

&lt;p&gt;One of the hardest choices: what tech stack to default to when the user doesn’t specify?&lt;/p&gt;

&lt;p&gt;I went with:&lt;/p&gt;

&lt;p&gt;Layer Choice Rationale Framework Next.js 14 (App Router) Server components, great DX, wide adoption Language TypeScript (strict) Type safety catches bugs early Styling Tailwind + shadcn/ui Fast iteration, good defaults Database Prisma + PostgreSQL Type-safe queries, easy migrations Auth NextAuth.js Flexible, well-documented Validation Zod Runtime + compile-time safety&lt;/p&gt;

&lt;p&gt;These aren’t universally “best” choices. They’re &lt;strong&gt;sensible defaults&lt;/strong&gt; that work for most projects. The skill explicitly says: override these if you specify otherwise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Tech Stack Defaults

Unless user specifies otherwise:

- **Frontend** : React 18+ with TypeScript, Tailwind CSS, shadcn/ui
- **Backend** : Next.js App Router with Server Actions
- **Database** : Prisma with SQLite (dev) / PostgreSQL (prod)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The “(dev) / PostgreSQL (prod)” detail matters. SQLite for local development means zero setup. The schema is portable to Postgres when you deploy.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Output Actually Looks Like
&lt;/h2&gt;

&lt;p&gt;Request: “Build an expense tracking app with receipt uploads”&lt;/p&gt;

&lt;p&gt;Output (abbreviated):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// prisma/schema.prisma
model Expense {
  id String @id @default(cuid())
  amount Decimal @db.Decimal(10, 2)
  description String
  category Category @relation(fields: [categoryId], references: [id])
  categoryId String
  receipt String? // S3 URL
  userId String
  user User @relation(fields: [userId], references: [id])
  createdAt DateTime @default(now())

  @@index([userId, createdAt(sort: Desc)])
}

// app/api/expenses/route.ts
export async function POST(request: NextRequest) {
  const session = await auth();
  if (!session?.user) {
    return NextResponse.json(
      { success: false, error: { code: 'UNAUTHORIZED' }},
      { status: 401 }
    );
  }

  const formData = await request.formData();
  const result = createExpenseSchema.safeParse({
    amount: formData.get('amount'),
    description: formData.get('description'),
    categoryId: formData.get('categoryId'),
  });

  if (!result.success) {
    return NextResponse.json(
      { success: false, error: { code: 'VALIDATION_ERROR', details: result.error.flatten().fieldErrors }},
      { status: 400 }
    );
  }

  // Handle receipt upload...
  // Create expense...
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what’s &lt;em&gt;not&lt;/em&gt; there: no comments explaining what &lt;code&gt;@id&lt;/code&gt; does, no placeholder &lt;code&gt;// TODO: implement auth&lt;/code&gt;, no skeleton code. It’s complete, runnable, follows the established patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Trade-offs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;This approach works when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You want a working prototype fast&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The requirements are reasonably common (CRUD apps, dashboards, landing pages)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You’re comfortable reviewing and adjusting generated code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You trust the default stack choices&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This approach fails when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Requirements are genuinely ambiguous (”build something cool”)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You need an unusual stack (Remix, Hono, Drizzle)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The project has existing patterns the skill doesn’t know about&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You want educational explanations alongside code&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skill doesn’t replace understanding. It replaces boilerplate. If you don’t understand the code it generates, you’ll struggle to debug it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Making It Your Own
&lt;/h2&gt;

&lt;p&gt;The skill is MIT licensed and designed to be forked. Common customizations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Change the stack:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Tech Stack Defaults
- **Frontend** : Vue 3 + Nuxt
- **Database** : Drizzle ORM + SQLite

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add domain-specific subagents:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# E-commerce Specialist Subagent

You are an expert in building e-commerce systems.

## Patterns
- Always use optimistic UI for cart operations
- Implement idempotency keys for payment endpoints
- Use database transactions for inventory decrements

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Adjust the aggression level:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you want &lt;em&gt;some&lt;/em&gt; clarification, add conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Response Protocol

Ask for clarification ONLY when:
- Request involves external services not mentioned (Stripe, AWS, etc.)
- Security implications are unclear (public vs. private data)
- Multiple valid interpretations exist with different costs

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Broader Point
&lt;/h2&gt;

&lt;p&gt;AI coding assistants are converging on a question: should the model be a &lt;strong&gt;collaborator&lt;/strong&gt; (asks questions, explains trade-offs, teaches) or an &lt;strong&gt;executor&lt;/strong&gt; (takes requirements, ships code)?&lt;/p&gt;

&lt;p&gt;The answer is probably “both, depending on context.” But right now, most defaults lean heavily toward collaborator. That’s appropriate for learning, frustrating for shipping.&lt;/p&gt;

&lt;p&gt;Cursor’s subagent architecture lets you build specialized executors that know your patterns, your stack, your preferences. The main agent collaborates at the architecture level; the subagents execute at the implementation level.&lt;/p&gt;

&lt;p&gt;This is where AI coding tools are heading: not one general-purpose assistant, but orchestrated specialists that handle different phases of the development workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;The skill is on GitHub: &lt;a href="https://github.com/oleg-koval/cursor-product-builder" rel="noopener noreferrer"&gt;cursor-product-builder&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clone it, copy &lt;code&gt;.cursor/&lt;/code&gt; to your project, and ask it to build something. Start with something concrete: “Build a todo app with categories and due dates” rather than “build me something.”&lt;/p&gt;

&lt;p&gt;If you improve it, PRs welcome. Particularly interested in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Alternative stack presets (Vue, Svelte, HTMX)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Domain-specific subagents (e-commerce, fintech, devtools)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better test generation patterns&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This is part of my series on distributed systems and developer tooling. &lt;a href="https://olko.substack.com/" rel="noopener noreferrer"&gt;Subscribe&lt;/a&gt; for more deep dives on the infrastructure that actually runs production systems.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olko.substack.com/subscribe?" rel="noopener noreferrer"&gt;Subscribe now&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question for readers&lt;/strong&gt; : What’s your experience with AI code assistants? Too many questions? Not enough? Have you built custom rules or prompts that changed the behavior significantly? Drop a comment - curious what patterns others have found.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>tooling</category>
    </item>
    <item>
      <title>33 Million Accounts Exposed: What the Condé Nast Breach Teaches Engineering Leaders</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Sun, 28 Dec 2025 10:09:34 +0000</pubDate>
      <link>https://dev.to/olegkoval/33-million-accounts-exposed-what-the-conde-nast-breach-teaches-engineering-leaders-53on</link>
      <guid>https://dev.to/olegkoval/33-million-accounts-exposed-what-the-conde-nast-breach-teaches-engineering-leaders-53on</guid>
      <description>&lt;p&gt;Here’s what happened, what went wrong, and the concrete steps you should implement Monday morning.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Breach in Brief
&lt;/h2&gt;

&lt;p&gt;An attacker exploiting multiple vulnerabilities in Condé Nast’s systems exfiltrated data on 33 million user accounts across their publication portfolio - including WIRED, Vogue, The New Yorker, and others. The compromised data included email addresses, names, phone numbers, physical addresses, gender, and usernames.&lt;/p&gt;

&lt;p&gt;The attacker initially posed as a security researcher seeking responsible disclosure. When Condé Nast failed to respond for weeks, 2.3 million WIRED records ended up leaked publicly and indexed by Have I Been Pwned.&lt;/p&gt;

&lt;p&gt;As of this writing, Condé Nast has issued no public statement.&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1765410845769-9c931a7728b7%3Ffm%3Djpg%26q%3D60%26w%3D3000%26ixlib%3Drb-4.1.0%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1765410845769-9c931a7728b7%3Ffm%3Djpg%26q%3D60%26w%3D3000%26ixlib%3Drb-4.1.0%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D" title="Abstract glitch art with red and white lines" alt="Abstract glitch art with red and white lines" width="3000" height="1629"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;](&lt;a href="https://images.unsplash.com/photo-1765410845769-9c931a7728b7?fm=jpg&amp;amp;q=60&amp;amp;w=3000&amp;amp;ixlib=rb-4.1.0&amp;amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" rel="noopener noreferrer"&gt;https://images.unsplash.com/photo-1765410845769-9c931a7728b7?fm=jpg&amp;amp;q=60&amp;amp;w=3000&amp;amp;ixlib=rb-4.1.0&amp;amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&lt;/a&gt;)&lt;/p&gt;




&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five Systemic Failures
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. No Vulnerability Disclosure Infrastructure
&lt;/h3&gt;

&lt;p&gt;Condé Nast—a multi-billion dollar media conglomerate—had no &lt;code&gt;security.txt&lt;/code&gt; file. No clear process for reporting vulnerabilities. The attacker spent days trying to find someone to contact.&lt;/p&gt;

&lt;p&gt;This is inexcusable for any organization handling user data, let alone 33 million accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Zero Response to Disclosure Attempts
&lt;/h3&gt;

&lt;p&gt;Multiple contact attempts via email and through WIRED staff went unanswered for weeks. The security team only engaged after a third-party blogger intervened repeatedly.&lt;/p&gt;

&lt;p&gt;This silence transformed a potential controlled disclosure into a public breach.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. API Authorization Failures at Scale
&lt;/h3&gt;

&lt;p&gt;The vulnerabilities reportedly allowed attackers to view any account’s information and change any account’s email and password. This pattern—IDOR (Insecure Direct Object Reference) combined with broken access controls—suggests fundamental failures in API security architecture.&lt;/p&gt;

&lt;p&gt;When an attacker can enumerate 33 million records, you don’t have a vulnerability. You have an architectural deficiency.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. No Rate Limiting or Anomaly Detection
&lt;/h3&gt;

&lt;p&gt;Downloading 33 million user records takes time and generates traffic. Either no monitoring existed, or alerts were ignored. Both scenarios indicate operational blind spots.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Post-Breach Silence
&lt;/h3&gt;

&lt;p&gt;Even after data appeared on breach forums and HIBP, Condé Nast issued no public acknowledgment. Users whose data was exposed learned about it from security bloggers, not the company entrusted with their information.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prevention Checklist for Engineering Leaders
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Disclosure Infrastructure (Implement This Week)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Deploy a &lt;code&gt;security.txt&lt;/code&gt; file at &lt;code&gt;/.well-known/security.txt&lt;/code&gt; with contact email, PGP key, and expected response timeframe&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Establish a dedicated &lt;code&gt;security@&lt;/code&gt; alias routed to a monitored, triaged queue—not a black hole&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Define SLAs: acknowledge within 24 hours, triage within 72 hours, remediation timeline within 7 days&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consider a vulnerability disclosure program (VDP) or bug bounty—even a modest one signals maturity&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Security Architecture (Q1 Priority)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Audit all endpoints for authorization checks: never rely on obscurity of IDs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implement rate limiting per endpoint, per user, and per IP—with graduated responses&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enforce object-level authorization: every request must validate the authenticated user has permission to access the specific resource&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploy anomaly detection on bulk data access patterns: 33 million sequential reads should trigger alerts within minutes&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Incident Response Readiness
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Document and drill an incident response playbook quarterly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pre-draft breach notification templates for regulators and affected users—you won’t have time during a crisis&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Establish a cross-functional incident team: engineering, legal, communications, and executive sponsor&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Define escalation triggers and communication protocols before you need them&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Monitoring and Detection
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Log all authentication events, password changes, and bulk data access&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alert on mass enumeration patterns: sequential ID access, unusual query volumes, scraping signatures&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implement honeypot records in your database that trigger alerts when accessed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conduct purple team exercises: have your own team attempt exfiltration and measure detection time&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Organizational Dimension
&lt;/h2&gt;

&lt;p&gt;Technical controls matter, but this breach also exposed cultural failures.&lt;/p&gt;

&lt;p&gt;When disclosure attempts go unanswered for weeks, it signals that security is someone else’s problem—or no one’s. Lead engineers must ensure that vulnerability reports reach people empowered to act, not bureaucratic dead ends.&lt;/p&gt;

&lt;p&gt;When breaches happen (and they will), the first hour matters. Having legal and communications aligned in advance isn’t optional. The absence of any public statement from Condé Nast isn’t prudent caution—it’s reputational damage compounding daily.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Means for Your Organization
&lt;/h2&gt;

&lt;p&gt;The Condé Nast breach wasn’t caused by zero-days or nation-state actors. It was caused by missing basics: no disclosure process, unmonitored APIs, and organizational silence.&lt;/p&gt;

&lt;p&gt;If you’re a lead engineer or responsible person, ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Can a security researcher contact us easily right now?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Would we know if someone was enumerating our user database?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do we have a communication plan ready for breach disclosure?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the answer to any of these is “no” or “I’m not sure,” you have work to do.&lt;/p&gt;

&lt;p&gt;The attackers aren’t getting less sophisticated. But in this case, they didn’t need to be.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What’s your organization’s disclosure process? I’m curious how other engineering teams handle vulnerability reports—especially at scale. Drop a comment or reply.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olko.substack.com/p/33-million-accounts-exposed-what/comments" rel="noopener noreferrer"&gt;Leave a comment&lt;/a&gt;&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>privacy</category>
      <category>security</category>
    </item>
    <item>
      <title>When Someone Dismisses Your Work. Why You Should Keep Building Anyway</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Sun, 07 Dec 2025 11:32:18 +0000</pubDate>
      <link>https://dev.to/olegkoval/when-someone-dismisses-your-work-why-you-should-keep-building-anyway-503o</link>
      <guid>https://dev.to/olegkoval/when-someone-dismisses-your-work-why-you-should-keep-building-anyway-503o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1704968806827-469f486e4445%3Ffm%3Djpg%26q%3D60%26w%3D3000%26ixlib%3Drb-4.1.0%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1704968806827-469f486e4445%3Ffm%3Djpg%26q%3D60%26w%3D3000%26ixlib%3Drb-4.1.0%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D" title="a little girl pushing a wagon with a statue of a man in the background" alt="a little girl pushing a wagon with a statue of a man in the background" width="760" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I came across a post that summarized a mindset many engineers know too well.&lt;/p&gt;

&lt;p&gt;The author argued that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the AI bubble is about to collapse&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“real engineers” will return to low-level tools like Zig&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;modern frameworks and simple app domains (especially todo apps) are “just vibe coding”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;most developers today are not serious enough&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;only hardcore, old-school engineering counts&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No names needed. You’ve seen this type of sentiment before.&lt;/p&gt;

&lt;p&gt;It is a mix of nostalgia, irritation at hype cycles, and a belief that anything simple is automatically trivial.&lt;/p&gt;

&lt;p&gt;If you are building something today, this kind of message can hit unexpectedly hard.&lt;/p&gt;

&lt;p&gt;Especially if your current project looks “simple from the outside”.&lt;/p&gt;

&lt;p&gt;It can make you feel like your work is not substantial.&lt;/p&gt;

&lt;p&gt;Like your domain is not respectable.&lt;/p&gt;

&lt;p&gt;Like you are wasting time.&lt;/p&gt;

&lt;p&gt;That reaction is human.&lt;/p&gt;

&lt;p&gt;But it does not reflect reality.&lt;/p&gt;

&lt;p&gt;Here is the reality.&lt;/p&gt;

&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. A simple domain does not make you a weak engineer&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Todo projects look basic to people who never built one properly.&lt;/p&gt;

&lt;p&gt;The moment you add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;authentication&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;sync logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;permissions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;offline support&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;clean architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;performance constraints&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;mobile/web parity&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;design decisions for real users&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…the “simplicity” disappears.&lt;/p&gt;

&lt;p&gt;Trello was “just a board”.&lt;/p&gt;

&lt;p&gt;Linear was “just issues”.&lt;/p&gt;

&lt;p&gt;Notion was “just an editor”.&lt;/p&gt;

&lt;p&gt;Everything looks trivial until you build it well.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. Hype or anti-hype does not define your value&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Some people react to AI hype with frustration.&lt;/p&gt;

&lt;p&gt;Some defend older ecosystems like Zig, Rust, C, Vim.&lt;/p&gt;

&lt;p&gt;Some prefer JS, TS, Python.&lt;/p&gt;

&lt;p&gt;Some love LLM-assisted workflows.&lt;/p&gt;

&lt;p&gt;These are perspectives, not universal truths.&lt;/p&gt;

&lt;p&gt;Your right to build is not dependent on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;someone else’s taste&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;someone else’s nostalgia&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;someone else’s frustration with the industry&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;someone else’s idea of “real engineering”&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The only thing that defines the seriousness of your work is how you execute it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Every project is a training ground for real skills&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Even the simplest domain forces you to learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;systems thinking&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;clean abstractions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;readable code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;data modelling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;handling real-world edge cases&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;making trade-offs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;designing for maintainability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;iterating and shipping&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is engineering.&lt;/p&gt;

&lt;p&gt;Not ideology. Not hype.&lt;/p&gt;

&lt;p&gt;Practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Dismissive takes are noise. Your progress is signal.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;People online can say whatever they want.&lt;/p&gt;

&lt;p&gt;They do not see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;your architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;your reasoning&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;your growth&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;your consistency&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;your ability to refine, fix, and finish&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They comment.&lt;/p&gt;

&lt;p&gt;You build.&lt;/p&gt;

&lt;p&gt;Those are different worlds.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;5. Keep building, even if someone belittles your path&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Every engineer hits moments where a throwaway opinion cuts into motivation.&lt;/p&gt;

&lt;p&gt;Where someone’s “hot take” makes your work feel small.&lt;/p&gt;

&lt;p&gt;Where you suddenly doubt the value of what you are doing.&lt;/p&gt;

&lt;p&gt;The answer is simple.&lt;/p&gt;

&lt;p&gt;Keep going.&lt;/p&gt;

&lt;p&gt;What you build, what you ship, what you learn -that is what counts.&lt;/p&gt;

&lt;p&gt;Not commentary. Not condescension. Not hierarchy of “real” and “not real” engineering.&lt;/p&gt;

&lt;p&gt;The industry moves forward because of people who show up and create.&lt;/p&gt;

&lt;p&gt;And if you are one of them, your work matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;The Reality Behind All the Noise&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There is a recurring character in tech who loves announcing what counts as “real engineering”.&lt;/p&gt;

&lt;p&gt;They deliver manifestos instead of products, write diagnoses instead of code, and somehow always know exactly what everyone else should be building.&lt;/p&gt;

&lt;p&gt;It would almost be impressive if it wasn’t so predictable.&lt;/p&gt;

&lt;p&gt;This type doesn’t talk about your work.&lt;/p&gt;

&lt;p&gt;They talk about &lt;em&gt;any&lt;/em&gt; work they’re not doing themselves.&lt;/p&gt;

&lt;p&gt;Their formula is simple:&lt;/p&gt;

&lt;p&gt;When they slow down, they preach.&lt;/p&gt;

&lt;p&gt;When they stop shipping, they set standards.&lt;/p&gt;

&lt;p&gt;When they feel irrelevant, they declare which domains “matter”.&lt;/p&gt;

&lt;p&gt;It is the safest place to be — above the builders, below the responsibility.&lt;/p&gt;

&lt;p&gt;That mindset doesn’t deserve outrage.&lt;/p&gt;

&lt;p&gt;It deserves indifference.&lt;/p&gt;

&lt;p&gt;Because the only thing that shuts down this performance is progress they are not part of.&lt;/p&gt;

&lt;p&gt;Nothing is colder than quietly moving forward while others debate definitions of “real engineering”.&lt;/p&gt;

&lt;p&gt;Let them keep writing their think-pieces.&lt;/p&gt;

&lt;p&gt;Let them keep defining seriousness from the sidelines.&lt;/p&gt;

&lt;p&gt;People who build don’t need permission.&lt;/p&gt;

&lt;p&gt;And they don’t seek validation from those who stopped.&lt;/p&gt;

&lt;p&gt;Thanks for reading Olko - Tech/Engineering! This post is public so feel free to share it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olko.substack.com/p/when-someone-dismisses-your-work?utm_source=substack&amp;amp;utm_medium=email&amp;amp;utm_content=share&amp;amp;action=share" rel="noopener noreferrer"&gt;Share&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;___&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olko.substack.com/p/when-someone-dismisses-your-work/comments" rel="noopener noreferrer"&gt;Leave a comment&lt;/a&gt;&lt;/p&gt;

</description>
      <category>motivation</category>
      <category>mentalhealth</category>
      <category>discuss</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>From Idea to Impact: Applying the "RADIO-AI" Pattern for Effortless AI Agent MVPs</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Wed, 26 Nov 2025 12:27:10 +0000</pubDate>
      <link>https://dev.to/olegkoval/from-idea-to-impact-applying-the-radio-ai-pattern-for-effortless-ai-agent-mvps-5gon</link>
      <guid>https://dev.to/olegkoval/from-idea-to-impact-applying-the-radio-ai-pattern-for-effortless-ai-agent-mvps-5gon</guid>
      <description>&lt;h2&gt;
  
  
  Why Most AI Projects Stall - and How to Fix It
&lt;/h2&gt;

&lt;p&gt;We all know the feeling: a flash of inspiration for the “next big thing” (a killer recommendation engine, an email assistant) - but too often, execution gets lost in the weeds.&lt;/p&gt;

&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The real secret?&lt;/strong&gt; Structure. The difference between endless tinkering and delivering something amazing is a system you can rely on, especially as you iterate.&lt;/p&gt;

&lt;p&gt;Today, I’ll share the “RADIO-AI” pattern- a system design framework distilled for rapid, scalable, maintainable AI integrations. Inspired by modern social app architectures and proven engineering practice, it’s your shortcut to building MVPs that actually ship.&lt;/p&gt;




&lt;h2&gt;
  
  
  The RADIO-AI Pattern: Five Steps to Realising AI Goals
&lt;/h2&gt;

&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1670234192944-5d5d06b762be%3Ffm%3Djpg%26q%3D60%26w%3D3000%26ixlib%3Drb-4.1.0%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimages.unsplash.com%2Fphoto-1670234192944-5d5d06b762be%3Ffm%3Djpg%26q%3D60%26w%3D3000%26ixlib%3Drb-4.1.0%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D" title="an old radio on a table" alt="an old radio on a table"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;](&lt;a href="https://images.unsplash.com/photo-1670234192944-5d5d06b762be?fm=jpg&amp;amp;q=60&amp;amp;w=3000&amp;amp;ixlib=rb-4.1.0&amp;amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" rel="noopener noreferrer"&gt;https://images.unsplash.com/photo-1670234192944-5d5d06b762be?fm=jpg&amp;amp;q=60&amp;amp;w=3000&amp;amp;ixlib=rb-4.1.0&amp;amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;strong&gt;Requirements: Focus on What Matters&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Define what your AI agent should do.&lt;br&gt;&lt;br&gt;
&lt;em&gt;Don’t boil the ocean.&lt;/em&gt; Start with one pain-point: “Auto-tag my photos,” “Summarize my chats,” or “Offer smarter search results.”&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Functional&lt;/strong&gt; : What is the &lt;em&gt;one&lt;/em&gt; user story?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Non-Functional&lt;/strong&gt; : How fast should it respond? Does it need to be explainable?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. &lt;strong&gt;Architecture: Strong Foundations, Fast Iterations&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Lay out where AI fits in your flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Frontend&lt;/em&gt;: Does the agent spark in the UI, or work quietly behind-the-scenes?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Layering&lt;/em&gt;: Keep code modular (think: plug-and-play). One place for core logic; one for presentation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Evolve without fear&lt;/em&gt;: Use feature flags to test and swap models painlessly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. &lt;strong&gt;Data Model: Speak the Agent’s Language&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Good contracts = less tech debt, more speed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inputs/Outputs&lt;/strong&gt; : Sketch what your agent receives/returns (draw a simple JSON or TypeScript interface).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feedback Loop&lt;/strong&gt; : Log every decision- future-you (or your users) can help refine the magic.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. &lt;strong&gt;Interface: Make It Plug-and-Play&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Expose clear, &lt;em&gt;simple&lt;/em&gt; APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;REST, GraphQL, or event-driven - whatever matches your stack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Power users can hook in, but even your UI “just works.”&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. &lt;strong&gt;Optimization: Iterate Like the Pros&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cache clever answers for speed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bake in user feedback for smarter AI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use toggles: Roll out changes to a few, observe, tweak, repeat.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🎯 How Simple Can It Be?
&lt;/h2&gt;

&lt;p&gt;Imagine you want to add an AI helper to your photography site:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requirement&lt;/strong&gt; : “Auto-tag photos as ‘street’, ‘portrait’, or ‘landscape’.”&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt; : A lightweight serverless API triggers every upload.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Model&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simple input/output contract&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PhotoInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TagsOutput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Interface&lt;/strong&gt; :&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimisation&lt;/strong&gt; :&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Repeat for any feature. It’s &lt;em&gt;that&lt;/em&gt; modular.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kickstart Your MVP - Today
&lt;/h2&gt;

&lt;p&gt;You don’t need a team of AI PhDs or a 100-page system doc.&lt;br&gt;&lt;br&gt;
You need &lt;em&gt;intentional structure&lt;/em&gt; and the courage to start small (&lt;em&gt;but right&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next Actions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Identify one task your audience would love automated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sketch the “RADIO-AI” steps on paper or Notion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build your first agent behind a feature flag - even a mock model works.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Share progress. Iterate. Involve your audience.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;You’re not “late” to AI. You’re exactly on time.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Don’t overcomplicate - build, ship, and learn.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Let’s get started.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Have questions? Need more concrete code? Drop a comment; let’s turn ideas into energy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olko.substack.com/p/from-idea-to-impact-applying-the/comments" rel="noopener noreferrer"&gt;Leave a comment&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How Distributed Systems Really Talk: REST, gRPC, GraphQL, and tRPC in Practice</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Sun, 23 Nov 2025 11:56:59 +0000</pubDate>
      <link>https://dev.to/olegkoval/how-distributed-systems-really-talk-rest-grpc-graphql-and-trpc-in-practice-4pg9</link>
      <guid>https://dev.to/olegkoval/how-distributed-systems-really-talk-rest-grpc-graphql-and-trpc-in-practice-4pg9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;REST, GraphQL, gRPC, and tRPC are not just protocol choices. They are political choices between teams. Here is when each one works best, and when it will fight you.  &lt;/p&gt;

&lt;p&gt;When you scale from a handful of backend services to a network of teams shipping independently, you discover something quickly: &lt;strong&gt;APIs are politics.&lt;/strong&gt; Distributed systems are rarely brought down by storage engines or consensus protocols. More often, teams trip over something far more mundane: how services talk to each other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every endpoint, response code, and contract revision is a small treaty between teams.&lt;/p&gt;

&lt;p&gt;Over the past two decades, we’ve accumulated a surprising number of “languages” for machines to negotiate with. Each emerged for a reason, solved a pain, and introduced new ones. Below is a practical, engineer-first view of how these protocols evolved, where they shine, and where they are the wrong tool.&lt;/p&gt;

&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

&lt;p&gt;Thanks for reading oleg’s Substack! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe2ql8nkhhna3hxpni7w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe2ql8nkhhna3hxpni7w.jpeg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;](&lt;a href="https://substackcdn.com/image/fetch/$s_!I7Ab!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52ce7a5c-dd31-4f50-b096-cf9889ea0caf_2400x1601.jpeg" rel="noopener noreferrer"&gt;https://substackcdn.com/image/fetch/$s_!I7Ab!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52ce7a5c-dd31-4f50-b096-cf9889ea0caf_2400x1601.jpeg&lt;/a&gt;)&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;1. HTTP: The Common Language We Still Rely On&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;HTTP/1.1 remains the most widely adopted communication layer in distributed systems.&lt;/p&gt;

&lt;p&gt;It works because it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;simple&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;predictable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;well-understood&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;universally supported&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It gave us a shared vocabulary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GET&lt;/strong&gt; – retrieve&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;POST&lt;/strong&gt; – create&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PUT&lt;/strong&gt; – replace&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DELETE&lt;/strong&gt; – remove&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And a tone of voice through status codes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;200&lt;/strong&gt; : all good&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;404&lt;/strong&gt; : not here&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;500&lt;/strong&gt; : your server caught fire&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite its age, HTTP continues to be the stable foundation on which everything else is built. You can replace frameworks. You cannot replace HTTP.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;strong&gt;2. REST: When APIs Became Civilized&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;REST was not created to be “yet another API style.”&lt;/p&gt;

&lt;p&gt;It was created to impose &lt;em&gt;order&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Roy Fielding’s dissertation argued that networked systems should revolve around &lt;strong&gt;resources&lt;/strong&gt; (nouns), not verbs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /orders/123
POST /users
DELETE /sessions/42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;REST gave teams:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;statelessness&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;predictable semantics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;cacheability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;standardization&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This model worked exceptionally well for public APIs and internal boundaries where stability mattered more than speed or flexibility.&lt;/p&gt;

&lt;p&gt;The biggest complaint? &lt;strong&gt;Overfetching.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;REST returns the full representation of a resource, even when the client wants two fields.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where REST is a good fit&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Example: Stripe / GitHub style public APIs.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Example: Internal “platform” APIs between teams.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where REST is usually the wrong tool&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your mobile app makes 6–8 REST calls to render a single screen, overfetching large payloads. Latency and data usage are now a product problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your frontend needs to assemble data from 4–5 services per view. You start building ad-hoc “backend for frontend” aggregation endpoints to paper over REST limitations. At this point, GraphQL is often a better abstraction.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;3. SOAP, RMI, CORBA: The Empires That Collapsed&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before REST, enterprise engineering tried RPC over heavy, rigid contracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;RMI&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CORBA&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SOAP&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They assumed distributed systems should behave like local function calls.&lt;/p&gt;

&lt;p&gt;It looked nice on whiteboards and failed in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;systems tightly coupled across languages and vendors&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;brittle XML contracts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;versioning nightmares&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;huge payloads&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These approaches taught the industry one important lesson:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When your service boundary looks like a shared class, you’re building a distributed monolith.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where SOAP still makes sense&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Example: Legacy payment, insurance, telecom backends.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where SOAP is the worst option&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Greenfield product, 2025, building a public API for a web and mobile client. Choosing SOAP here is self-sabotage. REST, GraphQL, or gRPC will all be strictly better in tooling, performance, and developer experience.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;4. GraphQL: The Negotiator&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Facebook developed GraphQL because frontend teams were tired of REST returning massive payloads.&lt;/p&gt;

&lt;p&gt;GraphQL flipped the contract upside down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The client chooses the shape of the data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The server must comply.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;query {
  shipment(id: 42) {
    origin
    destination
    fuelUsed
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;precise data retrieval&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;strong types&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;single endpoint&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;complex caching rules&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;backend resolvers easily turn into N+1 factories&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;schema ownership shifts toward frontend teams&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;more infra and operational overhead&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GraphQL is great when UI teams outnumber backend teams and iteration speed matters more than backend control.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where GraphQL is a good fit&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Example: Shopify Storefront API / GitHub GraphQL API.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Example: Mobile apps under tight latency and bandwidth constraints.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where GraphQL is the wrong tool&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Internal service-to-service communication where:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simple public APIs where you:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;5. gRPC: The High-Performance Hotline&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As systems grew, some teams needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;speed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;type safety&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;bi-directional streaming&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;efficiency over public accessibility&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;gRPC (Google’s modern RPC over HTTP/2) filled that gap.&lt;/p&gt;

&lt;p&gt;Proto files define strict typed contracts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service TradeService {
  rpc InitiateTrade(TradeRequest) returns (TradeResponse);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Strengths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;binary, compact&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;extremely fast&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;codegen for many languages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;great for internal service-to-service calls&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tradeoffs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;harder to debug over the wire&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;not ideal for random third-party clients&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;browser support requires gRPC-Web and extra infra&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where gRPC is a good fit&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Example: Internal trading / risk / pricing microservices.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Example: ML inference and data pipelines.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where gRPC is the wrong tool&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Public APIs aimed at:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Browser-only clients without gRPC-Web. You will end up building HTTP/JSON shims anyway.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;6. tRPC: The TypeScript Shortcut&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Teams building full-stack TypeScript apps (Next.js, Node) realized something:&lt;/p&gt;

&lt;p&gt;“Why maintain two schemas—one for backend, one for frontend—if both sides already use TypeScript?”&lt;/p&gt;

&lt;p&gt;tRPC removed the boundary entirely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;no schema files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;no codegen&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;types flow automatically through the stack&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works exceptionally well when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the entire system is TypeScript-based&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;you control both sides of the API&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;you want fast iteration over long-term stability&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where tRPC is a good fit&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Example: B2B SaaS admin / dashboard app.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Example: Internal tools and ops consoles.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Where tRPC is the wrong tool&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You need a public API for third-party customers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You expect to migrate parts of the stack to Go, Rust, or Java.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;7. API Gateways: Bureaucracy That Scales&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Once an organization has enough services, APIs need governance.&lt;/p&gt;

&lt;p&gt;This is where API gateways and service meshes come in.&lt;/p&gt;

&lt;p&gt;Gateways handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;authentication&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rate limits&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;versioning&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;routing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;monitoring&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Service meshes handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;mTLS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;retries&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;service discovery&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;request shaping&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This structure turns chaotic service communication into enforceable policy.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Real-world patterns&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Example: Public-facing platform API.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Worst case: “Gateway as dumping ground.”&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;8. When to Use What: A Practical Decision Table&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;[&lt;br&gt;
 &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21NrEr%21%2Cw_1456%2Cc_limit%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F83ed548f-a966-4b6a-a80f-6ed47cfffa7a_1834x508.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsubstackcdn.com%2Fimage%2Ffetch%2F%24s_%21NrEr%21%2Cw_1456%2Cc_limit%2Cf_auto%2Cq_auto%3Agood%2Cfl_progressive%3Asteep%2Fhttps%253A%252F%252Fsubstack-post-media.s3.amazonaws.com%252Fpublic%252Fimages%252F83ed548f-a966-4b6a-a80f-6ed47cfffa7a_1834x508.png" title="Protocol Best For Strength Weakness REST Public APIs, clear boundaries Stable, cacheable, simple Overfetching, weak contracts GraphQL Rich frontends, many data sources Flexible queries, single endpoint Complex caching, heavier infra gRPC Internal microservices Fast, typed, streaming Harder to debug, public-hostile tRPC Full-stack TS apps End-to-end types, no schema drift TS-only, not for 3rd parties SOAP/RMI Legacy enterprise integration Strict contracts, existing infra Heavy, outdated for greenfield" alt="Protocol Best For Strength Weakness REST Public APIs, clear boundaries Stable, cacheable, simple Overfetching, weak contracts GraphQL Rich frontends, many data sources Flexible queries, single endpoint Complex caching, heavier infra gRPC Internal microservices Fast, typed, streaming Harder to debug, public-hostile tRPC Full-stack TS apps End-to-end types, no schema drift TS-only, not for 3rd parties SOAP/RMI Legacy enterprise integration Strict contracts, existing infra Heavy, outdated for greenfield" width="800" height="221"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;](&lt;a href="https://substackcdn.com/image/fetch/$s_!NrEr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ed548f-a966-4b6a-a80f-6ed47cfffa7a_1834x508.png" rel="noopener noreferrer"&gt;https://substackcdn.com/image/fetch/$s_!NrEr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F83ed548f-a966-4b6a-a80f-6ed47cfffa7a_1834x508.png&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;9. The Real Lesson&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;APIs are not technology choices.&lt;/p&gt;

&lt;p&gt;They are &lt;strong&gt;alignment choices&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The real job is ensuring that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;teams agree on contracts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;versioning is respected&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;breaking changes are controlled&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;services remain independently deployable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;communication remains predictable&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Distributed systems fail on semantics long before they fail on transport.&lt;/p&gt;

&lt;p&gt;The better the protocol, the easier the negotiation.&lt;/p&gt;

&lt;p&gt;But the negotiation is unavoidable.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;10. Final Thought&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The industry keeps inventing new ways for machines to communicate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;REST will not die.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GraphQL will not replace REST.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;gRPC will not replace GraphQL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;tRPC will not replace anything outside TypeScript ecosystems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each solves a different piece of the same problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we get independent systems—and teams—to understand each other well enough to ship?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In that sense, HTTP really is the diplomacy layer of modern software. Everything else is negotiation technique.&lt;/p&gt;

&lt;p&gt;Thanks for reading oleg’s Substack! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

</description>
      <category>api</category>
      <category>architecture</category>
      <category>microservices</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Consistency Models: Why Your Database Lies to You (And When That’s Fine)</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Wed, 05 Nov 2025 09:28:01 +0000</pubDate>
      <link>https://dev.to/olegkoval/consistency-models-why-your-database-lies-to-you-and-when-thats-fine-j75</link>
      <guid>https://dev.to/olegkoval/consistency-models-why-your-database-lies-to-you-and-when-thats-fine-j75</guid>
      <description>&lt;h2&gt;
  
  
  The Day Amazon’s Shopping Cart Became Haunted
&lt;/h2&gt;

&lt;p&gt;In 2007, Amazon engineers discovered something disturbing: deleted items were coming back from the dead.&lt;/p&gt;

&lt;p&gt;A customer would remove an item from their cart, continue shopping, then check out—only to find the “deleted” item had reappeared and been charged to their card. Support tickets flooded in. The bug wasn’t random—it happened during network partitions between Dynamo replicas.&lt;/p&gt;

&lt;p&gt;Here’s what was happening: when a customer deleted an item, the write went to Replica A. Replica B, temporarily partitioned, never got the message. When the network healed, Replica B’s version—which still contained the item—merged with Replica A’s version. No clear “winner,” so the item resurrected.&lt;/p&gt;

&lt;p&gt;Amazon’s response? They didn’t fix the bug. They &lt;strong&gt;redesigned the entire system to embrace it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The result was &lt;a href="https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf" rel="noopener noreferrer"&gt;Dynamo&lt;/a&gt;, the database that pioneered eventual consistency at scale, introduced vector clocks for conflict resolution, and changed how we think about distributed data.&lt;/p&gt;

&lt;p&gt;This is where most engineers’ understanding stops: “CAP says you can’t have consistency and availability during partitions.” True. But that binary misses the entire spectrum of &lt;strong&gt;how consistent&lt;/strong&gt; your system actually needs to be.&lt;/p&gt;

&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Consistency Spectrum Nobody Explains
&lt;/h2&gt;

&lt;p&gt;CAP doesn’t say your data is either “perfectly consistent” or “complete chaos.” Between those extremes lies a gradient as wide as the difference between a bank transfer and a Twitter like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The full spectrum:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Strong ←────────────────────────────────────────────────→ Weak
│ │ │ │ │
Linearizable Sequential Causal Session Eventual

High latency Low latency
Expensive Cheap
Simple reasoning Complex bugs

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every distributed database picks a point on this line. Your job as an engineer: know which point, understand the trade-offs, and not promise guarantees your system doesn’t provide.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Four Models That Matter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Linearizability (Strongest)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; Every operation appears to execute atomically at some point between its start and completion. All clients see operations in the same real-time order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think of it as:&lt;/strong&gt; A single-threaded system, no matter how distributed it actually is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code behavior:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Client A writes
await db.write(’x’, 5); // completes at time T1

// Client B reads immediately after
const val = await db.read(’x’); // guaranteed to see 5
console.log(val); // always prints 5, never 0 or stale value

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real systems:&lt;/strong&gt; Google Spanner (using TrueTime atomic clocks), etcd, Zookeeper&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; High latency. Every write needs global coordination. Cross-region writes can take 100ms+.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Financial transactions, inventory management, anything where “approximately right” means “catastrophically wrong.”&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Causal Consistency (The Pragmatic Middle)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; If operation A causally affects operation B (e.g., B reads A’s write), all nodes see them in that order. Independent operations can appear in any order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think of it as:&lt;/strong&gt; Preserving the story’s plot, but letting unrelated subplots unfold in parallel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code behavior:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Thread 1: Post a tweet
await db.write(’tweet:123’, ‘Hello world’);
await db.write(’tweet:123:likes’, 0); // causally dependent

// Thread 2: Read elsewhere
const tweet = await db.read(’tweet:123’); // may be stale
const likes = await db.read(’tweet:123:likes’);
// Guarantee: if likes exists, tweet must also be visible
// No guarantee: how fresh either value is

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real systems:&lt;/strong&gt; Azure Cosmos DB (default), Cassandra with careful config, some Redis setups&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Medium latency. Requires tracking causal dependencies (vector clocks, version vectors) but no global locks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Social networks, collaborative apps, anywhere causality matters but exact timing doesn’t.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Sequential Consistency
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; Operations from each client execute in program order, but there’s no guarantee of real-time ordering across clients.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think of it as:&lt;/strong&gt; Everyone agrees on A happening before B for one client, but Client 1’s timeline and Client 2’s timeline might interleave differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code behavior:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Client A
await db.write(’x’, 1);
await db.write(’x’, 2);

// Client B always sees 1 then 2 (or just 2, never 2 then 1)

// But Client C might see:
// Client A: x=1, x=2
// Client D: something else from D, x=1, x=2
// Different global orders are allowed

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real systems:&lt;/strong&gt; Some distributed SQL databases, older MongoDB replica sets&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Medium-low latency. Cheaper than linearizability but still requires some coordination.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Analytics systems, read-heavy workloads where per-user consistency matters but cross-user doesn’t.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Eventual Consistency (Weakest, Fastest)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; If no new updates occur, eventually all replicas converge to the same value. Before then: anything goes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Think of it as:&lt;/strong&gt; “Trust me, it’ll make sense... eventually.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code behavior:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Write to DynamoDB
await dynamoDB.putItem({
  TableName: ‘Users’,
  Item: { userId: ‘123’, name: ‘Alice’ }
});

// Read immediately from different replica
const user = await dynamoDB.getItem({
  TableName: ‘Users’,
  Key: { userId: ‘123’ },
  ConsistentRead: false // eventual consistency
});

console.log(user.Item.name);  
// Might print: undefined (write hasn’t propagated)
// Might print: “Bob” (old value still cached)
// Eventually prints: “Alice”

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Real systems:&lt;/strong&gt; DynamoDB (default), Cassandra at consistency level ONE, most CDNs&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; Lowest latency. Writes return immediately, reads hit local cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; View counts, likes, analytics dashboards, CDN content—anywhere staleness is annoying but not damaging.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hybrid Models You’ll Actually Use
&lt;/h2&gt;

&lt;p&gt;Real systems rarely pick one model globally. Instead, they offer &lt;strong&gt;tunable consistency per operation&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  DynamoDB: Eventual by Default, Strong on Demand
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Fast but potentially stale
const staleUser = await dynamoDB.getItem({
  TableName: ‘Users’,
  Key: { userId: ‘123’ },
  ConsistentRead: false // default, eventual
});

// Slow but guaranteed fresh
const freshUser = await dynamoDB.getItem({
  TableName: ‘Users’,
  Key: { userId: ‘123’ },
  ConsistentRead: true // forces read from primary
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;AWS documentation:&lt;/strong&gt; &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html" rel="noopener noreferrer"&gt;Read Consistency Options&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cassandra: Choose Per Query
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Write to majority of replicas (CP-leaning)
await cassandra.execute(
  ‘INSERT INTO users (id, name) VALUES (?, ?)’,
  [123, ‘Alice’],
  { consistency: cassandra.types.consistencies.quorum }
);

// Read from any replica (AP-leaning)
const result = await cassandra.execute(
  ‘SELECT name FROM users WHERE id = ?’,
  [123],
  { consistency: cassandra.types.consistencies.one }
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pattern:&lt;/strong&gt; Strong writes for critical data, eventual reads for performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  Session Consistency: The Mobile App Sweet Spot
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; Within a single user session, you see your own writes and causally-related operations. Across sessions: no guarantees.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Users expect their own actions to be reflected immediately. They don’t care if other users see stale data for a few seconds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Mobile app example
async function updateProfile(userId, newBio) {
  // Write with session token
  await db.write(
    `user:${userId}:bio`, 
    newBio,
    { sessionToken: user.session }
  );

  // Immediate read in same session - guaranteed to see new bio
  const profile = await db.read(
    `user:${userId}:bio`,
    { sessionToken: user.session }
  );

  return profile; // always returns newBio
}

// Different user reads same profile - might see old bio
// But that’s fine, they’ll see the update within seconds

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Systems that provide this:&lt;/strong&gt; Azure Cosmos DB (session consistency), MongoDB with read preference primary&lt;/p&gt;




&lt;h2&gt;
  
  
  The Decision Tree
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Choose &lt;strong&gt;Linearizable&lt;/strong&gt; when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Money is involved (payments, account balances)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inventory is limited (ticket sales, product stock)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Regulatory compliance requires audit trails&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pattern:&lt;/strong&gt; Correctness &amp;gt; Speed, always&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Choose &lt;strong&gt;Causal&lt;/strong&gt; when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Social interactions (posts, comments, reactions)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Collaborative editing (Google Docs, Figma)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chat applications&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pattern:&lt;/strong&gt; User expectations require logical ordering&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Choose &lt;strong&gt;Session&lt;/strong&gt; when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;User profiles and preferences&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shopping carts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any single-user workflow&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pattern:&lt;/strong&gt; “I see my changes immediately” matters, cross-user sync doesn’t&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Choose &lt;strong&gt;Eventual&lt;/strong&gt; when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Analytics and metrics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Content recommendations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Search indices&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View/like counts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pattern:&lt;/strong&gt; Speed matters, approximate is good enough&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How Systems Fail (And Recover)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Twitter’s 2014 Timeline Ordering Bug
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Tweets appeared out-of-order during replication lag&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; Causal consistency violated—replies appeared before original tweets&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Added explicit happens-before tracking for tweet threads&lt;/p&gt;

&lt;h3&gt;
  
  
  Reddit Vote Count Jumps
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Upvote count changes dramatically on page refresh&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; Eventual consistency—counting across replicas with stale reads&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Added “updated X seconds ago” indicators, set user expectations&lt;/p&gt;

&lt;h3&gt;
  
  
  The Amazon Shopping Cart (2007)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Deleted items resurrected after partition&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Root cause:&lt;/strong&gt; Eventual consistency with no conflict resolution&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Vector clocks + client-side merge logic in Dynamo&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key lesson:&lt;/strong&gt; Weak consistency isn’t failure. Hiding it from users is.&lt;/p&gt;




&lt;h2&gt;
  
  
  Debugging Consistency Issues
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Symptom: “My write disappeared”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Check if you’re reading from a different replica than you wrote to&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verify write acknowledgment (did it actually succeed?)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Look for partition healing—merges can “undo” writes&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Symptom: “Data time-travels backward”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reading from replicas with different lag&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check read-after-write guarantees in your client library&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consider session consistency or sticky routing&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Symptom: “Conflicts I can’t explain”&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Concurrent writes during partition&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check if system uses last-write-wins (LWW) or vector clocks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Look for application-level conflict resolution bugs&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Practical Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Consistency is a spectrum, not a binary&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Stop saying “my DB is consistent.” Specify: linearizable? causal? eventual?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Most apps need multiple consistency levels&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Bank balance: strong. User bio: session. Feed ranking: eventual.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Latency and consistency are inversely related&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Every 9 of consistency costs you a 0 in latency. Pick your battles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Communicate your guarantees to users&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
“Updated 5 seconds ago” &amp;gt; silent staleness. Honesty scales.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Test with partitions, not just load&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Use chaos engineering (Chaos Monkey, Gremlin) to simulate real failure modes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf" rel="noopener noreferrer"&gt;Amazon Dynamo Paper (SOSP 2007)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://lamport.azurewebsites.net/pubs/time-clocks.pdf" rel="noopener noreferrer"&gt;Lamport’s “Time, Clocks, and the Ordering of Events” (1978)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://research.google/pubs/pub39966/" rel="noopener noreferrer"&gt;Google Spanner Paper (OSDI 2012)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://queue.acm.org/detail.cfm?id=1466448" rel="noopener noreferrer"&gt;Werner Vogels: Eventually Consistent (ACM Queue 2008)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/consistency-levels" rel="noopener noreferrer"&gt;Cosmos DB Consistency Levels&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This is Chapter 2 from my book on distributed systems fundamentals. &lt;a href="https://olko.substack.com/" rel="noopener noreferrer"&gt;Subscribe&lt;/a&gt; for weekly breakdowns of consensus, replication, and the other concepts that actually matter in production.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick context&lt;/strong&gt; : If you’re jumping in here, this builds on CAP Theorem—the fundamental trade-off between consistency and availability during network partitions. &lt;a href="https://dev.to/olegkoval/cap-theorem-what-senior-engineers-actually-need-to-know-bg2"&gt;Start with CAP first if you haven’t read it yet&lt;/a&gt;. This post assumes you understand why systems can’t have perfect consistency AND availability.&lt;/p&gt;

&lt;p&gt;This is where most engineers’ understanding stops: “CAP says you can’t have consistency and availability during partitions.” True. But that binary misses the entire spectrum of **how consistent** your system actually needs to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Question for readers:&lt;/strong&gt; Have you debugged a consistency bug in production? What was the “aha” moment when you realized it was a replication/consistency issue? Drop a comment—building a collection of war stories.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://olko.substack.com/p/consistency-models-why-your-database/comments" rel="noopener noreferrer"&gt;Leave a comment&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>database</category>
      <category>computerscience</category>
      <category>architecture</category>
    </item>
    <item>
      <title>What I Learned From 60 Days of Brutal Honesty in My Work Journal</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Fri, 31 Oct 2025 08:37:47 +0000</pubDate>
      <link>https://dev.to/olegkoval/what-i-learned-from-60-days-of-brutal-honesty-in-my-work-journal-lgf</link>
      <guid>https://dev.to/olegkoval/what-i-learned-from-60-days-of-brutal-honesty-in-my-work-journal-lgf</guid>
      <description>&lt;p&gt;Two months ago, I started keeping a work journal. Not just task lists and meeting notes - the sanitized version of my workday — but the unfiltered reality: how I felt, where I failed, and what scared me.&lt;/p&gt;

&lt;p&gt;Here are four practices that emerged from this experiment in radical self-management.&lt;/p&gt;

&lt;p&gt;Thanks for reading Olko - Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. I Stopped Hiding From My Mistakes
&lt;/h2&gt;

&lt;p&gt;After a significant fuckup that frustrated management, I could have written a polite note of apology and moved on. Instead, I wrote two words at the top of my journal: “I FUCKED UP.”&lt;/p&gt;

&lt;p&gt;Then I built a system to prevent it from happening again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A formal requirements validation process before writing code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A design review checkpoint to verify understanding&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Clarifying questions to ask upfront, including: “What would you NOT build?”&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the most important step was writing a document titled “How You Can Help Me” for my manager. I outlined how leadership could provide more explicit constraints and challenge my assumptions.&lt;/p&gt;

&lt;p&gt;I wasn’t just fixing my mistake—I was taking ownership of how clearly I understood future assignments. By defining how my manager could help me succeed, I was actively coaching my own leadership. This shift from reactive apology to proactive system-building changed how I approach every project.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. I Started Tracking Energy Like a Performance Metric
&lt;/h2&gt;

&lt;p&gt;Every day, I rate three things on a 1-to-10 scale: Energy, Focus, and Mood.&lt;/p&gt;

&lt;p&gt;This felt silly at first. But after two months, the patterns became impossible to ignore.&lt;/p&gt;

&lt;p&gt;During a brutal multi-week grind on a complex feature, my scores plummeted. Energy dropped to 3-4/10. Focus deteriorated. Mood stayed consistently poor for over two weeks. The moment the feature shipped, everything rebounded to 10/10.&lt;/p&gt;

&lt;p&gt;This isn’t just feelings—it’s data. I can now see exactly which types of work drain me and which energize me. I can predict when I’m trending toward burnout weeks before it hits. I can make strategic decisions about when to push and when to recover.&lt;/p&gt;

&lt;p&gt;Most professionals treat well-being as an afterthought. I now treat it as a critical resource to be monitored, managed, and strategically deployed.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. I Stopped Going to Meetings and Started Managing Up
&lt;/h2&gt;

&lt;p&gt;I used to show up to 1-on-1s with my manager and wait for direction. Now I prepare like I’m co-creating my role.&lt;/p&gt;

&lt;p&gt;Before my last 1-on-1, I prepared three categories of questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To Understand Broader Context:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“From your perspective, what are the team’s biggest challenges right now?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;To Proactively Define Success:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“I want to balance delivery with deeper architectural understanding—what would success look like for me in the first 3 months?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;To Show Initiative on Team-Wide Issues:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“What’s your vision for developer experience improvements over the next quarter?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This preparation changed everything. I’m no longer a passive employee waiting for instructions. I’m a strategic partner aligning my growth with the company’s most important objectives.&lt;/p&gt;

&lt;p&gt;My manager once told me these conversations are the most valuable hour of their week. That’s not because I have all the answers—it’s because I show up prepared to help lead.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. I Started Analyzing Team Dynamics Under Pressure
&lt;/h2&gt;

&lt;p&gt;During a particularly difficult period for the team, I noticed how stress changed our communication patterns. People became more reactive, less constructive. Frustration leaked into conversations in ways that hurt rather than helped.&lt;/p&gt;

&lt;p&gt;In my journal, I started analyzing what made communication break down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Venting without specific problems to solve&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Blame without actionable feedback&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Emotion without structure for moving forward&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Writing these observations wasn’t just venting. It was practice. By deconstructing what went wrong, I was training myself to communicate better under pressure. I was reinforcing the principles of psychological safety that high-performing teams need.&lt;/p&gt;

&lt;p&gt;Now when I feel frustrated, I pause. I ask: “What specific behavior or outcome am I concerned about? What would improvement look like?” This mental discipline protects my team’s ability to perform when stakes are high.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Changed
&lt;/h2&gt;

&lt;p&gt;Peak performance isn’t about maintaining a perfect image. It’s about engaging in a consistent, private practice of radical self-awareness.&lt;/p&gt;

&lt;p&gt;In my journal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Failures become systems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Moods become data&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Meetings become strategy sessions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Communication breakdowns become learning opportunities&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The insight isn’t in the words I write. It’s in the discipline of writing them—of being brutally honest with myself about what’s working and what isn’t.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s the one thing you could start tracking tomorrow?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading oleg’s Substack! Subscribe for free to receive new posts and support my work&lt;/p&gt;

&lt;p&gt;&lt;a href="https://olko.substack.com/p/what-i-learned-from-60-days-of-brutal?utm_source=substack&amp;amp;utm_medium=email&amp;amp;utm_content=share&amp;amp;action=share" rel="noopener noreferrer"&gt;Share&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>mentalhealth</category>
      <category>productivity</category>
    </item>
    <item>
      <title>CAP Theorem: What Senior Engineers Actually Need to Know</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Tue, 28 Oct 2025 16:17:34 +0000</pubDate>
      <link>https://dev.to/olegkoval/cap-theorem-what-senior-engineers-actually-need-to-know-bg2</link>
      <guid>https://dev.to/olegkoval/cap-theorem-what-senior-engineers-actually-need-to-know-bg2</guid>
      <description>&lt;p&gt;&lt;a href="https://olko.substack.com/subscribe?" rel="noopener noreferrer"&gt;Subscribe now&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When GitHub Chose Consistency Over Your Pull Request
&lt;/h2&gt;

&lt;p&gt;At 3:11 a.m. UTC on October 21, 2018, GitHub’s monitoring detected replication lag spiking from milliseconds to hours between U.S. data centers. Within minutes, the platform serving 30 million developers began showing stale data.&lt;/p&gt;

&lt;p&gt;GitHub’s response? They deliberately &lt;strong&gt;froze all writes for five hours&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The banner every developer saw that morning:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“GitHub is experiencing degraded availability while we recover replication consistency.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This wasn’t incompetence—it was the most expensive proof of CAP Theorem in production history.&lt;/p&gt;

&lt;p&gt;When their MySQL cluster split across coasts, GitHub faced the choice every distributed system eventually faces: serve requests with potentially wrong data, or stop serving requests entirely. They chose the latter. &lt;a href="https://github.blog/2018-10-30-oct21-post-incident-analysis/" rel="noopener noreferrer"&gt;Their post-mortem&lt;/a&gt; is worth reading.&lt;/p&gt;

&lt;p&gt;If you’re designing anything beyond a single server—DynamoDB tables, Kafka clusters, replicated Postgres, microservices—you will make this exact choice. Understanding CAP isn’t optional. It’s the gravitational law of distributed computing.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64c54eig79nb93mtvh6a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64c54eig79nb93mtvh6a.png" alt="Triangle of quality: CAP" width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;





&lt;h2&gt;
  
  
  The Theorem in 30 Seconds
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CAP Theorem&lt;/strong&gt; (Brewer 2000, formalized by Gilbert &amp;amp; Lynch 2002): In a distributed system experiencing a network partition, you can guarantee &lt;strong&gt;at most two&lt;/strong&gt; of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consistency (C)&lt;/strong&gt; – All nodes see identical data simultaneously&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Availability (A)&lt;/strong&gt; – Every request gets a non-error response&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Partition Tolerance (P)&lt;/strong&gt; – System functions despite network failures between nodes&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since network partitions are inevitable in distributed systems, you’re really choosing between &lt;strong&gt;C or A&lt;/strong&gt; when failures occur.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters: The Coffee Shop Test
&lt;/h2&gt;

&lt;p&gt;Two branches of a coffee chain share a loyalty-points database. The network between them fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 1: Choose Availability (AP)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Both locations keep accepting purchases&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customer spends 500 points at Downtown, then immediately drives to Uptown and spends the same 500 points again&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;System reconciles later, discovers the conflict&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Result: Lost revenue, but no angry customers&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Scenario 2: Choose Consistency (CP)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Downtown can’t verify points balance with Uptown&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Register locks until sync returns&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Result: Guaranteed correctness, angry customers waiting&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No architecture eliminates this trade-off. You only choose where to suffer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code: Seeing the Choice
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AP System (Availability-First)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// DynamoDB-style eventual consistency
async function purchaseWithPoints(customerId, points) {
  try {
    // Write to local node immediately
    await localDB.write({ customerId, points, timestamp: Date.now() });

    // Replicate asynchronously (fire and forget)
    replicateAsync(customerId, points).catch(err =&amp;gt; {
      logger.warn(’Replication delayed’, err);
    });

    return { 
      success: true, 
      consistency: ‘eventual’,
      message: ‘Purchase recorded, replicating...’
    };
  } catch (err) {
    // Still succeed even if remote nodes unreachable
    return { success: true, replicated: false };
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This code prioritizes uptime.&lt;/strong&gt; Even if 2 of 3 replicas are down, customers transact. Conflicts get resolved through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Last-write-wins (simple, potentially lossy)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vector clocks (complex, deterministic)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conflict-free replicated data types (CRDTs)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real-world AP systems:&lt;/strong&gt; DynamoDB, Cassandra, Riak&lt;/p&gt;




&lt;h3&gt;
  
  
  CP System (Consistency-First)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// MongoDB-style primary-secondary with write concerns
async function purchaseWithPoints(customerId, points) {
  const session = await startTransaction();

  try {
    // Write to primary
    await primaryDB.write({ customerId, points }, { session });

    // Block until majority of replicas confirm
    await waitForReplication({
      writeConcern: ‘majority’,
      timeout: 5000 // fail if can’t replicate in 5s
    });

    await session.commitTransaction();
    return { 
      success: true, 
      consistency: ‘strong’,
      message: ‘Purchase confirmed on all replicas’
    };
  } catch (err) {
    await session.abortTransaction();
    // Return error if replication fails
    return { 
      success: false, 
      error: ‘Network partition detected, refusing write’
    };
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This code prioritizes correctness.&lt;/strong&gt; During partitions, requests fail rather than create divergent data. MongoDB’s evolution toward this model came after &lt;a href="https://www.mongodb.com/blog/post/multi-document-transactions-in-mongodb-4-0" rel="noopener noreferrer"&gt;data loss incidents in early versions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-world CP systems:&lt;/strong&gt; Spanner, HBase, MongoDB with majority write concern&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hybrid Reality: Tunable Consistency
&lt;/h2&gt;

&lt;p&gt;Modern databases rarely pick a single point on the spectrum. Instead, they let &lt;strong&gt;you&lt;/strong&gt; choose per operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DynamoDB example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Strong read (CP behavior)
const item = await dynamoDB.getItem({
  TableName: ‘Users’,
  Key: { userId: ‘123’ },
  ConsistentRead: true // Forces read from primary
});

// Eventual read (AP behavior)
const item = await dynamoDB.getItem({
  TableName: ‘Users’,
  Key: { userId: ‘123’ },
  ConsistentRead: false // May read from stale replica
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cassandra’s quorum tuning:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Write to all 3 replicas, succeed when 2 confirm (CP-leaning)
await cassandra.execute(query, params, { 
  consistency: Consistency.QUORUM 
});

// Write to 1 replica, succeed immediately (AP-leaning)
await cassandra.execute(query, params, { 
  consistency: Consistency.ONE 
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Decision Tree: When to Pick What
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Choose &lt;strong&gt;CP (Consistency &amp;gt; Availability)&lt;/strong&gt; when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Financial transactions (double-spending is catastrophic)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inventory systems (overselling angers customers)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Config management (inconsistent configs break prod)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Medical records (wrong data kills people)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pattern&lt;/strong&gt; : When incorrect data causes more damage than downtime.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choose &lt;strong&gt;AP (Availability &amp;gt; Consistency)&lt;/strong&gt; when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Social media feeds (stale likes don’t matter)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Analytics dashboards (approximate counts acceptable)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Shopping cart contents (user fixes conflicts themselves)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Messaging “read receipts” (eventual accuracy sufficient)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pattern&lt;/strong&gt; : When downtime frustrates users more than temporary staleness.&lt;/p&gt;

&lt;h3&gt;
  
  
  The gray area:
&lt;/h3&gt;

&lt;p&gt;Most systems need &lt;strong&gt;both&lt;/strong&gt; —strong consistency for writes, eventual for reads. This is where PACELC extends CAP: even when there’s no partition, you trade latency for consistency.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About “CA” Systems?
&lt;/h2&gt;

&lt;p&gt;The CA corner (Consistency + Availability, no Partition Tolerance) is theoretically impossible in truly distributed systems. Network partitions aren’t optional—they happen.&lt;/p&gt;

&lt;p&gt;Single-node databases like standalone Postgres or Redis are “CA” but only because they’re not distributed. The moment you add a replica, you’re playing CAP.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Lesson: Partitions Choose For You
&lt;/h2&gt;

&lt;p&gt;Eric Brewer (the “CAP” in CAP Theorem) said it best in his 2000 PODC keynote: partitions aren’t theoretical. They’re Tuesday.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cross-datacenter links fail&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rack switches crash&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;OS updates hang&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cloud providers have “availability zone degradation”&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you haven’t explicitly chosen CP or AP, the network will decide for you during the outage—usually in the worst possible way.&lt;/p&gt;

&lt;p&gt;GitHub chose CP, went down for 5 hours, but preserved data integrity.&lt;br&gt;&lt;br&gt;
AWS DynamoDB chooses AP by default, stays up during partitions, accepts stale reads.&lt;/p&gt;

&lt;p&gt;Neither is “better.” Both are intentional choices aligned with business requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  Takeaway Box
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use CP when:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Incorrect data causes financial loss, safety issues, or user-facing inconsistency that support can’t fix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use AP when:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Downtime loses revenue, user trust, or competitive edge faster than eventual consistency causes problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use tunable consistency when:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Different operations have different requirements. Read-heavy analytics can be eventual; write-heavy checkout must be strong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test your choice:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Simulate partitions using chaos engineering (Netflix’s Chaos Kong, Gremlin.com). Discover your actual behavior before production does.&lt;/p&gt;




&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.blog/2018-10-30-oct21-post-incident-analysis/" rel="noopener noreferrer"&gt;GitHub’s Oct 2018 Post-Mortem&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dl.acm.org/doi/10.1145/564585.564601" rel="noopener noreferrer"&gt;Gilbert &amp;amp; Lynch’s CAP Proof (2002)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html" rel="noopener noreferrer"&gt;AWS DynamoDB Consistency Model&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://research.google/pubs/pub39966/" rel="noopener noreferrer"&gt;Google Spanner Paper (OSDI 2012)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This is Chapter 1 from my upcoming book on distributed systems fundamentals. If you found this useful, &lt;a href="https://olko.substack.com/" rel="noopener noreferrer"&gt;subscribe&lt;/a&gt; for weekly deep-dives on consensus, eventual consistency, and other concepts that matter in production.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions? Disagree with something?&lt;/strong&gt; Leave a comment—I’m testing this material and want to know what I got wrong.&lt;/p&gt;




&lt;p&gt;Thanks for reading Olko Tech/Engineering! Subscribe for free to receive new posts and support my work.&lt;/p&gt;

</description>
      <category>distributedsystems</category>
      <category>systemdesign</category>
      <category>database</category>
      <category>architecture</category>
    </item>
    <item>
      <title>A collaborative collection of Interview questions</title>
      <dc:creator>Ed</dc:creator>
      <pubDate>Thu, 05 Dec 2019 21:57:39 +0000</pubDate>
      <link>https://dev.to/olegkoval/a-collaborative-collection-of-interview-questions-43m5</link>
      <guid>https://dev.to/olegkoval/a-collaborative-collection-of-interview-questions-43m5</guid>
      <description>&lt;p&gt;Ideally, the interview process is a conversation between equal parties. Not among superiors and inferior – it's hard to find good companies because it's even harder for them to find good employees. You, as Interviewee, should have a way to distinguish good from the bad - this list of questions will help you facilitate that process. So that's why this resource exists: &lt;a href="https://counter-interview.dev" rel="noopener noreferrer"&gt;https://counter-interview.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to add new questions!&lt;/p&gt;

</description>
      <category>career</category>
      <category>hiring</category>
      <category>help</category>
      <category>interview</category>
    </item>
  </channel>
</rss>
