Before we get into this week’s article, I just want to state again – for the record – that I’m a huge fan of Clean Architecture. I think it’s the type of thinking that we need to learn and use to help preserve business value for the long term.
That doesn’t mean that I think, as it stands, it’s perfect. In fact, I think there is room for improvement and refinement.
We don’t need to reinvent the wheel for those improvements and refinements though. Instead, I think we should look to OOSE – the thing that inspired Clean Architecture – for some left behind ideas and incorporate them into what we have come to think of as Clean Architecture.
Clean Architecture Gets a Lot Right
One of the things we’ve been working to achieve for as long as I can remember is an application that is built to be ignorant of its view and external dependencies. The reason we have been striving for that is that we noticed the need for business logic to remain unchanged when we change the view or external dependencies.
Even in applications that kept focus on this separation, it has still proven difficult to pull it off cleanly, because we moved our entities down into the database and built our application on top of that.
Clean Architecture Separates Us From Our Chosen Persistence Approach
It’s interesting, I think, to imagine how in one thought we can think that we want to protect our application from becoming coupled to external dependencies. In the next, we think that coupling our Entities to some type of persistence technology is the way to go.
Entities are the most fundamental element of any application. Everything is dependent upon them (as should be the case). By coupling Entities to persistence, the chance that our application as a whole becomes coupled to a specific database is raised. In many environments, it’s a downright certainty.
Using Clean Architecture, Entities are relocated to their rightful place – the center of our application – and are protected from becoming coupled to a specific persistence strategy along with the remainder of the application.
This doesn’t mean we have to go all the way back to SQL. It doesn’t mean we have to ditch declarative transaction handling. It doesn’t really change anything, except to ensure that Entities don’t depend on anything external of the application.
Clean Architecture Separates Us From Our Chosen View Approach
Back in the early days of Java web applications, we did a lot of processing in the view of our application. We would call services, get responses back, and format that response into the view.
Even now, a lot of applications simply emit entities to the view and let that be where data gets formatted.
Clean Architecture formalizes how output leaves an Interactor. It gives us a Response and a Presenter. Output is collected in the Response and passed on to the Presenter to be transformed into a ViewModel that is then forwarded to the View.
Clean Architecture Helps a Ton
From separating business logic to making everything else dependant upon that business logic. Formalizing input, output, and giving a definite place for view formatting to occur.
Yep, Clean Architecture gives us a lot we haven’t had before. The service layer architecture doesn’t do it.
Now, About That Fly …
You’re probably confused right now. You thought this was going to be an article that railed against Clean Architecture, but it hasn’t exactly done that.
It’s true! Clean Architecture is awesome. In fact, if you’re building a simple application, it may be more than enough.
The Shortcomings of Clean Architecture
For more involved applications, it just isn’t a full answer. You’ll still have to put your design hat on squarely and … design! Or, better yet, identify a complementary approach that can be combined to simplify those more involved applications.
In an application that has a lot of business logic, it is very likely that you may want to use one story within another. Think, for example, about how you might complete a task in a task management application:
- Receive input on the request
- Use the request data to load the task
- Update the task to indicate that it is complete
- Save the task
- Create a response and send it to the presenter
Depending on how you do it, steps 2-4 could be combined. You’d lose information when things went wrong, but if you were really looking to save time and energy you could absolutely combine them.
I wouldn’t, but some folks would.
Normally, what you’d do here is to use the request data to load the task identified by the data. Then, because the completeness of a task relates to data on the task, we’d probably ask the task to become complete.
Perhaps we’d follow Martin Fowler’s notion of things and have a beComplete method on the task. Perhaps we’d strive to be closer to the JavaBeans specification and simply call it setComplete. Either way, knowing how to update the state of a task to “become complete” is something the task should probably know about.
Finally, we’d want to save the state of that task so that everyone could know – now and forever – that the task had been completed.
Steps 2 and 4 could be written directly. That doesn’t seem very DRY though, and in my view it does not really honor the Single Responsibility Principle either. No, in my experience, I’m always going to want to write the story for find and save and then leverage them here. Then, not only do I not have to worry about what type of validation they might do, but – if they ever do change – I’m able to apply updates in one spot.
As it stands though, that’s a really unhandy thing to do. Not only would I need to create a request for each of those included stories, but I would have to create a presenter and manage that entire execution to successfully integrate everything.
Only the most loyal followers are going to do that. It’s just not efficient!
I’m a flat-out “neat freak” when it comes to writing code, and even I would be grumbling under my breath every time I had to do it. … and I’d be constantly looking for a better way.
Improving Story Composition Was a Struggle
The fact is, I did grumble under my breath in the beginning – when I was trying to figure out what Clean Architecture was all about. I did look for a better way.
I can’t tell you how much I struggled to keep with the core elements that Uncle Bob had given us. I mean, I thought he was nuts the first time I read Clean Code, but the more I incorporated the ideas in that book the less crazy he seemed. Nowadays, I think I’m almost as crazy as I thought he was back then.
At first, I thought I was having this same struggle with Clean Architecture. Then, I remembered that Clean Architecture was born out of OOSE!
OOSE to the Rescue!
I went back and studied OOSE some more. I had done some cursory study of it in response to having heard Uncle Bob’s Architecture – The Lost Years keynote presentation at Ruby Midwest 2011, but I was starting to think I’d missed something or forgotten something.
In fact, I had – and it was significant! In OOSE, the Boundary object is separate from the Interactor!
In OOSE, the Boundary serves as an entry point to application behavior. A great deal of that behavior is built into Control objects (what Uncle Bob calls the Interactor).
This separation means that composition is much simpler. It lets us receive the request above, call the stories that are required (find and update), and add our own special sauce in the middle – asking the task to become complete.
Wrapping It Up
Clean Architecture is a wonderful methodology, but I think it’s equally important to understand the downside as to be seduced by the upside. I don’t really view this fly as being an obstacle. We should always break things up in ways that make sense – no matter what anyone says.
Apply design principles. If they don’t have the desired outcome, you’ve missed something. Go back and apply them again. Make sure you understand the things you’re modeling and how they interact.
Use your noodle! It’s capable of a lot more than growing hair!
I hope you’ve enjoyed this week’s article as much as I’ve enjoyed writing it. If you found it useful, please use the share icons at the top and bottom of the article to share it with your own network.
That’s all for this week. Until next time, this is Eddie Bush with Craftsmanship Counts reminding you to keep your tests passing and your code clean!