Comparison · Craft vs structure

Clean Code vs Clean Architecture: Same Author, Different Altitude

Clean Code governs what happens inside a function; Clean Architecture governs which way dependencies point between modules. What each one actually rules on, why neither rescues the other, and which to reach for given a specific symptom.

By Michał Jaskólski Updated 8 min read
  1. 01 Clean Code clean-code Writing readable, maintainable code
  2. 02 Clean Architecture clean-architecture Building maintainable, testable software architectures
  3. 03 Software Design software-design-philosophy Reducing complexity through thoughtful software design
  4. 04 Refactoring refactoring-patterns Improving code design through systematic refactoring
  5. 05 Legacy Code working-with-legacy-code Safely change untested code: seams and characterization tests

Two books, one author, half a shared title. That is most of the reason people install one expecting the other, then wonder why their agent is renaming variables when they asked where the repository interface belongs.

The distinction is altitude. Clean Code (2008) operates inside a file: naming, function size, how errors are signalled, whether the next reader can follow a method without decoding it. Clean Architecture (2017) operates between modules: which component may know about which, where the framework sits, whether a business rule can run without a database. One is craft, the other structure, and the failure modes they prevent are unrelated.

We publish both as free agent skills and see them installed together constantly, so to be clear: this is not a which-is-better piece. If the format is new to you, start with what an AI agent skill is.

What does Clean Code actually govern?

The unit is whatever you can hold in your head at once: a name, a function, a class, a file. The rules are correspondingly local — intention-revealing names, functions that do one thing at one level of abstraction, exceptions rather than return codes, a comment treated as a small failure to express intent in the code itself.

It reaches a rung higher in places — the chapter on classes argues for cohesion and the Single Responsibility Principle, the chapter on boundaries for wrapping third-party APIs so their shape does not spread. But the frame never changes: a person reading this file, trying to understand it. The yardstick is comprehension per line.

It is therefore the highest-frequency skill in a coding-agent stack: it applies to every diff, and its output is a rename or an extraction — nothing that commits you to a project shape.

What does Clean Architecture actually govern?

The unit is the component, and there is essentially one rule.

The Dependency Rule: source code dependencies may point only inward, toward higher-level policy. An inner circle must not name anything declared in an outer one — not a class, not a function, not a variable, and especially not a data format the outer layer defines. Entities sit innermost, use cases wrap them, interface adapters wrap those, frameworks and drivers sit at the edge.

The half people drop is what happens when control flows outward at runtime, which it constantly does — a use case genuinely needs to save a record. Dependency Inversion resolves that without an exception to the rule: the use case declares the interface it needs, an outer layer implements it, and the source dependency still points inward while the call goes out. That move is what turns “the database is a detail” from a slogan into a claim about code.

Around it sits the rest: SOLID at class level, component cohesion and coupling principles, boundaries only at points of real volatility, and a rule about what a crossing may carry — plain data, never a framework type or an ORM entity. Note what it says nothing about: your names or your function length.

Clean Code vs Clean Architecture: the altitude table

Clean CodeClean Architecture
Unit of concernName, function, class, fileComponent, layer, boundary
The core ruleExpress intent so the next reader needs no explanationSource code dependencies point only inward
What it decidesHow something is writtenWhere it lives and what it may know about
Reviewed byReading a diffReading an import graph
Failure symptom”I can’t tell what this does without reading all of it""One requirement change touched nine files”
Cost of getting it wrongSlow comprehension, bugs from misread codeRewrites, untestable core, framework lock-in
Cost to fix laterLow — local, mechanical, reversibleHigh — moves code across module lines
Blast radius of a violationThe fileEverything downstream of the boundary

The “reviewed by” row is why these are separate jobs: a Clean Code violation is caught by anyone reading the diff, while a Dependency Rule violation shows up only in an import graph — which is why it survives review and compounds.

Clean Code is about the sentences. Clean Architecture is about the floor plan. A beautifully written sentence in the wrong room is still in the wrong room.

Why does clean code inside a bad boundary still rot?

Because readability is local and coupling is global, and only one of them determines what a change costs.

Take a pricing rule living in an HTTP controller: perfect names, six-line functions, textbook error handling. Now a nightly batch job and an admin tool need the same rule. There is nothing to reuse — it is entangled with a request object — so it gets copied twice and the three copies drift. No naming discipline prevents that, because the problem was never in the prose. It was in an import.

That is change amplification, a property of where code sits rather than how it reads, and good craft hides it: the code stays pleasant while the cost per change climbs, so the diagnosis arrives late — usually as “we can’t test anything without spinning up the whole stack.”

Prompt

Use the clean-architecture skill to find the Dependency Rule violations in this codebase — business rules importing a framework type, an ORM entity or an HTTP request object — and for each one show the interface the inner layer should declare and which outer module should implement it

Clean Architecture

Is a clean architecture full of unreadable functions any better?

No, and in one way it is worse. Layering multiplies the files you read per change: one feature now runs through a controller, a request model, a use case, a repository interface, an implementation and a mapper. That trade only pays if each stop is quick to understand. When every layer is a 200-line method with tmp, flag2 and four nested conditionals, you have bought the navigation cost of structure without the comprehension it was meant to fund.

The Dependency Rule also offers no protection against a use case that quietly does five unrelated things — it is satisfied by where code sits. Whether the thing sitting there is coherent is Clean Code’s question, and Refactoring is how you fix it with the tests green.

Which one should I reach for? Match the symptom

Stop at the first line that matches what you are actually seeing.

  1. A function is impossible to follow without reading all of it. Clean Code — local problem, local fix.
  2. You cannot run a business rule in a test without a web server and a database. Clean Architecture: your dependencies point the wrong way.
  3. Swapping the ORM, the queue or the payment provider would touch files everywhere. Clean Architecture. There is no boundary where you assumed one.
  4. The code reads well and a one-line change still touches nine files. Clean Architecture. Craft is not your bottleneck.
  5. The structure is wrong and the fix must stay reviewable. Refactoring — named transformations, small steps, tests green in between.
  6. There are no tests and you daren’t touch it. Legacy Code first; the others assume you can tell when you broke something.

One caveat, plainly: four concentric circles, an interface per gateway and a DTO at every crossing can cost more than they save on a CRUD app with one datastore. What survives at any size is the direction rule plus a real boundary at your points of genuine volatility. The folder count is negotiable.

Do they contradict each other anywhere?

Barely — and where they seem to, it is usually Clean Code against a third position rather than against Clean Architecture.

The live disagreement is function length. Martin’s stance — functions should be small, then smaller — is the most contested claim in either book. John Ousterhout argues the opposite in A Philosophy of Software Design: splitting a function purely to shorten it can produce shallow modules, push complexity into the interfaces between the fragments, and leave the reader chasing behaviour across more places than before.

Install Clean Code and Software Design together and they will disagree about one long, cohesive function — usefully, because you get the argument instead of a silent rule. Clean Code is an opinionated style to push back on, not a linter. Clean Architecture sits out that fight entirely.

Prompt

Use the clean-code skill to review this module for readability only — intention-revealing names, functions at one level of abstraction, error handling that does not obscure the happy path — and leave the module boundaries and dependency direction untouched

Clean Code

Frequently asked questions

Are Clean Code and Clean Architecture by the same author?

Yes — Robert C. Martin wrote both, Clean Code in 2008 and Clean Architecture in 2017. The shared branding is why they get confused, but they were written nine years apart about different levels of a system, and reading one tells you little about the other’s content.

Which one should I install first?

Clean Code, usually, because it applies to every diff your agent produces. Add Clean Architecture when a structural symptom appears — an untestable core, a framework you cannot upgrade — or at the start of a new system, where the direction rule is nearly free and retrofitting it is not cheap.

Will the two skills conflict if I install both?

No — they rule on different decisions, so an agent applying both checks naming and function shape while also checking which module may import which. The conflict people report is Clean Code against Software Design over function length. If your team has settled on other conventions, say so in the prompt.

Does Clean Architecture include SOLID?

Yes — as the class-level principles feeding the component-level ones, with Dependency Inversion doing the heavy lifting for the Dependency Rule itself. Clean Code touches the Single Responsibility Principle in its chapter on classes but does not work through the rest.

Can code be clean without being well architected?

Routinely — it is the most common state of a healthy-looking codebase in trouble. Every file reads well and the pricing logic still lives in a controller, so it cannot be tested without HTTP and gets copied the first time a second caller needs it. Readability makes bad structure survivable, which is precisely what hides it.

Where to go next

If the real question is where a boundary belongs rather than which way it points, that is Domain-Driven Design vs Clean Architecture. To apply all of it from a blank page, see how to design the best possible architecture for a new app.

Both skills are free and MIT-licensed, alongside the rest of the Code Quality and Architecture & Systems collections:

npx skills add wondelai/skills --all --global
Work with us

We build the skills you already use. Now we’ll build yours.

Custom skills · Subagents · MCP integrations — shipped to production, not demoed.

Sprints from $3K · shipped to production, or you don’t pay the final milestone.