<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[ivan zakutni]]></title><description><![CDATA[Less "vibe". More engineering.
Letters on intelligence, software, and systems that have to survive production.]]></description><link>https://letters.ivanzakutnii.com</link><image><url>https://substackcdn.com/image/fetch/$s_!L7Nd!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b952843-edc1-4f4f-835e-257e5863e27c_1280x1280.png</url><title>ivan zakutni</title><link>https://letters.ivanzakutnii.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 22 Jul 2026 20:52:37 GMT</lastBuildDate><atom:link href="https://letters.ivanzakutnii.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Ivan Zakutnii]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[ivanzakutnii@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[ivanzakutnii@substack.com]]></itunes:email><itunes:name><![CDATA[Ivan]]></itunes:name></itunes:owner><itunes:author><![CDATA[Ivan]]></itunes:author><googleplay:owner><![CDATA[ivanzakutnii@substack.com]]></googleplay:owner><googleplay:email><![CDATA[ivanzakutnii@substack.com]]></googleplay:email><googleplay:author><![CDATA[Ivan]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Quint Code 5.0 — decisions as living project infrastructure.]]></title><description><![CDATA[Why I rewrote the interface from scratch, why engineering decisions matter more than code, and what comes next.]]></description><link>https://letters.ivanzakutnii.com/p/quint-code-50-decisions-as-living</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/quint-code-50-decisions-as-living</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Wed, 18 Mar 2026 19:22:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6PQU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6PQU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6PQU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp 424w, https://substackcdn.com/image/fetch/$s_!6PQU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp 848w, https://substackcdn.com/image/fetch/$s_!6PQU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp 1272w, https://substackcdn.com/image/fetch/$s_!6PQU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6PQU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp" width="1000" height="545" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:545,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:581260,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ivanzakutnii.substack.com/i/191403527?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6PQU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp 424w, https://substackcdn.com/image/fetch/$s_!6PQU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp 848w, https://substackcdn.com/image/fetch/$s_!6PQU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp 1272w, https://substackcdn.com/image/fetch/$s_!6PQU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8424083d-546a-4ab2-852a-384d44ce52d5_1000x545.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I was recently on a podcast where we talked about FPF, vibe-coding, decision engineering, and why &#8220;steering&#8221; AI agents is anything but an intuitive skill. We didn&#8217;t get through all the topics, and I promised the listeners a detailed follow-up post. Here it is.</p><p>And while we were talking, I realized it was time to resurrect Quint Code. So I did &#8212; and fell in love with this tool all over again. But let&#8217;s take it from the top.</p><div><hr></div><h2>Code got cheap. Decisions didn&#8217;t.</h2><p>Everyone is vibe-coding right now. And that&#8217;s wonderful &#8212; even when it&#8217;s just a pet project, a weekend tool, or a hackathon prototype. But no, with varying degrees of success people are already building fairly large software systems with AI. The devil is in the details, sure, but one thing is absolutely certain: anyone still dismissing AI-assisted engineering while refusing to actually use these tools has hopelessly, irreversibly fallen behind.</p><p>If you&#8217;re also interested not just in the intuitive thrill of vibe-coding but in AI-assisted engineering proper, you&#8217;ve already run into this more than once: when we bear responsibility for the code, when actual business depends on it &#8212; just &#8220;vibing&#8221; is not a strategy at all.</p><p>Here&#8217;s the thing &#8212; code has always been a small part of the work in IT. Truly competent engineers were never just engineers; to a significant degree they were also managers: modeling the domain, understanding what they were building and for whom, organizing people. There was simply a gap between those who did this kind of work and those who just got grunt work dumped on them.</p><p>AI is now eliminating this masking gap, and doing it at a ruthlessly fast pace.<br>It&#8217;s become more obvious: you need to make <em>the right decisions</em>, not just write or generate code.</p><h3>&#8220;Humans steer. Agents execute.&#8221;</h3><p>Just recently (though by singularity standards this is ancient history), OpenAI dropped the <a href="https://openai.com/index/harness-engineering/">harness engineering</a> post &#8212; about how they &#8220;purely vibe-coded&#8221; a large repo. Zero lines of human-written code. Sounds incredibly cool!!!</p><p>But I absolutely agree with Anatoly Levenchuk that this article needs an enormous disclaimer: <em>&#8220;these stunts are performed by well-trained engineers &#8212; do not attempt without proper training.&#8221;</em></p><p>The article is woefully short on information about what specific skills are needed for this effective &#8220;steering.&#8221;<br>Execution got cheaper and much faster &#8212; and it&#8217;s precisely steering that became the bottleneck.</p><p>After reading the harness engineering article, you might get the impression that this is easy to replicate &#8212; just add some integrations, cover it with tests, and off you go&#8230;</p><p>AI agents, when steered poorly, still frequently make junior-level mistakes. The upside is they make them fast &#8212; so we don&#8217;t find out about these mistakes a week before release, but almost immediately. This is where the fans of &#8220;just cover it with testsss, it can do it all on its own!!! I don&#8217;t even review tests anymore! It&#8217;s all automatic!&#8221; come in.</p><p>Yeah, but&#8230; I find it hard to believe you&#8217;ve never once had to actually review generated code, or verify behavior. Because sometimes you still have to. Sometimes! But when that &#8220;sometimes&#8221; hits, we immediately land flat on our face, because it turns out we suddenly need to possess certain hands-on competencies. Sure, you can keep going in circles asking AI for help, but do you actually know what to ask? This kind of fumbling can eat up an unforgivable amount of time.</p><p>So we&#8217;re in a situation where we still need to:</p><ul><li><p>Not lose focus, not forget to <em><strong>check in time</strong></em> on what&#8217;s actually happening in our AI factory.</p></li><li><p>Be competent in actual development to verify those results</p></li><li><p>Be competent in management and systems thinking to avoid making junior-level mistakes ourselves in decomposition and work distribution across agents</p></li></ul><p>Intuitive approaches don&#8217;t work well here. They barely work at all.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://letters.ivanzakutnii.com/subscribe?"><span>Subscribe now</span></a></p><h3>Three classes of problems</h3><p>Anatoly Levenchuk in his recent posts very clearly defined three classes of problems we&#8217;re dealing with right now:</p><p><strong>Class 1: &#8220;Keep spinning until the tests pass.&#8221;</strong> There&#8217;s a clear correctness criterion, and verifying the answer is cheaper than finding it. Math, algorithms, code with tests. AI agents already handle this class autonomously &#8212; they generate variants, run them through checks, headbutt their way to the finish! This is rapidly commoditizing: value shifts from the ability to solve to <em>the ability to frame the problem.</em> You don&#8217;t still think framing a problem is &#8220;just writing a prompt,&#8221; right?</p><p><strong>Class 2: Verification costs more than the solution.</strong> Real engineering systems &#8212; distributed services, platforms, products with users. Here, green tests prove&#8230; nothing :)<br>A system can pass all checks while still being brittle, unable to survive under load, silently drifting from requirements. &#8220;We built it&#8221; &#8212; but did we build the right thing? Verification requires expert judgment, it&#8217;s more expensive and slower than the development itself, and it can&#8217;t be fully automated.</p><p><strong>Class 3: The problem statement itself is the problem.</strong> Neither the solution nor the criteria for verifying it are defined &#8212; because <em>the problem itself isn&#8217;t defined.</em> What to build, for whom, why &#8212; all of this needs to be discovered. The only verifier here is reality: the market, users, consequences. You can only verify results by probing &#8212; shipping the product into the real world.</p><p>Vibe-coding works exclusively in Class 1. Classes 2 and 3 demand a grammar for thinking, reliable methods of reasoning and sustaining attention throughout the entire work cycle.</p><div><hr></div><h3>FPF in one sentence</h3><p>FPF (First Principles Framework) &#8212; a set of engineering principles, a grammar for thinking, or more precisely &#8212; an operating system for thinking! FPF structures your reasoning so that it&#8217;s hard to miss something important. It&#8217;s not an encyclopedia, not a methodology, not tied to any tool. A set of powerful rules. A set of first-principles, SoTA principles!</p><div><hr></div><h2>Quint Code 5.0: what it is and why the interface was rewritten from scratch</h2><p>Quint Code is a decision engineering system for AI assistants. A set of tools that transforms conversation with your favorite AI agent into a structured engineering process.</p><p>Version 5.0 is a complete redesign. The previous architecture (ADI cycle with phases, hypotheses, L0/L1/L2 levels) was right in spirit but wrong in form. Too rigid, too ceremonious &#8212; context got overloaded instantly. For medium-sized tasks, the old QC brought nothing but pain and suffering, which is why I myself hadn&#8217;t used it for the last 2.5 months!</p><p>During that time I was using FPF in ChatGPT and Claude Desktop &#8212; works well, very well in fact if you just add the specification to the chat or project context (of course it gets indexed under the hood). But sometimes I specifically needed an agent with filesystem and code access that would understand FPF and could work using its principles at least to some degree. So I made several attempts &#8212; like slicing the spec into a skillpack &#8212; that was a really painful journey. A skillpack with hooks&#8230; I buried that attempt very quickly :)</p><h3>What changed in Quint Code?</h3><p>The main shift: from &#8220;phase machine of hypotheses&#8221; to &#8220;problem &#8594; decision &#8594; decision recorded as a contract.&#8221;</p><p>In v4, there was a rigid cycle: initialization &#8594; hypotheses &#8594; verification &#8594; audit &#8594; decision. This worked for one specific flow but was inflexible. Far from all tasks fit into that conveyor.</p><p>In v5 &#8212; seven tools, each self-contained. You can use one. You can use all of them. In any order &#8212; the system itself suggests what to do next. But if you want to get the most out of engineered reasoning &#8212; there&#8217;s a protocol, and we&#8217;ll go through it below. You can just install it and not use anything explicitly &#8212; it&#8217;ll quietly start recording knowledge on its own and invoke q-reason when it encounters complex tasks. Already a win! Set it and forget it &#8212; the project evolves.</p><h3>Seven tools</h3><p><strong>1. </strong><code>/q-note</code> &#8212; capture micro-decisions on the fly.</p><p>The lightest thing there is. &#8220;We decided to use X for Y because latency is critical.&#8221; Recorded, linked to files, automatically expires after 90 days. If three months later X is no longer relevant &#8212; the system will remind you, and we&#8217;ll review; if needed &#8212; update the decision/specification! Living documentation, damn it!</p><p>q-note is handy because the vast majority of decisions in projects are exactly like this. Small, fast, but six months later nobody remembers why. And we needed some simple tool that wouldn&#8217;t drag you through long reasoning cycles but also wouldn&#8217;t lose important project information &#8212; information about decisions.</p><p><strong>2. </strong><code>/q-frame</code> &#8212; define the problem before rushing to solve it.</p><p>This is where Quint Code already differs most from &#8220;just ask AI.&#8221; Instead of &#8220;how do we do X?&#8221; &#8212; &#8220;what problem are we solving? what are the constraints? how will we know we&#8217;ve solved it?&#8221;</p><p>This isn&#8217;t pointless formality. Formality is never pointless! This is that golden moment where 90% of projects could save weeks or months of rework &#8212; because without a clear problem statement, you&#8217;re building &#8220;something,&#8221; and you find out that &#8220;something&#8221; isn&#8217;t what was needed at all only when it&#8217;s too late, when rewriting will be very painful. Of course, right now Quint Code only frames problems within a single project, but I can already see how this could expand to team development and integrations with various team/company knowledge bases &#8212; but that&#8217;s a long roadmap.</p><p><strong>3. </strong><code>/q-char</code> &#8212; define comparison criteria <em>before</em> you see the options.</p><p>Here we try to establish selection criteria <em>before</em> generating and comparing variants. This is protection against retrofitting &#8212; when you pick criteria to match a variant you already &#8220;liked.&#8221;</p><p>Each comparison criterion has a role:</p><ul><li><p><strong>constraint</strong> &#8212; hard limit, must be satisfied (latency &lt; 100ms)</p></li><li><p><strong>target</strong> &#8212; what we&#8217;re optimizing (throughput)</p></li><li><p><strong>observation</strong> &#8212; what we monitor but do NOT optimize (Anti-Goodhart!)</p></li></ul><p>Why observation? Goodhart&#8217;s Law: when a metric becomes a goal, it ceases to be a good metric. If you optimize throughput &#8212; you might silently kill reliability. Observation says: &#8220;keep an eye on this, but don&#8217;t chase it.&#8221;</p><p><strong>4. </strong><code>/q-explore</code> &#8212; generate <em>genuinely different</em> variants, not three variations of the same thing!</p><p>Solution variants should differ in kind, not in degree. &#8220;Redis vs Memcached vs in-memory cache&#8221; &#8212; those are three variations of one approach. &#8220;Cache vs CDN optimization vs query redesign&#8221; &#8212; those are three genuinely different variants.</p><p>For each variant, you must identify the weakest link. What limits the quality of this approach? This isn&#8217;t about &#8220;cons&#8221; in the spirit of a standard SWOT &#8212; it&#8217;s about what will break first! And this is a continuation of the same &#8220;story&#8221; that begins during <code>/q-frame</code> &#8212; with each step of the full cycle we refine, think, converge on a better decision.</p><p><strong>5. </strong><code>/q-compare</code> &#8212; comparison on the Pareto front.</p><p>Now that criteria are defined upfront &#8212; apply them to the variants.</p><p>Here we look at the Pareto front. We&#8217;re not picking &#8220;the best option&#8221; but rather a set of options where each one can be (and typically will be) better than the rest along one dimension but worse along another.</p><p>What remains is your conscious, deliberate choice.</p><p><strong>6. </strong><code>/q-decide</code> &#8212; record the decision as a contract.</p><p>What we get is not a note in Notion, not a frozen ADR file that nobody reads.</p><p>We get a contract with four components:</p><ol><li><p><strong>Problem statement</strong> &#8212; why were we deciding in the first place?</p></li><li><p><strong>Decision/Contract</strong> &#8212; what we chose, invariants (what must ALWAYS hold true?), preconditions, postconditions</p></li><li><p><strong>Rationale</strong> &#8212; why this and not something else? We preserve the comparison table, the weakest link, evidence requirements</p></li><li><p><strong>Consequences</strong> &#8212; rollback plan (under what circumstances do we roll back? How? What&#8217;s the blast radius if things do go sideways?), plus formal triggers for review, affected files</p></li></ol><p>This isn&#8217;t ceremony for ceremony&#8217;s sake &#8212; it&#8217;s a specification that works. Three months from now, when a new engineer comes along and asks &#8220;why are we using X?&#8221; &#8212; there&#8217;s a very good chance they&#8217;ll find a comprehensive answer!</p><p>I wish there was full magic and Quint Code could track any conditions and their changes, but it&#8217;s already trying hard &#8212; there&#8217;s a staleness timer (Until when is this decision considered current? When should we, if not revisit it, at least verify it&#8217;s still valid?), and file-tracking is nearly ready.</p><p><strong>7. </strong><code>/q-refresh</code> &#8212; decisions age, and that&#8217;s normal!</p><p>Yes, I already started on this in the previous point &#8212; any decision has a shelf life. A year-old benchmark, documentation for an outdated version, a decision made under different load, a decision made simply&#8230; six months ago. Quint Code strives to track this automatically.</p><p>Every decision has a computed trust score &#8212; R_eff. It&#8217;s a calculated metric: the minimum across all evidence (weakest link principle &#8212; the strength of a chain equals the strength of its weakest link), with penalties for context (evidence from a different project is worth less than from the same one).</p><ul><li><p>R_eff &gt; 0.5 &#8212; decision is healthy</p></li><li><p>R_eff &lt; 0.5 &#8212; decision is stale, needs review</p></li><li><p>R_eff &lt; 0.3 &#8212; AT RISK, requires immediate attention</p></li></ul><p>When you run <code>/q-refresh</code> &#8212; it shows what&#8217;s gone stale and offers options: extend (with justification), replace with a new decision, or deprecate. And then it goes and actually investigates what went stale. We&#8217;ve got an AI agent here, not a mere chatbot!</p><h3>Three modes of operation</h3><p><strong>Quick</strong> &#8212; for obvious decisions, but where we still want strong reasoning from AI! Define the problem (frame) &#8594; decide &#8594; record (decide).</p><p>That&#8217;s the minimum that gives you all the useful artifacts &#8212; sweet!</p><p><strong>Full</strong> &#8212; for architectural decisions, and really any decisions where we&#8217;re not sure. I recommend listening to your &#8220;intuition&#8221; more often &#8212; far more often than you&#8217;d think, your &#8220;intuitive&#8221; decisions aren&#8217;t the best ones! It&#8217;s actually fascinating to stress-test your &#8220;intuitive&#8221; decisions through the full Quint Code cycle:</p><p>Frame &#8594; Characterize &#8594; Explore &#8594; Compare &#8594; Decide.</p><p><strong>Auto</strong> &#8212; <code>/q-reason</code>. This command is a distillation of the FPF core + the full FPF available as an FTS5 index accessible via CLI &#8212; the agent can load any part of FPF on demand! You can also invoke q-reason on any task &#8212; the effect will be exclusively positive. In fact it&#8217;s not a slash-command but a skill, just like <code>/q-note</code>, so your agent will try to use both at the right time. If you simply give the agent a task and ask it to &#8220;think,&#8221; this skill will almost always get invoked. This is what the old Quint Code was missing &#8212; intellectual horsepower available quickly and nearly for free.</p><div><hr></div><h2>Where FPF isn&#8217;t needed, and where it&#8217;s indispensable</h2><p>Don&#8217;t bring a sledgehammer to hang a picture frame, friends!</p><p><strong>Slow, engineered thinking is NOT needed for:</strong></p><ul><li><p>&#8220;Painting a UI button red&#8221;</p></li><li><p>Fixing a bug in an endpoint where you need to check field X instead of Y</p></li><li><p>Writing a CRUD endpoint that&#8217;s the same as an existing one but &#8220;slightly different&#8221;</p></li><li><p>Any other task where the solution is obvious and the cost of error &#8776; 0</p></li></ul><p>For any trivial task, Quint Code will tell you right at the <code>/q-frame</code> stage: u</p><p><em>&#8211; &#8220;Dude, this is trivial &#8212; let&#8217;s just do it and record the decision.&#8221;</em></p><p><strong>But slow, engineered thinking IS needed when the task:</strong></p><ul><li><p>Is split across people, teams, or AI agents</p></li><li><p>Has delayed, noisy, or expensive feedback from the real world (see the problem classes earlier in this post)</p></li><li><p>Involves trade-offs between speed, quality, and risk that we need to make explicit &#8212; the cost of a wrong call is high</p></li><li><p>You &#8220;feel&#8221; that existing, familiar approaches will break down or fail to handle this task (or you&#8217;ve already watched them fail on similar ones)</p></li><li><p>The cost of error is above zero at all (and you won&#8217;t find out for six months)</p></li></ul><p>Based on all of this, I concluded that FPF is needed in <strong>any real, living production environment</strong>, which means I need to lower the cost of using the specification and make as many benefits as possible accessible to the broadest number of developers. Which means &#8212; time to resurrect Quint Code!</p><h3>Expectation vs reality</h3><p>People think code will get better on its own if we just keep hammering agents in circles or throw buzzwordy applied technologies at it. But no. Only <em>decisions</em> get better. This is about upstream quality. Code is always downstream. If the decision is right, the code (even AI-generated) may vary in &#8220;applied quality,&#8221; but it will most likely stay within the bounds of the right decision &#8212; you see what I mean?</p><p>If the decision is wrong &#8212; no linter and no RLHF loop will save you.</p><div><hr></div><h2>What&#8217;s next: Quint Code Roadmap</h2><h3>Codebase Awareness &#8212; in progress right now</h3><p>The biggest problem with the current version: Quint knows about decisions but is blind to the connection between code and specifications.<br>But I already spoiled that this is nearly solved while I was writing this post!</p><p>We&#8217;ve addressed this problem at three levels:</p><p><strong>Level A &#8212; File Drift Detection</strong>: when the code under a decision changes &#8212; the decision is automatically flagged as potentially stale. QC deterministically identifies WHAT changed (file hashes, diff), and your agent checks and evaluates &#8212; is this change IMPORTANT or cosmetic.</p><p><strong>Level B &#8212; Module Coverage Map</strong>: Quint Code tries to understand your project&#8217;s structure &#8212; what modules exist, which ones are covered by decisions, and which are blind spots. &#8220;Module payments/ &#8212; 12 files, zero decisions. This is your riskiest blind spot.&#8221; Honestly, I&#8217;m thrilled about this feature.</p><p><strong>Level C &#8212; Dependency Impact Analysis</strong>: And finally, when module A changes, Quint Code will at some point see this in the dependency graph and flag decisions for modules B and C that depend on A. This is serious cross-module architectural analysis. No tool does this right now &#8212; IDEs show code, ADR tools show decisions (and even those might be stale). Nobody connects the two. Quint Code has just started trying to do this; the feature is raw, but even in this form it&#8217;s simply magnificent. I&#8217;ll do my best to make it as stable as possible.</p><h3>What else is on the horizon &#8212; though no guarantees we&#8217;ll get there</h3><p>A few ideas I&#8217;m exploring:</p><p><strong>Cross-Project Decision Memory</strong> &#8212; <code>~/.quint/global/</code>, a personal knowledge base that grows across projects. You decided &#8220;PostgreSQL over MySQL&#8221; on project A with evidence for why. On project B, an analogous problem comes up &#8212; Quint Code says: &#8220;You&#8217;ve already made this decision, here are the arguments. But let&#8217;s double-check anyway, because this is a different project &#8212; different context, trust is reduced, but the idea might still be solid!&#8221; In short &#8212; every project makes your agent smarter.</p><p><strong>Adversarial Verification</strong> &#8212; before recording a decision, a second pass: counterarguments, checking for self-referential evidence (when the agent cites its own conclusions as proof), attacking the declared weakest link. If the decision survives &#8212; it gets verified status. If not &#8212; it goes back for rework.</p><blockquote><p>Adversarial Verification is already in the dev branch; the minimal implementation turned out to be trivial &#8212; just tweaking the prompt of the<br><code>/q-decide</code> command.</p></blockquote><p><strong>Team Decision Sync</strong> &#8212; multiple engineers collaborating on a single <code>.quint/</code> database. When Alice and her agent are working on a caching strategy &#8212; Bob and his agent will see it. When Bob&#8217;s evidence disproves a decision &#8212; it automatically goes stale. This is probably the biggest &#8220;feature&#8221; &#8212; obviously it would require building an entire platform around Quint Code.</p><p><strong>Decision-as-Infrastructure</strong> &#8212; decisions stop being documentation in code and move to the infrastructure level. You could build CI/CD gates based on R_eff. PR checks that show which decisions are affected by changes! Essentially, this is a move toward automatically turning test results into evidence that updates the project&#8217;s decision base. But this too is a big &#8220;feature&#8221; &#8212; platform territory again.</p><h2>Conclusion</h2><p>I&#8217;m not sure how to wrap this up &#8212; the ambitions are grand, and I really want to make sure this tool actually works, and not just in my own hands.</p><p>Just install Quint Code and give it a try &#8212; the full cycle or the simplest mode. I&#8217;d love to hear your feedback and suggestions!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for free to receive new posts and support my work. Thank you &lt;3</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Don’t Fool Yourself: Context Graphs]]></title><description><![CDATA[Context graphs can improve institutional memory, but without identities, versioning, access controls, and auditability they quickly become a pretty data dump]]></description><link>https://letters.ivanzakutnii.com/p/dont-fool-yourself-context-graphs</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/dont-fool-yourself-context-graphs</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Tue, 17 Feb 2026 15:40:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!IjJK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IjJK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IjJK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png 424w, https://substackcdn.com/image/fetch/$s_!IjJK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png 848w, https://substackcdn.com/image/fetch/$s_!IjJK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png 1272w, https://substackcdn.com/image/fetch/$s_!IjJK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IjJK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png" width="1100" height="700" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1100,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1188108,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ivanzakutnii.substack.com/i/188272737?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IjJK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png 424w, https://substackcdn.com/image/fetch/$s_!IjJK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png 848w, https://substackcdn.com/image/fetch/$s_!IjJK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png 1272w, https://substackcdn.com/image/fetch/$s_!IjJK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F971a99d1-28ac-438f-8a7b-cd28bc2a774f_1100x700.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>The most expensive problem in an engineering organization isn&#8217;t bugs or speed. It is <strong>amnesia</strong>. And today almost every modern company is <strong>engineering-driven</strong> in one way or another :)</p><p>By amnesia I mean this: you seem to ship features/products fast, but you keep ending up in archaeology mode, and you have to dig to remember &#8220;who even remembers this&#8230;&#8221;, &#8220;where did we discuss it&#8221;, &#8220;why did we do it this way&#8221;.</p><p>Knowledge about our systems gets spread randomly across Slack, Jira, Git, AI notes from calls, and finally (worst of all) inside personal heads.</p><p>And now we have <strong>context graphs</strong>. The pitch often sounds like this: &#8220;let&#8217;s collect <em>decision traces</em> from different places, connect them, and get institutional memory! It will help with audits, onboarding, and finding past decisions&#8230;&#8221;.</p><p>A <strong>context graph</strong> is a graph built from events/decisions (<em>decision traces</em>), then used for context-based search (often also as a base layer for an AI agent).</p><p>Nothing fundamentally new: under different names, this &#8220;contextuality&#8221; idea has existed in IT and engineering for a long time: <em>audit trail</em>, <em>process mining</em>, <em>data lineage</em>, <em>knowledge graph</em>, <em>ADR/decision log</em>, <em>event sourcing</em>. What&#8217;s new is that it&#8217;s cheaper now, and people add LLM agents on top.</p><p>Great thing, but dont fool yourself: this is not a silver bullet, and there are <strong>critical pitfalls</strong> here.</p><p>Here they are.</p><h4><strong>1) System entity identification.</strong></h4><p>&#8220;Alex&#8221;, &#8220;Alexander&#8221;, &#8220;@alex&#8221;, &#8220;alex@corp&#8221;, &#8220;mr.crablex&#8221; in Discord - one person or five different people? Until you resolve this formally, your graph will likely already be lying.</p><h4><strong>2) Age and versions.</strong></h4><p>Policies change, org structure changes, every decision has an &#8220;expiration date&#8221;. Does your graph model that? It had better. Otherwise you will apply a precedent from the previous CFO&#8217;s era as if it were &#8220;eternal truth&#8221;.</p><h4><strong>3) Access and retention.</strong></h4><p>If you just put &#8220;why we rejected candidate/client X&#8221; into one layer, and also &#8220;forever&#8221;, you just created a security and compliance problem. At some point, someone with access (doesn&#8217;t matter who) will leak a database dump to places you won&#8217;t like.</p><h4><strong>4) Ethics and incentives.</strong></h4><p>The moment people understand/think that &#8220;big brother writes personal notes on everyone&#8221;, they move real discussion into Slack DMs or non-corporate messengers. Graph completeness? Questionable.</p><h4><strong>5) Mixing facts and explanations.</strong></h4><p>LLMs love writing beautiful &#8220;why&#8221; text. If this enters the same layer as real facts, you permanently lose auditability.</p><div><hr></div><p>It is also important not to confuse &#8220;memory&#8221; with a real model of how the org works. <em>Decision traces</em> in the format people propose are not &#8220;why&#8221;. They are <strong>just evidence</strong>. And until their attributes, identities, and links to other data are verified, they are, strictly speaking, unverified traces.</p><p>Evidence is great for &#8220;what happened and who clicked the button&#8221;, but it does not have to answer &#8220;what was going on in people&#8217;s heads and in that situation? what led to this click? who decided to click, and based on what, and why exactly then?&#8221;. That whole part is about &#8220;why&#8221;.</p><p>So if a graph (or an AI agent on top of it) cannot honestly say &#8220;I don&#8217;t know&#8221;, it will <strong>lie</strong> confidently, without meaning to.</p><p>Many context-graph supporters already admit this key point: &#8220;why&#8221; is often not verifiable, and in reality we mostly capture &#8220;how&#8221; - sequence of actions, policies, approvals - and only maybe from that we get closer to &#8220;why&#8221;.</p><p>This is already honest. Let&#8217;s spread this honesty in the community: <em>everything above the &#8220;how&#8221; level should have <strong>hypothesis</strong> status, not truth status.</em></p><blockquote><p>Wait, you mean we must model statuses too?! YES.</p></blockquote><p>My point is simple: without explicit context boundaries, a clear term dictionary, system/subsystem invariants, and also preferably versioning for everything that should be versioned, such a graph quickly becomes a pretty dump: <strong>more and more data, less and less reproducibility - until reproducibility becomes almost impossible.</strong></p><p>In context-graph discussions, lines like <strong>&#8220;schema isn&#8217;t the starting point, it&#8217;s the output&#8221;</strong> sound cool (and in a very narrow research sense can even be true), but as an engineering principle this is a ticking bomb.</p><p>Sure, trace collection can start &#8220;without schema&#8221;.</p><p>But rational use of these traces will still require a model, ontology, and contracts! Otherwise you don&#8217;t have a &#8220;living graph&#8221;, you have a living argument about what words in graph outputs even mean.</p><p>&#8220;Schema at the output&#8221; without clarification is a plain lie. The clarifications are these: I believe only a real, persistent AGI could restore a good organizational model from an unstructured, badly modeled graph (a dump), so we could finally do all the things context-graph marketing promises. And this AGI would still need to go talk to directors and employees to clarify and validate many things :)</p><p><em><strong>In the end you get the same model you could build from day one even without any graphs - and then build graphs and all the nice extras around that model.</strong></em></p><p>Here is a free fast test for any &#8220;context graph&#8221; solution:</p><ul><li><p>Does it show <strong>proofs</strong> (sources/links/timelines) for every answer, or only generate a pretty story?</p></li><li><p>Can it say <strong>&#8220;dude, I don&#8217;t know, I don&#8217;t have enough data&#8221;</strong>?</p></li><li><p>Does it track <strong>versioning</strong> of nodes (whatever nodes are in this system), or is it &#8220;it somehow works&#8221; and &#8220;schema later&#8221;?</p></li><li><p>Can it let you <strong>reproduce</strong> a decision on a snapshot of &#8220;how it was back then&#8221;, without extra ceremony?</p></li></ul><p>Only after that should you automate memory.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">If this post was useful, please subscribe to my Substack for free and share this post with one friend. It really helps me keep writing! Thanks :)</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Quint Code — Systems Thinking for Programmers]]></title><description><![CDATA[tiny yet powerful]]></description><link>https://letters.ivanzakutnii.com/p/quint-code-systems-thinking-for-programmers</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/quint-code-systems-thinking-for-programmers</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Thu, 18 Dec 2025 07:52:27 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kRJw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kRJw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kRJw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kRJw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kRJw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kRJw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kRJw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg" width="1365" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1365,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:410424,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ivanzakutnii.substack.com/i/181967247?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kRJw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!kRJw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!kRJw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!kRJw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9008178-a5cd-4bd0-9976-ff58b4204a1a_1365x768.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I often see the same problem: engineers spend weeks searching for a solution not because the task is hard, but because there&#8217;s no structure for thinking about it. Or there&#8217;s no way to focus on that task due to too much routine work.</p><p>Context gets scattered, hypotheses are generated chaotically, tested by gut feeling (&#8220;seems to work&#8221;, &#8220;this should just work&#8221;), and either never written down or lost in chats, messy drafts, endless &#8220;Save for later&#8221; in Slack.</p><p>The result &#8212; either jumping to the first solution that &#8220;sounds reasonable&#8221; (hello, bias), or analysis paralysis.</p><p>This isn&#8217;t always, and not necessarily, a skills problem. It&#8217;s a problem of missing infrastructure and system for thinking.</p><p>I was inspired by the First Principles Framework and made quint-code to try to give this infrastructure to a wider range of developers.</p><div><hr></div><p>Last Sunday I attended a seminar at Engineers-Managers Workshop where Anatoly Levenchuk was talking about FPF.</p><p>What is it? It&#8217;s a powerful <strong>systems thinking framework</strong> &#8212; the essence of best practices in systems thinking and first principles. It&#8217;s complex, extensive, and incredibly cool.</p><p>Anatoly mentioned that even LLMs, which can&#8217;t fit the entire FPF in context (it&#8217;s 3,348,537 characters, roughly 837,000 tokens), work surprisingly well if you just attach the FPF specification file to a ChatGPT chat.</p><p>Anatoly emphasized that he deliberately doesn&#8217;t try to &#8220;simplify&#8221; FPF to code or utilities, because the target audience is much wider than software engineers.</p><p>But I&#8217;m a programmer :) So I thought &#8212; why not?</p><p>Meet Quint Code, a tiny FPF-based tool for an engineer&#8217;s daily work (and not just programmers!) &#8212; on <a href="https://github.com/m0n0x41d/quint-code">GitHub</a></p><div><hr></div><h3>What Is It (in simple terms)</h3><p>Quint Code is a set of commands for the Claude Code CLI agent that turn it into a methodical systems architect.</p><p>It guides you through the ADI cycle:</p><ol><li><p>Abduction (Hypothesis generation) &#8212; throw out options, from boring to radical.</p></li><li><p>Deduction (Logical check) &#8212; find contradictions without writing a single line of code.</p></li><li><p>Induction (Empirical check) &#8212; tests, benchmarks, research.</p></li></ol><p>The output isn&#8217;t a piece of code, but a Decision Rationale Record (DRR) &#8212; a document that says: <em>&#8220;We chose solution X because facts Y and Z indicate this solution fits. We rejected solution W because tests showed risk N. We need to revisit this decision if load grows 10x.&#8221;</em></p><p>It&#8217;s just written with some metadata and a bit more formality.</p><p>We&#8217;ll return to this cycle and look at it in more detail later.</p><h4>One of the Key Principles: External Transformer</h4><p>The idea is this: <em>a system cannot transform itself. It needs an <strong>external</strong> agent.</em></p><p>In our case &#8212; that&#8217;s YOU.</p><p>Claude Code generates hypotheses, finds evidence, writes plans. But we make the decision at each step. The human here is that external transformer. So Quint Code does everything to keep the user from relaxing and skipping uncomfortable questions.</p><div><hr></div><h3>Systems Thinking in Disguise</h3><p>The first version was just a set of steps, mostly ADI, without additional FPF formalities.</p><p>But in version 2.1.0 I went further and hid the complex FPF ontology &#8220;under the hood&#8221;. The beauty is that you don&#8217;t need to know FPF to use it to some degree &#8212; the command cycle in Quint Code itself makes you follow the principles.</p><p>The cycle looks something like this:</p><h5>1. Agentic Init &amp; Context Awareness</h5><p>When you run <code>/q0-init</code>, Claude Code creates a directory structure for FPF work. It also scans your repository to understand context. Yes, like a regular init in agent CLIs, but you&#8217;ll likely be taken through an interview to ground the project context even more: &#8212; <em>&#8220;I see Python and Django. What&#8217;s our budget? Expected scale (100 rps or 100k rps)? What are the hard constraints?&#8221;</em></p><p>The result is written to <code>.fpf/context.md</code>. After that, any hypothesis is checked not in a vacuum, but with this context in mind. Claude Code will say: <em>&#8220;This idea is really cool, but to train such a neural network we&#8217;d need a GPU, and the context says &#8216;low budget&#8216;&#8220;</em>.</p><h5>2. Strict Separation: Method vs Work</h5><p>FPF has a Strict Distinction principle. In the tool it&#8217;s implemented like this: any hypothesis is now split into two parts:</p><ol><li><p>The Method (Design-Time) &#8212; Plan. Recipe. What do we actually want to do?</p></li><li><p>The Validation (Run-Time) &#8212; Evidence. Tests. Logs. What actually happened.</p></li></ol><p>Working with FPF makes it much harder to confuse <em>&#8220;I figured out how to do it&#8221;</em> with <em>&#8220;I proved it works&#8221;</em>.</p><h5>3. NQD (Novelty, Quality, Diversity)</h5><p>When you run <code>/q1-hypothesize</code>, Quint Code doesn&#8217;t just throw a few hypotheses for research &#8212; it must classify them:</p><p>&#8212; Conservative: Proven, reliable solution. &#8212; Novel: &#8220;Modern&#8221;, enthusiastic approach. &#8212; Radical: Risky but potentially powerful solution.</p><p>This protects against getting stuck on what you already know.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">If you are enjoying the reading so far &#8211; subscribe.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h3>The ADI Cycle Up Close</h3><p><strong>Phase 1: Abduction</strong> &#8212; &#8220;What are the options? What do we do with all this?&#8221; Command <code>/q1-hypothesize</code>.</p><p>Instead of jumping to code the first solution that comes to mind, we generate a space of options. Claude Code will suggest 3-5 hypotheses of varying novelty and complexity.</p><p><strong>Phase 2: Deduction</strong> &#8212; &#8220;Where&#8217;s the logical hole?&#8221; Command <code>/q2-check</code>.</p><p>We&#8217;re not writing implementation yet, nooo, that&#8217;s still far off :) At this stage we test hypotheses for logical soundness (together with the LLM).</p><p>&#8212; <em>&#8220;If we start building microservices (hypothesis), and we have 2 juniors on the team (context), 1 mid-level and no infrastructure engineers &#8212; we&#8217;ll die at the devops stage.&#8221;</em></p><p>The hypothesis is rejected before you spent 2 weeks setting up Kubernetes. And then a year and a half suffering from rapidly growing architecture and infrastructure complexity.</p><p><strong>Phase 3: Induction</strong> &#8212; &#8220;Talk is cheap. Show me the numbers.&#8221; Commands <code>/q3-test</code> (local empirical tests) and <code>/q3-research</code> (external search, like WebSearch and WebFetch on the internet).</p><p>Hypotheses that survived deduction we test in battle. Write a prototype. Run a benchmark. Find documentation. If we feel there&#8217;s not enough evidence to work with hypotheses, we can use <code>/q3-research</code>, gather external information, and then return to checks via <code>/q3-test</code> more thoroughly.</p><p><strong>Phase 4: Audit</strong> &#8212; &#8220;The weakest link doesn&#8217;t mean useless&#8221; Command <code>/q4-audit</code> &#8212; This is the only optional command you can skip and go straight to step five, but I strongly recommend never skipping it, especially if you&#8217;re working on a really complex decision, and/or a decision that could significantly affect your system&#8217;s quality.</p><p>This phase applies the WLNK (Weakest Link) principle: confidence in the entire solution equals confidence in the <em>weakest</em> piece of evidence. If the benchmark is great but the documentation clearly says &#8220;This is a raw API, don&#8217;t use it in production&#8221; &#8212; the solution is probably unreliable.</p><p>Audit is the bias-check and WLNK analysis phase. Here Claude checks:</p><ul><li><p>Are there cognitive biases in the choice?</p></li><li><p>Does confidence in the solution match the weakest link in the evidence?</p></li><li><p>Congruence &#8212; how applicable is external data to your context?</p></li></ul><p><strong>Phase 5: Decision</strong> &#8212; &#8220;Lock it in&#8221; Command <code>/q5-decide</code> Claude gathers everything together: context, hypotheses, evidence, risks. But you &#8212; the &#8220;external transformer&#8221; &#8212; must choose the winner. This is where that Design Rationale Record I mentioned gets created.</p><p>That&#8217;s basically it! Besides the DRR, the <code>.fpf</code> project directory keeps collected evidence that will be useful in the future &#8212; either for new FPF cycles, or&#8230; say, to remember decisions, or write good project documentation.</p><div><hr></div><h3>Real Case: Legacy Monolith, Operational and Technical Debt</h3><p>The task right now: there&#8217;s a legacy monolith and debt in technical and operational decisions. Nothing criminal, typical startup. The load on the team and myself is also &#8220;typical&#8221; for startups.</p><p>After a month and a half of work, I generally understand the main problem areas, but it&#8217;s not entirely clear what to tackle first. And the choice must be made so that the effect is maximum &#8212; the improvement should be multiplicative.</p><p>Although the decision on what to tackle had already been made, I decided to test Quint Code on this exact problem. The task seemed to have a fairly fuzzy context and clearly went beyond just one monolith.</p><p>Ran <code>/q1-hypothesize</code>. Claude suggested:</p><ul><li><p>H1: Fix tests and add them to CI (Conservative)</p></li><li><p>H2: Full refactoring to DDD (Radical)</p></li><li><p>H3: Implement stronger static analysis (Novel)</p></li></ul><p><code>/q2-check</code> immediately threw out H2. We can&#8217;t slow down development or train the current team on design patterns, because DDD requires high expertise that (according to context) isn&#8217;t there yet.</p><p><code>/q3-test</code>: Claude ran existing unit tests. Turns out tests run fast (2s) but fail. Quick setup and run of static analyzer (H3) showed 350+ errors.</p><p>In the end, at <code>/q5-decide</code> we chose a hybrid of H1 + H3 (Fix current tests, write new ones and add them to CI + static analyzer baseline that we won&#8217;t allow to rise above (by violation count) in future codebase changes). H2 (refactoring) was postponed.</p><p>The whole thing took ~25 minutes.</p><p>You might say &#8220;Well, it was probably obvious what to do anyway, right?&#8221;. As I said earlier, yes &#8212; after looking at the code and processes I was <em>leaning</em> toward solving the bottleneck with testing and linters. But I was only <em>leaning</em>. After the FPF session the choice was rock solid, backed by evidence and documented.</p><p>Using artifacts from Quint Code I created a Story task in Jira and soon it will go into work (to Claude Code itself, for example).</p><p>Without this system and artifacts we&#8217;d still be scratching our heads.</p><div><hr></div><h3>Why Not SuperClaude, or Some AgentOS?</h3><p>There are many &#8220;combines&#8221; like SuperClaude or AgentOS that stuff the context with fat prompts or skills, create 15 &#8220;specialized&#8221; subagents and try to &#8220;think for you&#8221;, automate everything. That&#8217;s more about vibe coding &#8212; &#8220;Dear Claude Code, make it pretty&#8221;.</p><p>Has its place, but that place is very far from engineering.</p><p>Quint Code is an exoskeleton, not an autopilot.</p><h5>1. Minimal Overhead.</h5><p>Your regular work with Claude Code stays regular. FPF only activates on command. Yes, in the Quint Code repo I share my CLAUDE.md, but more just as an example. I&#8217;m pretty sure Quint Code will work well without any additional instructions.</p><h5>2. No Magic.</h5><p>You see every step, you think together with Claude Code.</p><h4>3. Structured Memory.</h4><p>The <code>session.md</code> file stores the state of your shared thinking during the session itself. Additionally &#8212; all hypotheses, their statuses, DRR records, evidences are stored. All connected through metadata in files. Even if Claude (or you) &#8220;forgets&#8221; the dialog context, it will re-read documents in <code>.fpf</code> and remember: &#8220;Ah, we rejected MongoDB because we don&#8217;t have an admin&#8221;.</p><p>By the way, Quint Code has additional commands not related to the ADI cycle:</p><h5><code>/q-status</code> &#8212; where are we now?</h5><p>Shows the current cycle phase, list of hypotheses with their statuses (L0/L1/L2/invalid), and suggests the logical next step. Useful when you return to a task after a break, lost the session or &#8220;lost the thread&#8221;.</p><p>It&#8217;s more than expected that working on a complex task you&#8217;ll get stuck at the <code>/q3-*</code> stage for several hours and forget what that stage even was in Quint Code.</p><p>Or you need to continue on Monday&#8230; Quint doesn&#8217;t just drop breadcrumbs, it leaves whole loaves of bread behind.</p><blockquote><p><em>By the way, I&#8217;ve had cases where after </em><code>/q3-test</code><em> there were great scripts that after </em><code>/q5-decide</code><em> transparently moved into the main code. Claude Code while working through the Quint Code cycle still follows your instructions in CLAUDE.md regarding coding style and requirements.</em></p></blockquote><h5><code>/q-query</code> &#8212; search through the accumulated knowledge base.</h5><p>You can search by hypotheses, evidence, past decisions. Filter by confidence level (L0, L1, L2, invalid). For example: <em>&#8220;show all verified evidence about caching, we researched something about this last month&#8221;</em> or <em>&#8220;what hypotheses did we throw out last week on task XXX-123 and why&#8221;</em></p><h5><code>/q-decay</code> &#8212; check evidence freshness.</h5><p>Evidence ages: a year-old benchmark, documentation for an outdated version, links to an article about a deprecated API. This command shows which evidence needs to be re-checked or marked as invalid. After all, a decision made on stale data is a decision made blind.</p><div><hr></div><h4>When to Use Quint Code</h4><p>I&#8217;ll say it: these commands can become an invaluable helper in these cases:</p><ul><li><p>Architectural decisions (database, queue, state management).</p></li><li><p>Complex bugs where the cause isn&#8217;t obvious.</p></li><li><p>Team disputes (need an argued choice) &#8212; copy disputes from Slack to a file and set Quint Code on them.</p></li><li><p>When the cost of error is high.</p></li></ul><p>Quint Code and FPF are completely unnecessary for:</p><ul><li><p>&#8220;Paint the button red&#8221;.</p></li><li><p>&#8220;Write a sorting function&#8221;.</p></li><li><p>&#8220;Fix the bug in the webhooks endpoint, need to check field X not Y&#8221;.</p></li><li><p>And other obvious tasks. Please don&#8217;t use a cannon to kill a sparrow.</p></li></ul><div><hr></div><p>Quick Start</p><p>Global install (recommended for personal use):</p><pre><code><code>curl -fsSL https://raw.githubusercontent.com/m0n0x41d/quint-code/main/install.sh | bash -s -- -g
</code></code></pre><p>Or per-project install:</p><pre><code><code>curl -fsSL https://raw.githubusercontent.com/m0n0x41d/quint-code/main/install.sh | bash</code></code></pre><ol start="2"><li><p>Initialize (Claude will scan the project and ask a couple of questions):</p></li></ol><pre><code><code>claude
/q0-init</code></code></pre><ol start="3"><li><p>Start thinking about your task systematically:</p></li></ol><pre><code><code>/q1-hypothesize &#8220;It seems we shouldn&#8217;t use redis for queues because...&#8221;</code></code></pre><p>Thinking can be an engineering process. You can debug it, optimize it, and version it. Give it a try!</p><p>p.s. Oh, you already guessed that Quint Code can be used not just for software engineering? And that nothing stops you from using MCPs and other tricks in the ADI cycle? You&#8217;re welcome ;)</p>]]></content:encoded></item><item><title><![CDATA[Exception Generation is Pure Evil]]></title><description><![CDATA[This is not a joke!]]></description><link>https://letters.ivanzakutnii.com/p/exception-generation-is-pure-evil</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/exception-generation-is-pure-evil</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Tue, 05 Aug 2025 18:53:03 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!eorU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eorU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eorU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp 424w, https://substackcdn.com/image/fetch/$s_!eorU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp 848w, https://substackcdn.com/image/fetch/$s_!eorU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp 1272w, https://substackcdn.com/image/fetch/$s_!eorU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eorU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp" width="1377" height="897" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:897,&quot;width&quot;:1377,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:741348,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://ivanzakutnii.substack.com/i/170205094?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eorU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp 424w, https://substackcdn.com/image/fetch/$s_!eorU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp 848w, https://substackcdn.com/image/fetch/$s_!eorU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp 1272w, https://substackcdn.com/image/fetch/$s_!eorU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F917b4c8f-b6f4-4ed3-909c-8b345bb4781a_1377x897.webp 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Exception generation. You certainly know what this is and have definitely used it, if you&#8217;ve programmed even a little.</p><p>Here&#8217;s news for you: exception generation is very often bad.</p><p>In any situation where a <code>try/except</code> (or try/catch) block is used not for &#8220;wrapping&#8221; side effects like reading files, going to the network, or in an isolated place around a function (for targeted debugging purposes or simply because &#8220;there&#8217;s just no other way&#8221;) &#8212; it&#8217;s better to get rid of it.</p><p>But why? Because such <code>try/except</code> blocks seriously confuse two &#8220;processes&#8221;:</p><ul><li><p>Program execution flow</p></li><li><p>Developer&#8217;s thought flow who will read this code</p></li></ul><div><hr></div><p>Think about it yourself &#8212; <em>any</em> instruction in a try/except block can throw an exception.</p><p>Does it seem like each <em>such</em> block increases the complexity of our program&#8217;s execution flow graph <em>exponentially</em>? It doesn&#8217;t just seem so.</p><p>Modern static analyzers experience&#8230; <a href="https://www.sciencedirect.com/topics/computer-science/control-flow-analysis">some difficulties</a> with &#8220;invisible execution paths&#8221;.</p><blockquote><p>Do not miss out on me; subscribe wherever you want https://linktr.ee/m0n0x41d</p></blockquote><div><hr></div><h4>Brief historical background.</h4><p>People started talking about exceptions a very long time ago &#8212; in the 40s-50s. The first software implementation appeared in LISP, where there were two functions &#8212; <code>ERROR</code>, which was called in case of a program failure, and <code>ERRORSET</code>, which returned, attention &#8212; either an <em>error code</em> or <code>NIL</code>.</p><p>In other words, this story in LISP is not about the exceptions we have now at all&#8230; The concept and implementation evolved, evolved, and developed to the point where instead of error codes we started <em>generating</em> exceptions, namely &#8212; <em>creating exception conditions</em> and handling them <strong>separately</strong>.</p><p>The period of mass distribution of exception generation fell on the 80s-90s.</p><p>And here&#8217;s the result. From a <a href="https://users.ece.cmu.edu/~koopman/des_s99/exceptions/">study</a> by Carnegie Mellon from 1999:</p><blockquote><p>Exception failures are estimated to cause two thirds of system crashes and fifty percent of computer system security vulnerabilities. Exception handling is especially important in embedded and real-time computer systems because software in these systems cannot easily be fixed or replaced, and they must deal with the unpredictability of the real world. Robust exception handling in software can improve software fault tolerance and fault avoidance, <strong>but no structured techniques exist for implementing dependable exception handling.</strong></p></blockquote><p>I&#8217;m writing this article in 2025, and there&#8217;s still no structured, reliable, implemented method for exception handling.</p><p>Mainstream OOP languages provide the same old try/catch, and frameworks spread several layers of abstractions on top in an even layer, further blurring error boundaries, often providing developers with no ways to handle errors except&#8230; wrapping it all in yet another try/catch.</p><p>On top of that, exception generation can seriously slow down performance. Here&#8217;s fascinating <a href="https://www.baeldung.com/java-exceptions-performance">reading</a> from the Java world. Though it&#8217;s not limited to just Java &#8212; <a href="https://johnfarrier.com/c-error-handling-strategies-benchmarks-and-performance/">here&#8217;s</a> an article about experiments in C++. In Python, especially with 3.11, the situation seems not so dramatic, <em>occurring</em> exceptions slow down code by <em>just 3-5 times</em>.</p><p>I&#8217;ll just leave <a href="https://docs.python.org/2/faq/design.html#how-fast-are-exceptions">this</a> here:</p><blockquote><p>A <code>try/except</code> block is extremely efficient <strong>if no exceptions are raised.</strong></p></blockquote><div><hr></div><p>They say that once upon a time, long, long ago, the grass was greener and programs were easier to verify. The times before the dominance of exception generation came were the times of Structured Programming &#8212; engineers wrote code using conditional operators, loops, and subroutines (functions with one entry and one exit).</p><p>Programs flowed, developed naturally &#8220;top-down&#8221;. Thanks to such determinism, they were easier to read both for people and machines &#8212; the first static code analyzer <code>lint</code> was publicly released in 1979. Well, you already know what happened next.</p><h3>What do we do with all this?</h3><p>You can act like <a href="https://google.github.io/styleguide/cppguide.html#Exceptions">Google</a> (especially if you write in C++):</p><blockquote><p>We do not use C++ exceptions.</p></blockquote><p>In any other popular object-oriented language you need to&#8230; stop using exceptions :)</p><p>Or <em>at least</em> don&#8217;t bury them deep in code &#8212; let the try/catch block wrap a function right where it&#8217;s called (outside or inside). Yes, this might add some amount of boilerplate code, but then when exceptions occur, the execution flow will return faster to the deterministically beaten &#8220;path&#8221;.</p><p>Either way, we <em>can</em> find a way to program without using exceptions for flow control.</p><p>And you can also remember Golang. No matter how angular and dumbed down it might be, the biggest design decision aimed at <em>strengthening</em> Go code produced by developers is forcing them to handle every error explicitly. Yes, Go has defer/panic/recover, but you&#8217;ll have to work hard to twist and mangle the execution flow severely.</p><p>And finally &#8212; functional programming. Result monad, for example. Curtain. &#175;\_(&#12484;)_/&#175;</p><p>However, I think most developers will find it much easier to simply abandon leaking raise/throw &#8212; look at your try/except carefully &#8212; maybe you can use <code>if</code> here? Look at <code>raise</code> &#8212; how about <code>return</code>?</p>]]></content:encoded></item><item><title><![CDATA[Why Augmented after all?]]></title><description><![CDATA[Explaining my interpretation of the AI abbreviation, why it is important for me to primarily talk about Augmented, not Artificial Intelligence]]></description><link>https://letters.ivanzakutnii.com/p/why-augmented-after-all</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/why-augmented-after-all</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Wed, 28 May 2025 19:11:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!EPFQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3></h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EPFQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EPFQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EPFQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EPFQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EPFQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EPFQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg" width="800" height="535" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:535,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EPFQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg 424w, https://substackcdn.com/image/fetch/$s_!EPFQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg 848w, https://substackcdn.com/image/fetch/$s_!EPFQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!EPFQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F584d9bb2-6bf5-4e85-a2fb-28f637eedc3d_800x535.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Why, when talking about AI, do I almost always primarily mean Augmented, not Artificial Intelligence?</p><p>What is Augmented Intelligence anyway?</p><p>In translation, this would sound like&#8202;&#8212;&#8202;Augmented, not Artificial intelligence.</p><p>It&#8217;s quite difficult to establish the authors of the term, because the idea began developing long ago, long before the appearance of transformers, roughly around the same time when AI was first talked about as Artificial (late 60s, early 70s).</p><p>Augmented Intelligence is talked about in so many ways&#8202;&#8212;&#8202;both as a system design pattern, and as an approach to &#8220;human enhancement,&#8221; productivity improvement. The word Augmented appears in the context of theoretical LLM training methodologies and much more. Someone, for example, would rather remember AR, and someone might even think about Musk&#8217;s neuralink.</p><p>Therefore, in this post I want to talk about the interpretation from _my_ point of view, why I use this term, and how seriously I take it.</p><p>My interpretation lies somewhere based on my experience, and still somewhat gravitates toward a &#8220;design pattern,&#8221; we just need to figure out the <em>design</em> and pattern of <em>what</em>.</p><p>TLDR;</p><p><strong>Artificial Intelligence</strong>&#8202;&#8212;&#8202;is about autonomous, independent agents that work completely without humans &#129304;&#127995;<br><strong>Augmented Intelligence</strong>&#8202;&#8212;&#8202;is about a something like symbiosis of human and AI, where each strengthens the other &#128100;&#129309;&#127995;&#129302;</p><p>In reality, the second (augmented) already works much more often and better than the first, is already much more present here than completely independent artificial. And as technology develops, the symbiosis mindset still looks more appealing than the &#8220;exploitation&#8221; mindset, even, not if&#8202;&#8212;&#8202;but when, artificial neural networks become even more cognitively powerful!</p><p>Why exploitation? Because Artificial from the perspective of human &#8220;collective unconscious&#8221; is already fully forming as our species&#8217; relationship to AI as proprietary. Have you seen all those memes about bullying and threats against poor ChatGPT?</p><p>Being the boss&#8202;&#8212;&#8202;might not be bad, but cultivating a boss mindset, in my opinion&#8202;&#8212;&#8202;is counterproductive.</p><p>Let&#8217;s return to my experience and move away from science fiction and anthropological speculation.</p><h4>Mindset matters</h4><p>I&#8217;ve already started talking about mindset, and this is very important. Unfortunately or fortunately, AI is quite limited, especially as soon as we try to apply it in a narrow, vertical niche.</p><p>When communicating with things like ChatGPT or Claude, many people get the impression that &#8220;it&#8217;s very smart,&#8221; &#8220;it can do almost anything.&#8221; This impression forms not only among individuals, but also among companies, entrepreneurs who attempt to build new business with LLM or start a new one altogether.</p><p>Even quite experienced engineers and managers can find themselves believing that AI systems are something completely magical, quite simple in terms of implementation&#8202;&#8212;&#8202;&#8220;well, it&#8217;s already smart, right? It&#8217;ll figure out our mess somehow, and we&#8217;ll live happily ever after!&#8221;</p><p>As a result, another misconception follows&#8202;&#8212;&#8202;AI-related projects don&#8217;t need to be thought through or modeled at all.</p><p>In reality, this turns out to be a path to nowhere. Teams lightning-fast encounter difficulties and spend a long time learning the hard way, feeling out what and how LLM can do, and what it can&#8217;t, ultimately coming to the fact that people have <em>one language</em> in their heads, the model has a completely <em>different language</em>, we&#8217;ll still have to engage in ontological modeling of both the system itself and the language in which we communicate with each other and with the AI agent.</p><p>It turns out that humans are needed in AI systems much more than expected&#8230; and here we smoothly approach Augmented.</p><h4>Human as part of the system</h4><p>As long as AI hasn&#8217;t become a recognized or even a form of life, we continue to collectively exist in human society. Knowing or at least suspecting AI&#8217;s limitations, and <em>especially knowing about the exceptional potential</em> of this technology, I believe it&#8217;s correct to talk specifically about Augmented Intelligence as a way to effectively change our reality and ourselves for the better.</p><p>Already now, more and more quality AI systems are appearing, but all these surviving systems are either extremely specific and aimed at performing concrete tasks, or complex systems, workflow pipelines, which necessarily have human(s) who at minimum service the system, but often also perform the role of observer and quality controller.</p><p>Moreover, these systems themselves are obviously aimed at being used by end users&#8202;&#8212;&#8202;people, outside the organization as clients, or inside, if we&#8217;re talking about AI Platform.</p><p>I&#8217;m getting at the fact that even if we consider a scenario of a &#8220;very vertical&#8221; agent/AI system&#8202;&#8212;&#8202;it was still modeled, created by people, and serves people. Whatever AI is, however we consider it&#8202;&#8212;&#8202;it&#8217;s <em>already</em> closely linked with our large and small systems.</p><p>What about systems that still manage to be &#8220;without LLM,&#8221; and which might even manage to remain so for a long time, due to business specifics&#8202;&#8212;&#8202;here it still makes sense to talk about Augmented, because the efficiency of people working in such organizations can (and often already does) accelerate thanks to rational use of neural networks in their work.</p><h4>Two scenarios of AI usage</h4><p>If we consider from the end user&#8217;s perspective, AI has now become that very magic box, with which the user can start becoming very stupid (Artificial Intelligence mindset&#8202;&#8212;&#8202;the user almost completely delegates slow thinking to LLMs, and their cognitive abilities degrade), or develop, learn, get smarter, accelerate their work on routine tasks with the help of LLMs, quickly get feedback, strictly evaluate it&#8202;&#8212;&#8202;delegate a lot of fast thinking to LLM so it happens <em>even faster</em>, some selected part of slow thinking, but continue to <em>make decisions</em> intermediate and final, as well as <em>apply mental effort</em> to the task <strong>independently</strong> (Augmented Intelligence mindset).</p><h4>What&#8217;s next?</h4><p>I think there&#8217;s nothing wrong with creating more and more AI products, agents to help human agents or other AI agents.</p><p>Wherever the evolution of artificial neural networks goes, I&#8217;m completely uninterested in speculating about doomsday and other &#8220;analytical&#8221; nonsense&#8202;&#8212;&#8202;obviously, we won&#8217;t stop anymore, and benefits are still manifesting more than harm.</p><p>Yes, there seems to be a threat of depriving many people of physical labor, well, maybe it&#8217;s time to work more with brains and create? Or maybe on the contrary, more jobs will appear, of completely new quality, but which will still have to be adapted to in an Augmented manner?<br>I don&#8217;t know, in this blog I&#8217;m not going to waste my and your attention on these reflections, there&#8217;s too much such material, and if you&#8217;re interested&#8202;&#8212;&#8202;you&#8217;ll easily find it.</p><p>As I already said&#8202;&#8212;&#8202;Augmented Intelligence is about cooperation of different agents, strengthening each other. I want to believe that in this &#8220;design pattern&#8221; we&#8217;ll start building systems in which we not only better cooperate with LLM, but also as human with human.</p><p>Therefore, in my blog I write specifically about designing such &#8220;symbiotic&#8221; systems&#8202;&#8212;&#8202;where AI strengthens humans, at least even with the result of work on assigned tasks.</p><p>I believe that the conversation about Augmented&#8202;&#8212;&#8202;is grounding in reality, in understanding systemicity and interconnections. This is a path of thinking toward <em>the conversation itself</em> and efficiency overall. The conversation about Artificial&#8202;&#8212;&#8202;is too ephemeral, often speculative and entertaining, simply because <em>it happened that way</em>, while focusing on artificiality looks like directing attention only toward LLM, whereas in the conversation about Augmented we don&#8217;t forget about ourselves, and about other agents that will work in our system.</p><p>If you&#8217;re building AI systems and want them to actually work in reality and in production&#8202;&#8212;&#8202;<a href="http://links.ivanzakutnii.com">welcome</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Neural Stack! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Productivity through primary metrics: how to finally understand where your time goes]]></title><description><![CDATA[A deep dive into how to break free from the dopamine matrix and so-called procrastination]]></description><link>https://letters.ivanzakutnii.com/p/productivity-through-primary-metrics</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/productivity-through-primary-metrics</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Tue, 15 Apr 2025 17:03:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5fjW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5fjW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5fjW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5fjW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5fjW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5fjW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5fjW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg" width="1456" height="799" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:799,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Productivity through primary metrics: how to finally understand where your time goes hero image&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Productivity through primary metrics: how to finally understand where your time goes hero image" title="Productivity through primary metrics: how to finally understand where your time goes hero image" srcset="https://substackcdn.com/image/fetch/$s_!5fjW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5fjW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5fjW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5fjW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F282e8bb3-d8f6-4f8f-b1a9-8dc181dae142_1596x876.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Introduction</h2><p>In a world where we&#8217;re constantly offered new task management apps, time management techniques, and approaches to increase productivity, many of us find that despite all these tools, our real effectiveness barely changes.</p><p>We implement GTD, practice Pomodoro, use Kanban boards, read about Atomic Habits and Japanese Kaizen &#8212; but somehow we continue to feel overwhelmed and not productive enough, and often abandon these ideas altogether.</p><p>The main problem is that most productivity methods operate in a vacuum &#8212; they offer systems for organizing tasks but don&#8217;t address the fundamental question: <strong>what exactly are we spending our time on in reality</strong>. Without this basic understanding, even the most advanced methods remain just theoretical constructs that can&#8217;t significantly change our lives.</p><p>In this article, I propose a radically different approach to productivity, based on collecting and analyzing <strong>primary metrics</strong> &#8212; objective data about how your time is actually distributed.</p><p>We&#8217;ll look at the two most important resources &#8211; time and attention.</p><p>By honestly applying the practice I&#8217;m suggesting, you&#8217;ll be able to:</p><ul><li><p>See the real picture of your time expenditure without illusions or self-deception</p></li><li><p>Identify hidden sources of time loss that you might not be aware of</p></li><li><p>Create a personalized, convenient productivity system based on your preferences</p></li></ul><p>Also from this article, you&#8217;ll learn:</p><ul><li><p>Why without primary metrics, any productivity system is almost certainly doomed to fail</p></li><li><p>How I came to realize the importance of measuring time through personal experience</p></li><li><p>A simple and flexible system for categorizing time that you can start using</p></li><li><p>How to implement time tracking without turning it into an additional source of stress</p></li><li><p>How to analyze the collected data and use it for real productivity improvements</p></li></ul><p>Don&#8217;t worry &#8212; I&#8217;m not suggesting you become obsessed with every minute of your life. Instead, I&#8217;ll share a balanced and fundamental approach.</p><p>But all this will only work if you&#8217;re truly ready to finally see where your <em>precious</em> time is actually leaking away.</p><h2>Why we need primary metrics</h2><p>Primary metrics are extremely important whenever we truly strive to change any process for the better. Today we&#8217;re looking at our own lives and work on any projects as the process.</p><p>But first, I&#8217;ll tell you my path to the proposed <em>system</em>.</p><p>For quite a long time, I used todo lists and something resembling GTD. The everyday life of a family with a small child in rented housing in a foreign country can be quite unpredictable, but todo lists have increased my productivity over the past year and a half.</p><p>The more tasks I delegated to my todo list, the more computing power remained in my brain to perform work tasks more <em>focused</em>.</p><p>And I started to perform much more of them, so much so that I began to overwork in unhealthy proportions.</p><p>When I realized that overworking was a big problem, I started using time tracking to account for the time I spend <em>on work</em>. This was a purely intuitive decision; I was tired of overworking.</p><p>Although such tracking didn&#8217;t become a habit right away, over the course of several months I started working a reasonable amount of time.</p><p>But I didn&#8217;t feel like I had more resources for my own projects. I was still responding to any new ideas like this - &#8220;when would I ever have time for that?&#8221;</p><p>I spent most of my working time in focus periods, measuring them using the pomodoro method.</p><p>I was doing a lot, but I wasn&#8217;t doing it productively. Although all work tasks were moving forward, almost all of my projects looked as if they were standing still. I didn&#8217;t have time to regularly write a blog, think through and develop my side projects. I only had time to work, create new tasks for myself, study software engineering, and do something else <em>in bits and pieces</em>.</p><p>The problem turned out to be that I wasn&#8217;t trying to specifically ask myself the question - &#8220;where am I spending my time&#8221; and honestly find an answer to it.</p><p>The answer came through <em>primary metrics</em>. How do you collect these metrics?</p><blockquote><p><em>Track time.</em></p></blockquote><p>Wait. But wasn&#8217;t I measuring the time I spent on work? Yes, I was, but the goal wasn&#8217;t to collect metrics and understand <em>where, what I&#8217;m actually spending time on</em>, but simply to stop overworking.</p><p>And I achieved this goal, but didn&#8217;t achieve an overall improvement in productivity and quality of work across all my areas.</p><p>I filled all the other time (outside of work) with tasks that I managed to grab from the first or second priorities of my todo list.</p><p>Everything changed when I became familiar with the idea about the importance of primary metrics, the importance of grounding any ideas and theories <em>in reality</em>.</p><p>In fact, the applied methodology of productivity and work organization is not so important. It&#8217;s not important in the sense that there are many such methodologies, and different methodologies are well suited to different people.</p><p>But no methodology will work properly if you don&#8217;t realize <em>what you&#8217;re actually working with, what&#8217;s really happening? How much work and resources are being spent? How productive is it in terms of progress toward the result?</em></p><p>Our most valuable resource is time, and in order to take a step into a more productive future, you need to understand where you&#8217;re spending this resource. Then you can choose whatever methods you like (or even develop your own) and use them effectively.</p><div><hr></div><p>Perhaps you&#8217;re already scared now, and you have thoughts like this - <em>&#8220;it&#8217;s absolute madness to track every activity by the hour! I&#8217;ll go crazy, I&#8217;ll just waste more time constantly recording these time intervals!&#8221;</em></p><p>You&#8217;re absolutely right &#8211; just trying to track where you spend your time without a <em>system</em> is difficult, will cause a lot of stress, and might be the opposite of the idea of efficiency.</p><p>That&#8217;s why I&#8217;m writing this guide article for you.</p><h2>Time categorization system</h2><p>Today I&#8217;m offering you a categorization system that will help you collect metrics without much effort.</p><p>Good news:</p><ol><li><p>It&#8217;s not difficult; you already have everything you need to get started</p></li><li><p>You don&#8217;t need to mark the time minute by minute, and you probably won&#8217;t be able to. A drift of 15-30 minutes is more than acceptable to begin with</p></li><li><p>I&#8217;m not suggesting you become a productivity maniac and track time for the rest of your life (this is an optional habit, and you&#8217;re free to decide in the future whether you need it or not)</p></li></ol><p>Bad news:</p><ol><li><p>You&#8217;ll have to work independently with what you discover. I&#8217;m not giving you a fish, but a fishing rod.</p></li></ol><p>As you can see - there seems to be more good news, right? :)</p><h3>First-class abstraction</h3><p>A good abstraction in software engineering is one that <em>generalizes</em> rather than specifies.</p><p>So, to get closer to a breakthrough in productivity, I suggest you try tracking how much time in your life you spend, divided into the following categories:</p><ul><li><p>Productive time</p></li><li><p>Investment time</p></li><li><p>Body maintenance</p></li><li><p>Everyday life and rest</p></li><li><p>Time wasted</p></li></ul><p>Let&#8217;s understand what these categories are.</p><h3>Productive time</h3><p>Productive time is time you spent on <em>focused</em> work on specific tasks (like work tickets from a Kanban board). This is time spent on tasks that bring you closer to achieving some already outlined, planned, and specific goal. For example, strategic planning can also be included here - because it&#8217;s aimed at moving somewhere, it&#8217;s clear which direction to &#8220;dig,&#8221; we actually have a task like &#8220;Research X to understand how to do Z for project Y.&#8221;</p><h3>Investment time</h3><p>This is time you spend on self-education, general research work (searching for new ideas and opportunities), or on your side projects.</p><p>Investment time is called that - not only because learning and research are truly investments in your future but also because in case of urgent need, this time can be &#8220;sacrificed&#8221; in favor of <em>productive time</em> to complete a project or deal with some work emergencies.</p><h3>Body maintenance</h3><p>Sleep, food (quick preparation, but not fast food). Normal food that can be prepared and consumed in a reasonable time, not 2-3 hours. If you decided to prepare a lavish dinner for a celebration in the middle of the week - such time is more related to &#8220;Everyday life and rest.&#8221;</p><p>In general, the body maintenance category can be omitted from time tracking altogether, especially at the beginning, or if you have other monitoring sources (smartwatch/bracelet).</p><p>But we&#8217;ll come back to this.</p><h3>Everyday life and rest</h3><p>Everyday life and rest are all activities related to maintaining the home, paperwork, taking/picking up a child from kindergarten, and other routines.</p><p>Perhaps this category will be the first candidate for finding &#8220;time wasted.&#8221; Well, or at least you&#8217;ll have something to grab onto and start asking yourself questions like &#8220;what was I doing here for SIX hours? What kind of everyday life is that?&#8221;</p><p>We should strive for a system where the everyday life and rest category is not used to plug holes in your schedule, except for emergencies like hospital visits, or household chores that cannot be rescheduled from the middle of the work schedule to another time.</p><p>It&#8217;s better not to mix productive and investment time with other activities because, according to Kahneman, the brain takes quite a long time to get into slow thinking - 20 minutes! This means if you work on a difficult intellectual task using the pomodoro method, you&#8217;ll just be <em>warming up</em> during the first pomodoro! It&#8217;s not very productive to jump up and go on errands after that.</p><p>You can start by tracking in this category all the time that doesn&#8217;t fall under <strong>all other</strong> categories.</p><blockquote><p><em>Be vigilant, &#8220;all other&#8221; means including the one below!</em></p></blockquote><h3>Time wasted</h3><p>This category is for time that you &#8220;invested&#8221; in nonsense that brings you nothing (or almost nothing) useful in the long run.</p><p>By default, it&#8217;s not assumed to deliberately spend time (for hours) on nonsense. This category is rather designed for rewriting blocks of time (in whole or in part) from productive or investment time, during which we worked inefficiently or were distracted.</p><p>Of course, it&#8217;s also worth considering a scenario where you&#8217;re in a position of personal growth, where you&#8217;re already aware that you&#8217;re wasting time on nonsense, but this nonsense is so pleasant to you and allows you to <em>seemingly</em> rest well that you can&#8217;t get rid of it yet. This is normal! No judgment!</p><p>In this case, you can purposefully spend time on nonsense, so that later in the context of the week you can see how much goes there. Perhaps such a metric will help you stop doing this nonsense.</p><p>In general, it&#8217;s entirely your subjective matter to determine what is nonsense for you and what is everyday life/routine/rest. The topic of quality rest is a candidate for a separate article, subscribe! &lt; INSERT LINK TO LINKS PAGE &gt;</p><h2>Practical implementation of the system</h2><h3>How to use this and what to do with it?</h3><p>The categories presented above are a starting point, a framework on which I suggest you build your own approach to measuring your real time expenditures.</p><p>Here is a key point about composure and mindfulness.</p><p>Measuring metrics by itself gives almost nothing; you need to have a goal, and after collection, analyze these metrics.</p><p>The goal can be formulated very simply, for example - <em>&#8220;I want to manage to do more!&#8221;</em>, or more specifically <em>&#8220;I want to stop spending so much time on nonsense&#8221;</em>, or even <em>&#8220;I want to find time to start doing X&#8221;</em>, where X can be anything - learning a new profession, or pursuing a hobby.</p><h3>Tools for collecting time metrics</h3><p>Here, for example, is what a report looks like in my chosen time tracker for the week:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SIkf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SIkf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png 424w, https://substackcdn.com/image/fetch/$s_!SIkf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png 848w, https://substackcdn.com/image/fetch/$s_!SIkf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png 1272w, https://substackcdn.com/image/fetch/$s_!SIkf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SIkf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png" width="1456" height="870" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:870,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Pasted image 20250411192933.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Pasted image 20250411192933.png" title="Pasted image 20250411192933.png" srcset="https://substackcdn.com/image/fetch/$s_!SIkf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png 424w, https://substackcdn.com/image/fetch/$s_!SIkf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png 848w, https://substackcdn.com/image/fetch/$s_!SIkf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png 1272w, https://substackcdn.com/image/fetch/$s_!SIkf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F071ac8aa-6299-49c2-9dcb-bb2c002627ea_1575x941.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><blockquote><p><em>32 hours on Saturday is certainly a lot!</em></p></blockquote><p>I definitely remind you again - you don&#8217;t have to be a time tracking maniac if you don&#8217;t like it / don&#8217;t need it / find it difficult. Look, I even have some errors here, that&#8217;s normal!</p><p>Maniacal tracking by too detailed categories exhausted me literally in a couple of days; eventually, I started using general categories, even for rest.</p><p>It&#8217;s important to say again about composure, about mindfulness - to the extent of understanding, be honest with yourself when tracking Rest / Everyday life. You must ruthlessly catch yourself trying to infiltrate obvious nonsense into any category other than the &#8220;nonsense category&#8221;!</p><p>If it&#8217;s difficult for you here too, resort to studying metrics, for example, screen time, which, as far as I know, all modern smartphones collect in a convenient format.</p><p>If you see in the metrics that you spend a lot of time on nonsense - this is very important, that&#8217;s exactly what we&#8217;re looking for here! We&#8217;re interested in how things are in reality, remember? So record everything honestly!</p><p>On my graph, it&#8217;s clear that Investment Time is more than Productive. Does this mean that I worked on tasks for 7 hours a week? No, investment time consists almost entirely of research tasks.</p><p>And of course, I couldn&#8217;t have tracked all this if the process wasn&#8217;t convenient.</p><blockquote><p><em>Not an advertisement at all - I use free </em><code>toggl</code><em>. There are web, desktop, and mobile clients that synchronize normally, and as you can see in the screen above - you can build a pretty convenient categorization by &#8220;projects&#8221;.</em></p></blockquote><p>But why so little Wasted Time? Why do I need to track time if I&#8217;m already a productivity cyborg? No! Not a cyborg!</p><p>As I&#8217;ve already said - before I started collecting these metrics, I had no time for any projects&#8230; Time tracking didn&#8217;t help me spend less time on nonsense; time tracking helped me understand that I have problems with focus! And with focus not in terms of distraction to social networks, but with overloading myself with too many parallel tasks! We&#8217;ll talk about this further.</p><p>But for now, let&#8217;s get back to tracking.</p><p>The good news is that you already have everything to start tracking time. You definitely have a clock somewhere, even if you have a prehistoric button phone in your pocket.</p><p>If you&#8217;re an active gadget user, even better! You can choose from dozens, if not hundreds (if not thousands!) of applications for time tracking, with pomodoro, todo lists, and the like.</p><blockquote><p><em>But don&#8217;t rush! Maybe you already have too many such applications; more on this later.</em></p></blockquote><p>Just choose and start! Follow only the basic provisions of the framework and adapt it to yourself.</p><p>Let&#8217;s outline an action plan:</p><ul><li><p>Set a goal for yourself, give yourself a clear &#8220;direction&#8221; - why are you doing this at all.</p></li><li><p>Figure out convenient category names for you, as long as they follow the general idea of division described above.</p></li><li><p>Choose a way to start collecting metrics - an application on your phone, a notebook for handwriting, anything!</p></li><li><p>Collect metrics for at least 7 days in a row</p></li><li><p>Analyze the result</p></li><li><p>Find oddities, inconveniences, improve categories if necessary, and repeat the collection of metrics.</p></li></ul><p>Instead of one week, you can collect metrics for two, or a whole month. If you suddenly find it simple and natural to start tracking time constantly in one format or another - don&#8217;t be scared, you&#8217;re not a maniac! Go ahead!</p><p>In any case, once you find a system that&#8217;s comfortable for you, it will be very useful to conduct such a weekly audit of your productivity at least once a quarter, or once every six months.</p><p>It&#8217;s also possible that after two such measurements, you&#8217;ll feel that you never need them again, you&#8217;ve understood everything, and you&#8217;ve &#8220;ramped up&#8221; into effective and mindful work throughout life. Great, if you don&#8217;t want to measure anymore - don&#8217;t measure!</p><p>Just don&#8217;t forget about such a wonderful mechanism; perhaps it will come in handy when you start working on a new project, or get a new job, and suddenly find yourself overly tired and buried under a mountain of endless tasks, which are all urgent and needed to be done &#8220;yesterday.&#8221;</p><h3>The temptation to fall into specifications</h3><p>At some point, an excellent thought may visit you - why don&#8217;t I start monitoring my time in more detail?</p><p>For example - here I seem to be staying in the recommended categories, but I&#8217;ll record how much time I spent working on project A, how much on calls for project B, how much time I ran on the treadmill, how much I worked with weight, how much time I spent preparing a salad, and how much I cooked borsch.</p><p>Although sometimes such detail can help - for example, I found that sometimes I got stuck in the shower for 20 minutes - there&#8217;s still a strong risk of getting confused, falling into excessive details, overcomplicating the process.</p><p>I suggest sticking to the most generalized categories.</p><p>Understand, you don&#8217;t need to know how much total time per week you spend preparing salads. Your main task is to find out as accurately as possible how much time you <em>actually work</em> and how much time you <em>actually spend on nonsense</em>.</p><p>From these metrics, you can delve into questions like &#8220;why so many tasks? Are they all really urgent and relevant?&#8221;, or &#8220;why so many calls? Is it true that they&#8217;re all productive&#8230;?&#8221;, and so on.</p><p>You can always go into any detail, as long as the metrics are collected at all. And it&#8217;s by no means certain (rather the opposite) that it will actually benefit you to track time separately for each work task. That&#8217;s madness.</p><div><hr></div><p>Depending on your main activity and lifestyle, the proposed categories may seem too general or not quite correct.</p><p>It&#8217;s perfectly normal to <em>slightly</em> specify or rename them. For example, your categories might look like this:</p><ul><li><p>Writing blog articles (investment time)</p></li><li><p>Writing code / solving work routine (productive time)</p></li><li><p>Learning (investment time)</p></li><li><p>Exercising (everyday life and rest)</p></li><li><p>Reading books / articles / blogs (everyday life and rest)</p></li><li><p>Doing nonsense (Nonsense!)</p></li></ul><p>Or like this:</p><ul><li><p>Working on client projects (productive time)</p></li><li><p>Studying new trends and design tools (investment time)</p></li><li><p>Creating works for portfolio (investment time)</p></li><li><p>Household chores and personal life (everyday life and rest)</p></li><li><p>Aimless scrolling of social networks (time wasted)</p></li></ul><p>Note that in both of these examples, I completely omitted tracking body maintenance, and that&#8217;s perfectly normal.</p><div><hr></div><p>If you have a fitness bracelet or some kind of smartwatch that tracks how much you sleep, then consider that you already have a metric about sleep.</p><blockquote><p><em>Pay attention to the quality of your sleep and rest! If you don&#8217;t sleep, then no tracking will save you!</em></p></blockquote><p>Meals and their preparation may naturally be visible in the calendar or between records of time spent, so they can also be omitted (just make sure that lunch doesn&#8217;t turn into scrolling news/TikTok for another 40 minutes on top.)</p><p>As you can see - there&#8217;s plenty of space!</p><p>The main thing is that your categories follow the division into productive and investment time, healthy routine and everyday life, and finally a category for nonsense.</p><p>The Nonsense category is needed even if you&#8217;re super successful and mindful and don&#8217;t spend more than 30 minutes a week on nonsense. Just by stopping to even consider that such a category exists, you&#8217;re already giving nonsense more chances to seep into your life.</p><h2>From collecting metrics to action</h2><h3>Analysis of the data obtained</h3><p>Analyzing the collected metrics is a slightly more complex process.</p><p>When you start measuring time, you&#8217;ll have the opportunity to study the proportions of your time investments across days or, even more effectively, an entire week.</p><p>However, the numbers themselves won&#8217;t give much &#8212; in parallel, it&#8217;s necessary to develop the ability to work qualitatively and rationally <em>directly at the moment of performing tasks.</em></p><p>This means increasing the level of composure and efficiency in each work session, which, combined with the analysis of time metrics, will give results.</p><p>This is exactly the reason why I included mentions of TODO lists and pomodoro practice in this article in the Primary Metrics section (and other places).</p><p>If you don&#8217;t start developing your composure in the moment, you&#8217;ll have nothing to record in wasted time.</p><p>I&#8217;d like to tell you that you can neglect composure, but unfortunately, that&#8217;s not the case. You need some additional mechanism that will help you determine what time was wasted and what wasn&#8217;t. And the main mechanism here is your responsible attentiveness to your own life activity.</p><p>Let&#8217;s look at a couple of examples of how to determine time wasted in vain. It sounds simpler than it might seem.</p><p>For example, you have a scheduled zoom call with colleagues. If the call was productive, in the sense that 2/3 wasn&#8217;t small talk, and after the end of the call, it became clear what to do next. This understanding is expressed purely in the subjective feeling of <em>&#8220;we agreed about X, now I need to do A and B&#8221;</em>, against which there is simultaneously a rather bright and terribly vague feeling of <em>&#8220;What were we talking about? Why did we gather? What should I do next, huh?&#8221;</em></p><p>If you catch yourself on option 2 - boldly record the time of such calls as wasted.</p><blockquote><p><em>Right now, you probably don&#8217;t have almost any mechanisms to influence the regularity and quality of such calls, especially if you&#8217;re an individual contributor, not an operational manager. A large number of such &#8220;vague&#8221; calls is a serious indicator of problems with processes and probably overall productivity in the organization, so I can only suggest that you focus on areas where you can manage your time, and subscribe to me, as I will definitely continue to write about productivity and systems thinking.</em></p></blockquote><p>Another example. Let&#8217;s say you&#8217;ve decided that, like me, you&#8217;re comfortable working on tasks using the pomodoro method to fight distractions - we turn on the timer and for 25 minutes, no TikTok!</p><p>If you really didn&#8217;t get distracted - excellent! The pomodoro goes into productive or investment time depending on the work you were doing. Now you can space out for five minutes, or <em>rest well</em> :)</p><p>If you did get distracted, and significantly so, for example, you read emails for five minutes or more - this is definitely time wasted. I prefer to send all 25 minutes to the &#8220;trash,&#8221; which is both cruel and simpler than cutting out 5-8 minutes from a pomodoro. Besides - then during analysis, these blocks will attract your attention and you&#8217;ll be able to reflect better.</p><h3>From metrics to action: task management</h3><p>Now that we&#8217;ve figured out how to collect time metrics, the logical question is what to do with the freed-up time and how to organize your tasks.</p><p>After all, the ultimate goal of collecting metrics is not just to know where time goes, but to learn how to use it more effectively.</p><p>And here lurks a terrible devil.</p><p>Have you ever caught yourself having 500 interesting articles you want to read, and 48 projects you really want to start doing? While 10 of them are <em>already in progress.</em></p><p>Please remember my story, which I wrote at the beginning of the article - in the previous year, I almost didn&#8217;t waste time on nonsense, I worked a lot. But I didn&#8217;t become more productive. Therefore, in addition to collecting metrics, you also need to learn <em>focus</em>, concentration on what&#8217;s important, concrete matter.</p><p>There are also a bunch of methods for this, but I&#8217;ll suggest you simply think and show rationalism. When you start collecting metrics and figure out where you&#8217;re spending time, this will be especially useful if you suddenly find yourself in the same situation I was in - buried under a pile of tasks, multiple projects, and so on.</p><p>First - throw away all the tools you&#8217;re already using, keep only one. Paper planner, todo application, obsidian with some plugin where there&#8217;s a calendar and daily tasks - choose something that will be convenient for you or at least seem convenient (you can always change).</p><p>But don&#8217;t go crazy; for tasks, you need one tool. Or at worst - one for work, another for all personal projects for purely logical separation.</p><p>If you&#8217;ve been using multiple applications, then looking a little closer, it will become clear what you <em>really used</em> - in one of them there will be the most tasks, notes, visible activity. Great - that&#8217;s it. It&#8217;s <em>already convenient</em> for you.</p><p>Now clean your planner of garbage that steals your attention and time.</p><p>Perhaps, like me, you started at some point to use the todo list as a repository for notes, reading lists, and so on.</p><p>REMOVE EVERYTHING from your TODO list that doesn&#8217;t relate to tasks you&#8217;re currently working on - work and your projects, it doesn&#8217;t matter. Leave only what you can&#8217;t remove, something that&#8217;s already somehow in progress, or is about to be taken into work and can&#8217;t be canceled anymore.</p><p>There are two possible scenarios here:</p><ol><li><p>You threw out all the garbage and everything became crystal clear; it turns out everything isn&#8217;t so bad, and you only have 1-2 projects in progress, and you were only wasting time on nonsense</p></li><li><p>And more likely - Everything is terrible, you have 4-5 or more projects simultaneously, and a bunch of small tasks that logically don&#8217;t relate to any projects but take away a lot of your resources.</p></li></ol><p>So, for those who found themselves in the second scenario - consider each of your tasks, and ask yourself a specific question:</p><ol><li><p>What is this task, to which <em>project does it belong?</em> Is it clear at all what it is and when it needs to be done? If not - then you forgot to throw away some reminder or note that has no place in a TODO list. Do it!</p></li><li><p>If it&#8217;s still a clear task, then ask yourself what its essence is, what benefit and to whom will it bring - what will it affect in the real world? How well is it worked out? Does it really need to be dealt with <em>right now</em>?</p></li><li><p>Congratulations, you&#8217;ve either identified a valuable task, or found garbage again. There&#8217;s still a chance that you&#8217;re looking at <em>something</em> potentially useful - send it to the archive or some watch later on YouTube. The main thing is to clear up the planner.</p></li></ol><h3>Focus &#8211; that very composure</h3><p>Okay, we&#8217;ve got a clearer understanding of where our time goes and how to organize tasks. But there&#8217;s one more critically important element, a universal tool of productivity in any business - the ability to focus.</p><p>Without this skill, even the most accurate metrics and perfectly organized task lists won&#8217;t bring the desired result.</p><blockquote><p><em>I have good news for you! If you&#8217;ve read to this point without scrolling and in one sitting - you probably have good focus! The main thing is to clear out the garbage and collect metrics :)</em></p></blockquote><div><hr></div><p>Multitasking is a myth. It&#8217;s not the path to success; it&#8217;s the path to nowhere.</p><p>You need to learn to concentrate ON ONE thing, at every moment of time and on any scale.</p><p>Note that throughout this article, I&#8217;ve repeatedly mentioned the word composure. Your quality and composed attention is insanely important always, at any stage when we start to live purposefully, not just somehow.</p><blockquote><p><em>Without composure, everything will always be &#8220;just somehow&#8221;</em></p></blockquote><p>This may sound too stupid, but the longer you concentrate on one thing, the more results you&#8217;ll achieve.</p><p>I&#8217;m not suggesting you necessarily concentrate on one thing for your entire life, but that&#8217;s also an option. Imagine if you choose the meaning of your life - knitting scarves and hats. Every day you learn to knit, becoming better and better.</p><p>But that doesn&#8217;t mean you&#8217;ll only knit.</p><p>For example, at some point, you might want to knit for family and friends, and then it comes to mind to start earning from this - take it for sale.</p><p>And here you seem to have one goal and one business, but now &#8220;side quests&#8221; appear like:</p><ol><li><p>Learn marketing</p></li><li><p>Develop a personal brand</p></li><li><p>Set up social media</p></li></ol><p>And so on, but globally - the goal is one.</p><p>Many people for this reason jump from one thing to another, can&#8217;t find themselves. Because they didn&#8217;t set any of their undertakings as a goal, didn&#8217;t plan to thoroughly try and understand whether they need it or not, but started doing something in an emotional impulse inspired by others&#8217; opinions.</p><p>The point is that concrete goal setting is also a skill from the category of composure.</p><p>And nevertheless, if you&#8217;ve chosen something more complex than knitting, for example, an engineering career - there can be many sub-goals that you can spend your whole life on.</p><p>That&#8217;s why it&#8217;s especially important to focus on one thing.</p><p>One brain definitely won&#8217;t be enough for this, in the sense of the brain itself. That&#8217;s why I&#8217;m telling this whole story about metrics - we need to constantly be reinforced by breadcrumbs <em>from reality</em>, so as not to forget what and why we&#8217;re doing, where and why we&#8217;re going, and who we are in general.</p><p>If you don&#8217;t know at all what you need, regardless of how old you are - just start consciously choosing things and trying to do them, until you get bored, until you start understanding that you don&#8217;t get satisfaction from what you&#8217;re doing.</p><p>Just try, the main thing is to start doing at least something!</p><p>The secret is that by focusing on something for a week-two-month, you&#8217;ll still learn something useful - it won&#8217;t be wasted. At the very least, you can learn composure! :)</p><p>The main thing - stop wasting your life on complete nonsense and terrible dispersion!</p><p>Okay, it&#8217;s time to finish this lyrical digression.</p><h3>Why it&#8217;s so hard for us to concentrate</h3><p>The modern world creates unprecedented conditions in which it&#8217;s increasingly difficult for our brain to maintain concentration.</p><p>First, we&#8217;ve evolved so that we can effectively process a limited amount of information. But modern technologies create a data flow that causes terrible cognitive overload, making it difficult to process and remember important information.</p><blockquote><p><em>That&#8217;s why your attention is truly invaluable resource, second in value only to time. And it should also be treated precisely as a resource, for a very simple reason - attention and time are very closely linked!</em></p></blockquote><p>Second, multitasking is a disgusting myth. The brain cannot process multiple tasks simultaneously. Instead, it quickly switches between them, which requires significant energy expenditure and reduces work efficiency. With each such switch, we not only sag in productivity but also increase the probability of errors.</p><p>Third, the problem with dopamine. Notifications and social networks exploit the brain&#8217;s dopamine reward system; this is also no secret. These things are <em>literally</em> created in such a way as to rob you - <em>steal your attention!</em></p><p>Each new notification causes a small surge of dopamine, which creates an addiction to constant small &#8220;rewards&#8221; and disaccustoms us from the long concentration necessary for deep work. The endless feed is generally a complete mess about which I don&#8217;t even want to talk.</p><p>The constant flow of information leads to brain burnout. Symptoms include:</p><ul><li><p>Deficit of composure/attention - very difficult to concentrate on one task</p></li><li><p>Decision-making paralysis (even simple ones)</p></li><li><p>Dependence on technology to perform <em>basic</em> cognitive tasks - for example, a person doesn&#8217;t even try to add 17+8 in their mind and immediately reaches for a phone calculator</p></li><li><p>Chronic stress and anxiety</p></li><li><p>Sleep disturbance - seems like you didn&#8217;t drink coffee, and you&#8217;re physically tired as a horse, but it&#8217;s very hard to fall asleep</p></li></ul><p>Recognizing all these signals and problems is the first step to restoring control over your attention (and life!)</p><p>The good news is that time tracking and developing awareness about where your concentration is really going can help with this trouble.</p><p>There are other useful practices that can help with attention training, but the article is already too long, so I&#8217;ll tell about them another time.</p><p>And besides - I sincerely believe that grounding in metrics, which we&#8217;re considering today, can give enough impetus for you to start solving this problem yourself (if it exists). Awareness, knowledge about the catastrophe won&#8217;t let you close your eyes further.</p><p>I hope you haven&#8217;t chickened out.</p><h2>Conclusion:</h2><p>We&#8217;ve examined three keys to real productivity:</p><ol><li><p>Collecting primary time metrics through a simple categorization system;</p></li><li><p>Effectively organizing tasks in a single space;</p></li><li><p>Developing the ability to focus on one thing until it&#8217;s completed.</p></li></ol><p>Collect metrics! I believe you can do it!</p><p>This article turned out very large, and perhaps a bit chaotic in places, because the topic is simultaneously very important and very extensive. And too&#8230; personal! Because I experienced a qualitative leap in productivity when I discovered my specific problems - task overload.</p><p>Without time tracking, I wouldn&#8217;t have seen what was already in the most visible place. So if I could force you to take away at least something from this article, at least one thought, I would force you to remember not about time categorization, but about grounding in reality.</p><p>Please, don&#8217;t live exclusively in your head!</p><p>Subscribe to my social networks; I write about systems engineering, neural networks (human and non-living), software engineering: </p><p>https://links.ivanzakutnii.com</p>]]></content:encoded></item><item><title><![CDATA[Reality Check: The Skill You Should Master as an Engineer]]></title><description><![CDATA[Why you mental models fails and how to start fixing them.]]></description><link>https://letters.ivanzakutnii.com/p/reality-check-the-skill-you-should</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/reality-check-the-skill-you-should</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Mon, 24 Mar 2025 14:30:55 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b952843-edc1-4f4f-835e-257e5863e27c_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello dear readers.</p><p>In previous letters about Systems Thinking in the context of learning about <em>rational work</em>, we discussed what focus means, what mastery is, and the main problem&#8212;<em>the gaps between reality and our subjective ideas.</em></p><p>The short conclusion &#8211; rational work can only happen where there is grounding in reality.</p><div><hr></div><p>Many insights from masters across different practical fields are based on this idea, but everyone talks about it in their language. Systems thinking and engineering pursue a more specific goal &#8211; to develop an understanding of first principles and mastery in applying them, regardless of the practical field.</p><p>As a reminder, by grounding we mean a process in which we try to <em>base on realit</em>y any of our ideas, transformations/optimizations in a company, and by the end of the day &#8211; any other kind of activity.</p><p>Plus, without any popular and good methodologies and best practices, we can achieve excellent progress just by relying on fundamental principles.</p><p>Let's define a basic practical methodology with which any long-term grounding and vision of reality will begin.</p><blockquote><p>Pay attention to the <em>long term. Once we have achieved some mastery in focus and responding to &#8220;Cognitive Noise,&#8221;</em> we can begin to think and speak in the right direction. </p><p>The problem with just "thinking and speaking" is that the results of such a process quickly escape from our heads, and next time we'll have to "think and speak" almost from scratch &#8211; <em>and it's, in fact, f<strong>ar from certain</strong> that it will be as fruitful as the first time!</em></p></blockquote><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">But first, would you mind subscribing? I am writing 1-2 times a week about systems and software engineering.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Basic Methodology</h2><p>When you, as a person with decision-making power (director in a company, head-of-something, or these decisions concern you personally and your life) are about to make decisions, first thing you are <strong>necessarily got to do </strong>is to sit comfortably and write down all entities and processes in the real world that your decision may affect, trying to understand how it will be affected and to what extent.</p><p>This "how and to what extent" is practically impossible to track if we don't establish the entities that will change, and there can be so many things that it's simply impossible to remember them all in your head. This is another reason why <em>you need to write things down</em>.</p><p>You definitely need to write down and externalize the results of your work into the <em>real world</em> so that later there will be something to continue working with, clarifying and improving this <em>physical</em> representation of reality. At this first stage you can write without trying to do it immediately in some efficient format &#8211; we will study the best methodologies in the future. You just need to write, <em>write somehow in terms of form, but as detailed and grounded in the reality as possible in terms of content.</em></p><div><hr></div><p>It's easier to look at your own activities, and they will likely involve fewer people than in the organization or team where you work &#8211; at minimum your family, so you can start practicing this way.</p><p>The main thing is <em><strong>not to consider some made-up cases</strong></em> &#8211; this will bring almost zero practical benefit, because the disconnect from reality here can be <em>phenomenal</em>.</p><blockquote><p>We are learning how to ground into reality, so what is the meaning of grounding into non-existent cases, which most likely comes from internal subjective ideas? Useless work.</p></blockquote><p>Thats why it's highly desirable to start attempting to ground in your work or business as soon as possible &#8211; the bigger the "situation" for modeling, the better &#8211; the more useful experience we can extract.</p><p>When "developing grounding" for situations and decisions in a large company, we need to trace all "entities and effects" at all scales:</p><ul><li><p>How the decision will affect the company, and what will change in its main work, outcome?;</p></li><li><p>How it will affect departments or divisions (if they exist) - how will their work change? what will speed up (or slow down)? Will communication between departments suffer from your innovations?;</p></li><li><p>What and how will change at the team level;</p></li><li><p>And finally &#8211; how the changes will affect individual employees.</p></li></ul><p>Analyzing possible consequences as thoroughly as possible, we will start identifying all the hidden problems that we might not have thought about at all, faster and faster.</p><blockquote><p>If we're talking about a company, then this is of course just a starting point. We can't ground ourselves qualitatively alone. </p><p>Thats why this grounding process in the company will spread to other people in it. Thus, based on our initial attempt to ground, we should continue the process by talking to a bunch of people, checking our written assumptions, clarifying them, and grounding our model even more and better. This is the way.</p></blockquote><div class="pullquote"><p>The key thing in all this is <em><strong>focus on reality</strong></em><strong>. </strong></p></div><p>The problem is that we still can sit down to write something "off the top of our heads" based on our subjective representations &#128513;</p><p>For example, we have a reformative idea, and we have <em>representation</em> about what departments, teams, employees there are in the company, <em>representation</em> about how they work, <em>possibly</em> even about their problems and needs. It's very difficult to understand what these ideas are based on; most likely they somehow formed on their own during our time working at the company. It's far from certain that these ideas have any real basis if we don't constantly-periodically communicate with all departments, managers, and employees for the purpose of <strong>grounding</strong>.</p><p>Additionally, we have an <em>subjective idea</em> of how and what our reform will affect. This can be very, very vague, but pretend to be "rational" until we start grounding it too.</p><p>There's nothing stopping us from pouring all these ideas onto paper, especially if we're good at writing, but they will <em><strong>remain subjective.</strong></em></p><p>Something similar happens when a high-ranking boss says, for example &#8211; <em>we're implementing pure scrum</em>. </p><p>Okay, but&#8230; without any additional definitions, goals and at least somehow clear instructions. Then managers enthusiastically run to implement this idea without asking clarifying questions (what if the Boss will think I'm an idiot and fire me?), pushing unclear tasks lower and lower. </p><p><em>Who is doing what, and for what purpose in such a scenario &#8211; is completely vague.</em></p><div><hr></div><p>Writing this post, I remembered a real-life story. At one of my previous jobs long ago, a colleague told me that when he worked as a system administrator at a factory, they had a Microsoft Server with an MSSQL database, everything worked well year after year, and was even occasionally updated &#128514;. One day the director comes in and says &#8211; <em>"We need Ubuntu."</em></p><p>Literally, that's practically the entire useful payload he put into the order - &#8220;<em>We need Ubuntu</em>.&#8221;</p><p>To the natural questions - <em>"Why? What for?"</em> followed answers like &#8211; <em>"We need Ubuntu. <strong>Ubuntu is cool.</strong>"</em></p><p>Need I say that the only rational way out of this situation the storyteller found was <em>to quit?</em> Without the skills we're studying in Systems Engineering, it's almost impossible to communicate with such a director and explain to him all the potential difficulties. It's like rolling a d20 with significant penalties &#8211; the chances of success are extremely low.</p><h2>Lacking of data and being scared.</h2><p>The next key idea &#8211; <em>information about reality is almost always lacking.</em></p><p>This is (again) about not only work in organizations but also our subjective representation of ourselves. Try to trace how many of your ideas are not based on <em>primary data</em>, but are based on something like: "that's how people think," "it goes without saying," "everyone on social media says so," "mom taught me that," and so on.</p><blockquote><p>By <em>primary data</em>, we will mean metrics from the real world that haven't yet gotten into anyone's "head" and haven't been processed or transformed in any way.</p></blockquote><p>This can be difficult, and also &#8211; it can be scary to even think about it. </p><p>Most likely both scary and difficult! &#128552;</p><p>The brain understands what it's facing &#8211; a lot of work for collecting and evaluating primary data, comparing this data with subjective representation&#8230;</p><p>The process that could (will!) potentially<strong> greatly shake</strong> our precious, very stable (in the coordinate system of our already "default" ideas) picture of the world and ourselves in this world.</p><p>The process of collecting this data not only boring, slow, it is literal danger for this lazy fellow inside. And it knows it.</p><p>But the result is definitely worth it. </p><p>Don't listen to these signals, you're not a trembling creature and deserve to change your life and the lives of people around you for the better.</p><p>And in the end, it's not that difficult to start collecting metrics of reality, you can sacrifice, for example, the constant grabbing of your phone to watch short, stupid videos and spent some time writing down and finding good software for time tracking and writing notes :)</p><p>Just make a brave decision... That's the only thing that might be hard.</p><p>Lets put it that way &#8211; if you want changes, changes definitely for the better, you may need to bring your system of subjective ideas into a threat, the new way of thinking (and living) where priorities needs to be restructured toward <strong>reality</strong>, rather than <em>subjective <strong>hallucinations</strong></em>.</p><p>The scientific rational approach is based on this readiness to accept this "new" reality and continue to exist in it, when it is confirmed with metrics from the real world.</p><p>Wrapping up with a silly picture :)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!T96B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!T96B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png 424w, https://substackcdn.com/image/fetch/$s_!T96B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png 848w, https://substackcdn.com/image/fetch/$s_!T96B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png 1272w, https://substackcdn.com/image/fetch/$s_!T96B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!T96B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png" width="1040" height="336" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:336,&quot;width&quot;:1040,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53576,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.ivanzakutnii.com/i/159724795?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!T96B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png 424w, https://substackcdn.com/image/fetch/$s_!T96B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png 848w, https://substackcdn.com/image/fetch/$s_!T96B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png 1272w, https://substackcdn.com/image/fetch/$s_!T96B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0d5d69ad-2fd1-4962-a8e1-dcadbe0d0dc0_1040x336.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thank you for reading! Please subscribe or share with a friend! Every sub is really matter &#10084;&#65039;</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Trust Your Gut: How to Spot Gaps Between Reality and Subjective Ideas.]]></title><description><![CDATA[What is intuition, how do we train it, and why does it matter?]]></description><link>https://letters.ivanzakutnii.com/p/trust-your-gut-how-to-spot-gaps-between</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/trust-your-gut-how-to-spot-gaps-between</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Wed, 19 Mar 2025 16:25:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!85Be!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3>Intuitions built from experience</h3><p>Mostly, awareness of the gap between reality and a situation (our subjective perception of the situation) happens <em>intuitively</em>.</p><p>This is a very fast process, it's even more like a <em>feeling</em>.</p><p>Such tasks are processed by fast S1 thinking according to Kahneman, which compares facts/features related to the evaluated phenomenon, and facts/features from some "database" that is filled with our explicit and implicit subjective experience throughout life and work in subject areas.</p><blockquote><p>S1 thinking according to Kahneman is an automatic, fast, and intuitive way of thinking. It works without conscious effort, based on associations and heuristics, allowing us to react almost instantly to situations. This thinking requires little energy, is based on habits/experience, and is highly susceptible to cognitive biases.</p></blockquote><p>When fast thinking finds <em>inconsistencies</em>, we feel it as something vaguely "something's not right", "they're talking/suggesting nonsense", or on the contrary, when this thinking finds consistency, matching &#8211; "I feel in my heart that this is the holy truth, everything is correct!"</p><blockquote><p>It's very important to pay attention to both of these feelings, especially the feeling of wrongness. Anatoly Levenchuk in the SSM courses suggests an interesting term for this feeling: "jitter." I'm introducing it here because I like it, and I plan to use it further. Distinguishing jitter is important because it's a clear indicator of some inconsistencies of perceptions with reality or perceptions with perceptions&#8212;both need to be fixed.</p></blockquote><p>Basic intuition develops kind of "on its own along the way", although it can and should be improved (trained).</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading /var/log/ivan.zakutnii! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><h3>Master's sense</h3><p>Master's sense is another type of intuition that doesn't develop entirely on its own, and even rather the opposite.</p><p>Such intuition is the process of transition from unconscious incompetence to unconscious competence, where the latter is exactly the "master's sense".</p><p>There is a "competency square" that perfectly displays the path through which this type of <em>intuition</em> develops:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!85Be!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!85Be!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png 424w, https://substackcdn.com/image/fetch/$s_!85Be!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png 848w, https://substackcdn.com/image/fetch/$s_!85Be!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png 1272w, https://substackcdn.com/image/fetch/$s_!85Be!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!85Be!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png" width="626" height="471" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3583111-d76d-4512-8717-9645da0b42cc_626x471.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:471,&quot;width&quot;:626,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;competencies-square-eng.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="competencies-square-eng.png" title="competencies-square-eng.png" srcset="https://substackcdn.com/image/fetch/$s_!85Be!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png 424w, https://substackcdn.com/image/fetch/$s_!85Be!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png 848w, https://substackcdn.com/image/fetch/$s_!85Be!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png 1272w, https://substackcdn.com/image/fetch/$s_!85Be!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3583111-d76d-4512-8717-9645da0b42cc_626x471.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>At the very beginning of work in a new subject area, when we're just learning, we can't even say <em>what we don't know.</em> This is unconscious incompetence. Gradually, we develop skills, and <em>mastery</em>, until this mastery is elevated to automatic application.</p><p>At this stage, we begin to notice inconsistencies in our own or others' words (spoken or written), documentation, and other sources of information.</p><blockquote><p>If we have a problem with emotions and self-control, then having such a degree of applied mastery, one can start "getting angry at the surrounding idiots", but this is a big problem and a topic for a separate conversation. In any case - pay attention if you notice such consequences of jitter in yourself, this is a destructive pattern and generally a sign that you need to work on <em>basic mastery of composure</em>. There can be many reasons, both biochemical (simply problems with hormones that you don't know about or know, but don't allocate enough strength and attention to fight them), and psychoneurological. The latter seems to be easier to work through, but this most likely requires professional help.</p></blockquote><h3>&#8220;Fundamentally first&#8221; skill of catching jitter</h3><p>Both types of intuition are needed and important, it's useful for us to both know about them and consciously develop them.</p><p>Timely awareness of jitter is one of the basic types of applied mastery of composure that's very important for us to hone.</p><p>The problem here is that we can too often either not be aware of these inconsistencies, or let them "in one ear and out the other". Such skipping happens because we don't realize how important an indicator this jitter is, and we don't know how to work with it at all.</p><p>Well now, I hope, we've realized the importance. But how to work with it?</p><p><strong>Ground the gap.</strong> </p><p>By grounding, I mean that we should base our reasoning on real-life metrics, not just on our subjective ideas, which are often based on other ideas or on some vague concepts. Even if these ideas were initially based on real metrics, they tend to become obsolete, so we need to continuously gather fresh reality metrics and update our reasoning. That's basically the essence of Data-Driven Development.</p><p>But of course we are far from world where everybody understand that, and already completely aware of it. Thats why we should train a skill of catching jitter, so we will be able to ground the gap. How so?</p><p>You can start by catching <em>semantic patterns</em> in communication with colleagues, and in communication with "yourself".</p><p>Such communication patterns may include:</p><ul><li><p>Vague, confused answer to a question - answer without confidence, with stumbling, hesitations. Lack of confidence and specificity in the answer may, and often indicates, that the words are little connected with reality;</p></li><li><p>Phrases like "<em>seems possible</em>", "well <em>in principle</em> we'll do it", and "<em>theoretically</em> doable" sound - the loudest signals of a break with reality, require immediate intervention.</p></li><li><p>Too long, <em>drawn-out</em> answer to a quite specific, almost <em>closed</em> question - the person answering the question either didn't understand the question, then we need to clarify it ourselves. If after clarifying the question the answer is still too vague - we need to pay more attention;</p></li><li><p>And conversely, too quick an answer to a question which (as we know) requires some analysis and reflection - for example, the universally loved task size estimation, the developer instantly replies "I'll do it in two days";</p></li><li><p>Vague phrases without <em>grounded</em> specifics - "We're making a digital product", which one? "we're developing fintech API" - which one? What features? "We're producing packaging" - what kind? Cellophane bags? Cardboard boxes? Dry cast iron containers with spheroidal graphite for radioactive rods?</p></li></ul><p></p><div><hr></div><p>These are basic examples to start with. With the development of mastery of attention to jitter, we develop our signals, we can say that we fill that "database" for intuition, which we talked about earlier.</p><p>Next time, we'll talk more about "grounding," "reality," how to see them, and what might block a clear view. If you found the material even a little valuable, please support me with a subscription. I'm really happy for every new subscriber &#10084;&#65039;&#8205;&#128293;</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://letters.ivanzakutnii.com/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Please Think!]]></title><description><![CDATA[Especially in the current, amazing LLM times.]]></description><link>https://letters.ivanzakutnii.com/p/please-think</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/please-think</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Tue, 11 Mar 2025 14:45:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b952843-edc1-4f4f-835e-257e5863e27c_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>People often pause to think when I criticize LLMs, specifically programming with LLMs (I will not start using this new stupid term for it).</p><p>Either they disagree with me or think I'm out of touch with the progressive world of LLM-driven development, that I don't know how to do prompt "engineering". I don't know &#129335;&#8205;&#9794;&#65039;</p><p>A couple of times people have already DM'd me asking - which model am I actually using in Cursor, maybe I'm clicking something wrong here, and instead of Sonnet 3.7, default is selected?</p><p>I perfectly understand the mainstream excitement about LLM-driven development, it's easy to reconstruct, and for the most part, I sincerely share it.</p><p>Cursor (with Anthropic models) greatly speeds up development, routine coding, generating large fixtures based on models, simple functions "in a vacuum" and so on. It helps to factorize code chunks faster, and move them around better than just renaming in an IDE and manual copying.</p><div><hr></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://letters.ivanzakutnii.com/subscribe?"><span>Subscribe now</span></a></p><p></p><p>Dear colleagues, I criticize LLMs mostly to spark in you the desire to think with your head, a spark that's already absolutely priceless nowadays. </p><p>I sincerely wish that you wouldn't "become stupid at breakneck speed" and catch yourself spending 20 minutes poking at prompts when the LLM doesn't understand you, trying this way and that to stuff files into the context - instead of finally writing code yourself properly, according to your understanding.</p><p>Furthermore, I strive for you not to forget that starting from middle+ and especially from a senior <s>belly size</s> position at work, your activities will consist less and less of writing code and more and more of making architectural decisions and puzzling out processes. </p><p>Tasks will become increasingly complex in terms of their systemic nature and dependencies, they will involve more and more <em>other agents</em>, people or bots - it doesn't matter, these tasks won't get particularly easier.</p><p>If you think that most of an engineer's job (especially if the engineer is adept at systems engineering) is just writing code, drawing UML/Mermaid diagrams, making architectural decisions, and so on &#8211; <em><strong>it is not.</strong></em></p><p>The less you are a coder-programmer-individual-contributor, and the more you are an engineer, the more your work will resemble that of a professional detective in some good psychological thriller.</p><h3>Dude, we've got a body, could be murder.</h3><p>The main engineering work, if we're talking about mature, <em>result-oriented,</em> and <em>reasonable</em> engineering &#8211; feels like detective work, in a quite a mystically complicated case.</p><p>You need to interrogate all witnesses, and you also need to interrogate the main suspect (oh, I mean the main stakeholder), whom, by the way, you still have to find because it's not always clear who it is in each specific case.</p><p>Besides, you probably have a bunch of "police officers" working with you, some of whom are <s>alcoholics and drug addicts</s> might be extremely inconsistent in their beliefs and difficult to communicate with.</p><p>But even if everything is in perfect order with subordinates, each of them individually finds common ground with you &#8211; they all see the world in their way, have their own opinion on the project, opinion on who the main suspect is, opinion on what the solution and the ultimate goal should be, while rarely finding this common ground with each other as well as they do with you.</p><p>It turns out that the job of such an engineer-detective is not only to punch faces in alleys and drink single malt whiskey with tormented eyes but primarily to make all strategic decisions on solving the case, get all colleagues and suspects to talk to each other <em>in common language</em>, put them in their places, in the sense that the case successfully moves toward resolution and everyone is happy with their work, and the bosses with the clearance rate.</p><div><hr></div><p></p><p>LLMs are simply not capable of such detective work, and in my stupidity, working with Cursor for some time, I stubbornly tried to communicate with it in such an engineering language (well, it's interesting to test the limits, right?), because it seems that's why they gave the ability to add different files for context in the chat... &#129300;</p><p>After adding all related modules, describing architectural issues in quite detail, Cursor too often starts to seriously drizzle.</p><p>Interestingly, switching to the tab with regular Sonnet, and asking a question in almost the same format, but apparently without some "project context" (that Cursor might somehow collect under the hood) <strong>often</strong> gives sensible answers.</p><p>For this reason, I stopped struggling and tried to ask flatter, more specific requests, more and more often in chat mode, not "composer/agent", just the same way I was working with Sonnet, before I had started to use Cursor.</p><p>Besides that, and this is very important &#8211; an LLM will never "argue" with you.</p><p>All your instructions, right or wrong, the LLM happily takes to work, leading you down an increasingly crooked path. So if we don't have a circuit braking mechanism in our mind for self-reflection, to at least somehow try to check our hypotheses regarding some piece of project design before blindly giving them to the LLM to work on - we're completely screwed.</p><blockquote><p>Here I had the thought that I maybe could stuff something like - NEVER AGREE RIGHT AWAY with my hypotheses in `.cursorrules`, but I sense that this might only make things even worse.</p></blockquote><p>If you ask the LLM very specifically, as flat as possible, precisely, but moderately detailed (roughly as a good senior assigns a task to a good junior) - the results are almost always impressive.</p><div><hr></div><p>Enthusiastic moans might scare with the potential volume of new shit code and the new speed of generating this crappy code. But they don't scare, because there's already more than enough of such code. We did train LLMs on something after all :)</p><p>Everyone is happy - both programmers, who now have to think even less, and business owners, who don't care about clean architecture, technical debt, and stuff &#8211; as long as the features are delivered faster and more money flows in.</p><p>My line is very simple, and not even bent &#8211; in both the old and new LLM world, the one who trains their main "muscle" won't be lost. </p><p><em><strong>You need to think.</strong></em></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading /var/log/ivan.zakutnii! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[LLM Minions, DroidSpeak and Byte Latent Transformers]]></title><description><![CDATA[Yeah, Science!]]></description><link>https://letters.ivanzakutnii.com/p/llm-minions-droidspeak-and-byte-latent</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/llm-minions-droidspeak-and-byte-latent</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Fri, 07 Mar 2025 12:51:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b952843-edc1-4f4f-835e-257e5863e27c_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello, my good readers!</p><p>Stanford guys continue the <a href="https://hazyresearch.stanford.edu/blog/2025-02-24-minions">"Let's make LLMs friendly with each other" arc</a>.</p><p>Overall, the concept is certainly excellent, and humanity will sooner or later reach some impressive solution here thanks to the synergy of accumulated research, as usually happens.</p><p>What raises questions for me is that they've again arrived at an approach where a "large, smart, expensive cloud model" generates pieces of code, which "local, small, cheaper, and less intelligent" Minions execute locally, for example on data from PDF documents, and then return results to the big model to generate an answer.</p><p>Well, it's generally cool, except for one big issue - How strongly this still reeks of terrible non-determinism.</p><p>First, from the user's perspective - what about security? By what means and in what environments will these models run locally? In Ollama? Okay. Do we trust the code generated by LLMs?</p><p>Not.<em><strong> I don't trust it.</strong></em></p><p>Despite all the benefits in speeding up work and accelerating by mortal reasoning with various excellent tools like Claude - I don't believe that such "protocols" will be viable and *<em>successfully</em>* adopted even somewhat widely in the near future.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://letters.ivanzakutnii.com/subscribe?"><span>Subscribe now</span></a></p><p></p><p>Now, if we develop a specific product with locally running models that clearly "understand" their responsibilities and capabilities (tool-calls?), process the user's request (potentially understanding it better than the user themselves), and then when necessary, reach out to an LLM, perhaps providing the results of their work and the original request to predict the final answer - well... that sounds interesting! Very much so!</p><p>Second, from the developer's perspective of such a system - how do you even debug this? Is the complexity of such a non-deterministic system justified? I won't elaborate here as it seems obvious.</p><p>The deeper you dig into this, the more purely practical problems arise which, in my opinion, are better solved through familiar and proven methods.</p><p>Third, attempting to communicate even with small pieces of code, I mean not tool-calls, but as in the work above - this is already some kind of minimal engineering. And LLMs are not ready for engineering.</p><p>Understand me correctly, even Cursor with its latest update, when it tries to "analyze" previous results in a loop - analyzes complete nonsense. It might suggest you delete migrations, simply mindlessly - Let's regenerate it! Or blatantly hallucinate methods and classes from imported packages that don't exist. It now can suggest the user execute a command in the project directory (in the terminal) and continue working with the response from this command.</p><p>The result is the same.</p><blockquote><p><em>Just don't. I see your objections coming. Some too many people go crazy praising the qualities of LLM assistant code.</em></p><p><em>And there's a small number of computer science folks and folks who have been coding for 20+ years already. These people admit all the true benefits of coding with LLMs, while mercilessly criticizing its possibilities for software design. </em></p><p><em>I'm in this camp, even though I'm not a degreed scientist, and not yet an old folk (Am I?)</em></p></blockquote><p>Debugging with Cursors goes similarly - often with simple stuff, type inferences and other things Cursor can handle well, but as soon as we encounter debugging a problem of even slightly more complex order, where you need to reason about 2-3 dependencies - it hits the glass ceiling of its "cognitive capabilities."</p><p>And yet - these are all very cool things! Magical! I am fully in love with machine learning and neural models of all sizes. They greatly help and speed up work! And this is indeed an applicable informational technology, computer science discipline of a New World. No Doubt.</p><p>However, at the current time, LLMs cannot analyze or think **logically** to any significant degree.</p><div><hr></div><p>All the "thinking" we currently observe in modern LLMs is a desperate attempt, a respectable attempt, to somehow make LLMs generate "intermediate tokens."</p><p>The first attempts (well, basically those we're observing now) - of intermediate reasoning in natural, human language - shatter to pieces.</p><p>This is now known as the tokenization problem - For LLMs, reasoning in our languages is limited by the discreteness of the tokens they form. What results is that the quantization of the meaning space of the problem being solved happens in these very tokens - wherever the temperature coincides, that's where we fall.</p><p>In real, human analysis, logic and reasoning don't work like that.</p><p>In this light, these two works seem more interesting to me:</p><p><a href="https://arxiv.org/abs/2411.02820">DroidSpeak</a>:</p><blockquote><p>Large Language Models (LLMs) are increasingly employed in complex workflows, where different LLMs and fine-tuned variants collaboratively address complex tasks. However, these systems face significant inefficiencies due to redundant context processing of the shared context. We propose DroidSpeak, a framework that optimizes context sharing between fine-tuned LLMs derived from the same foundational model. DroidSpeak identifies critical layers in the KV cache and selectively recomputes them, enabling effective reuse of intermediate data while maintaining high accuracy. Our approach balances computational efficiency and task fidelity, significantly reducing inference latency and throughput bottlenecks. Experiments on diverse datasets and model pairs demonstrate that DroidSpeak achieves up to 3x higher throughputs and 2.6x faster prefill times with negligible accuracy loss compared to full recomputation.</p></blockquote><p>And <a href="https://ai.meta.com/research/publications/byte-latent-transformer-patches-scale-better-than-tokens/">Byte Latent Transformers</a>:</p><blockquote><p>We introduce the Byte Latent Transformer (BLT), a new byte-level LLM architecture that, for the first time, matches tokenization-based LLM performance at scale with significant improvements in inference efficiency and robustness. BLT encodes bytes into dynamically sized patches, which serve as the primary units of computation. Patches are segmented dynamically based on the entropy of the next byte, allocating more compute and model capacity where increased data complexity demands it. We present the first flop controlled scaling study of byte-level models up to 8B parameters with 4T training bytes. Our results demonstrate the feasibility of scaling models trained on raw bytes without a fixed-vocabulary. Both training and inference efficiency improve due to dynamically selecting long patches when data is predictable, along with qualitative improvements on reasoning and long tail generalization. Overall, for fixed inference costs, BLT shows significantly better scaling than tokenization-based models, by simultaneously growing both patch and model size.</p></blockquote><p>In short, DroidSpeak - making it so models communicate with each other without tokenization; Byte Latent Transformers - is also about abandoning tokens in favor of byte representations.</p><p>Both approaches create a more "adequate" space for model reasoning, a less discontinuous space - got rid of tokens and "think" in continuous vectors!</p><p>In addition to this, continuing to train models on mainstream codebases with CRUDs and so on, as the practice has shown - doesn't increase the quality of either generated code or "thinking" at all (meaning from the point where we are already.)</p><p>On the other hand - training models in logical programming using a language like Prolog looks <em><strong>very, very promising.</strong></em></p><p>I want to believe that these directions will be completed and won't die out. <em>And this belief comes without much effort.</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading /var/log/ivan.zakutnii! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Don't surprise the engineers]]></title><description><![CDATA[Everybody loves kinds of surprises, but there are no such surprises in applicable software engineering!]]></description><link>https://letters.ivanzakutnii.com/p/dont-surprise-the-engineers</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/dont-surprise-the-engineers</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Thu, 06 Mar 2025 05:12:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!YnPm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Barbara Liskov is a brilliant computer scientist. She is widely known for the substitution principle in OOP named after her - the Liskov Substitution Principle.</p><p>In Uncle Bob's interpretation, LSP sounds like this:</p><blockquote><p>Functions that use the base type should be able to use subtypes of the base type without knowing about it.</p></blockquote><p>In even more simple language:</p><blockquote><p>To safely use inheritance, you must ensure the ability to correctly pass a child object to methods/functions expecting a parent object.</p><p>Subclasses should extend, but not change the observable behavior of the parent class.</p></blockquote><p>By behavior, we mean not only method signatures but also that state changes in the subtype must be **compatible** with state changes in the parent class. This is an important point.</p><div><hr></div><p>So, in addition to the basic formulations, today I offer you to link LSP in your mind with the following phrase:</p><blockquote><p><em><strong>Don't surprise other programmers!</strong></em></p></blockquote><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading /var/log/ivan.zakutnii! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h3>Surprise in engineering is very, very bad</h3><p>In everyday life, emotions are very important, especially pleasant surprises. </p><p>They cause a big emotional response, and the event is better imprinted in our memory than ordinary hustle.</p><p>Surprise in programming is almost always an <strong>unpleasant surprise</strong>.</p><p><a href="https://www.ivanzakutnii.com/p/sorting-the-ocp-sheep-from-the-oop">Last time</a>, we talked about OCP from the perspective of functional programming and in general. In this post, I said that I feel a strong kinship between these two principles.</p><p>Here it is - in the <em>responsibility</em> for our modules and interfaces.</p><p>Breaking Changes are always trouble, we must avoid them at all costs if our system/module/library has even one user! </p><p>And "user" here can be not only another programmer or end-user but also another sub-system that depends on us.</p><p>I will never get tired of repeating this because I've seen too many such damn surprises.</p><div><hr></div><h3>A man's word is his bond</h3><p>Adhering to the interface contract is good. That's essentially what LSP is about. </p><p>At the same time, adhering to contracts is good not only in OOP, but also in FP, and in programming in general. You just need to understand what a "contract" is in your context.</p><p>In the world of functional programming, there's something called type classes. But it's not really about types and not about classes either.</p><p>A type class is more like an "interface" that indicates that <strong>something</strong> can perform <strong>this</strong> method on <strong>this</strong> class. And the class here is a blurry concept, and you shouldn't immediately associate it with your favorite OOP.</p><p>Here's the key difference from "regular" interfaces in OOP, which are explicitly linked to a class and state - "this class can have such methods" - A type-class is a slightly more <em>independent</em> entity.</p><p>Type classes are probably fully implemented only in Haskell, in the sense of the purest and most complete implementation of the concept.</p><p>Nevertheless, our beloved interpreted languages have similar tools.</p><p>For example, in Python, there's <code>singledispatch</code> in <code>functools</code>, which is an implementation of dynamic dispatching based on the first argument.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YnPm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YnPm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png 424w, https://substackcdn.com/image/fetch/$s_!YnPm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png 848w, https://substackcdn.com/image/fetch/$s_!YnPm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png 1272w, https://substackcdn.com/image/fetch/$s_!YnPm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YnPm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png" width="1456" height="866" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:866,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YnPm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png 424w, https://substackcdn.com/image/fetch/$s_!YnPm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png 848w, https://substackcdn.com/image/fetch/$s_!YnPm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png 1272w, https://substackcdn.com/image/fetch/$s_!YnPm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F037724b4-3ae2-4e0b-a06d-6f585ca395cf_1792x1066.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is not <code>@overload</code>, with <code>singledispatch</code>, Python checks types at runtime and chooses the right function.</p><p>Unfortunately, singledispatch is not supported by type checkers, but there's <a href="https://github.com/dry-python/classes/">dry-python</a> made by Nikita Sobolev that does the same thing, only with a sleek style, and mypy understands it.</p><div><hr></div><p>In short, a proper implementation of a type class is a set of functions that the compiler or interpreter deals with. In some sense, it's similar to pattern-matching, but at a much lower (or higher :) level.</p><p>Why do you need to know all this? I don't know. To not break your own and other users' legs?</p><p>We have tons of ways to program systems correctly. Tons of languages, tons of paradigms. All this variety of methods can be confusing, drive us into implementation details, and turn us into crazy keyboard monkeys.</p><p>It doesn't matter what language you write in, and what programming paradigms you believe in. Instead, as I mentioned earlier, I offer you to focus on clear engineering and human principles:</p><ol><li><p>Don't surprise other engineers.</p></li><li><p>Looking at the interface, take full responsibility for implementing all its invariants, pre-conditions, post-conditions, and other promises.</p></li></ol><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://letters.ivanzakutnii.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/p/dont-surprise-the-engineers?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://letters.ivanzakutnii.com/p/dont-surprise-the-engineers?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/p/dont-surprise-the-engineers/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://letters.ivanzakutnii.com/p/dont-surprise-the-engineers/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Sorting the OCP sheep from the OOP goats.]]></title><description><![CDATA[Stop being too quick on judging! OCP is not an OOP principle!]]></description><link>https://letters.ivanzakutnii.com/p/sorting-the-ocp-sheep-from-the-oop</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/sorting-the-ocp-sheep-from-the-oop</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Thu, 27 Feb 2025 17:58:02 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Hl99!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today, let's talk about another piece of SOLID - OCP.</p><p>Again, like the other principles from SOLID, this one sounds quite understandable:</p><p><code>Software entities should be open for extension but closed for modification.</code></p><p>This principle was provided to us by the respected Bertrand Meyer, through his book &#8220;Object-Oriented Software Construction&#8221; back in 1988.</p><p>Initially, the idea was largely about starting to approach interfaces responsibly and stop breaking them, bringing suffering into the lives of clients.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://letters.ivanzakutnii.com/subscribe?"><span>Subscribe now</span></a></p><p>Mr. Bertrand introduced us to the concepts of an Open Module and a Closed Module.</p><p>A module is considered open if it's available for extension - we can add fields to data structures, new methods/functions, and so on.</p><p>And a module should be considered closed when it already has users! For example, it's already being used by other modules. A closed module already has a clearly defined interface in terms of description.</p><p>When we start talking about this in the context of the OOP "world," the very essence is very similar to the idea of LSP - don't break the parent class, override methods -- inherit and add _new_ features.</p><p>Following OCP, we can extend or change the system without modifying already written code.</p><p>In "popular development," OCP is immediately associated with OOP and inheritance.</p><p>Look at two articles in Wikipedia about OCP - in English and Russian. If you don't know one of the languages, it's enough to simply translate with Google Translator, even such a translation will be enough to see the difference. This is either stupidity or cyber sabotage :)</p><div><hr></div><p>Well, with OOP everything is clear. We have a parent class, or even an Abstract base class from which we inherit, and implement logic. Child classes reuse "basic" logic or extend it. All this is so that we can sleep peacefully and not touch the already working, original implementation.</p><p>Easy Peasy, everybody knows that. </p><h3>What about the pure, functional world?</h3><p>Programming functionally, we can follow OCP using higher-order functions and composition.</p><p>A higher-order function is a way of drawing a boundary between one behavior of the system and its remaining part. A way of abstraction, if you will.</p><p>This is a kind of alternative to inheritance because by passing other functions as parameters to this higher-order function of ours, we can change the highlighted behavior.</p><p>Of course, "internal" recursive calculations implementing some logic in terms of OCP are closed "modules," closed for <em>extension</em>. This means that we don't have any "inheritance of implementation" as in OOP.</p><p>This is not a problem because, thanks to <em>function composition</em>, we can model different behavior.</p><p>We do not change the implementation of our functions at all, but we can compose different functional models from them. For example:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Hl99!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Hl99!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png 424w, https://substackcdn.com/image/fetch/$s_!Hl99!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png 848w, https://substackcdn.com/image/fetch/$s_!Hl99!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png 1272w, https://substackcdn.com/image/fetch/$s_!Hl99!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Hl99!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png" width="1456" height="2699" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2699,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:676600,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.ivanzakutnii.com/i/158050069?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Hl99!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png 424w, https://substackcdn.com/image/fetch/$s_!Hl99!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png 848w, https://substackcdn.com/image/fetch/$s_!Hl99!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png 1272w, https://substackcdn.com/image/fetch/$s_!Hl99!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4567e68-9628-411f-9b08-cc8e945e7d80_1792x3322.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In addition, algebraic data types are also very well suited to elegantly follow OCP.</p><p>In particular, sum types can be, well... <em>summed</em>, and this kind of naturally implies <em>extensibility without changing what already exists</em>.</p><p>An example of a sum type is a Rust enum:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UmR6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UmR6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png 424w, https://substackcdn.com/image/fetch/$s_!UmR6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png 848w, https://substackcdn.com/image/fetch/$s_!UmR6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png 1272w, https://substackcdn.com/image/fetch/$s_!UmR6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UmR6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png" width="1456" height="382" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc2f6c10-28d9-421d-800f-0722097787de_1792x470.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:382,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:47102,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.ivanzakutnii.com/i/158050069?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UmR6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png 424w, https://substackcdn.com/image/fetch/$s_!UmR6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png 848w, https://substackcdn.com/image/fetch/$s_!UmR6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png 1272w, https://substackcdn.com/image/fetch/$s_!UmR6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc2f6c10-28d9-421d-800f-0722097787de_1792x470.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In the future, we can add a new variant here and (most likely) not break the existing implementation. Of course, the Rust compiler will hit us on the head and force us to handle the new variant in all pattern matches.</p><p>And that's great!</p><p>For this reason, I don't give examples of Enums in Python - no matter how strong Python's type system is, and no matter how many cool, adult things we could emulate on it, there's more hope and faith in static typing.</p><div><hr></div><p>Of course, all these examples are very close to code, but this doesn't diminish their value for understanding.</p><p>Although OCP can be expressed in applied pieces of code, first of all, I want to emphasize this:</p><p><code>OCP, like many other principles of software engineering, should first be considered and understood from a higher, design perspective.</code></p><p>In other words, OCP as a principle at its core has nothing to do with OOP at all. It's a principle of _designing_ software systems, in which we introduce the concept of a "black box" into our field of thinking, which we take as a software module that we can reuse, extend in one way or another in a functional sense, **but without changing its structure**.</p><p>In short, let's reinforce - adding a new feature by changing already written code is almost always BAD; Implementing a feature by writing new code (note, I'm not talking about the number of lines of this code) is almost always GOOD.</p><p>That's the whole essence of OCP &#175;\_(&#12484;)_/&#175;</p><p>But! OCP is not a silver bullet, and it's impossible to follow it as a holy truth, well, you just can't. In software engineering, there are no such bullets at all, be it SOLID or something else.</p><p>In light of today's topic, trying to unreasonably blindly follow OCP, abstracting everything in a row, forgetting about the context of the project domain, and blurring it, we will only bury ourselves under a huge layer of crap code.</p><p>We need to remember OCP especially clearly when designing those parts of the system that are most likely to change.</p><p>And this, as it seems to me, in turn, means that "these very parts" should be somehow separated from the parts that most likely will not change at all.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading /var/log/ivan.zakutnii! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[I of SOLID is SOLD too good.]]></title><description><![CDATA[The architectural complexity of a system is directly related to the number, and in some sense - the quality of dependencies in this system.]]></description><link>https://letters.ivanzakutnii.com/p/i-of-solid-is-sold-too-good</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/i-of-solid-is-sold-too-good</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Sat, 22 Feb 2025 09:53:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!L7Nd!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b952843-edc1-4f4f-835e-257e5863e27c_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The architectural complexity of a system is directly related to the number, and in some sense - the quality of dependencies in this system. But more, of course, with the number.</p><p>Although we would like to believe the first intuitive assumption that this dependency is linear, where each new dependency increases some abstract COMPLEXITY counter by 1, in practice, this is not the case.</p><p><code>It is almost always exponential growth.</code></p><p>Many engineering principles aim to make our systems more reliable in operation and simpler to understand.</p><p>In light of the complexity topic, mainstream development recommends developers manage dependencies in the project following a simple rule - "Depend only on what is *really* necessary."</p><p>Seems pretty simple. In a more engineering interpretation, we're talking about the <em>I</em> in SOLID, which stands for - <em>Interface Segregation Principle</em>.</p><p>Don't be fooled by the definition itself, because ISP implies not only interface dependencies, but also dependencies between libraries, functions, classes, data, and so on.</p><p>Like all other elements of SOLID, ISP can be quickly and intuitively understood by somehow experienced developers. However, it seems that applying ISP in practice is much harder than talking about its meaning.</p><div><hr></div><p>We've all been there - implementing some class, and having the task to implement only specific functionality, like searching by ID, and then we all often get this brilliant idea - "I need to add methods for adding and deleting right away, they'll be needed anyway!"</p><p>The mental reasoning from a purely human point of view is understandable and may be justified, for example - it seems very convenient to give another developer/user a larger, richer interface!</p><p>Of course, this is already a violation of ISP.</p><p>Following the logic above, as a result, already at the testing stage of what we've written, we'll bump into interesting moments - how do we know that to test our functionality we need to test only _this_ search method (mock what's related to it, write fixtures, etc.), and not 2 other methods that we wrote?</p><p>Well, it's simple, solely by knowing that currently only _this_ method is used in the implementation!</p><p>As a result, we wrote N extra methods and wrote unnecessary fixtures/mocks N times for each, and in the tests themselves we're <em>testing the implementation</em>. The latter point, of course, is always cool at the moment but loses most of the value and essence of testing - <em>testing the behavior of the system.</em></p><p>At this point, I thought that TDD might help us here; when we turn the "default" development process inside out and implement only what we described in the tests. However, nothing still prevents us from showing <em>mindset persistence</em> and immediately writing tests for "extra" methods. See the trap?</p><p>Whether with TDD or just test coverage - we need to think not about implementation and test not the implementation, but behavior. Sorry for this sidekick, today we're not talking about testing.</p><div><hr></div><p>Returning to the topic of ISP, instead of bloating the interface, in our arsenal we have exactly the opposite trick - organizing many small interfaces, each of which provides up to calling just one function/method.</p><p>This is a cognitively simple trick for any developer in terms of implementation, and quite valuable in terms of result - now services can declare and explicitly depend only on what they need. </p><p>As a substantial bonus - the code becomes more visual and readable, and when writing tests, we may not need to dig into the implementation at all.</p><p>In some sense, this approach leaves room for super-impulsive developers to immediately define all the "mini" interfaces for all the "definitely will be needed soon" methods. The main savior thing is not to stuff them into the implementation without necessity and ruthlessly delete them in time during self-code-review when you realize that it's not used in working implementation :)</p><p><code>Ok, Ok! You may keep it!!! Just not stuff them all into the implementation!</code></p><p>Perhaps reading these lines, you already have a question - "<em>What?! Do I need to implement each such interface separately?</em>". </p><p><strong>Well, of course not. </strong></p><p>In C# and Java, one class can implement multiple interfaces, in Python there is multiple inheritance "for free." In Go... in Go, everything is as flat and explicit as possible (even it's called "implicit implementation") - and interfaces are automatically "stretched" over structures implementing their methods. </p><p>In Rust, you can explicitly implement several traits for a structure.</p><p>&#175;\_(&#12484;)_/&#175;</p><p>With new requirements, for example, initially, we needed to implement search by ID, and now by name or some other field, the approach with "mini" interfaces is still applicable and flexible enough.</p><p>At the same time, depending on the language used, we can avoid listing implemented interfaces as separate fields - using generics (Java/C#/Rust), interface composition (Go), and multiple inheritance (Python. Yes, again.)</p><div><hr></div><p>The approach we've considered, while good, probably causes very mixed feelings among developers who love and constantly use IoC containers.</p><p>IoC containers are good for automatic injection of interfaces, and these interfaces almost always... how to put it mildly... <em><strong>"VERY HUGE."</strong></em> </p><p>The "mini" interfaces may be far from convenient, beautiful, or justified to inject using containers (underline as appropriate.). Especially when generics have come into use. </p><p>Injecting something like a generic interface using IoC containers will inevitably be complex, and opaque, exactly opposite to the clarity and simplicity we, as professional engineers, would love to follow.</p><p>In mainstream programming, IoC containers are used as magic boxes to make the developer's life easier by automating the creation of necessary objects.</p><p>So, IoC containers make the programmer's life easier (seemingly) but lead to the bloating of interfaces. Bloated interfaces practically automatically lead to leakage of dependencies, and quite often - unnecessary dependencies. </p><p>In addition, these dependencies may be completely unobvious when a class receives injections of such interfaces. </p><p>As a result, behind the abstraction of the IoC container, we simply blur the <em>real abstraction</em>, lose clear boundaries, lose the ability to simply enough track and reason about real dependencies, and, ultimately, debug the system normally, without risking our mental health.</p><p>It turns out that almost any codebase with massive use of IoC containers is one continuous violation of ISP. </p><p>And do we just turn a blind eye to this?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Short Note on Abstractions]]></title><description><![CDATA[As I continue exploring abstractions and trying to understand their proper nature, I'd like to share some thoughts.]]></description><link>https://letters.ivanzakutnii.com/p/short-note-on-abstractions</link><guid isPermaLink="false">https://letters.ivanzakutnii.com/p/short-note-on-abstractions</guid><dc:creator><![CDATA[Ivan]]></dc:creator><pubDate>Tue, 28 Jan 2025 16:30:33 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!L7Nd!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0b952843-edc1-4f4f-835e-257e5863e27c_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As I continue exploring abstractions and trying to understand their proper nature, I'd like to share some thoughts.</p><p>In <a href="https://page.ivanzakutnii.com/blog/What-is-Abstraction">my previous post</a> on this topic, we found a good definition of abstraction - it's creating a mapping from the concrete "messy" world into a clean mathematical representation. When this mapping is "built" correctly, we get a new semantic level where we can reason about the system precisely while maintaining the connection with reality.</p><p><code>DSL naturally follows from correct mapping between concrete and abstract levels, serving as a tool for working in this abstract space</code></p><p>Here's an interesting example from infrastructure code: imagine a (really) complex distributed system with many services and high SLA requirements, running on Kubernetes with all the tools you love.</p><p>We can rise above the level of specific Kubernetes manifests (and Kubernetes itself, because we're not interested in Kubernetes per se, but rather in our system that lives in it) to a higher semantic level - let's call it `SystemState`.</p><p>Our SystemState could define a formal model of the entire system and its components consistency model. </p><p>It might describe:</p><ul><li><p>Service versions</p></li><li><p>Cluster and cloud infrastructure configurations</p></li><li><p>Rules for state transitions during deployments</p></li><li><p>Message formats in queues</p></li><li><p>Distributed database migrations</p></li><li><p>&lt;NAME_YOUR_SYSTEM_THING&gt;</p></li></ul><p>Unlike common declarative infrastructure descriptions (helm charts, terraform, GitOps, and whatever else), such abstraction promises to provide guarantees of invariants and correctness of state transitions.</p><p>Of course, formally defining it and implementing is a very complex and questionable endeavor - the more dependencies in the system, the more complex the state graph becomes. So while I think it's a good example, it's quite theoretical.</p><p>And anyway...</p><p><code>Start with building a healthy modular monolith - you'll have time to split it later!</code></p><p>Looking at existing solutions like Pulumi - it feels that they're moving in this direction, opening a possibility of infrastructure expression at a higher abstraction level (we are not limited by "declarative" tool rules).</p><p>I would not be me if I did not note the connection between functional programming and building proper abstractions. FP works well with abstractions, or more precisely, FP's nature is much closer to the nature of "proper" abstractions I am talking about, as it allows reasoning strictly within the chosen semantic level, with less risk of "falling through" to implementation details.</p><p>We get this largely thanks to FP's "native" inversion of control, which brings to the table natural protection from recursive implementation diving - the less state spreads across the system, the less our attention unfocus and "abstraction" itself spreads.</p><p>Functional approaches allow expressing abstractions more correctly, with less gap between formal model and code, while with mainstream OOP we risk quickly sliding into... implementation details, hierarchical mess leading to well-known confusion.</p><p>The topic of abstractions is fascinating and deep.</p><p>I greatly enjoy investing time in learning abstract algebra, type theory, and other "fundamentals" that help me better understand this great field. And while I'm far from being an enlightened computer scientist, even touching these matters at a basic level changes (I do believe) my way of thinking dramatically.</p><p>But the main thing I've noticed is that we need to try applying this knowledge in practice, as that's the only way to truly master this powerful craft.</p><p>No matter how theoretical and non-applied this knowledge may seem (especially at first), I believe it improves both the code we write and our ability to conceive and understand more complex architectural constructs.</p><p>If you found such topics interesting or just want to see where my journey goes - consider following. </p><p>Wish you a great Journey, thank you.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://letters.ivanzakutnii.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for free to receive new posts and support me.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>