<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
  <title>Tomas Maconko - Writing</title>
  <link>https://maconko.tech/blog/</link>
  <description>Practical essays on software architecture, domain modeling, modernization, distributed systems, and technical leadership.</description>
  <language>en</language>
  <item>
    <title>What working on both sides taught me about contractors and employees</title>
    <link>https://maconko.tech/blog/contractors-enter-employees-live-with-it/</link>
    <guid isPermaLink="true">https://maconko.tech/blog/contractors-enter-employees-live-with-it/</guid>
    <pubDate>Wed, 26 Aug 2026 09:00:00 GMT</pubDate>
    <description>Working both as a consultant and inside engineering teams taught me why outsiders see problems faster, insiders understand their consequences, and neither perspective is enough.</description>
    <content:encoded><![CDATA[<img src="https://maconko.tech/blog-images/contractors-veni-vidi-vici.webp" alt="A departing specialist walks confidently beyond a worn institutional gate while an employee remains behind repairing the road and maintaining its machinery" loading="lazy"/><p>For much of my career, consulting has overlapped with embedded engineering and leadership roles. I have entered organizations from the outside, but I have also stayed inside teams long enough to live with their decisions, incidents, workarounds, and handoffs.</p>
<p>Working on both sides changed how I think about the familiar comparison between contractors and employees. The conversation usually begins with price. The contractor has a day rate that looks expensive before lunch. The employee&#x27;s cost disappears into salary bands, benefits, recruitment, management, equipment, onboarding, retention, and several budgets that nobody puts next to one another. The comparison is tidy. Reality, as usual, is different.</p>
<p>Then come the familiar stereotypes. Contractors are fast, direct, and result-oriented. Employees are committed, understand the domain, and remain long enough to deal with the consequences.</p>
<p>There is enough truth in both descriptions to make them useful, but neither describes the whole job.</p>
<blockquote>
<p>In my experience, contractors are often better at entering a system. Employees are usually better at living with it.</p>
</blockquote>
<p>This is not a character judgment. It is what the two positions trained me to see. When I arrive as a consultant, I carry patterns from other organizations. When I work inside a team, I carry the memory of this one.</p>
<p>Neither view is complete.</p>
<h2>What I notice when I enter from the outside</h2>
<p>When I enter a new organization as a consultant, I have one unfair advantage: the organization is not normal to me yet. The twelve approvals, the release that needs six people in a call, the service nobody wants to touch, and the decision that has travelled through three steering groups still look strange.</p>
<p>I have also experienced the other side. Inside a company, I may see exactly the same problems, but I have had more time to learn which ones can be challenged, which ones will consume a month of discussion, and which ones everyone has agreed to step around. Yesterday&#x27;s temporary workaround becomes today&#x27;s process. Given enough time, the process acquires an acronym and becomes official.</p>
<p>Consulting across several projects makes these patterns easier for me to recognize. I can often identify a familiar queue, ownership gap, architectural constraint, or process whose purpose is no longer obvious before the organization has finished explaining why its situation is unique.</p>
<p>Every organization is unique, of course. Several are unique in surprisingly familiar ways.</p>
<p>That speed is valuable. It is also where I have to slow down.</p>
<p>A pattern is not the same as an explanation. An unusual validation rule may protect a contractual exception. A manual approval may reflect operational learning that is not documented elsewhere. An apparently confusing service boundary may follow a business boundary that is invisible in the repository.</p>
<p>I can name the pattern quickly and still have only part of the context needed for a decision.</p>
<p>The people who have lived with the system have something my breadth cannot replace: memory of consequences. They remember which customer depends on the strange behaviour, which migration was attempted before, and why a technically beautiful proposal changed when it reached operations. Some of that is real domain knowledge. Some of it is organizational folklore that nobody has revisited for years.</p>
<p>The difficult part is knowing which is which.</p>
<h2>I can be more direct from the outside</h2>
<p>My team is valued partly because we say things directly. We raise concerns that other teams have become comfortable with, question decisions that already have institutional momentum, and say when a proposed direction does not survive contact with the actual system.</p>
<p>I find that easier from the outside. As a consultant, I have fewer promotion paths to protect, fewer old disagreements attached to the current one, and less reason to pretend that a senior stakeholder&#x27;s favourite idea is merely “a promising direction that may need further validation.”</p>
<p>Sometimes the useful sentence is simply: I do not think this direction will give us the result we need.</p>
<p>That does not make me naturally braver when I consult or naturally more cautious when I work inside a company. The position changes the relationships around the conversation. Employees understand the history behind a proposal and know how today&#x27;s discussion will affect tomorrow&#x27;s collaboration. That context can make disagreement more deliberate.</p>
<p>External status creates room for directness, but directness is useful only when it comes with curiosity. A confident outside perspective should still make space for the people who understand the domain, explain its constraints, and will continue the work after the engagement. My independence matters most when I use it to make the organization more capable, not more dependent on me.</p>
<p>Directness is not a personality trait in this context. It is part of the product.</p>
<h2>One engagement changed how I think about continuity</h2>
<p>The narrowest version of contracting is easy to recognize. A group arrives, delivers a project against a defined scope, presents the result, and hands it to the employees who will operate and evolve it. The project is complete. Production, with its usual lack of respect for milestone dates, has only just become interested.</p>
<p>I have seen that model, but one of my recent engagements showed me the opposite. We worked on a time-and-materials basis with dedicated ownership. We had enough continuity to remain with the decisions, operate around their consequences, and adjust when reality disagreed with the original plan.</p>
<p>We were contractors on paper and long-term owners in practice.</p>
<p>That experience changed my view of continuity. It is often discussed as though it comes automatically with an employment contract. It does not. I have seen employees rotate to another team, accept a promotion, mentally leave long before resigning, or protect one narrow responsibility while the product deteriorates between organizational boundaries.</p>
<p>A contractor can remain for years and care for a system through several generations. An employee can leave after six months. Badges are excellent at opening office doors and less reliable at predicting ownership. The operating model tells us more: who owns the result, who receives production feedback, who is allowed to make decisions, and who is still present when the first confident assumption needs revision.</p>
<p>If contractors are treated as temporary hands, they will usually produce temporary ownership. If they are given context, trust, and responsibility for continuity, the line between an external and internal team becomes much less useful.</p>
<h2>Urgency works better with continuity</h2>
<p>I am usually brought into an organization because it wants movement. A migration needs a clearer direction, an architecture decision has remained open, or a team needs capability it cannot build quickly enough. There is an important objective and a clear expectation that something should change.</p>
<p>That pressure can be healthy. From the outside, I am more likely to cut through the landscape and ask which constraints are still real today. When I am embedded in the organization, I see more of the dependencies, stakeholders, historical constraints, and possible future consequences surrounding the same decision.</p>
<p>That makes <em>veni, vidi, vici</em> tempting. Latin also looks excellent on a steering committee slide. It is a useful mindset for creating momentum, but not a complete operating model.</p>
<p>Speed matters when the organization needs a decision or a bounded result. Continuity matters when that result must be operated, explained, and changed over time. The best engagements treat those as one responsibility: create movement now while leaving the team more able to continue without external help.</p>
<p>The same balance helps employees. Stewardship brings valuable care for dependencies and future consequences. An outside perspective can help turn that context into a timely decision. One provides momentum; the other makes the momentum sustainable.</p>
<p>Good contractors bring urgency without pretending that tomorrow does not exist. Good employees protect continuity without using tomorrow to postpone today.</p>
<h2>The two roles made different costs visible</h2>
<p>As a consultant, I know my cost is difficult to ignore. Hours are recorded, rates are visible, invoices arrive, and somebody reviews them. Invoices are refreshingly literal documents: every workshop, investigation, and implementation has a number attached to it.</p>
<p>In engineering leadership roles, I have seen how much less visible the cost of an employee can be. Employee costs prefer a distributed architecture. Salary is only the easiest part to see; recruitment, interviews, onboarding, equipment, benefits, management time, internal coordination, retention effort, paid absence, unfilled positions, and the time required to become effective are spread across the organization.</p>
<p>More importantly, employee investment is evaluated over a longer horizon. Domain knowledge, trusted relationships, and operational memory grow over time, while their value rarely appears next to one project budget.</p>
<p>A new rectangle on the organization chart does not automatically create movement, just as an external day rate does not automatically create expertise. Employees need the authority and environment to move an outcome. Contractors need enough context and continuity to make their contribution last.</p>
<p>But comparing a contractor&#x27;s rate with an employee&#x27;s salary is not financial discipline. It is comparing an invoice with a fraction of a cost.</p>
<p>The useful question is not how much a day costs. It is how much it costs to reach a useful result, how long that result continues producing value, and what capability remains after the people who created it move elsewhere.</p>
<p>An expensive contractor who helps a team reach an important decision sooner may be cheaper than extending uncertainty. A strong employee who preserves domain knowledge and improves that decision over time may be worth more than any short engagement.</p>
<p>Price is visible. Waste is patient.</p>
<h2>I now look for the missing behaviour</h2>
<p>Some organizations hire contractors for work that actually needs permanent ownership. A sequence of external people can add useful capacity, but retaining domain knowledge becomes difficult when every engagement has a separate end date.</p>
<p>Others hire employees when they need a focused intervention or an outside perspective. New employees can become durable owners, but they need time to build context and relationships before they can see the organization with the same contrast as someone arriving from elsewhere.</p>
<p>When I help make this choice, I begin with the behaviour the organization is missing. Does it need breadth from somebody who has seen the pattern elsewhere? Directness from people who can challenge internal comfort? Urgency around a bounded result? Or does it need deep domain memory, durable product ownership, and somebody who will still be there for the fifth version of the decision?</p>
<p>Sometimes the right answer is deliberately both. Contractors can notice what has become familiar, while employees explain which unusual parts carry real business history. One side brings contrast; the other protects context.</p>
<p>That works when neither group is treated as the only source of truth. Employment status does not guarantee a particular contribution. Both groups can create value, share knowledge, and strengthen ownership when the operating model allows them to work as one team.</p>
<p>Employment status is metadata. Ownership still needs an architecture.</p>
<p>Working on both sides taught me that entering and staying are different skills. The strongest teams help the people who enter understand what it means to stay, while the people who stay remain open to what a fresh perspective can reveal.</p>]]></content:encoded>
  </item>
  <item>
    <title>The system is strange for a reason</title>
    <link>https://maconko.tech/blog/the-system-is-strange-for-a-reason/</link>
    <guid isPermaLink="true">https://maconko.tech/blog/the-system-is-strange-for-a-reason/</guid>
    <pubDate>Mon, 10 Aug 2026 09:00:00 GMT</pubDate>
    <description>Mature software contains years of accumulated decisions and constraints. Before replacing it with something cleaner, we should understand what knowledge we are about to erase.</description>
    <content:encoded><![CDATA[<img src="https://maconko.tech/blog-images/the-system-is-strange-for-a-reason.webp" alt="Black-and-white caricature of a plumber proposing an elaborate apartment reconstruction while a single faucet drips" loading="lazy"/><p>A new engineer joins a team and encounters an unfamiliar system. The architecture looks dated, and several decisions do not match how they would build it today.</p>
<p>It rarely takes long before someone proposes a cleaner replacement. The system is too complicated, its boundaries are wrong, and its technology is old. A modern architecture would be easier to understand and better prepared for the future.</p>
<p>The proposal is usually presented as a technical improvement. Sometimes it is. But sometimes the strongest motivation is much simpler: rebuilding the system is more attractive than taking the time to understand it.</p>
<blockquote>
<p>The new design always looks clean because it has not encountered reality yet.</p>
</blockquote>
<h2>The plumber who wants to rebuild your apartment</h2>
<p>Imagine that a faucet in your apartment starts dripping. You call a plumber and expect them to inspect the tap, replace a worn part, and leave you with a working faucet.</p>
<p>Instead, the plumber explains that the entire plumbing system is outdated. They propose replacing every pipe, moving the bathroom, opening several walls, and installing modern devices they have recently been learning about. While they are there, they could divide the plumbing into independently maintainable sections.</p>
<p>Most of us would see red flags. We would ask how a dripping faucet became an apartment reconstruction, question the cost and disruption, and probably call another plumber.</p>
<p>In software engineering, proposals of similar proportions receive serious consideration. A local problem becomes evidence that an application should be rewritten. A difficult deployment becomes a platform initiative. An inconvenient boundary becomes a reason to split a system into services. The proposed solution grows far beyond the original problem, yet organizations still create working groups to explore it.</p>
<h2>Software makes reconstruction look cheap</h2>
<p>Physical reconstruction has visible costs: materials, permits, opened walls, and immediate disruption. Software creates a dangerous illusion because code has no visible material cost. Replacement can look like a matter of assigning enough engineers and waiting several months.</p>
<p>But a software rewrite does not begin from nothing. It begins with years of behavior that must be rediscovered and reproduced.</p>
<p>The real cost includes undocumented rules, data migration, parallel operation, integrations, operational procedures, and behaviors customers quietly depend on. These costs emerge when the replacement meets the same reality that made the old system complicated.</p>
<p>The existing system looks messy because its compromises are visible. The proposed system looks elegant because its compromises have not been discovered yet.</p>
<h2>Working software deserves respect</h2>
<p>Software engineers have repeated two phrases for years:</p>
<blockquote>
<p>“If it works, don’t touch it.”</p>
</blockquote>
<blockquote>
<p>“Working software is good software.”</p>
</blockquote>
<p>Neither statement is universally correct. Software can work while being insecure, prohibitively expensive, or unable to support what the business needs next. Refusing every change is not engineering discipline; sometimes it is simply fear.</p>
<p>Still, both phrases contain an important warning. Working software has encountered real customers, data, failures, integrations, and organizational constraints that no architecture proposal can fully reproduce.</p>
<p>That does not make it untouchable. It makes it evidence.</p>
<p>Before discarding a working system, we should be able to explain what we are gaining and what we are risking. “The new design is cleaner” is not enough. Cleanliness without context is often just unfamiliarity with the problem.</p>
<h2>Strange code may contain forgotten knowledge</h2>
<p>Systems that have operated for many years accumulate more than technical debt. They accumulate decisions.</p>
<p>A validation rule may exist because an external system once sent malformed data. A duplicated workflow may reflect contractual differences. An awkward field may preserve compatibility, while a misplaced boundary may reflect operational ownership.</p>
<p>Some of those decisions may no longer be relevant. Others may never have been good decisions. But we cannot tell the difference simply by reading the code and noticing that we would have designed it differently.</p>
<p>Too many improvement proposals treat every existing constraint as a mistake. The team removes the awkward parts before investigating them, then discovers that the awkwardness was carrying information.</p>
<p>Mature systems do not store their knowledge in one document. It is distributed across code, tests, data, support procedures, customer expectations, and the memories of maintainers.</p>
<p>When we rewrite such a system, we are not only replacing technology. We are attempting to transfer institutional memory from a form we do not fully understand into a design that has not yet been tested.</p>
<h2>The attraction of starting again</h2>
<p>Maintenance requires humility. It asks an engineer to enter a system built by other people, accept that many decisions lack obvious explanations, and spend time learning before suggesting large changes.</p>
<p>A rewrite offers a more flattering position. Instead of studying the existing system, the engineer becomes the architect of the new one. Their preferred patterns become the standard, and their name becomes associated with the transformation.</p>
<p>This does not mean every rewrite is a conscious search for recognition. The incentive is subtler: organizations celebrate launches and new platforms more visibly than another year of stable operation.</p>
<p>A maintenance change may prevent a problem nobody will notice. A rewrite produces diagrams, roadmaps, and new repositories. One looks like a minor task. The other looks like progress.</p>
<p>That difference affects our judgment. Personal preference becomes an architectural principle. Discomfort with unfamiliar code becomes evidence that the code is unmaintainable. The desire to work with newer technology becomes a business case about future scalability.</p>
<p>Eventually, “I would not build it this way” quietly turns into “this system should not exist.”</p>
<h2>Sometimes rebuilding is the correct decision</h2>
<p>Some systems should be replaced. A rewrite can be justified when the current system cannot meet important requirements, its technology is no longer supportable, security risks cannot be addressed safely, or meaningful changes have become unreasonably expensive.</p>
<p>The difference is that a justified rewrite begins with a demonstrated problem, not aesthetic disappointment. It explains why incremental improvement is insufficient and compares the full cost of replacement with continued evolution.</p>
<p>A responsible proposal treats migration as part of the architecture. It considers how data and integrations will move, how behavior will be compared, and how both systems will operate during the change. It does not preserve every historical decision, but it understands important behavior before removing it.</p>
<p>A rewrite should not be an escape from complexity. It should be a deliberate response to complexity that we understand well enough to change.</p>
<h2>Before approving the reconstruction</h2>
<p>Large refactorings and rewrites need more than promises of cleaner code and faster development. Before opening the walls, the team should answer:</p>
<ul>
<li>What measurable problem are we solving?</li>
<li>Can we improve it incrementally?</li>
<li>Which existing constraints have we verified rather than assumed?</li>
<li>What behavior must the replacement preserve?</li>
<li>Does the estimate include migration, parallel operation, operational learning, and decommissioning?</li>
<li>Would we still support the proposal if someone else received credit for building it?</li>
</ul>
<p>The last question may be uncomfortable. If the proposal becomes less exciting when recognition is removed, the problem may not be entirely technical.</p>
<p>Software should change when the problem requires it, and be replaced when evidence shows that replacement is better than continued evolution.</p>
<p>But unfamiliarity is not evidence, modernity is not a business outcome, and ambition is not an architecture strategy.</p>
<p>Before rebuilding the apartment, fix the faucet—or at least understand why the pipes were placed there in the first place.</p>]]></content:encoded>
  </item>
  <item>
    <title>The hardest part happens before the code</title>
    <link>https://maconko.tech/blog/hello-world/</link>
    <guid isPermaLink="true">https://maconko.tech/blog/hello-world/</guid>
    <pubDate>Tue, 21 Jul 2026 09:00:00 GMT</pubDate>
    <description>After ten years across different companies, projects, and teams, I keep seeing the same pattern: most IT problems are not technological.</description>
    <content:encoded><![CDATA[<img src="https://maconko.tech/blog-images/tomas-maconko-portrait.webp" alt="Portrait of Tomas Maconko" loading="lazy"/><p>Ten years ago, I attended training sessions with Greg Young, Alberto Brandolini, and other experienced practitioners. In the years that followed, I worked across different companies, products, and teams. The technologies changed, but many of the difficult problems looked remarkably similar.</p>
<p>One pattern kept returning: most IT problems are not purely technological.</p>
<blockquote>
<p>Writing code is often the straightforward part. The hardest work happens before the code.</p>
</blockquote>
<p>It happens while people are trying to understand the problem, agree on language, decide who owns what, and choose which trade-offs they are prepared to carry.</p>
<h2>The same problems in different systems</h2>
<p>Across startups and enterprises, I have repeatedly seen situations where:</p>
<ul>
<li>team members struggle to communicate, and silos and dependencies begin to grow;</li>
<li>architecture no longer reflects business reality and becomes expensive without producing enough value;</li>
<li>decisions take longer to make and cost more to implement than expected;</li>
<li>missing technical leadership makes consequential system changes feel too risky;</li>
<li>product and engineering start moving in different directions.</li>
</ul>
<p>The products were different. The people were different. The symptoms were often the same.</p>
<p>I have had the privilege and trust not only to build systems with teams, but also to help people find where delivery is actually getting stuck. Sometimes the constraint is in the code. Often it is in the process, communication, ownership, or an unresolved decision between several reasonable options.</p>
<h2>Technology cannot resolve every constraint</h2>
<p>Not every difficult system needs:</p>
<ul>
<li>microservices or event sourcing;</li>
<li>AI agents;</li>
<li>Kubernetes;</li>
<li>an enterprise architecture programme.</li>
</ul>
<p>These approaches are not inherently wrong. They are useful when they fit the problem. But applying them before the problem is understood can add another layer of complexity without removing the original constraint.</p>
<p>Sometimes the best solution is a well-built monolith. Sometimes it is a clearer boundary, a smaller decision, or a conversation between people who have been working from different assumptions.</p>
<h2>What I want to explore here</h2>
<p>This blog is where I will examine the difficult parts of software work that do not fit neatly into an implementation ticket:</p>
<ul>
<li>architecture and domain boundaries;</li>
<li>distributed systems and real-time data;</li>
<li>modernization without unnecessary rewrites;</li>
<li>engineering leadership and collaboration across teams;</li>
<li>where AI helps engineering work, and where it creates new problems;</li>
<li>lessons from decisions that worked and, just as importantly, those that did not.</li>
</ul>
<p>The examples will come from real systems and real delivery environments, with identifying details changed where necessary. The goal is not to promote one architecture style. It is to make the problem, the trade-offs, and the decision clearer.</p>
<p>That is the starting point: understand what is actually getting in the way, then choose the technology.</p>]]></content:encoded>
  </item>
  <item>
    <title>A successful project is not yet a successful product</title>
    <link>https://maconko.tech/blog/successful-project-is-not-a-successful-product/</link>
    <guid isPermaLink="true">https://maconko.tech/blog/successful-project-is-not-a-successful-product/</guid>
    <pubDate>Tue, 21 Jul 2026 09:00:00 GMT</pubDate>
    <description>A team can meet every requirement and deliver a high-quality solution, but that alone is not enough to make a product successful.</description>
    <content:encoded><![CDATA[<img src="https://maconko.tech/blog-images/building-a-product.webp" alt="Product development illustration showing engineering at work while other organizational functions stand around waiting" loading="lazy"/><p>Over the course of my career, I have seen at least four projects that could reasonably be called successful.</p>
<p>The requirements were implemented. The quality was good. The UX was decent. The team delivered what it had promised.</p>
<p>Yet none of them became a successful product.</p>
<p>They all reached roughly the same point – go-live – and stalled somewhere around it.</p>
<p>In one case, marketing spent a long time aligning on how to introduce the product to the market. In another, the project became stuck in legal processes. Elsewhere, business priorities changed during development and the initiative was stopped.</p>
<p>A team can execute a project flawlessly, but that does not mean the product will ever reach the customer.</p>
<p>Perhaps the problem is that we too often imagine product development as a relay race: product defines the need, engineering writes the code, and only then do marketing, sales, legal, finance, operations, and support join in.</p>
<p>In reality, a product is not a relay race. It is a shared effort in which all these functions need to move in the same direction long before anyone is ready to press “Go Live.”</p>
<p>That is why the hardest challenge is often not writing the code. It begins with agreeing on what we are building, why we are building it, how the product will reach the market, and what must happen before customers can actually use it.</p>
<p>This is also why much of my consulting work is not about technology. It involves helping different sides understand one another, surface unspoken assumptions, align expectations, and find a shared direction.</p>
<p>Because a good product is not simply the result of good engineering.</p>
<p>It emerges when the whole organization can bring it to the customer together.</p>]]></content:encoded>
  </item>
</channel>
</rss>
