Skip to content

01 · Why Architectural Thinking Comes First

Writing code is disappearing right before our eyes; deciding what to write, and what the system should look like, is what's getting more valuable. This chapter makes the case: why, starting today, you must put judgment ahead of implementation.


Something happening right now

For the past twenty years, a programmer's value rested largely on "can you write code correctly and fast." Whoever remembered more APIs, hit more pitfalls, typed faster — was worth more.

But one thing is rewriting that equation completely: writing code itself is disappearing.

AI already fluently completes functions, generates boilerplate, translates languages, fixes syntax, writes tests. The things you used to "memorize" or "learn by getting burned" — how to call some library, a particular regex, a concurrency trap — now come on demand. The market price of a concrete implementation is dropping at a visible pace.

This isn't bad news. It's your chance to be freed from the role of "typist." But there's a condition — you have to figure out one thing:

When "how to write it" becomes cheap, "what to write, and why" becomes the truly scarce thing.

That is the core of this chapter, and of the whole tutorial: architectural thinking — the ability to think the system through before you start.


Implementation ability vs architectural judgment: they're not the same thing

Many people treat "can code" and "can build systems" as different fluency levels of the same skill — as if writing enough, for long enough, naturally makes you good at architecture. This is a misconception. They are two different abilities answering two different questions.

┌─────────────────────────┬─────────────────────────────────────┐
│   Implementation         │          Architectural judgment      │
├─────────────────────────┼─────────────────────────────────────┤
│ Answers: how do I build  │ Answers: what should this system     │
│ this feature?            │   look like? where will it break     │
│                          │   first? what am I trading away?     │
├─────────────────────────┼─────────────────────────────────────┤
│ Cares about: syntax,     │ Cares about: boundaries, data flow,  │
│ libraries, perf tricks   │   trade-offs, failure modes          │
├─────────────────────────┼─────────────────────────────────────┤
│ Wrong? Fix a function    │ Wrong? Maybe rewrite the whole system│
├─────────────────────────┼─────────────────────────────────────┤
│ Fast feedback: run it    │ Slow feedback: surfaces months later │
├─────────────────────────┼─────────────────────────────────────┤
│ AI does more and more    │ AI can only advise; you still decide │
└─────────────────────────┴─────────────────────────────────────┘

An analogy. Implementation is like "knowing how to lay bricks": how to stack them, spread the mortar, level the surface. It's a craft, perfected by practice — and now machines can lay them fast and straight for you. Architectural judgment is like "designing the building": where the load-bearing walls go, how deep the foundation is, how many elevator shafts, whether the structure will hold when you add three floors later. Get those wrong, and no amount of bricklaying skill can save you.

Ever seen a beautifully built house on a crooked foundation? That's code with "strong implementation, zero architectural judgment": every function elegant, but the system ends up eventually-consistent where it needed strong consistency, tightly coupled where it needed to be decoupled, and it falls over the moment traffic climbs. Pretty bricks can't save a crooked foundation.

The key difference between these two abilities is in the last two rows: feedback speed and cost of correction. Get implementation wrong and you run it, see the error, and know within minutes. Get architecture wrong and you often won't find out until you're months into production, users have grown tenfold, and you're woken at 2 a.m. by an alert — only then do you realize "that decision back then planted a landmine." And by then, fixing it may mean starting over.

In one line: implementation mistakes, the code tells you; architecture mistakes, only time tells you. That's why architectural judgment is so hard to train and so valuable — its feedback is so slow that most people never get to learn it from their own mistakes.


So what is "architecture"?

The thing newcomers most easily misunderstand: thinking "architecture = drawing a few boxes and connecting some lines." Open a so-called architecture doc and you find a pile of rectangles and arrows that look impressive — but ask the author "why this and not that? what happens with another approach?" and they can't answer. That diagram is just decoration.

Here's a sharper definition of "architecture":

Architecture is the set of "important decisions" in a system. And "important" means decisions that satisfy all three at once: hard to change, system-wide in impact, and tied to quality attributes.

Take them one at a time and you'll see why none can be dropped.

Trait 1: Hard to change

The hallmark of an architecture decision is that it's expensive to change.

Rename a variable from a to count? Three seconds, anyone can do it. Not architecture. Split a whole system from a monolith into microservices? Or change the database from one instance to sharded? That takes months, involves everyone, and you migrate data with your heart in your throat. That's architecture.

A handy test: if you can easily reverse a decision next iteration, it's probably not architecture; if reversing it is so costly you'd "rather just live with it," then it definitely is. Architecture is precisely those decisions that, once set, everyone afterward has to work around.

Trait 2: System-wide impact

The other hallmark of an architecture decision is that its impact spreads to many corners of the system, rather than staying inside one module.

"What color is this button" affects only that button. But "do the internal parts communicate via synchronous calls or asynchronous messages" affects how every feature is written, how every failure propagates, and the whole system's latency and complexity. The former is local; the latter is global. Architecture is the set of "pull one hair and the whole body moves" choices.

Trait 3: Tied to quality attributes

This is the one newcomers most easily overlook, and the most crucial.

Architecture decisions almost never solve "can this feature be built" (that's implementation) — they solve "how well does the system do": is it fast, stable, can it scale, can it be changed, is it cheap, is it secure. These "how well" dimensions have a name: quality attributes (a.k.a. non-functional requirements).

For example: "let users send messages" is a feature, implementable a thousand ways. But "keep messages delivered within a second even when users explode to a hundred million, and lose nothing when a data center dies" — that's working on quality attributes (scalability, availability, reliability), and that is architecture's real battlefield.

Connecting the three: architecture = the key decisions that, once set, are hard to change, affect the whole system, and determine whether the system is "good." Drawing boxes and lines is merely the form that expresses these decisions; the decisions themselves, and the "why" behind them, are the soul of architecture.


A short story: two teams, one requirement

Definitions are dry. Let's look at a contrast — one that plays out in the real world almost every day.

The requirement: build a "team task collaboration" tool — create tasks, assign, comment, notify. Two teams take on the same job.

Team A: "ship first, think later"

Team A believes in action above all. The moment the requirement lands, they start coding that day. Create tables, write endpoints, wire up the UI — a working version in a week. The boss is thrilled: "Now that's execution!"

They made a pile of decisions, but nobody realized they were decisions:

  • Tasks, comments, notifications — all crammed into one big table ("simpler this way for now").
  • Notifications rely on "check for new messages when the user refreshes the page" ("good enough").
  • All logic in one service, everyone editing the same blob of code ("convenient").

For the first two months, all is well. Until users start to grow:

  • That "throw everything in" big table starts to slow down — listing tasks drags in piles of unrelated data, and indexes can't save it because reads and writes are fundamentally mixed together.
  • "Only see notifications on refresh" gets roasted by users as "message delays." They want real-time push, but discover the system never left room for "push" and needs a painful rebuild.
  • That blob of code now has three people editing the same file, conflicts daily, fixing feature A breaks feature B, and nobody dares touch it.

So Team A enters the "firefight while refactoring" loop. The "thinking time" they saved up front is now repaid with three to five times the interest.

Team B: "read the map before hitting the road"

Team B, given the requirement, did not start coding immediately. They spent two days asking questions first:

  • Roughly how many people will use this? A few hundred now, but the company is expanding — could be hundreds of thousands within a year. OK, so "can it scale" has to be considered from the start.
  • Which operations dominate? "View task list" and "receive notifications" — reads — vastly outnumber "create task" — writes. So reads and writes have different shapes; maybe they shouldn't be crammed into one table and one path.
  • How real-time must notifications be? Users are sensitive to "someone @-ed me" — a few minutes' delay earns complaints. So "real-time push" isn't a later concern; it's a slot to reserve in the architecture now.
  • What happens on failure? Losing task data is a disaster (needs strong consistency, reliability), but "a notification occasionally a few seconds late" is tolerable (can be eventually consistent). These two kinds of data have fundamentally different requirements.

Having asked these, they made a few deliberate architecture decisions: separate "core strongly-consistent data" like tasks from "delay-tolerant data" like notifications; reserve a dedicated channel for "real-time push"; split the parts likely to evolve independently so they don't fight later.

The cost: Team B shipped nothing usable in the first week, and the boss briefly thought them "slow."

A few months later

  • Team A: a pile of features, but the system teeters on the edge of collapse; most of the team's energy goes to firefighting and filling holes; new features get harder and harder to add.
  • Team B: slower to start, but the few fatal pits, they sidestepped from the beginning. When users grew, the system transitioned smoothly; when real-time push was needed, the slot was already there. Their pace now is actually faster than Team A's — because they're not defusing bombs while running.

The moral is not "Team B is smarter," nor "more thinking is always better." Team B really was slower in week one — a real cost. The moral is: some pits you can sidestep with two days of thinking before coding; fall in, and it may take two months to climb out. Architectural thinking doesn't guarantee you go faster, but it guarantees you're not sprinting full speed toward a cliff.

Note this isn't "think for three months before acting" — that's the other extreme (over-engineering, covered later). It's about a ratio: investing a little thought up front on the few hardest-to-change, most fatal decisions pays off enormously.


A programmer's growth path: from "can write" to "can judge"

If you draw a developer's growth, it roughly traces this road:

  can write         writes well        can build systems     can judge
 (makes it run) ──▶ (elegant, robust)──▶ (clean splits,    ──▶ (knows why,
                                          smooth seams)         counts the cost)
   │                  │                    │                    │
 "I can make it      "I can make it       "I can put it        "I know what this
  run"                run beautifully"     together"            choice bought me,
                                                                and gave up"
   ▲                                                            ▲
   └──── AI is rapidly catching up to, even passing, this ──┘  └─ this part,
                                                                  only you

The leftmost stretch — "can I make it run" — is exactly what AI is best at and what's depreciating fastest.

The rightmost stretch — "I know what this choice bought me, and what it gave up" — is what AI can't give you. Because making that judgment requires understanding your business, your constraints, your team, your risk appetite. AI can list options and weigh pros and cons, but the act of deciding, and owning that decision, can only be you.

The good news: on this road, the further right, the more durable the skill, and the harder to replace. Every bit of "judgment" you practice today is a deposit into an account that won't depreciate.

So how to start practicing? From today, for every technical choice you make, force yourself to answer two questions:

1. Why this one? (What reason do I have for picking this over the alternative? A real reason, or just "everyone uses it" / "I'm familiar with it"?)

2. What does it cost? (By choosing it, what did I give up? Where will I pay for it later?)

Sounds simple, but you'll be surprised how few technical choices survive these two questions. "Why this database?" — "Uh, it was the default." "Why split into so many services?" — "Microservices are trendy." When your answer holds only "habit" and "following the crowd," with no "constraint" and "trade-off," that's the signal you haven't thought it through.

Practicing these two questions doesn't require you to be an architect first, nor a big project. Start with the small feature in front of you: why put it here? what if I did it another way? where is its cost hidden? Ask often enough, and "think it through before acting" turns from effort into instinct.


Chapter summary

  • Writing code is depreciating; architectural judgment is appreciating. AI makes "how to write" cheap, so "what to write, and why" becomes the truly scarce skill.
  • Implementation and architectural judgment are two different abilities. The former: fast feedback, easy to fix, AI helps. The latter: slow feedback, may require a rewrite, only you decide. Pretty bricks can't save a crooked foundation.
  • Architecture isn't boxes and lines — it's a set of "important decisions" satisfying "hard to change, system-wide impact, tied to quality attributes." Diagrams only express decisions; the "why" behind them is the soul.
  • Some pits you sidestep with two days of thinking before coding; fall in and it's two months to climb out. Architectural thinking doesn't guarantee speed, but keeps you from sprinting toward a cliff.
  • The growth path is from "can write" to "can judge," more durable the further right. The practice is one thing: for every technical choice, ask "why this one? what does it cost?"

We now know: architectural judgment is the most valuable skill of this era, and its core is "making important decisions amid trade-offs."

But here's the question — is there a method you can follow to make those judgments? Or is it all talent and years of hitting pitfalls?

There is. The next chapter gives you a general thinking framework.

👉 Continue: 02 · The architect's thinking framework (translation in progress)