DEV Community

Cover image for Cleaning up your codebase with a clean architecture

Cleaning up your codebase with a clean architecture

Barry O Sullivan on May 15, 2017

Let's talk software architecture. Most of us know MVC, it's the foundation for pretty much every web framework. As your product grows though, pro...
Collapse
 
malinakirn profile image
malina-kirn

In this example, the database does not depend on the application -- and it would be smelly code if it did. Rather, you've abstracted the database into an interface and now inject the appropriate concrete implementation into the application, instead of constructing the concrete implementation in the application. Dependency inversion is almost always more appropriately phrased as dependency injection -- for exactly the reasons in this post (you've injected, but not inverted, which is exactly the right thing to do here).

I note that this example is also a great demonstration of the single responsibility principle, which you explain in the text (what if you want to change to a different database implementation?).

Collapse
 
courier10pt profile image
Bob van Hoove

That's a great example, complex enough to make the point, small enough to keep me engaged :)

If you compare the 2 versions of the SetProfileImage classes the second one is almost self explanatory.

Collapse
 
kjshah profile image
kjshah

Thanks! I don't see where you indicate to use the s3 implementation of the interface, but I imagine that happens typically in laravels service provider? How would you do that if the implementation choice (s3 vs g cloud) had to come from a database value?

Collapse
 
barryosull profile image
Barry O Sullivan

That's exactly how I do it, use Laravel's service provider to bind the interface to the implementation.

As to your question, if you needed to choose the implementation based on a config detail (database value in your example), you can do that in the service provider, binding the appropriate implementation choice based on the value.

You could also make an implementation of the interface that chooses which other implementation to use based on the database value, sort of like the proxy pattern, proxying the calls through to the appropriate concrete implementation.

Collapse
 
kjshah profile image
kjshah

ok, thanks, that makes a lot of sense! I always had trouble thinking through that second part of having configuration come from database values.

Collapse
 
pht profile image
Tuan Pham

Thanks for interesting article!

A minor mistake in class SetProfileImage:

class SetProfileImage 
{
    private $image_store; // Is this $image_repo?

Also, I have another question, in class EloquentUserRepostiory you are using Domain\User and function get return Domain\User, is it an Eloquent model?
If it is an Eloquent model, how do you implement the repository with MongoDB, which isn't supported by Eloquent?
Maybe, we should use Entity instead of Eloquent Model?

Collapse
 
barryosull profile image
Barry O Sullivan

Hi Tuam,

Thanks for pointing that out, I'll correct it shortly.

You are correct, the above get call would return an eloquent model, which isn't ideal. If I were to take this code example further, I would create a domain class for User that is completely independent from Eloquent, and then translate from it to the Eloquent model inside the repository.

Collapse
 
j7mbo profile image
James Mallison

This is a nice example of SoC, yet also yields to an anemic domain model when there exists a service layer operating on entities - the changes to which are not encapsulated within the entity (read: aggregate root in the case of a user changing their profile image here). ADMs are okay for CRUD, just as a rich domain model also has it's trade-offs, but I feel it's important to make the distinction clear. Purporting to use DDD yet only focusing on placing code in different directories is not DDD, it's a directory structure.

Collapse
 
barryosull profile image
Barry O Sullivan

Hi James,

I agree, the above isn't a solid example of DDD, and it should not be viewed as such.
The above code is a contrived example to explain the concept of a clean architecture, so it doesn't feature any of the richness that a real domain model would contain.

Collapse
 
davidszabo97 profile image
Dávid Szabó

There is a typo in one of the snippet: $this->image_reoo = image_repo; -> $this->image_repo = $image_repo;

Thank you for the article!

Collapse
 
barryosull profile image
Barry O Sullivan

Good spot, thanks for pointing that out. I've updated the code snippet.

Collapse
 
joeizang profile image
Joe Izang • Edited

Devs used to say this was microsoft and java concern (ddd) etc. But this is how to do it. Enjoyable piece

Collapse
 
buzzdan profile image
Dan Mordechay

How would you apply clean architecture with functional programming style ?
Is it possible ?

Thanks,
Dan

Collapse
 
barryosull profile image
Barry O Sullivan

Hi Dan,
I think it's entirely possible. Functional programming doesn't have objects, but you can still compose functions in the same way you compose objects. This means you can build high level functions (domain/usecase layers), that internally use lower layer functions that interact with infrastructure, in the same way that you'd inject services in the article above.

Collapse
 
tripper54 profile image
Phil Dodd

Excellent article, very succinct! I will share this with my team.

Collapse
 
elcotu profile image
Daniel Coturel

Good article

Collapse
 
powellfallon profile image
Powell

Clean your Home