When developers start designing a new system, one of the first questions is often:

“Which technology should we use?”

Should we use microservices or a monolith?

SQL or NoSQL?

REST or messaging?

Kubernetes or App Service?

Synchronous APIs or event-driven architecture?

Azure Service Bus or Event Hubs?

These are useful questions, but they are not the first questions an architect should ask.

The more important question is: What does the system actually need to achieve?

Architecture is not about selecting the most popular technology or creating the most sophisticated architecture. It is about making decisions that satisfy the business requirements while understanding the consequences of those decisions.

In other words:

Good architecture is the art of making the right trade-offs under real-world constraints.

Start With the Problem, Not the Technology

Imagine a business is building an e-commerce platform. The initial requirements sound simple:

  • Customers can browse products.
  • Customers can place orders.
  • Customers can make payments.
  • Inventory must be updated.
  • Customers receive notifications.

A technology-first discussion might immediately become:

“Let’s build microservices with Kubernetes, Kafka, Redis and several databases.”

But we still don’t know the most important things.

How many customers?

How many orders per second?

How much traffic occurs during peak periods?

Does the business operate in one country or globally?

How much downtime is acceptable?

Does inventory need to be strongly consistent?

Can an order take several seconds to complete?

What happens if the payment provider is unavailable?

What happens if the database becomes temporarily unavailable?

What is the expected recovery time?

How much operational complexity can the engineering team manage?

These questions change the architecture. The architecture should therefore begin with requirements and constraints, not technology.

Architecture Starts With Non-Functional Requirements

Functional requirements tell us what the system does. Non-functional requirements tell us how the system needs to behave.

For example:

RequirementExample
Availability99.99%
Response time< 300 ms for common APIs
Throughput20,000 requests/sec
Data durabilityNo loss of confirmed orders
RecoveryRTO < 30 minutes
Data lossRPO < 5 minutes
SecurityStrong identity and authorization
ScalabilityHorizontal scaling
GeographyMulti-region
CostControlled infrastructure spending

These requirements are much more useful to an architect than simply saying:

“We need microservices.”

Why? Because architecture patterns are solutions. Requirements are the problems.

One Requirement Can Change the Entire Architecture

Consider two applications.

Application A

A small internal HR application used by 300 employees.

Traffic:10 requests/sec

Availability requirement: 99.5% Single region.

Small development team. Moderate business impact if the application is unavailable for a few hours.

Application B

A global payment platform.

Traffic: 100,000+ requests/sec

Availability requirement: 99.99%+

Multiple regions. Strict security requirements.

Financial transactions.Very low tolerance for data loss.

These two systems should not have the same architecture. For Application A, a modular monolith with a relational database might be completely appropriate.

For Application B, we may need:

  • multiple regions
  • independent scaling
  • partitioned workloads
  • asynchronous processing
  • strong observability
  • resilient dependencies
  • carefully designed data ownership
  • automated failover
  • disaster recovery
  • progressive deployment
  • extensive security controls

The difference is not that one architecture is modern and the other is old. The difference is the problem being solved.

The Five Questions I Ask Before Choosing a Technology

Before selecting a major architectural component, I like to ask five questions.

1. What problem are we solving?

If we cannot clearly describe the problem, we probably shouldn’t introduce another technology yet.

For example:

Why do we need a message broker?

Possible answer:

Because payment processing does not need to block the customer’s request, and we need durable asynchronous processing.

That is a meaningful architectural reason. Compare that with:

“Because event-driven architecture is modern.”

That’s not an architectural requirement.

2. What happens if we don’t introduce it?

This is one of the most useful questions in architecture. Suppose someone proposes Redis.

Ask:

What problem exists without Redis?

Maybe the database cannot handle the read volume. Now the conversation becomes measurable. We can evaluate:

  • database load
  • query latency
  • cache hit rate
  • memory requirements
  • data freshness
  • invalidation complexity

Instead of simply saying:

“Redis will make it faster.”

We can ask whether caching actually solves the bottleneck.

3. What Complexity Does It Introduce?

Every technology has a cost beyond its license or infrastructure bill. Consider introducing a distributed message broker.

We gain:

  • asynchronous processing
  • decoupling
  • buffering
  • independent scaling
  • resilience

But we also introduce:

  • message delivery semantics
  • retries
  • duplicate messages
  • dead-letter handling
  • observability
  • schema evolution
  • consumer failures
  • operational complexity

This is the part of architecture discussions that is often overlooked. We don’t just ask:

“What do we gain?”

We also ask:

“What new problems are we creating?”

4. What Happens When It Fails?

A technology decision is incomplete until we understand its failure behavior.

Suppose we introduce:

Order API
    ↓
Payment Service
    ↓
Payment Provider

What happens if the payment provider takes 30 seconds to respond?

What happens if it returns a timeout?

What happens if the payment succeeded but our application never received the response?

What happens if we retry and accidentally charge the customer twice?

Now the architecture needs concepts such as:

  • timeout
  • retry
  • idempotency
  • circuit breaker
  • state management
  • reconciliation
  • audit trail

The technology itself didn’t solve these problems. The architecture has to.

5. Can We Operate It?

This question is especially important for cloud-native and distributed systems. A system may look beautiful on an architecture diagram:

        API Gateway
             |
    +--------+--------+
    |        |        |
 Service  Service  Service
    |        |        |
   DB       Cache    Queue
             |
        Event Stream
             |
      Multiple Consumers

But who operates it?

Who monitors it?

Who responds to incidents?

Who manages upgrades?

Who understands distributed tracing?

Who handles failed messages?

Who manages schema evolution?

Who performs disaster recovery testing?

Who understands the networking?

Who owns the platform?

Architecture must consider the people and operational model, not only the components.

The Architecture Trade-off Triangle

Most important architecture decisions involve competing goals. For example:

                 Reliability
                    /\
                   /  \
                  /    \
                 /      \
                /        \
               /          \
              /____________\
        Cost              Complexity

But real systems usually involve more dimensions:

                 Availability
                     /\
                    /  \
                   /    \
                  /      \
       Consistency       Scalability
              \            /
               \          /
                \        /
                 \      /
                   \  /
                    \/
                 Cost

And we shouldn’t forget:

  • security
  • latency
  • maintainability
  • operational complexity
  • developer productivity
  • time to market

Improving one dimension can affect another. For example:

Stronger consistency

May increase:

  • coordination
  • latency
  • coupling

More availability

May require:

  • replication
  • eventual consistency
  • conflict resolution

More scalability

May require:

  • partitioning
  • asynchronous processing
  • distributed state

More resilience

May require:

  • redundancy
  • additional infrastructure
  • operational complexity

Lower cost

May require:

  • reduced redundancy
  • lower performance
  • shared infrastructure

This is why architecture rarely has a single perfect answer.

Example: Synchronous vs Asynchronous Processing

Let’s take an order processing system.

Option 1 — Synchronous

Customer
   |
   v
Order API
   |
   v
Payment
   |
   v
Inventory
   |
   v
Notification
   |
   v
Response

This is simple. But the request now depends on every downstream component.

If notification is slow, the order request may become slow.

If inventory is unavailable, the entire request may fail.

If payment takes 3 seconds, the user waits.

Option 2 — Asynchronous

Customer
   |
   v
Order API
   |
   v
Order Database
   |
   v
OrderCreated Event
   |
   +--------> Payment
   |
   +--------> Inventory
   |
   +--------> Notification

Now we have better decoupling.

We can independently scale consumers.

We can absorb traffic spikes.

But we introduce new complexity.

The system may become eventually consistent.

Messages may be delivered more than once.

Consumers can fail independently.

We need:

  • idempotency
  • retries
  • dead-letter queues
  • event versioning
  • monitoring
  • correlation IDs

So which architecture is correct?

Neither universally. The answer depends on the business requirements.

Architecture Decision Matrix

One practical way to make architectural decisions is to create a decision matrix.

For example:

RequirementSynchronousAsynchronous
Immediate responseHighLow
Simple implementationHighMedium
Burst handlingLowHigh
Independent scalingLowHigh
Failure isolationLowHigh
Operational complexityLowHigher
Eventual consistencyLowHigher
Long-running processingLowHigh

The purpose isn’t to calculate a magical score. The purpose is to make the trade-offs visible.

Technology Selection Should Come After Architecture

Once we understand the problem, technology selection becomes much easier. For example, suppose our requirement is:

Process a very large number of independent events with multiple consumers and allow consumers to process events independently.

Now we can evaluate technologies that support those requirements. In Azure, depending on the workload, we might consider:

  • Azure Event Hubs
  • Azure Service Bus
  • Azure Event Grid

But the architecture question comes first:

Do we need event streaming, enterprise messaging, or event notification?

The technology follows the requirement.

The Same Principle Applies to .NET

Suppose we’re designing a new .NET application. We could choose:

ASP.NET Core
EF Core
SQL Server
Redis
Azure Service Bus
Azure App Service
Azure Monitor

But listing technologies doesn’t make the architecture. The architecture is the relationship between them.

For example:

                 Users
                   |
                   v
            Azure Front Door
                   |
                   v
             ASP.NET Core
                   |
          +--------+--------+
          |                 |
          v                 v
       Redis             SQL Server
          |
          |
          v
     Azure Service Bus
          |
     +----+----+
     |         |
     v         v
 Worker A   Worker B

Now we can discuss:

  • where scaling happens
  • where state lives
  • where failures are isolated
  • where asynchronous processing begins
  • where consistency changes
  • where observability is required
  • how deployment happens
  • how recovery works

That’s architecture.

A Principal Architect Thinks in Consequences

One of the biggest differences between implementation-level thinking and architecture-level thinking is the time horizon. A developer may ask:

“Can we implement this?”

A senior engineer may ask:

“Will this perform?”

An architect asks:

“What consequences will this decision create six months from now?”

And a Principal Architect goes further:

“How will this decision affect the business, engineering teams, operations, security, cost and future evolution of the platform?”

That doesn’t mean every decision needs a 50-page architecture document. It means important decisions should be intentional.

Architecture Decision Records Help

For significant decisions, an Architecture Decision Record can be simple:

Title:
Use asynchronous processing for order fulfillment

Context:
Order fulfillment can take several seconds and involves
multiple downstream systems.

Options:
1. Fully synchronous
2. Asynchronous messaging
3. Workflow orchestration

Decision:
Use asynchronous messaging for fulfillment.

Why:
- Better failure isolation
- Independent scaling
- Burst absorption
- Reduced API latency

Trade-offs:
- Eventual consistency
- Additional operational complexity
- Idempotency required

Consequences:
Consumers must support retries and duplicate messages.

This is much more valuable than a diagram with dozens of boxes and no explanation.

A Simple Architecture Decision Framework

Before making an important architecture decision, ask:

Business

What business problem are we solving?

Scale

What workload are we expecting?

Reliability

What happens when something fails?

Consistency

What must be immediately consistent?

Security

What are the trust boundaries?

Performance

What latency and throughput are required?

Operations

How will we monitor and operate it?

Cost

What will this architecture cost at expected scale?

Evolution

How difficult will it be to change later?

People

Does the team have the skills and operational capacity to own it?

If we cannot answer these questions, we’re probably not ready to make the technology decision.

The Most Dangerous Architecture Is Often the One We Don’t Understand

Complexity itself isn’t necessarily bad. A mission-critical banking platform may legitimately require:

  • multiple regions
  • distributed data
  • event streaming
  • asynchronous processing
  • redundancy
  • strong security
  • extensive observability

But every additional component should have a reason. The goal isn’t:

“Build the simplest architecture possible.”

The goal is:

“Build the simplest architecture that satisfies the real requirements.”

Those are very different statements.

Final Thoughts

Architecture isn’t about drawing boxes.

It isn’t about using microservices.

It isn’t about choosing the newest cloud service.

It isn’t about using the most sophisticated technology stack.

Architecture is about making decisions under constraints.

Sometimes the right decision is a modular monolith.

Sometimes it is microservices.

Sometimes it is synchronous communication.

Sometimes it is event-driven.

Sometimes a relational database is exactly what you need.

Sometimes you need partitioning and distributed data.

Sometimes adding another technology solves a problem.

Sometimes removing a technology makes the architecture better.

The important part is understanding why. For me, one of the simplest definitions of good architecture is:

Good architecture makes the important trade-offs explicit.

When the trade-offs are understood, technology becomes a tool rather than the decision itself. And that is where architecture thinking begins.

Architecture Checklist

Before making your next major architecture decision, ask:

  • What problem are we solving?
  • What are the measurable requirements?
  • What are the alternatives?
  • What do we gain?
  • What complexity do we introduce?
  • How does the design fail?
  • How does it scale?
  • How do we secure it?
  • How do we observe it?
  • How do we deploy and roll it back?
  • How much does it cost?
  • How difficult will it be to change later?

Don’t start with the technology. Start with the problem.

#SoftwareArchitecture #SystemDesign #PrincipalArchitect #DistributedSystems #CloudArchitecture #Azure #DotNet #EnterpriseArchitecture #EngineeringLeadership