Architecture & Frameworks
Build the simplest thing first, and use a framework everyone knows
System architecture is ridiculously difficult to boil down into a short chapter, but there are a few principles that are simple enough to state and important enough to remember.
Build the simplest possible thing
Always start with the simplest thing you can think of. There are two reasons for this.
First: it’s going to be way more complicated than you imagine. Whatever you think you’re building, the real version will have edge cases, dependencies, and requirements that you haven’t thought of yet. If you start with something complicated, it will become unmanageably complicated.
Second: think about constraints. Imagine you’re a startup with six months of runway. You design this beautiful application, hire the right people, and plan out a six-month build. You’ve already failed — because the thing is going to take three times as long as you think. You’ll hit the six-month mark barely started, and you’ll be out of money.
If you’ve got six months, build something that you think will take about a week. It’ll actually take about three weeks. At the end of those three weeks, you’ll have something you can ship to users and test. It’ll be horrible and broken, but it does something slightly useful and people can react to it. That’s where you want to be.
Don’t build for scale
It’s very tempting to say “this is going to need a hundred thousand users, so let’s build something that scales to a hundred thousand users.” Don’t.
You don’t know how many users you’ll have. And you don’t know how they’ll use it. Maybe you designed your app to post text and images, and you made it handle 10,000 text posts per second, but only one image per second — and then it turns out everyone uses it as a meme factory. You have no idea what your application is going to turn into once real users get their hands on it.
If you’re expecting 10,000 users, start with something that works for 100. Give it to 100 users and see what happens. If it works and everybody loves it, hire more people, throw the first version away, and build it again — now that you actually understand what you’re building.
Frameworks are about people, not technology
People argue about frameworks constantly, especially in JavaScript. But the key thing to remember is that the advantage of a framework is not a technical advantage — it’s a human one.
Ruby on Rails is the granddaddy of frameworks. Before Rails existed, onboarding a new developer was a three-month process. You’d bring someone in and spend weeks showing them where the database queries go, how the HTML works, the random place someone decided to keep the CSS — and some of it was also database queries. It took forever.
Rails changed that to zero. You walked in the door, were told “it’s a Rails app,” and you knew how to get started immediately. That one change massively reduced the cost of building web applications. The explosion of startup innovation that followed was a direct result of Rails making it possible to onboard developers in minutes instead of months.
The advantage wasn’t technical. The advantage was that a human could walk into your office and start contributing on day one. That’s true of all frameworks. It doesn’t matter which framework you use, as long as you don’t invent your own. If you’ve invented your own framework, you’ve thrown away the entire advantage, because now you have to explain to every new person how it works. Pick a framework that other people know and go with it.
Modularity is a scaling tactic
A complex web application might have a hundred thousand lines of code. No single human can hold that much code in their head. A developer can maybe keep about a thousand lines in their head at one time — having a thorough understanding of it, knowing what will break if they change something.
If you break your hundred thousand lines into a hundred modules of a thousand lines each, suddenly this impossible task becomes manageable. Each developer understands one thing. All they need to know beyond their own module is the contract — the API — between their module and everyone else’s.
As long as their tests pass and the contract is fulfilled, they can change their module’s internals freely without breaking anything for anyone else. They can add features, refactor, improve performance — all without risk.
This is how companies scale. Without modularity, your codebase will hit a barrier beyond which your team can no longer change anything without breaking everything.