
Better Software Design with Clean Architecture - lgclrd
https://fullstackmark.com/post/11/better-software-design-with-clean-architecture
======
barrkel
This design puts entities in the middle - everything else pivots around
entities. Additionally, it uses the OO approach of implementing logic as
methods on the entities.

After a couple of decades of experience, I've come to the conclusion that this
isn't right. Most business rules involve processes, which are inherently
procedural, or, from another perspective, functional - functions of the whole
state of the system to a new state of the system. Most processes don't
logically belong on an object, and when you stick them to one end, you create
lots of problems for yourself.

Just take that example Student entity class; what stops you from writing:

    
    
        student.RegisteredCourses.Add(course);
    

Moreover, when you have a relation between two entities, it's not uncommon for
the relation to be modelled at both ends; that is, a student has a list of
courses, and a course has a list of students. Do you implement the same
validation at both ends? Make one end (choose one) read-only? Do edits done on
one end automatically turn up on the other end? How do you protect the
visibility of methods that keep either end in sync, without exposing
invariant-violating APIs to other code?

Invariants and validations for fields are trivial with an OO approach; for
entities, they're reasonably easy, but sometimes you need partially invalid
versions while editing or constructing an entity; but once you bring in
multiple entities, and relations, everything starts getting hairy pretty
quickly. Assertions and validations that would be trivial to write [1] in a
relational language like SQL aren't possible in an object-oriented language
without a lot of system-building.

So I've come around to the idea that the database is a better thing to put at
the centre; that encapsulation and hiding of the main fact store is harmful to
the architecture of a system, especially in a heterogeneous environment where
your entities are represented in different languages, all backed by the same
fact store.

[1] Trivial to write, but not necessarily cheap to evaluate. I'm not
advocating writing all global validations in SQL.

~~~
UK-AL
This is solved by DDD and aggregates. Here's how i would do it.

    
    
       Course - Aggregate Root
    
       Student - Aggregate Root
    
           RegisteredCourses[RegisteredCourse[]) - Sub Entity Collection - with id reference to course. With metadata like date time when the registration occurred.
    
           RegisterForCouse Method
    

There should be no mutable public properties, internal methods should be
private. Everything should go through an aggregate root method.

~~~
mbrock
How did you decide that the registration is a property of the student and not
the course?

~~~
redy
Registration is definitely _not_ a property of the student.

It's always a good idea in these situations to appeal to real life. The actual
business will point the way of the business simulation. In the real world we
don't ask students to register for a course. Instead students ask the
_Registrar_ to register for a course. When the Registrar makes her decision
she considers far more than just the internal state of the Student; she
considers (1) does the course have any available seats? (2) has the Student
met all the course pre-requisites and, most importantly, (3) has the student
paid his tuition and is he even a valid member of the university community.

What the Student does have is a history and a context -- that is, a state --
that must be considered when registering for courses. The student may also
have preferences -- courses he wants to register for.

The language of the business should guide these decisions always. A student
submits a request tfor a course and it is the office of that accepts or denies
this request.

~~~
UK-AL
This guy has been thinking about this properly.

~~~
jstimpfle
Take this thinking to the end and realize that it leads to freestanding
functions. In general all the context of the program is needed to execute a
functionality. It's not like the registration office owns all the students.
It's not like a registration wouldn't change the student's context. Students
are both an independent and related concept. The proper object to call most
things on is a "Global" object. Now instead of

    
    
        Global.do_some_thing(foo, bar)
    

just

    
    
        do_some_thing(foo, bar)
    

There you have it. OO is an unsound approach which survived so long mainly due
to the perceived real world "analogy" and because the Object-Verb-Predicate
syntax simplifies code completion.

~~~
nlawalker
I like the simplicity of this. If the app is of appreciable size,
do_some_thing depends on databases, webservers, external processes,
filesystems and configuration. How do you test/debug/explore its functionality
without setting all of that up?

~~~
jstimpfle
I would actually say these all make good "objects", i.e. isolated pieces. On
the other hand, no runtime polymorphism is needed. To avoid OOP at a syntactic
level, what do you think of the following?

\- For tests at a smaller level, decompose the application such that most
parts are easily testable in isolation (without external "hard" dependencies).

\- For mid-sized tests with external dependencies but mostly unidirectional
dataflow, setup a global virtual table with all the mock methods (and
instances) that are needed. Alternatively, traditional linking methods.

\- For larger "integration" tests there is no substitute to testing the real
thing. At some scale and level of interactivity with the database, you just
have to talk to the true filesystem, the true database etc. You can still
setup a test instance for most cases where there is no interaction with
external services.

------
Spearchucker
I've seen this a few times before, and it led me to believe that I was stupid.
Comments like _"...business rules simply don’t know anything at all about the
outside world"_ left me wondering what components that DO know something about
the outside world, actually know about the outside world?

Turns out that the answer is a data access component might know where to find
a database, and a client app might know where to find a web service. These
things were rather obvious to me, so I failed by trying to find loftier
answers. Which probably says a lot of about how I think.

Also, the concentric circles did nothing for my way of thinking, as messages
are linear - they start from a place, and they end in a place. Thus a stack
was a lot easier for me to digest than these concentric circles.

And finally, the ambiguous language. Why should I care that there are
enterprise business rules, and application business rules? They're both rules.
Rules go into a component in the middle, or business layer.

And thus I found it a lot more useful to think of app design in terms of
vertical tiers (hardware abstractions), and layers (software abstractions).
Tiers include perimeter, DMZ and corpnet, and layers include (but not limited
to) user interface, façade/service gateway, business layer, and data layer.
With some cross-cutting concerns like comms, security and operational
management (logging, exceptions and so on).

I don't think either is better than the other. It was, however, the first time
I really understood that two people can be very knowledgeable about the same
thing, and yet speak using a completely different vocabulary.

~~~
coldtea
> _Also, the concentric circles did nothing for my way of thinking, as
> messages are linear - they start from a place, and they end in a place. Thus
> a stack was a lot easier for me to digest than these concentric circles._

Messages might be linear but scopes are encompassing inner scopes.
Encapsulation is not usually depicted as a stack.

> _And finally, the ambiguous language. Why should I care that there are
> enterprise business rules, and application business rules? They 're both
> rules._

Obviously because different scopes apply to the former than to the latter. TFA
even clarifies that: "The key is that they ("enterprise business rules")
contain rules that are not application specific - so basically any global or
shareable logic that could be reused in other applications should be
encapsulated in an entity".

In general, the similarities ("they're both rules") between two things don't
say much (if anything at all) without considering the differences. Shiitake
and Amanita Muscaria are "just mushrooms", but one can kill you.

~~~
pegasus
As an aside: according to wikipedia, there are no recorded deaths from
ingestion of Amanita Muscaria. It's not really a poisonous mushroom, though it
can have intense psychoactive effects when taken in large quantities.

~~~
coldtea
> _As an aside: according to wikipedia, there are no recorded deaths from
> ingestion of Amanita Muscaria._

Well, the Wikipedia lemma puts it this way:

    
    
      Although classified as poisonous, reports of human deaths 
      resulting from its ingestion are extremely rare. A fatal 
      dose has been calculated as 15 caps.[55] Deaths from this 
      fungus A. muscaria have been reported in historical journal 
      articles and newspaper reports,[56][57][58] but with modern 
      medical treatment, fatal poisoning from ingesting this 
      mushroom is extremely rare.[59] Many older books list 
      Amanita muscaria as "deadly", but this is an error that 
      implies the mushroom is more toxic than it is.[60] The 
      North American Mycological Association has stated that 
      there were: "no reliably documented cases of death from 
      toxins in these mushrooms in the past 100 years".

------
saltedmd5
Oh look, more kludgy over-designed enterprise gumf.

When are people going to learn that if you just start with the entry point
with granular components, letting each define the interface for its
dependencies, you get a much nicer, looser, more flexible structure than these
enterprise "patterns" that ultimately all just turn into a big ball of mud?

Stop pretending you can design codebases.

~~~
jdmichal
People forgot at some point that design patterns are for solving problems. The
key being that you should only be solving problems you actually have, and stop
making up imaginary problems in your head before you even start coding.

My code is typically some dumb data objects, static functions to apply rules
to that data, and a bunch of interfaces for abstracting external dependencies.
The code that ties everything together lives at the entry points, and is
hopefully written like one is reading a requirement.

To take the course registration example, the "register" entry point might look
something like:

    
    
        register(studentID, courseID):
            // Load student from data store interface.
            Student student = this.datastore.getStudent(studentID)
    
            // Business rules for whether a student can still register for classes.
            // This would check things like course overload and duplicate registrations.
            if (!Students.canRegister(student, courseID)):
                return CannotRegisterError
    
            // Record registration.
            this.datastore.addRegistration(studentID, courseID)
    

Advantages:

* Data objects are dumb. No need to even test them.

* Rules are all static functions, so you can call them anywhere, anytime, including for testing. Extremely flexible and allows easy remixing of rules for new requirements.

* All external dependencies live behind an interface, so they can all be mocked away for testing.

~~~
dyarosla
What kind of design is this? Is there a name for it? I'd like to read more
(both out of interest and being skeptical of how this scales)

~~~
jdmichal
I should come up with some catchy name and a blog post for it. It's basically
my own custom mix of procedural (entry points), functional (static
validations), and design by contract (external abstractions) in the noun
worlds of Java and C#. I arrived at it after seeing too many instances of:

* Architecture / design pattern lasagna, where breaking through abstraction layers felt like Inception. And adding a data field meant going through all 5 layers of code...

* Inheritance for functionality instead of typing.

* Also, breaking Liskov substitution willy nilly then wondering why things are hard to reason about. (Because your code becomes entirely reliant on the types actually present at runtime, since you can't rely on semantic equivalence.)

* Tacking methods into data objects because that's where the data is. See other comments on this post advocating a "register" function on the Student object, or should it be on the Course class... Answer is neither. Encapsulation is about maintaining invariants. It's not about putting all functions related to students in the Student class.

* Zero unit tests because external dependencies weren't isolated and all the logic is hard coded into exact use cases, which eventually end in hard coded external dependencies...

------
dayjah
I had been quite skeptical of Clean Architecture when I first came across it.
I don't find Uncle Bob's post on it particularly insightful; for me it's not
vocational enough.

Then a few years ago I had to maintain a software stack written by contractors
from Pivotal ([https://pivotal.io/](https://pivotal.io/)) in a Clean
Architecture style - it was truly a revelation for me; akin to that "aha"
moment of fully grokking homoiconicity in LISPs.

Now, up until this point, all code I'd encountered at Twitch heavily reflected
the domain of the problem it was solving and the technology in which it was
written. That is, if you were looking at a certain piece of architecture you
had to really fully understand not only _exactly_ the intent of that code base
but also the _details_ of the framework in which it was written. As codebases
increased in number and size, it became much harder to scale as an engineer.
Jumping from a Rails monolith, to a highly concurrent Golang HTTP CRUD-API, to
a highly asynchronous Twisted-Python request routing system (broadly the main
three backend techs) had a very large cognitive load. The eng org cleaved
along these lines and maintaining velocity in that world was very hard;
attempts to introduce new tech or join chunks of the org took on a "religious"
tone.

So initially coming across this clean architecture stack felt very similar to
that. It had a lot of "weird new things" in it, but once I understood that
much of it was routing (tagging inbound requests in a manner that a deeper
layer could understand the intent of the request and pass it to the correct
interactor, which would then work on the appropriate entities) it suddenly
became incredibly easy to hop around the code base and update the important
aspects of it.

I asked the authors who had been contracted to build this system where they
got their inspiration and they cited many lunchtime discussions and pair
programming sessions influenced heavily by Uncle Bob's clean architecture.

I would have really enjoyed seeing more systems built like this because, to
the maintenance programmer, it was _very_ clear where things had to go.
However only encountering one Clean Architected system didn't really give me a
solid idea of how well it would scale across various domains.

~~~
adamors
That codebase sounds interesting, is there a change some parts of it were open
sourced?

~~~
dayjah
Unfortunately no :(

~~~
tjarratt
Oh wow. I can't be sure, but I'm pretty sure I'm the engineer at Pivotal that
you paired with. I definitely remember you making reference to homoiconicity
in lisp when we were pairing the day that Clean Architecture really clicked in
your head. It was a really cool moment.

There's a lot of engineers at Pivotal, and we have a lot of projects, so maybe
I can prove I worked on that codebase by referencing obscure details from it?
I remember writing a LOT OF TESTS that used quotes from Wutang Clan and 36
Chambers as strings for names of entities, and a lot of references to 90s hip
hop. Was this the same project?

Also, I took some time after our project (and several others) to start a small
example of applying Clean Architecture in a toy Go Project, which is open
sourced. Maybe check it out?

[http://github.com/tjarratt/go-best-practices](http://github.com/tjarratt/go-
best-practices)

~~~
dayjah
Yes, it was you! Nice to reconnect :)

------
throwaway13337
Surprising this has been written in 2017. It looks like java written a decade
ago.

This can be a kind of organizational solution much like microservices to
separate concerns. This is important when collaborating with a large amount of
people. Clear boundaries and all that.

You pay for those boundaries with a convoluted mess of classes that describe
the design pattern rather than the business logic. You end up with
AbstractRequestInterfaceFactory type stuff.

Trade offs. Decide when they're worth it.

~~~
Spearchucker
_" You pay for those boundaries with a convoluted mess of classes that
describe the design pattern rather than the business logic. You end up with
AbstractRequestInterfaceFactory type stuff."_

I disagree. If a design (call it an architecture) is clean and coherent, it's
obvious.

Because obviously a client must send the order to a server, which is protected
by a gateway. And of course that gatway validates the client request, and the
data coming in. And of course the server must have business rules to validate
and process the order. And clearly the business components must call a data
access component to persist the orders to a database. Simple, no?

~~~
chii
> Simple, no?

what happens when the business rule clashes with the database's constraint
implementation, because different people either misinterpreted, or due to
incompetence or miscommunication?

I think splitting up sounds great in theory, but in practise, has lots of
pitfalls. That's not to say it's not a good idea, but one musn't look at it
with rose-tinted glasses.

~~~
Spearchucker
Well you'd test, which would catch that scenario. Assuming you're not testing
and discover it after releasing to production you'd just use your change
process.

Either way this is just part of building a system. Refector, re-test and
release (or re-release). It's hardly going to be the only bug you find.

------
grierson
I been using a very similar pattern [Port and
Adapters][http://blog.ploeh.dk/2016/03/18/functional-architecture-
is-p...](http://blog.ploeh.dk/2016/03/18/functional-architecture-is-ports-and-
adapters/) since moving to F#, paired with [Railway Oriented
Programming][https://fsharpforfunandprofit.com/rop/](https://fsharpforfunandprofit.com/rop/)
for the 'Adaptper' level and using DDD for modelling the 'Entities' & 'Use
Case' layers' and it been working well for me so far.

Scott Wlaschin has recently released an
[ebook][https://pragprog.com/book/swdddf/domain-modeling-made-
functi...](https://pragprog.com/book/swdddf/domain-modeling-made-functional)
on the topic which goes into more detail.

~~~
BoiledCabbage
These are all architecture ideas I've been interested in, I'll have to check
out the book.

Overall architecture in development is still early on in maturity.

------
andreasgonewild
You know someone is certified when you have to scroll code sideways because
the names don't fit the screen. I thought we already agreed that process is
the opposite of progress? I mean come on, RequestCourseRegistrationInteractor,
who are you trying to impress here? These processes were designed to turn
humans into machines; to decrease the dependence on creativity and skill at
the cost of additional effort and complexity; to enable large groups of
unmotivated developers to deliver mediocre software reliably; which makes them
sub-optimal for any other use case.

~~~
hasenj
I think you are opposing it for the wrong reason.

There should not be a lot of room for creativity when implementing specific
business rules. The goal should be clarity and readability.

These convoluted patterns obscure the logic and confuse the reader with their
pointless abstractions.

~~~
andreasgonewild
I think you are confused. The whole point of software is to create something
that didn't exist before, building the same software over and over again
doesn't make any sense. I'm not talking about creativity in interpreting
business rules, I'm talking about creativity in building software.

------
bsaul
IMHO, the most important thing in architecture are the concerns and goals of
the architecture. Not the particular architecture itself. A single
architecture can't check all the marks, or you end up with a monster. The job
of an architect is to identify the main risks and pain point of a particular
system, and adapt the structure of the project to address them best.

"Enforcing separation of concerns" is a good one. But so would be "identify
the various runtime threads of your system easily", or "minimize code surface
responsible for mutation of shared data", or "decouple configuration
primitives from the components themselves".

Those concerns are more or less important depending on your use case. MMORPG
server code or regular desktop app, or mobile webapps sold as templates, all
have very very different concerns, so i dont think it would make sense to use
a single architecture as a template for every problem.

------
edejong
It's interesting to note that a layered dependency architecture is nothing
new. As a matter of fact, it was one of the fundamental design decisions of
the 1968 THE Operating System [1], on which Edsger Dijkstra had been
programming and designing extensively.

[1]
[https://en.wikipedia.org/wiki/THE_multiprogramming_system](https://en.wikipedia.org/wiki/THE_multiprogramming_system)

------
Quarrelsome
Oh god no. DON'T POLLUTE THE CURRENCY.

This is a massive fuck up and it won't scale or be modular. The idea is fine
but you need the entities/currency into a smaller core with your DAL and
relationship objects above that layer. The only functions your currency should
have are accessors or read-only convenience calculations. Other operations
should be handled by another parent because let me tell you that that Course
collection is going to end up being null or empty A LOT when it "shouldn't"
be.

You'll want your use cases to return shallow object graphs (e.g. GetCourses =>
courses.Enrolled => StudentName, StudentId) from the data layer/services and
then if you want to look up a Students details you make that another call. The
alternative is to run some sort of "scope" object that defines the depth of
graph you want when accessing a general api. The thing you're looking to avoid
though is returning more information than is necessary.

Also who taught this guy to model? Students are in courses in this model the
courses are inside students and that's silly.

~~~
kromem
For shallow vs deep, what I decided for my code base was that I'd pick the
appropriate depth as a general rule for an object and not worry about I/O
micromanagement.

If it is cheap to pull the additional data and it makes sense to expect that
data in using the object, I'd simply embed the representation. If it was
expensive or not commonly used, I'd include a reference to the data (usually
ID(s) of the data).

Then in the repository, I'd just get everything necessary to return a full
object as designated.

An onion architecture gets funky if you don't know if the object you are
working with has all its data, especially because the object itself shouldn't
know how to fetch more data about itself.

In this particular case, the two objects probably shouldn't have ANY domain
connection, and there should just be a method on the course repository to
"GetCoursesForStudent" that accepts a student ID. It's perfectly ok to model
relationships in the database that don't have parallel relationships in the
domain objects.

Or, one could create a "SemesterEnrollment" object that contains a student
object and a collection of courses. Which would probably make more sense, as
that's the object that should be referenced to generate bills, report cards,
etc.

------
1_player
I was studying this topic yesterday, the same idea with another name,
functional core and imperative shell.

Came across this collection of articles and talks, for anyone interested:
[https://gist.github.com/kbilsted/abdc017858cad68c3e7926b0364...](https://gist.github.com/kbilsted/abdc017858cad68c3e7926b03646554e)

------
ryanmarsh
As a teenager I would sit in the offices of grey haired old men at the
software company I had no business working for after dropping out of high
school. These men would hand me a photocopy of an OOPSLA paper, or something
from a journal. I was told to read it, then come back and discuss. This was my
intro to many areas of software architecture.

I became familiar with the names of people like Booch, Rumbaugh, Jacobson and
others. Over the years I learned various object oriented programming languages
and patterns. Each new thing was like discovering a horcrux, at first magical
and powerful, but ultimately evil. Later I began to learn functional
programming and that's what I try to use most these days but it too has its
promises and lies. I have built and helped others reason about many many
complex systems and all I can say is this:

The only system that is well ordered internally is the one that accreted
complexity in increments, and was continually refactored along the way. Best
practices be damned.

Those systems might not look how you'd design them were you Uncle Bob. They
work, can be understood, and can be modified without much consternation. We
all can recite examples of masterpiece turned morass. Conversely some of us
can recite an example of a frog, a weird complex beast but ultimately very
well adapted to its environment and quite resilient. Frogs are not beautiful
but great at eating bugs.

One fact of complex systems is: humans cannot know the "right" design until
AFTER he has arrived at it.

If a human can know the design a priori then the problem is NOT COMPLEX and if
it is not complex then it is not modern software.

This is humbling knowledge for someone who wants to believe there can be a
language and pattern of order for all systems. One that can be expressed in
anything less precise than code itself.

Given a fanciful machine that could assemble subatomic particles in any
fashion the user desires none of us could, having never seen one, design a
frog.

------
kromem
I've been using a very similar architecture on an application for about 2
years now, and it's been incredibly smooth to work with, especially in Go
(passively satisfied interfaces and enfirced lack of inheritance), though I do
feel like the article overcomplicates the design (also recommend looking up
onion architecture).

Basically, for me, it boils down to the following:

1\. Create domain package(s) with the basic business entities (users, vendors,
products, etc) - can't import anything. 2\. Create usecases package(s) that
acts on these objects and can import anything in the domain package, but
nothing else (though can accept repository store interfaces). 3\. Create
infrastructure packages for taking to databases, caches, etc - can't import
from rest of application. 4\. Build repository stores to translate between
repositories and domain objects (can import domain and usecases, and accepts
interfaces for infrastructure). 5\. Add controllers/main packages that build
repository dependencies with infrastructure config, and pass those interfaces
into usecases that do the necessary work and spot back results (imports
everything).

The end result is a bit topsy turvy to get used to at first, but then it's a
dream. Extremely easy to test (very little dependency coupling in each
package), and the most complex parts of the application logic are totally
isolated from the complex parts of the infrastructure, so you end up with less
cognitive load when dealing with either.

After my experiences so far, I can't see ever switching back to "top down"
architecture instead of "inner out" when given a choice.

------
bg4
Also relevant to this discussion is 'Domain Driven Design and Onion
Architecture in Scala' by Wade Waldron from Scala Days 2016

[https://www.youtube.com/watch?v=MnNeDXg3Qao](https://www.youtube.com/watch?v=MnNeDXg3Qao)

------
luord
The entire time I read this I kept thinking of the fundamental theorem (and
its corollary). Also, considering this an all-solving hammer has the risk,
like with everything, of being premature optimization, methinks.

------
arwhatever
It's so refreshing to see vibrant discussion of _how_ a domain layer should be
implemented, when I have practically been run off from teams for suggesting
that a domain layer pattern, any domain layer pattern, should be used.

I've seen enormously complex domains implemented as DTOs that are acted
duplicately in ORM queries, in PDF rendering, in CSV exporting and then again
in CSV importing.

------
TekMol
Which language is he using? Is that C#?

It looks like this only deals with in-memory data structures. How does stuff
get read from / written to the DB?

~~~
salex89
Actually, very similar, since Entity Framework is usually used. Sources
implement the IQueriable interface which lets you write queries with method
chaining or LINQ. To be honest, it kinda looks better than it is. In reality I
find it produces sub-optimum performance and a lot of things can not be done
without spilling query logic to the app. Not to mention a lot of linq/method
chaining queries cannot be translated to SQL (by the database provider).

~~~
UK-AL
You can persist this model using anything you want.

You would have some kind adapter/library that handles the persistence.

It would take these models, and covert them into your datastore.

~~~
TekMol
How would that work in practice? Would this line stay the same:

    
    
        RegisteredCourses.Add(course);
    

And magically trigger an insert in the database?

~~~
UK-AL
The repository pattern in the original example would allow you serailise your
objects to whatever datastore you want. His object design isn't that great for
being persistence ignorant though. I would instead do something like this.

    
    
        Course - Aggregate Root
    
        Student - Aggregate Root
            RegisteredCourse[] - RegisteredCourses - An array objects with date time of registration, and id reference to course.
    

The method for adding a course would simply create a new RegisteredCourse and
place it in the registered courses array.

_studentRepository.save(student) would be a simple matter converting this in
memory representation into sql.

I'm not big fan of using lazy loading, and direct references to other
aggregates inside of other aggregates. This makes mapping these models without
ORM difficult.

~~~
TekMol
Can you show in real code, what you mean? From the text you wrote, I cannot
grok it.

------
lotsoflumens
If you see an architecture that has a box or a ring with the word "controller"
in it - the design is wrong.

------
ManuelKiessling
It's a shameless plug, but I just have to throw in
[http://manuel.kiessling.net/2012/09/28/applying-the-clean-
ar...](http://manuel.kiessling.net/2012/09/28/applying-the-clean-architecture-
to-go-applications/)

------
nradov
Every new system starts out fairly clean, at least in certain dimensions. Then
the real world intervenes.

------
paulio
At what point should basic validation be completed?

~~~
lgclrd
Superficial validation on things like form fields still occurs up in the UI
layer before a Use Case is invoked. Additional validation is likely to happen
in the Use Case as well. It's a ubiquitous thing so just like in any other app
it should be happening at a few different points but the stuff validated in
the Use Case is going to be related to the business rules it's trying to
execute.

~~~
Spearchucker
My approach has always been to validate anything that crosses a trust
boundary. This might be user->app; client->gateway; or app->database.

~~~
mariusmg
>My approach has always been to validate anything that crosses a trust
boundary.

That's a good approach unless a validation requires a db call with inner join
(for example). This becomes too costly to do it 5 times (for example) just to
get something written into db.

~~~
Spearchucker
It remains a good approach, even in your scenario - because that perf problem
is solved using a temporal cache.

~~~
barrkel
Caches are an excellent way to introduce path-dependent, time-sensitive bugs.

~~~
Spearchucker
The safest, most bug-free code is no code at all.

------
ninjakeyboard
looks like onion architecture, no?

~~~
kromem
Basically "Uncle Bob" took the onion architecture, changed it slightly, and
took ownership of it.

But yeah, regardless of the lame appropriation, a solid concept.

