Welcome to another deep dive. Today we're taking a plunge into something pretty fundamental in software engineering, Clean Architecture. Yeah, it comes up a lot. It really does. And it's not just, you know, a buzzword. It's a real approach to building software that's robust, adaptable. Our guide today is Software Engineering a Modern Approach by Marco Tulio Valente. Specifically Chapter 7, right? The one on building with clean architecture.
Exactly. And of course, you can't really talk about clean architecture without mentioning Robert Martin or Uncle Bob as most people know him. True, he really championed this philosophy. And the goals listed in the source? They're ambitious, high reusability, strong cohesion, technology independence and great testability. It sounds like the Holy Grail of software design. Almost. It does. So the big question for you listening in is probably OK, how? How does 1 architectural pattern
deliver all of that? What's the secret sauce here? Well, it's a great question and fundamentally clean architecture. It's a layered architecture, a sophisticated 1, sure, but layers are key. It's designed specifically to make software resilient, adaptable. And those diagrams, you always see the concentric circles. Yeah, those circles are actually crucial. They're not just decoration, they visually represent the core principles, how the separation works. Strategic separation, OK, I like
that. So to get it, we need to start right at the center. Yeah, the absolute core. Exactly. Go right to the middle, that innermost layer. That's where the most stable parts of your application live. The core business concerns. The real essence of what the software is for. Like totally separate from any specific tech. Precisely. And in that core, there are basically two kinds of classes. First, you've got entities. OK, These are classes often shared across multiple systems
in an organization. Think about university example from the source. Entities would be things like student, instructor, course, department. Things that lots of different parts of the university system would need to know about, right? And importantly, they don't just hold data, they also implement generic business rules. The source gives the example. Maybe a rule like every instructor must belong to exactly 1 department. That's a core business fact. Got it.
Not tied to how you store instructors, just a. Rule exactly. Then still in that inner circle you have use cases. Use cases. OK, these classes handle the specific operations for this system's domain. Sticking with the university use cases might be things like creating a new class, enrolling a student, cancelling an enrollment, maybe recording subjects covered in a lecture. So the actions, the verbs kind of to the entities nouns. That's a good way to put it.
These are the specific processes the system enables. So these central layers, I mean, this is where the real value, the intellectual property lives, right? Free from all the messy details of databases or I don't know, front end frameworks. Exactly, Imagine trying to change a core policy and finding it tangled up with sequel statements. It's a common headache. Clean Architecture keeps these rules pure insulated. You define the business first, then worry about tech.
OK, That makes a lot of sense. So moving out one layer from that core, we get to the adapters, what role do they play? They sound like middle men. They are crucial intermediaries, maybe skilled translators is good analogy. They manage the conversation between the inner core and the outside world. So adapters are classes and interfaces that well they adapt. They mediate between the external parts like UIS, databases, external services and that central business logic, the
use cases and entities. So take a system with a REST API that the source mentions this. The adapters would be the classes implementing those API endpoints. They get a request, figure out which use case needs it and pass it. On and then handle the response coming back. Exactly. They take the result from the use case, maybe format it as Jason, and send it back to the front end.
It ensures the core logic doesn't need to know anything about Http://orjason. Like skilled translators, as you said, making sure everyone understands each other even if they speak different technical languages, keeps the core clean. Precisely, it protects that core. OK, so that naturally leads us to the outermost layer, the edge of the circles. This is where What did the source say all the details go? That's the phrase, and it's very
apartment. This outer layer is home to classes from libraries, frameworks, external systems, all the specific technologies you're using. So like. Database drivers, E-mail library. Exactly. Databases, e-mail services, payment gateway integrations, maybe talking to specific hardware. The university example mentioned using a third party credit card provider for extension courses, right? The class this is for that specific provider would live out here. They're details from the core
business perspective. Uncle Bob in his own book really hammers this home. He says the frameworks and drivers layer is where all the details go. The web is a detail, the database is a detail. We keep these things on the outside where they can do little harm. Little harm. I like that it implies they could do harm if they were mixed in with the core logic. They absolutely could. Changes in those details could ripple inwards and break things.
So the big take away here is your core business logic. Those entities and use cases, they just don't care. SQL no SQL, send grid, mail gun doesn't matter to the core. Correct. That core is insulated, protected. Focus purely on the business rules. That's how you get that technology independence. You can swap out details more
easily. That sounds incredibly powerful for future proofing, but OK, this strict separation, how is it actually enforced, especially if, say, a use case needs to trigger something in an outer layer? This leads us to the dependency rule, right? Yes, the dependency rule is absolutely fundamental. It's the bedrock principle that makes this architecture work. So what is it exactly? Simply put, code in an inner layer cannot reference anything in an outer layer.
No direct dependencies pointing inwards. Nothing. No classes functions. Nothing. Uncle Bob is very clear. Nothing in an inner circle can know anything at all about something in an outer circle. In particular, the name of something declared in an outer circle must not be mentioned by the code. In an inner circle that includes, yeah, functions, classes, variables, anything named. Wow, that's strict. It has to be. The benefit is huge.
It makes those inner layers, the entities and use cases, incredibly stable. They don't change just because you decided to switch database vendors or adopt A new JavaScript framework. Because they literally don't know about them. Exactly. The business logic is shielded from technological churn. You avoid those cascading changes where updating a library forces changes deep in your core logic. OK. So that's what really keeps the
core clean. It's this strict dependency management discipline is key it sounds like. It definitely requires discipline. But then the obvious question arises, what if an inner layer, like a use case for enrolling a student, needs to do something that involves an outer layer, like sending a confirmation e-mail? The e-mail service logic is way out there in the details layer. A direct call is forbidden by the rule. Right, direct calls would break the architecture. So how do you solve that?
How does the inside talk to the outside without violating the rule? This is where the elegance of Inversion of Control comes in, usually implemented with interface. In version of control. OK, how does that work here? So instead of the use case directly calling say a mail service simple class in the outer layer. Which you can't do which. You can't do. Instead you define an interface right there in the inner use case layer, let's call it Mail
Service interface. It just defines what needs to be done, like a method send recipient message. So the use case only knows about this abstract interface defined right next to it. Precisely the use case depends only on this abstraction. Mail service interface, then way out in the external frameworks layer. Your concrete mail service simple class implements that mail service interface. I see. So the dependency arrow is flipped. The outer layer implementation now depends on the inner layer
interface. Exactly. The control of which implementation gets used is inverted. The inner layer defines the contract, the interface. The outer layer provides the implementation. The source has a class diagram showing this flow, how the dependencies point inwards towards abstractions. That is genuinely clever because the use case can trigger the e-mail sending via the interface, but it has zero knowledge of how it's sent or which service is doing it. The separation is maintained.
Perfectly maintained. You could swap mail service input for another mail service input tomorrow, and as long as it implement the mail service interface, the use case layer doesn't change. Not one line of code. That's the real power, adaptability without rewriting your core logic. OK, so we've walked through the layers, the crucial dependency rule and this smart inversion of control solution. Let's zoom out.
Why go through all this effort? What's the big picture benefit for you, the listener, The developer? Well, it connects directly back to those core software engineering concepts we always talk about and that the source emphasizes. Clean architecture isn't just some isolated idea, it's strongly promotes things like high cohesion within layers, loose coupling between layers, and a very clear separation of concerns makes sense.
It also heavily relies on principles like single responsibility, each layer, each class having a clear purpose and as we just saw dependency inversion and we talked about the adapter pattern being used explicitly. So it brings together a lot of best practices. It really does, and the source boils down the recommendations quite nicely. First, start by defining your entities, those core data structures and generic rules.
Right, the shared stuff. Then focus on the use cases this specific business operations for this application, but keep them totally technology agnostic. Remember the web is a detail, the database is a detail. Keep. Chanting that mantra. Pretty much. And finally, design the adapter classes, those intermediaries that handle the translation between the pure core and the messy outside world. Entities use cases, then adapters focus inward, then build the bridges outward.
That's a great way to summarize it. And if you follow that path, the ultimate benefit is an architecture that cleanly separates business interests from technology interests. Which means which means your system becomes way easier to test. You can test core logic without databases or UIS. And crucially, it's far easier to adapt to new technologies down the road. You're not locked in.
So less pain when the next big framework arrives or when you need to switch cloud providers or database types. Exactly. It's about building for change, building for the long term. It's about protecting your core business value from the turbulence of technology trends. Easier testing, easier adaptation. That's the promise, and when done well, Clean Architecture delivers. It sounds like it's about building software that embraces change, not fights it.
That's it perfectly. In today's tech landscape, which just keeps evolving faster and faster. Building software that embraces change, well, it isn't just good practice anymore, It's pretty essential for longevity. A really powerful idea to keep in mind. Thank you for joining us on this deep dive into Clean architecture today. Hopefully you feel a bit more equipped to think about these layers and dependencies in your own projects.
