← All Articles
Last updated: 2026-03-30

How to Make Technical Architecture Decisions You Won't Regret

Framework for technology decisions. Build vs buy, monolith vs microservices, database selection, architecture decision records.

TL;DR

Architecture decisions are the most expensive decisions in software. Changing a database at month 18 costs 10-100x more than choosing the right one at month 1. This guide gives you a structured framework for making technology decisions: evaluate with explicit criteria, document decisions in Architecture Decision Records (ADRs), and avoid the most common traps — including premature microservices, resume-driven development, and the sunk cost fallacy.

Prerequisites

Step 1: The Decision Framework

Every architecture decision should pass through the same structured evaluation. Gut feelings are not architecture — they are gambling with someone else's money.

The Five-Question Filter

Before evaluating any technology, answer these questions:

1. What problem does this solve? (Be specific — "we need it" is not an answer)
2. What are the constraints? (team skills, budget, timeline, compliance)
3. What are the alternatives? (minimum 3, including "do nothing")
4. What is the cost of being wrong? (can we reverse this decision?)
5. When do we need to decide? (urgency vs importance)

Reversibility Classification

Not all decisions are equal. Classify each decision:

Type 1 (One-way door): Irreversible or extremely expensive to reverse
  Examples: Programming language, primary database, cloud provider
  Action:  Invest significant time in evaluation. Get external review.

Type 2 (Two-way door): Reversible with moderate effort
  Examples: UI framework, CI/CD tool, monitoring solution
  Action:  Make a quick decision. Optimize for speed. Change later if needed.

Type 3 (Revolving door): Trivially reversible
  Examples: Code formatting, variable naming, folder structure
  Action:  Pick one, move on. Don't debate for more than 15 minutes.

Weighted Decision Matrix

For Type 1 decisions, use a weighted decision matrix:

Criteria (weight)      | Option A  | Option B  | Option C
-----------------------+-----------+-----------+----------
Team expertise (25%)   |  8 (2.0)  |  5 (1.25) |  7 (1.75)
Community/support (20%)|  9 (1.8)  |  7 (1.4)  |  6 (1.2)
Performance (20%)      |  6 (1.2)  |  9 (1.8)  |  7 (1.4)
Operational cost (15%) |  7 (1.05) |  4 (0.6)  |  8 (1.2)
Scalability (10%)      |  7 (0.7)  |  9 (0.9)  |  7 (0.7)
Learning curve (10%)   |  8 (0.8)  |  4 (0.4)  |  6 (0.6)
-----------------------+-----------+-----------+----------
Total                  |  7.55     |  6.35     |  6.85

The specific weights matter less than the exercise itself. It forces you to articulate what you value and why. If the scores are close (within 10%), the decision probably doesn't matter as much as you think — pick the one with better team expertise and move on.

Step 2: Build vs Buy

This is the single most impactful architecture decision most companies make — and they consistently get it wrong in both directions.

When to Buy (Use an Existing Service/Product)

When to Build

The Hidden Costs of "Buy"

Visible cost:    License/subscription fee
Hidden costs:    - Integration development (often 2-5x the estimated time)
                 - Vendor API changes and breaking updates
                 - Support response times when things break at 2 AM
                 - Data migration if you switch vendors
                 - Feature requests that never get prioritized
                 - Security vulnerabilities in code you don't control

The Hidden Costs of "Build"

Visible cost:    Development time
Hidden costs:    - Ongoing maintenance (plan for 20% of build time annually)
                 - Security patches and vulnerability management
                 - Documentation and knowledge transfer
                 - On-call responsibility for the team
                 - Opportunity cost — what else could the team build?

Step 3: Monolith vs Microservices

The most over-debated architectural decision in the industry. Here is the honest truth.

Start With a Monolith. Seriously.

Unless you have:

... you should build a monolith. A well-structured monolith with clean module boundaries can be split later. Premature microservices cannot be easily merged back.

The Real Cost of Microservices

What you gain:                    What you pay:
- Independent deployments          - Distributed system complexity
- Technology diversity              - Network latency between services
- Isolated failure domains          - Distributed tracing and debugging
- Independent scaling               - Service discovery and load balancing
                                    - Data consistency challenges
                                    - Integration testing complexity
                                    - Operational overhead (10-50 services
                                      = 10-50 things that can fail)

The Modular Monolith: The Middle Ground

Structure your monolith with clear module boundaries, well-defined interfaces between modules, and separate database schemas per module. This gives you:

# Modular monolith structure example
src/
  modules/
    users/
      api/          # Public interface for other modules
      internal/     # Private implementation
      tests/
    orders/
      api/
      internal/
      tests/
    shipping/
      api/
      internal/
      tests/
  shared/           # Truly shared utilities only
  main.py           # Composition root

When to Actually Use Microservices

If you match 3+ of these criteria, microservices may be justified:

Step 4: Database Selection

The database is the hardest technology to change later. Choose carefully.

Decision Tree

Is your data relational? (entities with relationships)
  ├── YES → Do you need ACID transactions?
  │     ├── YES → PostgreSQL (default choice for 90% of projects)
  │     └── NO  → PostgreSQL anyway (it handles non-ACID workloads fine)
  └── NO  → What kind of data?
        ├── Documents (JSON-like, schema varies) → MongoDB or PostgreSQL JSONB
        ├── Key-value (simple lookups, caching) → Redis
        ├── Time series (metrics, IoT data) → TimescaleDB or InfluxDB
        ├── Graph (complex relationships, traversals) → Neo4j
        ├── Search (full-text, faceted) → Elasticsearch or Meilisearch
        └── Wide column (massive scale, simple queries) → Cassandra/ScyllaDB

The PostgreSQL Default

If you are unsure, choose PostgreSQL. It handles:

Adding a specialized database is a Type 2 decision — you can do it later when you have proven you need it. Starting with a specialized database is a Type 1 decision that constrains your entire architecture.

Multi-Database Strategy

It is fine to use multiple databases — but each one must justify its existence:

PostgreSQL  — Primary data store (source of truth)
Redis       — Caching layer, session storage, rate limiting
Elasticsearch — Full-text search (if PostgreSQL tsvector is insufficient)

Do NOT add a database because:
- "MongoDB is better for documents" (PostgreSQL JSONB is usually sufficient)
- "Redis is faster" (than what? For what query pattern? Measured how?)
- "We might need it later" (YAGNI — You Aren't Gonna Need It)

Step 5: Architecture Decision Records (ADRs)

Every significant architecture decision should be documented. Not in a wiki that nobody reads — in the code repository, next to the code it affects.

ADR Template

# ADR-001: Use PostgreSQL as primary database

## Status
Accepted (2026-03-15)

## Context
We need a primary data store for the order management system.
Our data is relational (users, orders, products with foreign keys).
We need ACID transactions for payment processing.
Team has 3 developers with PostgreSQL experience, 0 with MongoDB.

## Decision
We will use PostgreSQL 16 as our primary database.

## Alternatives Considered
1. MongoDB — Good for document storage, but our data is relational.
   Would require manual transaction management for payments.
2. MySQL — Viable, but PostgreSQL has better JSON support,
   which we'll need for flexible product attributes.
3. CockroachDB — Distributed PostgreSQL-compatible, but we don't
   need multi-region yet, and it adds operational complexity.

## Consequences
- We get ACID transactions out of the box
- We can use JSONB for flexible schemas where needed
- We need to manage connection pooling (PgBouncer)
- We accept single-region deployment for now
- If we need multi-region later, we can migrate to CockroachDB
  (PostgreSQL-compatible wire protocol)

## Review Date
2026-09-15 (6 months)

Where to Store ADRs

project-root/
  docs/
    adr/
      0001-use-postgresql.md
      0002-modular-monolith.md
      0003-use-stripe-for-payments.md
      template.md

When to Write an ADR

Troubleshooting & Considerations

"We already made the wrong choice"

First, quantify the cost of living with it vs the cost of switching. Most of the time, the switching cost is higher than people estimate and the benefit is lower. If you do decide to switch, do it incrementally: strangler fig pattern for services, dual-write for databases, feature flags for frameworks.

"The team wants to use [new shiny technology]"

Ask: "What problem does this solve that our current stack doesn't?" If the answer is "it's more modern" or "it's what everyone is using," push back. Resume-driven development is one of the most expensive patterns in our industry. New technology is fine when it solves a real problem — but it must be evaluated against the framework, not adopted on enthusiasm.

"Stakeholders want a technology-specific solution"

Non-technical stakeholders sometimes request specific technologies ("build it in blockchain," "use AI for this"). Translate back to the problem: "What outcome are you looking for?" Often the problem is better solved with proven, simpler technology.

"We don't have time for proper evaluation"

A Type 1 decision made in 2 hours will cost you 200 hours to fix later. Block the calendar. Do the evaluation. The 2 days you spend now save 2 months later.

Prevention & Best Practices

The Technology Radar

Maintain a team technology radar with four rings: Adopt (use in production), Trial (use in non-critical projects), Assess (evaluate in spikes), Hold (do not use). Review quarterly. This prevents both reckless adoption and stagnation.

Proof of Concept Before Commitment

For any Type 1 decision, build a time-boxed proof of concept (1-2 weeks max). Focus on the riskiest aspect — not the happy path. If you're evaluating a database, test failure scenarios, backup/restore, and migration tooling, not just basic CRUD.

Architecture Reviews

Schedule quarterly architecture reviews. Look at ADRs, review their consequences section, and check: did reality match our prediction? Update or supersede ADRs that turned out wrong. This builds institutional knowledge about decision-making quality.

The "Boring Technology" Rule

Dan McKinley's "Choose Boring Technology" essay should be required reading. You get a limited number of "innovation tokens" — use them on your core product, not on your database, deployment pipeline, or monitoring stack.

Escape Hatches

When making a Type 1 decision, always design an escape hatch. Use an ORM so you can switch databases. Use a message queue abstraction so you can swap implementations. Use infrastructure-as-code so you can move cloud providers. The escape hatch may cost 10% more upfront but saves 10x if you need it.

Need Expert Help?

Want an expert opinion on your architecture? €250.

Book Now — €250

100% money-back guarantee

HR

Harald Roessler

Infrastructure Engineer with 20+ years experience. Founder of DSNCON GmbH.