Uncle Bob's Clean Architecture is quite the hype right now in the architects' world. But when it comes to actual implementations, nothing notable h...
For further actions, you may consider blocking this person and/or reporting abuse
🤔 Theoretically it sounds great. But for something "clean" it's hugely verbose. Real-world I can see it adding unnecessary time and complexity to a project, compared to something like single action classes - which are still testable and keeps business logic out of the controllers.
Hey @waynethorley thanks for your comment 👍
The complexity is the price to pay for layer isolation. It is tempting to simply relocate business logic from controller to actions (that's what JetStream is doing).
But without proper isolation one of these two scenarios will inevitably happen:
Scenario 1 : the presentation logic will leak to the controller
It might be fine for simple presentation logic but as your project grows, more logic will "leak" this way to the controller, defeating the purpose of isolating things in an action.
Scenario 2 : the response logic will leak into the use-case
In that case, the action will have to take care of choosing the view response itself, making it effectively a controller. Again, defeating the purpose...
So you could just add a presenter between the controller and the action like so:
And that's pretty much the same thing as the implementation I proposed, structured differently and without the interfaces, but very much the same concept (also I didn't bother mentionning the request/response/view model but you get the gist at that point.)
I encourage you to play a bit with these concepts and find the right balance for your projets. It is true that CA is complex. It is intended for large scale enterprise application software and require experts on your team to operate effectively and deliver the promised value.
It is not fitted for every project. It is not a silver bullet. Nothing is.
Very good! But many developers don't see the benefits for larger teams. The true gain is in code's maintenance.
The best of Clean Architecture comes in the long term.
Good morning, first I think your article is great since in my opinion it is one of the best I have found. I have a doubt about the use of key custom in the attributes of UserModelFactory->make since I have always had doubts about whether or not to use an array of data. My solution is the following and please could you give me your comment.
Hi @riter_angel thanks for your comment.
In my opinion, there is nothing wrong with using array as DTOs as long as you're using Psalm or PHPStan to declare and check their structure. Here's an example projet that makes extensive use of PHPStan array declarations.
Thank you for this explanation, for those as me who are discovering software architecture and this new professional path, these articles are precious. I add this context to my others where I learn clean architecture : a nextJs project and a java project.
Seems like overengineering for 95% of the apps out there.
I find many oop and design patterns add a lot of complexity with little to no benefit.
I am a big believer in YAGNI (you are not going to need it). Only implement design patterns when you have an immediate need of it, not just in case you might need it later or cause you want to just follow some best practice.
A big reason Laravel got so successful is because it makes things easy to read and keeps things simple.
I would say if you are working on some vendor package, or you are working in a very big team where you don't have influence on other development teams, then these oop and design patterns can be quite handy.
Thanks for your comment Bernard.
As I quote in the article
If Laravel's native architecture can support your use cases, which is likely to be the case for small / mid size or early project, then yes, maybe you don't need Clean Architecture.
As the system's architect (apointed or de-facto) it is your responsibiliy to pick the best architecture you can given the project, its scope, its constraints, and its team.
If CA is overkill, then pick something simpler 👍 Just make sure you can migrate later as the project grows.
Im seeing complexity here.
I hope the proposal is not introducing complexity to the framework.
It is not about the framework. It's about letting the framework be a detail of the implementation - domain and use cases separate from the framework. For a deeper look, I can recommend the talk by Matthias Noback on Hexagonal Architectures.
The framework is left untouched. This implementation is completely compatible with the rest of the Laravel ecosystem
Thank you for the article. In this implementation, framework is isolated but I can see a lot of complexities, which will cost a lot of time for adding any new use cases. Too many moving parts are involved.
I hope to see an updated implementation which is more simple compared to this one.
Yes, actually I plan on writing an article on how to structure use cases using Action, after I've finished the book Laravel Beyond CRUD. Follow me to stay tuned 👍
I think many commenters don't see one of the most significant things described in “Clean Architecture”.
Why making Framework a detail is that important? And why would you need to make such complexity?
— Because it allows you to make more code testable, independent of framework, which allows you to securely update from one version to another. You can only see the benefits of this approach over time.
Thank you for your sharing. It's really interested post!
I had created
lara-repository
to automatically generate files (Interface, Repository, Model, Controller) for Laravel repository structure. I hope you can take a look and give some feedbacksWe can share and learn together. Thank you so much!
dev.to/ngodinhcuong/auto-generated...
Hey @ngodinhcuong thanks for your comment 👍
Sure I’ll have a look 👀
Thank you for your effort and this insight into this type of architecture. In your
CreateUserInteractor
, the method seems quite long. Doesn't that violate Uncle Bob's Do One Thing rule?I don’t believe it does. Taking care of all the steps involved in account creation (in the example I used) can be considered one thing, it’s an account creation.
Plus, CA advocates against UC calling each other; they are vertical “slices” in your application layers and therefore should be isolated to avoid crossing boundaries.
This point in particular seems open to interpretation though and it’s a frequent topic on Stack Overflow.
DDD answers the issue of crossing boundaries with the notion of bouded contexts. You can read more about that on Martin Fowler’s blog.
At the end of the day, I believe you have the right, as an architect, to choose the trade offs that suits you the best 👍
I'm on board with @bdelespierre here. If you think from the perspective of reasons to change the
CreateUserInteractor
is not violating SRP at all.As you mention the collaboration between interactors, what's your appoach in this cases? How do you share behavior between interactors without having them call each other?
Behavior shared amongst use cases should go into shared services if and only if it's not incidental dupplication.
Hello,
wouldn't it be better if the interactor returned new CreateUserResponseModel($user)
and then controller, command, etc. could decide on the type of response? Those layers could also get injected with a proper object handling the response (Presenter). It looks a bit weird that InputPort "knows" about OutputPort.
It can, but it wouldn't adhere to the specifications of this diagram:
With your proposal, the flow of control would return in the controller for it to make the decision on how to update the view, forcing you to change it when the use case changes.
In summary, you absolutely can, but it's no longer Clean Architecure, it's Laravel Actions.
I also don't believe it's weird to have the Interactor knowing the output port while implementing the input port since it should control both.
I'm curious how you'll mitigate class AppServiceProvider bloat?
Also, isn't creating so many classes for every CRUD single operation a bit much? I think more thought should be lent here, but I've yet to read the Clean Architecture book, so I would like to hear your thoughts.
Hi @emperorkonstantin , thanks for your message 👍
On real projects I use many bounded contetxts and I create service providers for each of them.
Also, a use case is much more than a part of a CRUD and, on large scale projects, deserves a lot more attention. I don't believe most apps are CRUD, despite the apparences, especially in the early days of the project. but if it's indeed the case and what you have is a genuine CRUD app then 1. why are you using Laravel instead of a serverless solution like Firebase, which would make the CRUD operations for you and 2. a CRUD is little more than a scaffolder to reach the database layer from the view, it's very simple and doesn't need Clean Architecture.
Despite what is often say about CA, I don't believe it should be applied everywhere. It's indeed complex and involves a lot of abstraction, which is not for every project nor for every team. As an architect, it's you responsibility to make those tradeoffs.
Another issue that I find interesting is authentication and authorization, which is more pleasant, a simple if in the interactor or polymorphism of the interactor for each role of the system?
Can you provide examples for these?
Yes,
In a post creation case where the authenticated user can be a simple author or a moderator, where should publish permission be checked?
With a conditional in the interactor:
With derivations for each type of user:
Both approaches could work just fine IMHO. The second one is better suited if the two roles have a lot of differences in their use-cases, justifying the existence of two distinct use-cases.
I also believe the keyword interactor should be a suffix of the class like
CreatePostAsModeratorInteractor
.Also note that the interactor returning the entity directly is not a recommendation of the Clean Architecture as it will inevitably introduce coupling between the interactor and its callers.
Congratulations for the post, my question is in the case of a REST API, the viewmodel would be needed? If not what would be the default return type for presenter methods?
I believe in the case of REST API, the ViewModel would be a Laravel Resource wrapper:
I'll update the reference project with examples for a REST API and write another article about it. Stay tune!
Great article, this is how the framework can be a detail, and nothing more.
although i wouldn't use magic methods that much, but everything looks pretty clean.
Thanks for the great article, one of the best implementations of clean arch that I saw...
I was wondering why you created a port for use cases in the controller, being that the controller is outside the use case layer, the same for entities that were called from the use cases through ports as well