Q1: does vibe code == pain maintain?
Q2: How much could/should AI change this "standard model"?

This subject: work in groups; write quality code; maintain alien code; use SE + AI; establish on-line profile. (For more on above pic, see Fig3 of Long et.al, TSE'23.)
Layered Architecture
Event-Driven Architecture
Microkernel
Microservices
Space-Based Architecture
Client-Server
Manager-Agent
Pipe-Filter
LAMP
MEAN
Serverless
Micro-Frontends
Hybrid Rendering
Encapsulation
Information Hiding
Service Mesh
Architectural patterns describe recurring structures in software systems. Each pattern solves a class of problems while introducing trade-offs. This lecture walks through eight classic patterns and modern evolutions. I’ll not just describe them, but also highlight war stories and lessons from decades of practice.
Layered architecture is the bread and butter of enterprise systems. It separates code into tiers: presentation, business logic, data access, and database. Each layer hides its internals behind a stable interface. This reduces ripple effects when one part changes.
Case Study:
The LAMP stack (Linux, Apache, MySQL, PHP) was dominant in the
2000s. Every layer was replaceable. PHP could be swapped with Python,
MySQL with PostgreSQL. I recall projects where we changed database
engines midstream — painful, but possible because the data layer was
well-isolated.
Lessons Learned:
Layering adds clarity but can ossify. Too many layers slow delivery.
At one Fortune 500, I saw a layered insurance app with 13 tiers.
Changing a customer address required edits in 7 of them. This taught
me that abstraction is not free — it can paralyze.
Event-driven systems decouple producers from consumers. Producers publish events; consumers react. The pattern thrives where latency matters.
Examples:
- Stock trading: systems like Nasdaq stream trades as events.
- IoT health monitors: wearables send alerts when thresholds exceed.
- Uber dispatch: rider requests broadcast to drivers nearby.
Pitfalls:
Debugging is hard. Once, we traced a bug in a logistics system for
weeks. The problem was an event handler firing twice under rare load.
Logs showed nothing — events had no global ordering. This scarred me
enough to insist on correlation IDs in every event stream.
Takeaway:
Events scale, but testing and reasoning demand discipline. Without
good observability, event-driven systems rot.
A microkernel is a minimal core with plug-in services. Think of it as a small stage where actors enter and leave.
Examples:
- Mach kernel: small OS core, drivers as modules.
- Eclipse IDE: core editor with endless plug-ins.
- VS Code: modern descendent of the same idea.
Voice of Experience:
I once built a GIS tool with a microkernel. It started lean. But
within two years, plug-ins multiplied, each slightly different in API
style. Integrating them was chaos. Microkernels can become plugin
jungles if governance is weak.
Microservices extend modularity to deployment. Each service is small, independently deployable, with its own database.
Case Study: Netflix
Netflix migrated from a monolith to hundreds of microservices. Video
encoding, personalization, billing — all separate. This enabled
independent scaling. On a Friday night, recommendation services
saturate while billing idles.
But:
Microservices shift complexity. Networks fail. APIs drift. At a bank
I consulted, the move to microservices ballooned latency. A single
loan application triggered 47 service calls. Debugging required
spanning 10 teams.
Lesson:
Microservices are not a free lunch. They demand DevOps maturity:
monitoring, CI/CD, service meshes. Without that, they collapse under
their own weight.
Here computation happens across a distributed "tuple space," a shared memory visible to all nodes.
Use Case:
Retailers use it to handle Black Friday spikes. A cart update
writes to a space replicated across nodes. No single database choke.
Pitfalls:
State divergence is brutal. Two replicas disagree — who wins? I saw
an e-commerce cart where items vanished if two nodes wrote at once.
Customers screamed. We fixed it with CRDTs, but performance fell.
Lesson:
Space-based shines in extreme scale, but testing and debugging are
expensive. If you don't need it, avoid it.
Client-server is simple: centralized server, many clients. Early email (POP3, IMAP) and file sharing worked this way.
Client–server describes a distributed system where:
- A client program runs on the user’s machine (browser, mobile app, desktop app, IoT device, etc.).
- A server program runs on another machine, usually more powerful, managing data and shared services.
They talk over a network protocol (HTTP for web apps, but also gRPC, WebSocket, MQTT, raw TCP/UDP, etc.).
The server usually:
- Holds the shared state (databases, files, computation engines).
- Provides APIs or endpoints.
- Serves multiple clients at once, enforcing security, concurrency, and consistency.
Manager-agent extends it. A manager delegates to many agents. Example: SNMP for network monitoring — routers as agents, manager polls them.
Data flows through filters, each transforming it. Compilers are the canonical example: lexical analysis → parsing → optimization → generation.
Unix Pipes:
Ken Thompson added | in 1973. Doug McIlroy dreamed it earlier:
"We should have some ways of coupling programs like garden hose."
Every engineer should try chaining grep | sort | uniq. It shows how
small tools scale better than one bloated app.
Example:
- ad hoc reporting
cat access.log | grep "ERROR" | cut -d' ' -f2 | sort | uniq -c - compilers:
Lexical analysis | Parsing | Semantic analysis | Optimization | Code generation - video processing:
resize | blur | sharpen | colorCorrect | compress - text mining:
downcase | tokenise | stemming | stopWords | tfIdf | sort | infoGain | cluster | classify
Experience:
I’ve seen students reinvent compilers as one giant class. Then they
realize debugging lexing vs parsing is impossible. Breaking into
filters clarifies bugs and allows reuse.
- but pipe and filter is one way street
- poor choice for interactive GUIs where users can perform operations in any order at all.
Then:
- LAMP: Linux, Apache, MySQL, PHP.
- MEAN: MongoDB, Express, Angular, Node.
Both layered, easy to teach, widely deployed.
Now (2025):
- Jamstack: pre-rendered static sites + APIs.
- Serverless: AWS Lambda, billed per request.
- Micro-Frontends: UI split into modules (Spotify).
- Edge logic: Cloudflare Workers near the user.
- Hybrid rendering: Next.js mixes SSR, CSR, ISR.
Patterns offer reusable wisdom. But each carries hidden costs. As engineers, our job is to ask: does the gain justify the pain? In my career, I’ve seen every pattern both shine and backfire. Knowing when not to apply a pattern is as valuable as knowing how it works.
- What risks arise when layering becomes too deep?
- How do correlation IDs help in event-driven debugging?
- Compare plugin sprawl in microkernels vs service sprawl in microservices.
- Why does space-based architecture struggle with state divergence?
- When should managers distrust agents? Give an example.
- Why is Pipe-Filter still relevant in 2025?
- Can you recall a system you used that embodied one of these patterns? How did it succeed or fail?