
The Clean Architecture (2012) - Flenser
https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html
======
develf
Prudent to remember that Robert Martin is a consultant and it's lucrative to
sell enterprises a story where their domain logic is a billion dollar asset
and following his very particular design pattern will enable them to
seamlessly evolve this asset with new technology.

Here's where the story breaks:

\- Most app's domain objects and rules are small. You could describe them on a
few sheets of notebook paper. The technology implementation (e.g. database or
http logic) is a much larger portion of the codebase.

\- In most teams, especially startups, the domain rapidly evolves. The
technology stacks (databases, SQL, etc) are quite stable and have already been
heavily abstracted for reuse over the years. Using these proven technologies
and excellent existing interfaces is how you go fast.

\- Technology choice isn't just about code interface. Each comes with its own
assumptions of system behavior and theory of operation. Plugging a different
implementation into your storage adapter interface is the least piece of work
you need to think about unless it's nearly a 1:1 swap like postgres -> mysql.

So following a strict clean architecture approach will probably pour concrete
around something changing all the time and create friction and extra work in
using excellent available technologies.

Instead I'd rather follow pragmatic design guidelines:

\- The concept of each component should be clear

\- Sensible responsibilities for each component

\- Abstractions should serve the composability of your existing design;
introduce adapter layers if you truly have more than one implementation

\- Keep it simple; optimize for reading the code end-to-end and easier
refactoring

These aren't inconsistent with Clean Architecture but probably more productive
than adding religious rules.

~~~
dfox
The design pattern in question is not that much special in the global sense.
It is special in the J2EE/.NET/Enterprise world because it should allow you to
automatically generate most of the UI in same way what eg. Flask-Admin does
while also taking all the bussiness rules into account. One of the things I'd
like to do is implement subset of Apache Isis (which is implementation of
essentially this pattern for J2EE) in Python on top of Flask.

~~~
develf
Automatically generating a UI from a domain may please a programmer but isn't
likely to please a user. That's how you get UIs like the one Salesforce has.

That could be the right choice in some situations -- it certainly worked out
well for Salesforce and allowing extensibility in their model. However if you
want to build an app with consumer usability you'll be putting a lot of unique
development effort into your view layer.

~~~
dfox
Reasonable UX for consumer facing application is something completely
different from what you want for the back office. And these architectures
target applications where the back office part is majority of the UI.

------
codemac
Has anyone ever done this in practice before without it mattering:

> _4\. Independent of Database. You can swap out Oracle or SQL Server, for
> Mongo, BigTable, CouchDB, or something else. Your business rules are not
> bound to the database._

MongoDB vs Oracle.. Ok architecture astronaut, you're gonna have a real bad
time when you swap those out for each other.

~~~
specialist
Your business is the database. Models matter.

Anyone who wants "database neutrality" (least useful common denominator), vs
leveraging the awesomeness of pgsql, mssql, oracle, should just use flat
files. Or mysql.

~~~
UK-AL
You can leverage whatever database feature you want, just a long as you do it
in the database adapter/gateway.

I write mine in raw sql normally.

~~~
specialist
Versus in situ (eg stored procedures)?

I currently agree.

There was a time when the database engine was the "app server". Before
client/server & ODBC.

I miss those days. That strategy is overdue for a comeback.

~~~
UK-AL
My raw sql can call out to stored procedure if that's the best tool for the
job.

A database is a perfectly good application core, if you application primary
about creating/updating/deleting records.

If your application is business workflows, and complicated business logic.
Then this is something to be considered.

~~~
pmart123
Good to see I'm not crazy! I think this can be easier than maintain, and with
tools like Datagrip now, seems to make a lot of sense. Coming from the data
science side, I observed many talented people spending time on projects like
[https://github.com/cloudera/ibis](https://github.com/cloudera/ibis) to
abstract SQL into something that I often thought was more verbose, less
literal and less portible in reality.

------
specialist
Turgid.

Most applications copy a string from here and paste it over there. Input,
processing, output. What we used to call data processing.

Add some defensive programming for sanity. Validation rules, "schemas", type
systems.

Favor composition over inheritance, a useful programming language over
"dynamic typing" (aka type hostile).

Extra credit for logging, monitoring, auditing, alerts, rolling deployments.

Life time victory achievement bonus award for setting breakpoints (debuggable)
and easy reproduction steps.

\---

Instafail if you use mappings (eg ORM), observer/listener, factories,
singletons.

~~~
computerex
> Instafail if you use mappings (eg ORM), observer/listener, factories,
> singletons.

Wait, why?

~~~
0x445442
What I've seen many times with ORM tools is blind interaction with the in-
memory object graph abstraction over the data store which results in many un-
needed queries. It's like the option of making one DB query which returns a
flat result set isn't even on the radar.

As far as I can tell Factories have been replaced with DI frameworks or just
hand rolled DI.

Singletons aren't so bad if you're working with an object oriented language
and the singleton is just an instance of a service which holds no state and
has methods that operate on a limited number of data types. At that point it's
essentially just a namespace for a functional library.

Observer/Listeners ... Not sure here unless the commenter is advocating
message queues or eventing.

------
agentultra
One thing I would note is that it's not _always_ necessary to abstract away
your database layer. It is if you are developing software for installation
into an existing infrastructure at a customer's datacenter. It's not necessary
if you're building your own application on your own infrastructure.

In my experience I've never seen an enterprise company change databases over
night. Uber perhaps being the exception to the rule. If you're choosing the
target platform that your software runs on you should exploit that platform
for all it's worth to get the best benefit from it. Yet I've seen plenty of
software shops that insist on writing/running heaps of code to abstract away
the database server on some imagined future point where someone decides
they're going to run it on Mongo now instead of MySQL.

~~~
sullenpaladin
Abstracting the database has another benefit you are neglecting. It is easy to
mock the database and test your application use cases if the database layer is
abstracted. This is nearly impossible if database access is baked into the
app.

~~~
Rickasaurus
But do you really need to mock the database when you can just deploy a
containerized one for testing?

~~~
mac01021
We used a real database for testing. In the short term it was less work than
architecting the application in a way that allowed the DB to be mocked.

Long term, the result was a 45-minute test suite which spent most of its time
setting up records in the DB, and which could not be parallelized except by
adding more instances of the real DB (otherwise the tests would interfere with
one-another's assertions about the DB state).

~~~
Rickasaurus
but now with containers you can have a snapshot that's already set up in the
right state. A separate build.

~~~
theptip
This is a powerful technique, though I'd say it's more useful for the build
pipeline than for developers running UTs while coding (since the schema can
change more frequently while doing so).

To provide a counterpoint though, an advantage touted by advocates of complete
decoupling from the DB is that your UT suite can run in O(one minute), rather
than O(ten minutes). E.g. see
[https://www.youtube.com/watch?v=tg5RFeSfBM4](https://www.youtube.com/watch?v=tg5RFeSfBM4).

I'm not 100% sold on this approach yet (separating your domain objects
entirely from the ORM wrapper is an uphill struggle), but it's interesting.

~~~
Rickasaurus
We run our tests on databases and it's on the order of one minute. Maybe it's
a hardware issue? We all have beefy computers with fast SSDs.

Also since we strive to make our databases upgradable, it's important that the
actual schema update scripts themselves are tested and used directly.

------
draw_down
> The overriding rule that makes this architecture work is The Dependency
> Rule. This rule says that source code dependencies can only point inwards.
> Nothing in an inner circle can know anything at all about something in an
> outer circle.

You can get pretty far just worrying about this part.

I tend not to find these acronym names and the diagrams very helpful in terms
of actually creating code. Separating concerns, as we all already know, is
crucial, as is being careful about where knowledge is located. But I've found
that if you buy in to these architecture patterns, you quickly become confused
about which part of the pattern a given class or module or area of
responsibility falls under. Like, is my `BazFrobber` a Gateway, or a
Presenter, or a Controller... ?

------
RubenSandwich
This is a very similar idea to Gary Bernhardt's: Functional Core, Functional
Core, Imperative Shell:
[https://www.destroyallsoftware.com/screencasts/catalog/funct...](https://www.destroyallsoftware.com/screencasts/catalog/functional-
core-imperative-shell).

I prefer Gary's explanation of it because he jumps right into the meat of the
problem and shows code that models this architecture. The video doesn't
require you to know Ruby to understand what he is saying, just as long as you
know some basic testing phrases; Mocking, Stubbing, Etc, you should be able to
follow along.

~~~
theptip
I like Bernhardt's rendition of this concept too. His talk "Boundaries" is my
favourite summary:

[https://www.destroyallsoftware.com/talks/boundaries](https://www.destroyallsoftware.com/talks/boundaries)

Note that the Functional Core architecture makes an additional restriction on
top of the Clean/Hexagonal architecture, namely that the core should be
functional; the OP doesn't make such prescriptions on how you implement the
Entities and business logic (though it doesn't discourage you from doing so
either of course).

~~~
RubenSandwich
You are right that the above article doesn't specifically mention the core
being functional. I merely interpreted that from one of the stated properties
of his and the other architectures he showcases:

"2\. Testable. The business rules can be tested without the UI, Database, Web
Server, or any other external element."

If that doesn't scream functional, then I don't know what does. :)

------
luckystarr
The thing to follow is that you shouldn't build a tower of babel abstraction
stack but a limited number of clearly defined abstractions. It's ok if you go
deeper than 4 in some cases but these things should then already be pretty low
level.

Too deep a stack will lead to code "scavenger hunts" when you want to figure
out what something does.

------
adamnemecek
These things are always nice in theory but I would really appreciate a small
sample app following the architecture.

~~~
BoorishBears
Android devs "(re)discovered" clean architecture around 1-2 years ago so there
are plenty of sample apps there you can understand with very little android
experience.

~~~
yupyup
And as always happen it ends misapplied to mobile apps that only paint on
screen the JSON received from the server.

Not everything is black or white (no architecture vs clean architecture). You
have to think about what you are doing (having fucked up on previous projects
help) and don't follow anything you've read blindly.

Silver bullets, yadda yadda

~~~
UK-AL
Clean architecture in this case is just the name of the architecture. There
are many others.

~~~
the_arun
Agreed. Also, there is no such thing as clean architecture. Every architecture
has holes and limitations

------
simplify
The article doesn't mention it, but this architecture is good for functional
programming as well. If you model those three inner circles as pure functions
operating on input and returning results + effects, your app becomes easy to
test and easily maintained by a good type system.

------
programminggeek
[http://retromocha.com/obvious/](http://retromocha.com/obvious/) is an
implementation of these ideas.

------
klipt
Thought this was an article about
[https://en.wikipedia.org/wiki/Clean_(programming_language)](https://en.wikipedia.org/wiki/Clean_\(programming_language\))

Disappointing.

------
edelans
The title should mention it's a 2012 article.

------
the_arun
Shouldn't DB be part of Entity - right in the middle? Why it is on the edge of
the circle outside gateway?

~~~
UK-AL
A lot of these architectures assumes DDD. (I'm not sure if clean architecture
does)

Domain driven design. You model you business problem using plain objects and
methods. The domain should do nothing else other than modeling the domain, and
solving the business problem you app is designed to solve. It should be
persistence ignorant.

Then everything else simply has adapters for interfacing with the domain.
Including a persistence adapter.

This is basically ports & adapters, and a lot of these architectures are
basically variations on that.

~~~
the_arun
Thanks. I think I see this reference in the article -
[http://jeffreypalermo.com/blog/the-onion-architecture-
part-1...](http://jeffreypalermo.com/blog/the-onion-architecture-part-1/)
which explains why DB should be outside. It makes sense in the services and
NoSQL world, but i would not put at the edge. Feels like we are doing
something wrong & insecure. It could be my mindset issue :)

~~~
UK-AL
I don't why it would be insecure...

~~~
the_arun
I mean from block diagram perspective, we are always used to keep data in the
center secured by all other layers. But that pattern is changing in the days
of AWS & Google Cloud, where data can be anywhere. If data is a service, it
doesn't matter where it is located. But if Data is a layer within the
application, we need to surround it by protective layers such as app, gateway
etc.,

~~~
UK-AL
Well those layers are really protecting the domain.

------
hasenj
This kind of thinking bothers me, but I'm not sure how to put my finger on
what exactly it is that bothers me, or how to put it into words.

The thing with these abstract architecture principles is they are not always
practical if you try to be puristic about enforcing them.

I get where these ideals come from. I've seen novice programmers take a stab
at writing mildly complicated apps, and the code is a nightmare to read
because everything is jumbled up together. This is bad and we can all agree on
that.

But I've also seen projects where everything is split into a tiny little
function or object that don't seem to be doing anything meaningful. Presumably
these projects are following the principles of "single responsibility" and
"loose coupling", but it's so loose that it's hard to put the pieces together
in your mind and nearly impossible to follow the flow of the program.

I consider generic rules of the form: "<X> related objects should not be doing
<Y> related stuff" to be harmful. (An example of such "bad rules" can be found
in the article under the heading "Use Cases")

Instead I prefer practical rules that make the code easy to read, understand,
and updated, without making it any more complicated that it needs to be.

* If a piece of logic can be contained in a function, let it be contained in one function without splitting it across 10 different objects and factories and coordinators. Even if that function is slightly long, there's no need to split it apart just because it's over the arbitrary threshold of say, 25 lines.

* Create abstractions around a set of vocabulary that you can use to describe the problem domain and the process of doing things within the application. Make sure to document your vocabulary well and try to keep it as small as possible (but not smaller)

A good example of this is git's vocabulary for commits, trees, and blobs.

Every operation doesn't need to be a class (or worse, a series of classes and
factories). Operations can be functions that operate on the structure's
(objects) you've defined.

* Keep related files and functions together.

If you have a server side module implementing an json API, and an html page
designed to display the API, and a javascript module designed to drive the UI
on the html file, and a sql file describing the data you're displaying, then
let's put all those files together in the same directory, instead of spreading
them thin across separate folders

    
    
        app/controllers/api/X/X.py
        app/templates/X/X.html
        app/js/views/X/X.js
        app/css/X/X.css
    

Why not put them all under:

    
    
        app/X/X.py
        app/X/X.html
        app/X/X.js
        app/X/X.css
    

Related material:

Object-Oriented Programming is Garbage: 3800 SLOC example

[https://www.youtube.com/watch?v=V6VP-2aIcSc](https://www.youtube.com/watch?v=V6VP-2aIcSc)

~~~
thatswrong0
I think you're conflating clean architecture with a bunch of other things. All
it is is a set of rules about how different layers of your app can depend on
one another. It doesn't say too much, if anything, about code organization or
design patterns like SRP or loose coupling or whatever.

I say this because we follow it pretty religiously at my work and it never
feels impractical nor does it really feel like it adds too much extra work to
anything we do, nor does it feel like related code is far apart nor are our
functions too small.

In practice, following the clean architecture means, for example, that my
business logic can't explicitly depend on some database related code. If we
have business logic that needs do stuff in the database, it defines an
interface of some methods that it expect the database repository to implement
that it can use. It then has an implementation that satisfies that interface
passed to it using dependency inversion (as pointed out in the article).

So it really means that if some business logic related to, say, tweets needs
to retrieve some from the database, it calls something like
"tweetRepository.findAllTweets()", which returns a bunch of "Tweet" domain
objects. It never sees database rows, it knows nothing about which database we
use, etc. Our business logic is focused _solely_ on dealing with the use case,
and nothing to do with the nitty gritty of how we interact with the database
or how we eventually return that data to a user that needs it.

Which is great, because it means if we ever change how our database layer
works, we only need to change our database repository code. We don't need to
worry about changing business code if we can satisfy the same interface as
before.

