Interactors and SRP

258 views
Skip to first unread message

Reed Law

unread,
Nov 13, 2013, 3:05:41 PM11/13/13
to clean-code...@googlegroups.com
In my experience trying to implement clean architecture, the interactors tend to take on more than a single responsibility. Not only are they handling the interaction between the controllers (as in MVC web frameworks) and the entities, but they also end up marshalling a lot of data from the database into the the entities.

A controller sends a request object which the interactor then uses by calling methods on the entities. The entities are not present when the controller sends the request so they have to be recreated from the data stored in repositories. I thought about having the repository classes handle the instantiation of entities, but this would violate the dependency inversion principle. So it seems like I need another type of class to handle the loading of objects so they can interact in an OO way. What would these classes be called? Loaders?

Andreas Schaefer

unread,
Nov 13, 2013, 5:19:31 PM11/13/13
to clean-code...@googlegroups.com
imo these classes ARE the repository classes. they are responsible for leveraging e.g. some kind of ORM framework to load the data from a persistance store like a RDBMS and shove it into the core domain objects (entities) which they then return to the interactor that called them.
by that you keep dependencies to plugged in frameworks away from the business rules.

repositories _might_ also be callable directly from within entities. so one could realize lazy loading of aggregate entities from within aggregate root entities. but i'm not entirely sure how to approach those DDD concepts regarding the clean architecture promoted by uncle bob

witali mik

unread,
Nov 14, 2013, 2:50:45 AM11/14/13
to clean-code...@googlegroups.com
@Andreas well basicly for the lazy loading purpose you can use the Proxy Pattern, so not your entities are using the REpositories but the Entity Proxies, your entities then are still clean.

@Reed since you inject the Repositories from outside , the repositories could store the entities internal within object storage or stuff like that, so you could pass one repository into multiple interactors and by calling the method findBySomething(); you just give the objects from the object storage back, instead of execute some queries and fetch the data from database..

so you call only once the query but reuse the objects in different interactors

Reed Law

unread,
Nov 14, 2013, 9:54:20 AM11/14/13
to clean-code...@googlegroups.com
From Uncle Bob's article:

The important thing is that isolated, simple, data structures are passed across the boundaries. We don’t want to cheat and pass Entities or Database rows.

Does this mean we don't want to pass Entities from the Gateways to the Interactors or we don't want to pass Entities to the Controllers/Presenters? Does it mean we don't want to pass Database rows inwards or outwards? It sounds like Uncle Bob is recommending passing only simple data structures at all the boundaries. But that would mean a lot code devoted to marshalling/demarshalling data from the database as well as conversion of data formats. It seems to violate DRY.

I don't think calling repositories from within entities is a good idea. It certainly violates the dependency inversion principle.

Reed Law

unread,
Nov 14, 2013, 10:28:19 AM11/14/13
to clean-code...@googlegroups.com
The Proxy Pattern sounds like a good idea, but if we use lazy loading in a view it could lead to N+1 queries.

I am using methods on the Repositories similar to findBySomething(). But those methods just return arrays or data attributes. To make them "dance" (in the sense of Uncle Bob's Impy Dance Mismatch), objects need to be instantiated and attributes set. This process of instantiating entities based on repository data is repeated throughout the interactors. It seems like there are classes in there wanting to be extracted. I'm just not sure what to call them or how to ensure their dependencies point in the right direction. Currently, this process is handled by the interactors and some interactors depend on other interactors for methods such as load_shifts_with_timesheets. This makes them brittle because sometimes the needs of each interactor change requiring a change to load_shifts_with_timesheets. Then this change breaks another interactor. There's a tension between keeping the code DRY and writing many similar methods that pertain precisely to each use case.

witali mik

unread,
Nov 14, 2013, 11:19:41 AM11/14/13
to clean-code...@googlegroups.com
to avoid N+1 queries and keep your repository clean, you could take a look at Specification pattern ;)

Reed Law

unread,
Nov 20, 2013, 9:10:40 AM11/20/13
to clean-code...@googlegroups.com
I've been looking at the Specification pattern and it looks like a good fit. I'm just not sure how to use it to build objects. In Evans and Fowler's paper they mention that Specification can be used either for validation or for building to order. But I couldn't find an example of building to order. My questions are: should specifications be used by the repositories to build data to return to the interactors? Or should they be used by the entities to test whether more data is needed from the repositories. I want to avoid coupling as much as possible. It seems like if specifications know about both entities and repositories then it forms a tight coupling between them. If specifications are only known by the interactors then the coupling is the same as for the interactors.

Andreas Schaefer

unread,
Nov 20, 2013, 1:14:19 PM11/20/13
to clean-code...@googlegroups.com
"The important thing is that isolated, simple, data structures are passed across the boundaries. We don’t want to cheat and pass Entities or Database rows."

in EBI the Boundary means only towards the transport layer (UI, e.g. done with MVC, MVP, MVVM, MV*).
repositories/gateways create, fill and return entities back to the interactors. no simple data structures are returned. BUT they might deal with simple data structures coming from the db, which they shove into the entities.

at least thats how I understood clean architecture.

Reed Law

unread,
Nov 20, 2013, 1:29:08 PM11/20/13
to clean-code...@googlegroups.com
If repositories create entities then there is a tight coupling between them and we may as well be using ActiveRecord.

I'm thinking about implementing "views" for repositories--actually builders like Rails' DSL for creating JSON structures. These builders could specify how data is returned to the interactors. The interactors could then return these simple data structures to the view, or use them to instantiate entities in order to perform business logic.

Andreas Schaefer

unread,
Nov 21, 2013, 2:56:38 PM11/21/13
to clean-code...@googlegroups.com
entities are more abstract than repository implementations (actually they are the most abstract classes in the whole architecture, together with the interactors, the interactor interfaces and the repository/gateway interfaces). thus it is absolutely valid that the concrete repository implementations point towards the abstract entities, they are plugIns to the architecture, implementing it's repository interfaces (which only reveal entitiy classes). they even shouldn't know about interactors or boundary DTOs, but of course they may know about ORMs like ActiveRecord.

Zamith

unread,
Dec 11, 2013, 6:55:28 AM12/11/13
to clean-code...@googlegroups.com
Exactly, entities should be plain objects, better yet (IMO) they should be value objects, these way you can pass them around, as they are in fact "isolated, simple, data structures". They should not know anything of how they will be displayed or/and persisted, though.

Terence McGhee

unread,
Dec 11, 2013, 2:05:20 PM12/11/13
to clean-code...@googlegroups.com
I think that maybe the definition of "single responsibility" could be examined here. 

The way that UB teaches the SRP, as long as each interactor is loyal to one (and only one) actor, it does indeed have a single responsibility. Now, you will definitely want to remove duplication which may, in turn, lead to the development of some type of loading mechanism. However, the fact that a lone interactor handles interaction between controllers and entities and  marshaling of data from the data store does not mean it has more than one responsibility.


Reply all
Reply to author
Forward
0 new messages