Skip to main content
Research
Opinion6 min read

Most Software Architecture Decisions Are Cargo Cult Engineering

Netflix uses microservices therefore we should use microservices. Airbnb uses React therefore we should use React. Stripe uses Go therefore we should use Go. This is not architectural reasoning. It is pattern imitation without context.

AuthorAbhishek Sharma· Founder, Fordel Studios

The architecture decision record says: "We are adopting a microservices architecture because this is the industry standard for scalable software at our stage." The company has 15,000 users. They have two backend engineers. The industry standard they are citing was developed by companies with millions of users and hundreds of engineers to solve problems that emerge from that scale. The company does not have those problems. They have adopted the solution before the problem.

Two years later, they have a distributed system with all the complexity of microservices and none of the scale that would justify it. Debugging spans three services. Deployment requires coordinating multiple repositories. The two engineers are spending 40% of their time on infrastructure instead of product. They have cargo culted their way into a maintenance burden that will outlast their startup.

···

What Cargo Cult Architecture Looks Like

The defining characteristic of cargo cult architecture is that the pattern is adopted because of where it came from, not because of the problem it solves. "Google uses it" is not an architectural reason. "Uber open-sourced it" is not an architectural reason. "All the senior engineers on the team are familiar with it" is a legitimate reason, if the problem it solves matches your problem.

The cargo cult pattern appears at every level of the stack. Domain-driven design adopted by a team that has not identified any genuine bounded contexts. Event sourcing implemented in an application where the audit log requirement was the only driver and a simple audit table would have served. Functional programming patterns applied to a domain where the complexity was organisational, not computational. The patterns are legitimate. The problems are not the ones the patterns were designed for.

Architecture should be the simplest thing that solves the problem you actually have, not the most sophisticated thing that solves the problem you want to have.

The Conference Problem

Architecture decisions in many organisations are heavily influenced by conference talks and blog posts from engineers at companies with fundamentally different constraints. A Netflix architecture post describes how Netflix solved Netflix's problems. Netflix has specific problems: global CDN requirements, extreme scale, hundreds of engineering teams working on the same platform simultaneously. These problems required specific solutions. Reading that post and applying those solutions to a startup with different problems produces a system optimised for Netflix's constraints and poorly suited for yours.

The engineers who write these posts are describing how they solved their problem. They are not prescribing solutions for your problem. The readers who adopt the solutions without mapping the constraints are doing the cargo cult: they saw the plane land, they built the control tower, they are waiting for cargo that will not come because the signal was never for them.

What Good Architectural Reasoning Looks Like

Good architectural reasoning starts with the problem, not the solution. What is slow, unstable, hard to change, or causing errors? What would have to be true about the system for that to stop being true? Which architectural patterns address those specific characteristics at this specific scale? The answer is usually something boring — a well-designed monolith, a clear module boundary, a simple database schema with appropriate indexes. Boring is good. Boring is correct.

The engineers who build the most maintainable systems are almost always the ones who resisted the interesting architecture until the system's actual problems demanded it. The interesting architecture arrived as a solution to a real problem, not as a vision adopted in advance of the problem. When it arrived, it was adopted precisely and minimally — the part that solved the problem, not the full pattern.

Loading comments...