And that is before discussing CI/CD, infrastructure as code, tracing, secrets management, autoscaling, disaster recovery, and security.
Modern infrastructure has undoubtedly become more powerful. But an important question is often overlooked:
Does your application actually need all of this complexity?
The answer, surprisingly often, is no.
The goal of good system design is not to use the largest number of technologies. It is to build the simplest architecture that reliably satisfies the system's current and reasonably foreseeable requirements.
This architecture is not outdated simply because it is simple.
For many SaaS platforms, internal business applications, content platforms, marketplaces, APIs, dashboards, and early-stage products, an architecture like this can remain effective for a long time.
Modern architectures became more complicated because the problems being solved became more complicated.
The mistake is assuming that because companies operating at enormous scale use a particular architecture, every application should start there.
1. The Entry Layer Became an Architecture of Its Own
Traffic once went almost directly to an application server.
Modern traffic may travel through several layers:
text
User
│
▼
DNS
│
▼
CDN
│
▼
WAF
│
▼
Load Balancer
│
▼
API Gateway
│
▼
Application
Each layer can solve a legitimate problem.
A CDN reduces latency and origin traffic.
A WAF can filter malicious requests.
A load balancer distributes requests between application instances.
An API gateway can provide authentication, routing, throttling, transformation, and API management.
Rate limiting protects systems against abuse.
But every additional layer introduces another configuration, dependency, monitoring requirement, and potential failure point.
Therefore, the correct question isn't:
"Should we use an API gateway?"
It is:
"What problem would an API gateway solve for this system?"
That distinction is fundamental to good architecture.
2. The Monolith Became a Network
A traditional monolithic application may contain authentication, billing, orders, notifications, reporting, and administration inside one deployable application.
A microservices architecture might instead look like:
text
API Gateway
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
User Order Billing
Service Service Service
│ │ │
└───────┬───┴────┬──────┘
│ │
Kafka Redis
│
┌───────┼────────┐
▼ ▼ ▼
Email Analytics Notification
Service Service Service
This provides significant advantages when used appropriately.
Services can scale independently.
Teams can deploy independently.
Failures can potentially be isolated.
Different workloads can use different technologies.
But something fundamental has changed.
Function Calls Became Network Calls
Inside a monolith:
text
order = get_order(order_id)
might simply call another function.
In distributed architecture, the equivalent operation could involve:
text
Order Service
│
│ HTTP/gRPC
▼
Inventory Service
│
│ Kafka
▼
Payment Service
Now the architect must think about:
network failures
timeouts
retries
duplicate messages
idempotency
authentication between services
distributed tracing
service discovery
circuit breakers
partial failures
version compatibility
The business operation did not necessarily become more complicated.
The infrastructure required to perform it did.
3. One Database Became Many Databases
A traditional application frequently relied on a relational database such as PostgreSQL or MySQL.
Modern distributed systems may use several specialized storage technologies.
For example:
Requirement
Possible Technology
Transactional data
PostgreSQL / MySQL
Cache
Redis
Document data
MongoDB
Search
Elasticsearch / OpenSearch
Large-scale distributed data
Cassandra
Files and media
Object Storage
Analytics
Data Warehouse
This approach is sometimes called polyglot persistence.
It can be extremely effective.
Redis is excellent at caching.
Elasticsearch/OpenSearch is designed for search.
Object storage is ideal for large files.
Relational databases are excellent for transactions.
But specialized databases introduce another major problem:
What happens when PostgreSQL updates successfully but Elasticsearch does not?
What happens when a Kafka consumer processes an event twice?
What happens when Redis contains stale information?
Distributed storage often trades simplicity for scalability and specialized performance.
That trade-off should be intentional.
4. Communication Became Its Own Infrastructure
Modern systems communicate using technologies such as:
REST
gRPC
GraphQL
Kafka
RabbitMQ
WebSockets
event streams
message queues
Synchronous communication is relatively straightforward.
text
Service A ───── Request ─────> Service B
<──── Response ─────
Asynchronous communication introduces a different model.
text
Order Service
│
▼
Kafka
│
┌────┼───────────┐
▼ ▼ ▼
Email Inventory Analytics
The Order Service no longer needs to wait for every downstream process.
This can dramatically improve scalability and resilience.
But it creates new questions.
Did the message arrive?
Was it processed?
Was it processed twice?
What happens if the consumer is offline?
How do we replay events?
How do we maintain ordering?
How do we trace a user's request across asynchronous consumers?
Event-driven systems can be powerful, but messaging infrastructure should exist because asynchronous processing solves a real requirement—not because Kafka happens to appear on modern architecture diagrams.
5. Operations Became Part of System Design
One of the biggest changes in modern software engineering is that application architecture and infrastructure architecture are increasingly inseparable.
The important part is keeping application boundaries clean enough that components can be separated later if necessary.
When Should You Introduce Microservices?
Microservices should solve organizational or technical constraints.
They become more attractive when:
Independent scaling is required. One workload needs 50 instances while another needs two.
Independent deployment becomes important. Teams need to release services without coordinating application-wide deployments.
Clear domain boundaries exist. Business capabilities can be separated naturally.
Different reliability requirements exist. Payment processing may require different guarantees from analytics.
Teams have grown. Multiple engineering teams need ownership over different domains.
The monolith has become an organizational bottleneck.
Microservices should therefore be considered a solution to specific problems rather than the default starting point.
When Should You Introduce Kafka?
Kafka is excellent when you need high-throughput event streaming, durable event logs, asynchronous workflows, multiple consumers, event replay, or loosely coupled event-driven services.
That is very different from starting with Kafka simply because "modern systems use Kafka."
When Should You Introduce Kubernetes?
Kubernetes is extremely powerful.
It can provide orchestration, self-healing, service discovery, rolling deployments, autoscaling, workload scheduling, configuration management, and a standardized deployment platform.
But a small application might work perfectly well with:
Goal: separate workloads that genuinely need independent behavior.
Stage 4 — Large Distributed Platform
Eventually there may be legitimate reasons for:
Kubernetes
microservices
Kafka
multiple databases
service mesh
distributed tracing
advanced autoscaling
multi-region deployments
At this point the complexity has been earned by scale and requirements.
Learn Problems, Not Product Names
One of the most valuable skills in system design is understanding architectural categories rather than memorizing technology logos.
Instead of learning:
"Every scalable architecture needs Redis."
Learn:
"What caching problem am I trying to solve?"
Instead of:
"Large systems use Kafka."
Ask:
"Do I need asynchronous communication, durable events, replay, or multiple independent consumers?"
Instead of:
"Kubernetes is industry standard."
Ask:
"Do I currently have a container orchestration problem?"
Technology changes rapidly.
Architectural problems change much more slowly.
Understanding the problem makes choosing the technology considerably easier.
The 3 AM Architecture Test
There is a practical way to evaluate architecture decisions.
Imagine the component fails at 3:00 AM.
Who will diagnose it?
Who understands it?
What metrics exist?
Where are its logs?
What dependencies does it have?
Can the system continue operating without it?
Can it be restored quickly?
If your team cannot confidently answer those questions, introducing the component deserves additional consideration.
Because every box added to an architecture diagram eventually becomes somebody's operational responsibility.
A Practical Decision Framework
Before introducing a new infrastructure component, ask:
Question
Why It Matters
What exact problem does it solve?
Prevents technology-driven architecture
Can the existing stack solve the problem?
Avoids unnecessary components
What happens if it fails?
Reveals reliability impact
Who will operate it?
Determines ownership
How will we monitor it?
Ensures observability
What security exposure does it add?
Controls attack surface
Can we remove it later?
Reduces architectural lock-in
Does our current scale justify it?
Prevents premature scaling
If the team cannot clearly explain why a component exists, it probably should not be added yet.
Simple Does Not Mean Unsophisticated
There is sometimes a misconception that a simple architecture indicates inexperienced engineering.
In reality, designing a simple system that remains reliable and scalable can require more engineering judgment than assembling dozens of fashionable technologies.
Experienced architects frequently optimize for:
fewer moving parts,
clear ownership,
predictable failure modes,
easy debugging,
low operational overhead,
and incremental scalability.
The goal is not to create an impressive architecture diagram.
The goal is to create a system that works.
Final Thoughts
Modern software engineering gives us extraordinary tools.
Kubernetes can orchestrate thousands of containers.
Kafka can process enormous event streams.
Redis can deliver extremely fast access to data.
Distributed databases can operate across massive datasets.
Service meshes can manage complex service-to-service communication.
Observability platforms can trace requests across distributed environments.
These technologies are valuable precisely because they solve difficult problems.
But that does not mean every system has those problems.
A good architecture might initially be nothing more than: