2

So I was reading Eric Evans DDD book and one point that was not clear to me is which Layer (in case of using Clean Code) should be reponsible to:

  • define the interface contract for an Entity (aggregate) Factory
  • implement such interface?

As of now I have two possibilities:

  • Domain should Define the Interface Contract and the Implementation (for injection later)

With this option we ensure the Factory can ONLY make use of purest layer: Factory can only accept Entity, Value Object and Primitive types as arguments.

This makes the factory workflow a pure workflow (no side effects) which leads to an easier time writing unit tests for it.

Since we are defining in the Domain layer we can (with Ports and Mappers) create the implementation and use it in the Application layer through proper injection.

  • Application should Define the Interface Contract and the Implementation

This approach allow us to expand the set of data types we can pass to the Factory.

My only issue here is: should the Application layer know how to implement it?

I do understand that the Domain's Entity Repositories should be implemented by the Infrastructure BUT I not sure why this would be case here for the Factory.

Question: Is any of the option above correct? If Not. What's the correct approach?

Here's some examples:

  • Domain defines the factory contract.

     my_app/
     domain/
     entities/
     car.py
     value_objects/
     wheel.py
     ports/
     factories/
     i_car_factory.py
     repositories/
     i_car_repository.py
     i_wheel_repository.py
     factories/
     car_factory.py <- i_car_factory.py
     application/
     ports/
     use_cases/
     i_new_car.py
     use_cases/
     new_car.py <- i_new_car.py
     infrastructure/
     repositories/
     car_repository.py <- i_car_repository.py (example: sqlite engine)
     wheel_repository.py <- i_wheel_repository.py (example: sqlite engine)
    

The User Case Interface i_new_car.py will have define the dependencies:

  • domain.ports.factories.ICarFactory

  • domain.ports.repositories.ICarRepository

    class INewCarUseCase:
     @injector
     def __init__(
     self,
     car_factory: ICarFactory,
     car_repository: ICarRepository,
     wheel_repository: IWheelRepository,
     ):
     self.car_factory = car_factory
     self.car_repository = car_repository
     self.wheel_repository = wheel_repository
    

The NewCarUseCase will receive the implementations

  • domains.factories.CarFactory
  • infrastructure.repositories.CarRepository
  • infrastructure.repositories.WheelRepository

So on the execute call we would need to carefully retrieve, map and translate all the data to types allowed by the Domain: entity, value object, primitive.

```python
class NewCarUseCase:
 # ...
 def execute(self, wheel_count: int) -> CarDTO:
 wheels = self.wheel_repository.get_wheels(wheel_count)
 car = self.car_factory.create_car(wheels)
 self.car_repository.save(car)
 # ...
```
Doc Brown
219k35 gold badges405 silver badges619 bronze badges
asked Aug 7 at 15:26
6
  • Just to be clear, you're talking about a factory for building entities from data returned by the repositories? Commented Aug 7 at 16:05
  • I’ve never used a factory to instantiate aggregates. Why can’t you use the constructor (or factory method) of the root entity of the aggregate? Commented Aug 7 at 16:09
  • @BernardoBeniniFantin Good question. I do understand that more often then not we will rely on Domain Repositories. But what about a scenario where an Application DTO can be easily converted (mapped) to a Domain Value Object? Commented Aug 7 at 16:20
  • @RikD I guess we could use it, right? If so I presume we would agreed that the Domain layer should define the Contract when using the Ports and Adapters architecture. Even more important that would define that: A Factory should NOT dependend on any data outside the Domain layer. Correct? Commented Aug 7 at 16:23
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. Commented Aug 7 at 18:10

2 Answers 2

1

So I was reading Eric Evans DDD book and one point that was not clear to me is which Layer (in case of using Clean Code) should be responsible to

Chapter 5 has most of the details provided by Evans

you create a factory to build something whose details you want to hide, and you place the FACTORY where you want the control to be.

So in the common case, your factory methods are going to be implemented within the domain model, and therefore the interfaces declared are also going to be within the domain model (otherwise you end up with dependencies pointing the "wrong" direction between layers).

(This assumes, of course, that you want an "object" responsible for building things, vs just invoking a bunch of "named constructors").

Where things get a bit more interesting: when you want to pull the information out of some data model that your "outer" layers understand, that your domain model shouldn't be coupled too

json -> aggregate

That's normally going to be done with two pieces, one that knows how to extract information from the outer data model (the json document) and another that the other that knows how to assemble that information into an domain object. The latter part is the factory we described above, but the former parts, and its interface are not going to be of the domain and won't normally be declared or implemented there.

The other place where things can get a bit twisted: when you are dealing with reconstitution of an object in the middle of its lifecycle. Unique identifiers and other lifecycle metadata are usually copied from your persisted representations, rather than generated anew; and depending on how you manage your unique identifiers, you may need to handle reconstitution and creation separately.


That all said, there's nothing particularly magic about "factories" vs "services" or other abstractions

  • make sure the dependencies point the correct "direction"
  • when the consumer is "inside" and the provider is "outside", the service provider interface will normally be declared "inside".

Also, a caution: you can get very deep into the weeds making this part of the design "better" without actually reducing your long term maintenance costs. Invest your time wisely.

answered Aug 8 at 3:40
1

In clean architecture the interfaces are devices that allow you to maintain the inward direction of references where you need some thing from an outer layer.

eg. (simplifying to three layers) Application needs to load an Entity from some Infrastructure

Application can only reference itself and Entity, not Infrastructure. So we add an Interface in Application and reference that instead.

Infrastructure can reference Application, so it can implement the interface.

Or, with a slightly less pure approach, you could allow for skipping over layers and put the interface in the Entity, since, in a single app, everything will need to reference it anyway.

In your case you have to ask yourself "Where am I using and implementing the Factory?"

Put the interface in the layer which uses the Factory, OR Entity. Put the implementation(s) of the factory in a Layer below the using layer.

Your example code follows the reference direction rule, but I would consider it slightly flawed because

  • The factory implementation is in the Entity layer.

    But you can imagine many implementations, some of which might not be pure logic, or not used by all applications. If you put all pure logic functions in Entity your Entity layer will end up bloated.

  • The repository and factory Interfaces are in the Entity layer, but used in the Application layer

    This is a practical approach for interfaces which will be shared by all components, or where the interface logicaly has to have a particular structure. But we can imagine other use case components that use factories with different interfaces, so a more pure approach would be to put the interface in the application module that uses it, or in its own shared application layer module.

My suggestion is to abandon the folder structure with layer names. The layers are only conceptual, you don't want to be moving files around when you decide that some module really should be in layer X instead of layer Y. Solidifying the layers as file structure just makes things painful.

If you hadn't made the folders in this case, your app would follow clean architecture, you just have a bunch of modules which all follow a direction of reference. If some nerd comes along and says "Your factory should in in Interface!!" you can just say "Ok I'll change that! (in my mind!)"

answered Aug 8 at 9:10

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.