{
    "componentChunkName": "component---src-templates-post-template-js",
    "path": "/pl/addition-by-subtraction-in-software-design/",
    "result": {"data":{"post":{"id":"aa164060-8777-506f-b74b-b83fadc75a4f","html":"<p>I want it all, and I want it now. This is not only a Freddie Mercury quote but also, too often, a general plan for our software product. The picture tells more than words, so here it is, the typical product we designed:</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; height: auto\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/e21f3e6a6f81e7da9dce92657435fa1f/d0606/2026-07-06-cover.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 62%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAUDBP/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAa3DQBkP/8QAGxAAAgIDAQAAAAAAAAAAAAAAAQIAAxESEzL/2gAIAQEAAQUCdxWOlhfWelAAjMc//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFxABAQEBAAAAAAAAAAAAAAAAACEQIv/aAAgBAQAGPwJyq3f/xAAbEAEAAgMBAQAAAAAAAAAAAAABABEhMUFhEP/aAAgBAQABPyEvZuBxk9ORLXVZhVZB7Naa1583/9oADAMBAAIAAwAAABCDz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAQADAAMBAQAAAAAAAAAAAAEAESExQVGBwf/aAAgBAQABPxALY4iHOe+zFUzG1d2/kARMsHcdnjkEZy06L+JZaT//2Q=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Swiss knife\"\n        title=\"Swiss knife\"\n        src=\"/static/e21f3e6a6f81e7da9dce92657435fa1f/c60e9/2026-07-06-cover.jpg\"\n        srcset=\"/static/e21f3e6a6f81e7da9dce92657435fa1f/37402/2026-07-06-cover.jpg 200w,\n/static/e21f3e6a6f81e7da9dce92657435fa1f/4cda9/2026-07-06-cover.jpg 400w,\n/static/e21f3e6a6f81e7da9dce92657435fa1f/c60e9/2026-07-06-cover.jpg 800w,\n/static/e21f3e6a6f81e7da9dce92657435fa1f/d0606/2026-07-06-cover.jpg 970w\"\n        sizes=\"(max-width: 800px) 100vw, 800px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n        decoding=\"async\"\n      />\n  </a>\n    </span></p>\n<p>And, well, that’s probably not what our user wanted. They might just want a sharper steak knife, so something more like:</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; height: auto\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/81e3d2fd0b0029983bdb275eb6529f2e/609ff/2026-07-06-steak-knife.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAEEA//EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHDq5QeikyiWCj/xAAbEAEBAAEFAAAAAAAAAAAAAAABABICESExQf/aAAgBAQABBQLZgniyI1WQ3vTf/8QAGBEAAgMAAAAAAAAAAAAAAAAAARARMUH/2gAIAQMBAT8BEajZX//EABURAQEAAAAAAAAAAAAAAAAAABAB/9oACAECAQE/ASH/xAAaEAACAgMAAAAAAAAAAAAAAAAQEQAhASBB/9oACAEBAAY/AsRdCtC9P//EABoQAQADAQEBAAAAAAAAAAAAAAEAESFBUXH/2gAIAQEAAT8h4OwkKTpTARqnp6MXWy2IBRdfYuolgey2f//aAAwDAQACAAMAAAAQhMdA/8QAFxEBAAMAAAAAAAAAAAAAAAAAEAExof/aAAgBAwEBPxCdBoP/xAAXEQEAAwAAAAAAAAAAAAAAAAABESAx/9oACAECAQE/EGdKf//EAB0QAQACAwEAAwAAAAAAAAAAAAEAIRExQVFxsdH/2gAIAQEAAT8QDFgbC6Zw2GufMC9SRx3JcHoPyKocVpgQ5Wp1lLD9ozqAohaJB7T/2Q=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Steak knife\"\n        title=\"Steak knife\"\n        src=\"/static/81e3d2fd0b0029983bdb275eb6529f2e/c60e9/2026-07-06-steak-knife.jpg\"\n        srcset=\"/static/81e3d2fd0b0029983bdb275eb6529f2e/37402/2026-07-06-steak-knife.jpg 200w,\n/static/81e3d2fd0b0029983bdb275eb6529f2e/4cda9/2026-07-06-steak-knife.jpg 400w,\n/static/81e3d2fd0b0029983bdb275eb6529f2e/c60e9/2026-07-06-steak-knife.jpg 800w,\n/static/81e3d2fd0b0029983bdb275eb6529f2e/6c738/2026-07-06-steak-knife.jpg 1200w,\n/static/81e3d2fd0b0029983bdb275eb6529f2e/609ff/2026-07-06-steak-knife.jpg 1500w\"\n        sizes=\"(max-width: 800px) 100vw, 800px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n        decoding=\"async\"\n      />\n  </a>\n    </span></p>\n<p>I’m also to blame; I’m falling into precisely the same trap too often. Like recently, while working on <a href=\"/pl/announcing-strictland-contract-testing\">Strictland, the contract testing library I announced in the previous article</a>.</p>\n<p>The idea behind it is to detect message schema drift easily. You write such a test:</p>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token annotation punctuation\">@Test</span>\n<span class=\"token keyword\">void</span> <span class=\"token function\">orderPlacedSchema_DoesNotChange</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Strictland specification</span>\n    <span class=\"token class-name\">MessageContract</span><span class=\"token punctuation\">.</span><span class=\"token function\">specification</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Json<span class=\"token punctuation\">.</span>Jackson</span><span class=\"token punctuation\">.</span><span class=\"token function\">defaults</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">given</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">OrderPlaced</span><span class=\"token punctuation\">(</span>orderId<span class=\"token punctuation\">,</span> <span class=\"token string\">\"Alice\"</span><span class=\"token punctuation\">,</span> placedAt<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">whenSerialized</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">thenContractIsUnchanged</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>It serialises the message and stores the payload inside the same git repository as the test. Thanks to that, you can keep it close and detect contract changes during the review by looking at the changed files.</p>\n<p>Initially, files were kept in the same folder as the test file. That made it accessible, as you don’t need to jump from one folder to another and see related test files. The file was named by message type class name (so in this case it’d be <code class=\"language-text\">OrderPlaced.approved.text</code>). Simple, but what if someone adds:</p>\n<ul>\n<li>Multiple tests, trying to store different snapshots for the same message type?</li>\n<li>Multiple test files dispersed across different folders that test the same message type (e.g., in the features that consume those messages)?</li>\n<li>Multiple message types across different modules/packages with the same name?</li>\n<li>Multiple tests for different message-type versions and variants (e.g., with all fields, with only required fields, etc.)</li>\n</ul>\n<p>All of that is solvable by some conventions, but what if you’re an open-source library creator like me? Then you can’t assume the same type of thinking, level of tidiness or knowledge of your users. You should be the one to take on the pain and make your users’ lives easier. And guess what? That applies not only to open source, but also to other products.</p>\n<p><em>“Taking the pain”</em> and <em>“helping users”</em> can be interpreted as an attempt to please everyone, which translates to the mentioned earlier: “I want it all, and I want it now.”</p>\n<p>That’s what I tried to do. I decided to add <em>“selectable storage layouts strategies”</em>:</p>\n<ul>\n<li><strong>Near the test file</strong> - so similar to the one we had,</li>\n<li><strong>In the nested folder near the test file -</strong> similar, but separating the snapshot files from tests, thanks to that, you could look in the nested folder, keeping the tests not polluted by the numerous tests,</li>\n<li><strong>In the root folder</strong> - putting it close to the root folder, keeping snapshots together- still the same repo but giving potentially better accessibility.</li>\n</ul>\n<p>And <em>”selectable storage layouts strategies”</em> were not enough for me. I also wanted to add <em>“various grouping strategies”</em> where one could select whether they want to group message snapshots by:</p>\n<ul>\n<li>Message type name,</li>\n<li>Test files and their names.</li>\n<li>Or just apply no grouping.</li>\n</ul>\n<p>It sounded smart to me, and hell, with GenAI, I wouldn’t even need to fight with it, as my friend Claude would do it for me, right? <a href=\"https://www.architecture-weekly.com/p/requiem-for-a-10x-engineer-dream\">RIGHT?</a></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 625px; height: auto\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/326242b6af0ce434b8e47b5c0d9cebde/a8e68/2026-07-06-thats-what-she-said.jpg\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 55.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwT/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABpdGXQSJ//8QAHBAAAQMFAAAAAAAAAAAAAAAAAQIDMgASISJD/9oACAEBAAEFAgrF1NjTo7BMf//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAQEAAgMAAAAAAAAAAAAAAAEAAiEiMUH/2gAIAQEABj8CeJv1tYjdRMX/xAAcEAACAgMBAQAAAAAAAAAAAAABEQAxIUFRYZH/2gAIAQEAAT8hKEPysUcBMhu4Mg0hwHRnEL57D+Qn/9oADAMBAAIAAwAAABAg7//EABcRAAMBAAAAAAAAAAAAAAAAAAEQETH/2gAIAQMBAT8QwRf/xAAWEQADAAAAAAAAAAAAAAAAAAAAITH/2gAIAQIBAT8QrKz/xAAeEAEBAAIBBQEAAAAAAAAAAAABEQAhcTFBYYGRof/aAAgBAQABPxBMutj4CYFCLXQe5kQmKQb+4pwUiII9cYICjiATxe2Nytrgz//Z'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"That&#39;s what she said meme\"\n        title=\"That&#39;s what she said meme\"\n        src=\"/static/326242b6af0ce434b8e47b5c0d9cebde/a8e68/2026-07-06-thats-what-she-said.jpg\"\n        srcset=\"/static/326242b6af0ce434b8e47b5c0d9cebde/37402/2026-07-06-thats-what-she-said.jpg 200w,\n/static/326242b6af0ce434b8e47b5c0d9cebde/4cda9/2026-07-06-thats-what-she-said.jpg 400w,\n/static/326242b6af0ce434b8e47b5c0d9cebde/a8e68/2026-07-06-thats-what-she-said.jpg 625w\"\n        sizes=\"(max-width: 625px) 100vw, 625px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n        decoding=\"async\"\n      />\n  </a>\n    </span></p>\n<p>Now, <em>”selectable storage layouts strategies”</em> should sound enough as a warning to me and <em>“various grouping strategies”</em> should ring a loud alarm bell. But it didn’t. I planned how to do it and started the implementation.</p>\n<p>A few iterations later, the permutations of those <em>various strategies</em> started to pile up. Some of them were just hard to do. Some were conflicting. And most of them weren’t even useful.</p>\n<p>Examples? I decided to make all files follow the unified format:</p>\n<p><code class=\"language-text\">{messageTypeName}.{version}.{variant}.snap.approved.{extension}</code></p>\n<p>And that’s fine, but then what to use as the message type name? Class name? Fine, but what about a flat layout, or grouping by message type name, with multiple messages of the same name?</p>\n<p>Let’s use the full class path as the name? Fine, but then what if you have a root folder and a nested folder strategy? Would you nest folders by the class path, and then repeat it in the name?</p>\n<p>Or maybe you’d differentiate the file name format depending on the strategy one chose?</p>\n<p>Ok, but what if the user decides to change the strategy at some point?</p>\n<p>I decided to run a sanity check I should have done earlier. Better later than too late. The discussion inside my head looked more or less like this:</p>\n<ul>\n<li><strong>Me:</strong> What’s the actual goal of this library?</li>\n<li><strong>I:</strong> To detect message schema drift.</li>\n<li><strong>Me:</strong> Ok, then do I need to build the snapshot library?</li>\n<li><strong>I:</strong> To some degree, I’m using snapshot comparison to detect that drift.</li>\n<li><strong>Me:</strong> Sure, but I probably don’t need to cover all the cases that the generic snapshot library has to, right?</li>\n<li><strong>I:</strong> Right.</li>\n<li><strong>Me:</strong> Ok, so what’s our bet for users? Are they advanced or just beginning the journey?</li>\n<li><strong>I:</strong> At the beginning.</li>\n<li><strong>Me:</strong> Then I should help them, set a sane default, and guide them. Especially since this is the early phase of this library, I haven’t yet received much feedback.</li>\n<li><strong>I:</strong> Agreed, maybe we could start then with the recommended layout and grouping, and then gather feedback. I can add more strategies as needed.</li>\n</ul>\n<p>That sounds like an obvious thing to do, but it requires pausing to find the time to evaluate our assumptions. We shouldn’t always be mad at ourselves for not predicting everything earlier. Some stuff is just hard to predict. Personally, I usually see some steps after I try to implement them. Those are also the steps I explained in the <a href=\"https://event-driven.io/en/vibing_harness_and_ooda_loops/\">article about the OODA loop</a>. We should:</p>\n<ul>\n<li><strong>Observe</strong> - This is the intake of raw, unfiltered information. In our world, this means looking at the state of the system.</li>\n<li><strong>Orient</strong> - This is the most critical and difficult stage. It’s where we filter our observations through your experience, culture, and technical knowledge.</li>\n<li><strong>Decide</strong> - Based on our orientation, formulate a hypothesis.</li>\n<li><strong>Act</strong> - We execute.</li>\n</ul>\n<p>Rinse repeat.</p>\n<p>If we think about it this way, the time spent considering those various cases is not wasted. It’s similar to the <a href=\"https://particular.net/blog/antirequirements\">anti-requirements exercise described by Andreas Öhlund and David Boike</a> or <a href=\"https://www.architecture-weekly.com/p/residuality-theory-a-rebellious-take\">Barry O’Reilly’s Residuality Theory</a>. We gather numerous needs and ideas about our product evolution and see what sticks and what remains. Not all ideas will be great; some will be bad, but that doesn’t matter; it gives us food for thought.</p>\n<p><strong>Still, we can’t forget about the most important part: subtraction.</strong></p>\n<p>We need to subtract all the stuff that’s not needed, leaving only the useful residues, the one that solves the main goal.</p>\n<p>For my case, I realised that if I chose the single strategy, it would organise my contract into the root test folder like this:</p>\n<div class=\"gatsby-highlight\" data-language=\"plaintext\"><pre class=\"language-plaintext\"><code class=\"language-plaintext\">📁 src/test/resources/\n  📁 contract-registry/\n    📁 com/acme/orders/OrderPlaced/\n      📄 OrderPlaced.1.default.snap.approved.json\n      📄 OrderPlaced.2.default.snap.approved.json\n    📁 com/acme/orders/OrderInitiated/\n      📄 OrderInitiated.1.AllData.snap.approved.json\n      📄 OrderInitiated.1.OnlyRequired.snap.approved.json\n      📄 OrderInitiated.2.AllData.snap.approved.json\n      📄 OrderInitiated.2.OnlyRequired.snap.approved.json\n    📁 InvoiceIssuedEvent/\n      📄 InvoiceIssuedEvent.1.default.snap.approved.json</code></pre></div>\n<p>By nesting by message type and full path and grouping by contract name, I’m not only keeping snapshots but also creating a Contract Registry.</p>\n<p>So this subtraction of some features not only gave me focus on the specific scenario but also enabled me to create scenarios that I would actually like to have eventually, for instance:</p>\n<ul>\n<li>keep the message schema in the same folder as snapshots,</li>\n<li>markdown docs of the message,</li>\n<li>Having defined the folder structure, generate documentation,</li>\n<li>check dependency, and who uses that,</li>\n<li>etc.</li>\n</ul>\n<p>That led me to conclude the following two rules:</p>\n<ol>\n<li>\n<p><strong>The addition of imaginary features subtracts the actual value.</strong></p>\n</li>\n<li>\n<p><strong>The subtraction of imaginary features adds the actual value.</strong></p>\n</li>\n</ol>\n<p>It’s also aligned with my motto: <a href=\"/pl/removability_over_maintainability/\">Removability over Maintainability</a>.</p>\n<h2 id=\"whats-the-lesson-then\" style=\"position:relative;\"><a href=\"#whats-the-lesson-then\" aria-label=\"whats the lesson then permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What’s the lesson then?</h2>\n<p>We’re not wasting time on building too slowly; we’re wasting time on building stuff that doesn’t matter. All those useless features we imagine without evaluating them with people are a wasted opportunity to deliver better for them.</p>\n<p>Nowadays, with LLMs, it’s tempting to rush into implementation and add every feature we can imagine. That’s never free. We’re increasing the cognitive load for our users and also for us; we waste time on stuff that doesn’t matter and are constantly distracted.</p>\n<p>Yet, if we don’t do sanity checks, trying things in a proof-of-concept way can be a big multiplier. If we stop after that and rethink.</p>\n<p>I’d still advocate doing a sanity check earlier than I did in the described scenario and thinking first, but not all can be forseen like that. So:</p>\n<ol>\n<li>Generate as many ideas as you can.</li>\n<li>Try to think about how they match together, think about the tradeoffs, the cost of adding them, the cost of removing them and the cost of changing your mind.</li>\n<li>Define potential solutions.</li>\n<li><strong>Stop the addition phase</strong> and rethink what you came up with. Ask yourself what you’re building and what the actual goal is.</li>\n<li><strong>Start the subtraction phase</strong> and cut as much as you can on the stuff that’s actually not needed. Of course, don’t drop ideas, remember that quantification is subjective. <a href=\"https://www.youtube.com/watch?v=yV97QwC5gnE\">Deliver a simple solution that will give you enough optionality to change your mind</a>.</li>\n<li>Send it wild and gather feedback.</li>\n</ol>\n<p>And that’s precisely what I did: I just released <a href=\"https://github.com/event-driven-io/strictland\">Strictrland 0.4.0</a> and will plan the next steps based on user feedback!</p>\n<p>Cheers!</p>\n<p>Oskar</p>\n<p><strong>p.s. Ukraine is still under brutal Russian invasion. A lot of Ukrainian people are hurt, without shelter and need help.</strong> You can help in various ways, for instance, directly helping refugees, spreading awareness, and putting pressure on your local government or companies. You can also support Ukraine by donating, e.g. to the <a href=\"https://savelife.in.ua/en/donate/\">Ukraine humanitarian</a> organisation, <a href=\"https://www.gofundme.com/f/help-to-save-the-lives-of-civilians-in-a-war-zone\">Ambulances for Ukraine</a> or <a href=\"https://redcross.org.ua/en/\">Red Cross</a>.</p>","excerpt":"I want it all, and I want it now. This is not only a Freddie Mercury quote but also, too often, a general plan for our software product. The…","fields":{"slug":"/addition-by-subtraction-in-software-design/","prefix":"2026-07-06","langKey":"pl"},"frontmatter":{"title":"Addition by subtraction in Software Design","author":"oskar dudycz","category":"Software Architecture","disqusId":null,"useDefaultLangCanonical":true,"cover":{"childImageSharp":{"resize":{"src":"/static/e21f3e6a6f81e7da9dce92657435fa1f/4fe8c/2026-07-06-cover.jpg"}}}}},"authornote":{"id":"295c4649-a20b-5147-9ca5-5cb77fbcfe66","html":"<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 800px; height: auto\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/f748655e118b2b9d5ce6b7dd6f9f4f85/d2429/2021-10-13-cover.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 55.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA6cAAAOnAEHlFPdAAAChUlEQVQozyXOTU/acBwA4J+FFmgp/5RCX2AlFVgUgxTCYZNA6KZMooPSiAoaZ8bLjTmEbALRePAygyaLBEl0lyWePGji1YsnT8YDBxMTE+9+iiXu+QQPPDw8nJ2dtVqtZrNZr9cbjUYul8tkMvl8vt1un5yc3Nzc3N7eDofDu7u74+Pj+/v7x8fH6+vr8/NzGA6HOzs73W53f3+/0+mUSqVisbi3t3d0dNTv9w8PDy8uLnq93sHBQblcrtfrp6enl5eXrVarUqnA8/OzruvLy8uDwUDTtJmZmWw22+12Nzc3q9VqKpUqFovT09OFQsHr9SaTyZWVlVgspmlaoVCAl5cXRVE4jotGowghiqJIkpybm/N4PAsLCwghRVF0Xff5fHa7HQDi8Xg6nQaASCQCT09PwWAQXrEsa7VaZVlOp9NjY2Nut1uWZYIgWJYVRZEkSYZhLBaL0WgkCCIUCkGv1xMEAcMwo9EIABRFEQQhSVI0GhUEwWAw0DQ9OjqK4zhFUQzD2O12HMc5jhMEAa6urmRZRgglEgmHwzEyMuJyuXZ3d2u12tTUFAAQBOF0Onmep2mae2V6heM4bG1tIYR4nk8kEqIoAkAgEOh0OvF4XJIkADCZTDzPu1wuk8lks9kQQhiGmc1mkiTB65U5zun3+xFCPp+P5znaRquqGg6HcdyIYRiO4+VyeWlp6f+CpmmDwWAxm0VRAFX9kM3mVlfXJidDPv/bN24pHI4kkyrDMCRJjo8HJMnz6dNsq9W2WmmzhWRZB2W1BSaCmqbDxrfK9naj/r2az2fWvxTfvY98La2pakxRJuY/zy4u5jLZtPox/uPnxvp6YTalLurz7WZt8PvX3z/9f7APp/oT02NdAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"cover\"\n        title=\"cover\"\n        src=\"/static/f748655e118b2b9d5ce6b7dd6f9f4f85/a331c/2021-10-13-cover.png\"\n        srcset=\"/static/f748655e118b2b9d5ce6b7dd6f9f4f85/36ca5/2021-10-13-cover.png 200w,\n/static/f748655e118b2b9d5ce6b7dd6f9f4f85/a3397/2021-10-13-cover.png 400w,\n/static/f748655e118b2b9d5ce6b7dd6f9f4f85/a331c/2021-10-13-cover.png 800w,\n/static/f748655e118b2b9d5ce6b7dd6f9f4f85/d2429/2021-10-13-cover.png 805w\"\n        sizes=\"(max-width: 800px) 100vw, 800px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n        decoding=\"async\"\n      />\n  </a>\n    </span></p>\n<p>Through my window, I see the result of good plans but poor execution. Opposite my flat, there is a partially completed construction place. Buildings were supposed to be eye-catching Mediterranean style apartments.  Delivery date? Two years ago. Actual? More and more unknown.</p>\n<p>Some time ago, I heard that using Event Sourcing makes creating Event-Driven Architecture easier. The arguments were correct, that if we’re already publishing events to trigger business workflows, then at some point, we may want to also store events to not lose information. Agreed. However, I also heard that keeping the state as events will simplify things. We’ll have a source of truth with a record of the system behaviour. This will allow, e.g. to confront the results of the operations with the recorded state. I’d agree with that, with one distinction. It’s easier as long as you already know Event Sourcing.</p>\n<p>Many people in the DDD community claim that the essential is to properly break down the system into autonomous parts called bounded contexts. Once we have it, the rest is secondary and will sort itself out. For sure.</p>\n<p>Many seasoned programmers speak similarly about new technologies. They claim that they can translate past experience into new technologies. That’s true that by analogy, they can catch the big picture quicker. But isn’t it a bold assumption to say that Win.Forms specialist will learn Angular quickly?</p>\n<p>The end result may differ a lot from the initial ideas. I saw the plan of those buildings next to me. Now I can see the effects of the execution. Or actually, the lack.</p>\n<p>I believe that we should carefully acknowledge not only the point of view of our authorities but also their seating point. If we want to find out how to form a wall, do we ask an architect or a foreman? An architect may know the theory, but the practice is what we’re looking for. On the other hand, if you want to know where to put the wall, you prefer the architect to do measurements. At least if you don’t want to have the roof falling to your head.</p>\n<p>After I had torn a ligament in my knee, I went to two qualified orthopedists. One said I should have surgery and do a reconstruction. The second stated that there is no need for that; rehabilitation should be enough. Guess which one had a specialization in surgery and which in rehabilitation?</p>\n<p>People usually give us advice from the point where they’re currently standing. They are entitled to a biased view. An architect who rarely does programming will tend to downplay the value of implementation and tactical patterns. Midlevel developers will focus on technicalities instead of the global system impact. The team manager or consultant will emphasize the importance of soft skills (or esoteric techniques known only to them).</p>\n<p>The truth is that we need all of them. The excellent plan will fall on the bad execution. The best execution for the wrong case will be just a waste of time. We should carefully evaluate the advice considering what we need and what an expert can give us.</p>\n<p>Therefore, when we’re reading an article, watching a talk, let’s also pay attention to the place where the person is standing. The perspective from there may be much different from where we are right now. That can be good, as it may push us in the right direction. But it may also be misleading, as we accidentally take biases of this person without understanding the tradeoffs. Personally, I prefer to follow not only people from pedestal but also those that are closer to my position. A bit further in the journey, but not too far. That helps me to calibrate my view as those people are more relative to my daily struggles.</p>\n<p>Polish historical leader <a href=\"https://en.wikipedia.org/wiki/J%C3%B3zef_Pi%C5%82sudski\">Józef Piłsudzki</a> reportedly used to say: <em>“Right is like an ass, everyone has its own”</em>.</p>\n<p>Cheers!</p>\n<p>Oskar</p>"},"site":{"siteMetadata":{"facebook":{"appId":""}}}},"pageContext":{"slug":"/addition-by-subtraction-in-software-design/","lang":"pl","langKey":"pl","prev":{"id":"c7398fbc-647d-528c-9b7f-0081934eeebd","fields":{"slug":"/announcing-strictland-contract-testing/","prefix":"2026-06-15","source":"posts","langKey":"pl"},"frontmatter":{"title":"Announcing Strictland - new contract testing library for message compatibility","category":"Testing"}},"source":"posts"}},
    "staticQueryHashes": ["2742854296"]}