↓ Skip to main content
Layered mountain ridges at sunrise, suggesting perspective and context

Technical decisions do not fail because of a lack of tools

Engineering Notes - This article is part of a series.
Part 1: This Article

Key ideas
#

  • A technical decision does not start with a technology, but with a problem we need to understand.
  • The same solution can be right or wrong depending on context, constraints, and team capacity.
  • Comparing alternatives requires making visible what we gain and what we accept losing.
  • A good decision does not seek a perfect answer; it seeks a reasonable answer for a particular situation.
  • Engineering is not only about choosing tools, but also about understanding their consequences.

A team maintains an application that has worked well for years. The business needs a new capability, the domain is beginning to grow, and every deployment requires more coordination. During a meeting, a familiar proposal emerges: split out a service, introduce events, and move operations to a more sophisticated platform.

Within minutes, the conversation stops being about the problem and starts revolving around tools. Microservices? Kubernetes? An event broker? Every option has solid arguments and enough documentation to defend it.

I have seen this scene repeat itself in projects with very different needs. The moment that changes the conversation most does not happen when someone presents another technology, but when the team asks a more uncomfortable question:

What changed in our context that made the current architecture no longer sufficient?

Sometimes the answer leads to a new service. Other times, better modularization, a simpler integration, or delegating part of the operation is enough. The lesson is the same: there is no correct answer without context.

The conversation changes when the question changes
#

Tools are easy to compare because they have visible features, metrics, and use cases. The real problem is usually less defined: perhaps we need to reduce delivery time, isolate failures, comply with a regulation, or allow two teams to work with greater autonomy.

That is why I try to start architecture reviews with the situation, not the product. Before asking which technology to use, I need to understand who has the problem, what outcome we expect, and under which conditions the solution must work. A list of tools answers none of those questions.

This does not mean ignoring technical experience. It means using it at the right time. Technology appears after understanding the problem, not before.

Constraints are part of the design
#

For a long time, I interpreted constraints as things to remove in order to reach an ideal architecture. Practice taught me the opposite: time, budget, regulation, team experience, and operational capacity are design information.

A small team may prefer a managed service so it can focus on the product. Another team, with strict control requirements and platform specialists, may operate the same capability internally. Both decisions can be correct because they respond to different constraints.

When a proposal only works if we ignore the team’s real conditions, we do not have an architecture; we have an assumption.

An example: processing business events
#

Imagine that an operation needs to publish events without blocking its main flow. The team can operate a broker, use a managed service, or keep a synchronous integration while volume remains manageable. No alternative is inherently good.

flowchart TD
    A[Problem: process events without blocking operations] --> B{Viable options}

    B --> C[Self-managed broker]
    B --> D[Managed service]
    B --> E[Synchronous processing]

    C --> C1[Control / operational load]
    D --> D1[Less operations / dependency]
    E --> E1[Simplicity / less decoupling]

    C1 --> F[Decision based on context and constraints]
    D1 --> F
    E1 --> F

The decision changes when we answer specific questions:

  • What level of availability does the operation need?
  • Can we recover or replay events?
  • What volume do we expect over the next few months?
  • Who will support the platform when it fails?
  • How much complexity can we take on today?

If the team is small and delivery time is limited, reducing operational load may matter more than retaining full control. If there are particular security, cost, or performance requirements, the balance may change. Architecture emerges from that conversation, not from the name of the chosen product.

Four decisions without a universal answer
#

The same tension appears in common engineering decisions. Framing them as a competition between technologies hides the variables that really matter:

  • Monolith or microservices. The answer depends on domain boundaries, team autonomy, change frequency, and operational maturity.
  • Synchronous integration vs. event-driven asynchronous integration. Temporal coupling, consistency, traceability, and how the business responds to partial failures all matter.
  • Virtual machines or containers. Portability and deployment speed must be compared with isolation, the available platform, and team experience.
  • Managed or self-managed. More control also means taking on maintenance, upgrades, observability, and incident response.

These questions do not have one winning option for every system. They are useful because they force us to make explicit what each alternative solves and what cost it introduces.

A practical framework for thinking about decisions
#

Over time, I have found it useful to structure the conversation in six steps. I do not see it as a rigid methodology, but as a way to prevent a technical preference from becoming a decision before it has been examined.

flowchart LR
    P[Problem] --> A[Context]
    A --> B[Constraints]
    B --> C[Alternatives]
    C --> D[Trade-offs]
    D --> E[Decision]
    E --> F[Consequences]

1. Context: what problem are we solving?
#

Context describes the current situation, the people affected, and the outcome we seek. It matters because two technically similar systems can have completely different business and operational priorities.

2. Constraints: within what limits must we decide?
#

Here we make time, budget, regulation, experience, and operational capacity visible. An alternative that cannot be sustained within those limits is not really an alternative.

3. Alternatives: which paths are viable?
#

Comparing at least two options prevents us from confusing a preference with a decision. We do not need an extensive list; we need paths that solve the same problem and can be evaluated under the same conditions.

4. Trade-offs: what do we gain and what do we accept losing?
#

More control usually brings more responsibility. Faster delivery may limit future flexibility, and a lower operational burden may increase dependence on a provider. Making this exchange visible allows us to discuss consequences instead of preferences.

5. Decision: why does this alternative make sense now?
#

The decision should connect the chosen option with the context and its constraints. It does not claim that it will always be correct; it explains why it is reasonable with the information available today.

6. Consequences: what changes after we choose?
#

Every decision creates work, risks, and new conditions. It is useful to define which signals would force us to revisit it: an increase in costs, a change in volume, new requirements, or operational capacity that did not exist before.

Recording the decision preserves context
#

I have learned that a team’s memory compresses decisions. Months later, we remember which technology we chose, but not always the constraints that justified the choice. A small record can preserve that information without becoming a document that is difficult to maintain:

id: ADR-001
status: accepted

context:
  Process business events without blocking the main operation

decision:
  Use a managed messaging solution

drivers:
  - small team
  - limited delivery time
  - need for event recovery

review_when:
  - significant cost increase
  - change in requirements
  - new operational capacity

The value is not only in recording what we chose, but in remembering why we chose it and when we should revisit it.

A good technical decision should also be explainable. Months later, someone will ask:

Why did we do this?

The most useful answer is not “because it was the recommended technology,” but an explanation that connects the problem, the options considered, and the accepted consequences. Architecture is also communication: if a decision cannot be explained, it will be difficult to operate, question, or evolve it as a team.

Continuing the conversation
#

This way of analyzing decisions is the basis for future writing about how to apply this framework to different scenarios and discuss the trade-offs behind each alternative.

Conclusion
#

Tools will continue to change, and knowing them will remain part of the work. But knowing a technology is not the same as knowing when to use it.

Engineering is not only about choosing tools. It is about understanding problems, evaluating alternatives, and consciously accepting the consequences of a decision.

A technical decision is stronger when it can be explained, defended, and revisited. Not because it is perfect, but because it makes explicit the problem it solves, the limits it recognizes, and the consequences the team chooses to accept.

Engineering Notes - This article is part of a series.
Part 1: This Article