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
- A clear understanding of the problem you are solving (see our requirements engineering guide)
- Knowledge of your constraints: team size, budget, timeline, compliance requirements
- Stakeholder alignment on business priorities (speed to market vs long-term scalability)
- Willingness to choose "boring" technology when it is the right answer
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)
- It is not your core differentiator. Authentication, payment processing, email delivery, monitoring — these are solved problems. Unless you are building an auth company, do not build auth.
- The time-to-value gap is significant. If buying saves 3+ months and the annual cost is less than one developer-month of salary, buy.
- Compliance is involved. PCI DSS for payments, SOC 2 for data handling — vendors have already passed these audits. You haven't.
- Maintenance is non-trivial. A database, a message queue, a search engine — the build cost is 10% of the lifetime maintenance cost.
When to Build
- It IS your core differentiator. The thing that makes your product unique should be under your full control.
- Vendor lock-in is unacceptable. If switching costs would threaten the business, build or use open-source alternatives.
- The existing solutions don't fit. If you'd spend more time working around limitations than building from scratch, build.
- Data sovereignty requires it. Some data cannot leave your infrastructure. Period.
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:
- 20+ developers who can't work on the same codebase without constant conflicts
- Components with fundamentally different scaling requirements (CPU-bound vs I/O-bound)
- A dedicated platform/DevOps team to manage the infrastructure
- Clear, stable domain boundaries that won't change for at least a year
... 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:
- Simple deployment and operations (one artifact)
- Clean architecture that can be split later
- No distributed system problems
- Easy local development and testing
# 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:
- Your team has 30+ developers
- You deploy more than 10 times per day
- Different components have 10x+ different load patterns
- You have a dedicated platform team (3+ people)
- Your domain boundaries are stable and well-understood
- You've already outgrown a well-structured monolith
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:
- Relational data (it's a relational database)
- JSON/document data (JSONB columns with indexing)
- Full-text search (built-in tsvector)
- Geospatial data (PostGIS extension)
- Time series (with TimescaleDB extension)
- Key-value patterns (HSTORE or JSONB)
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
- Choosing a database, framework, or language
- Deciding on architecture style (monolith, microservices)
- Selecting a third-party service (payment, auth, hosting)
- Making a significant deviation from convention
- Deciding NOT to do something (these are often the most valuable ADRs)
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 — €250100% money-back guarantee