0

From what I have read and seen clean architecture assumes that you have some entities which know nothing about persistence though at the same layer as they reside there might be an interface which has a purpose to be a contract on how the entity should be read/updated/deleted.

// project Core
public class CarModel
{
    public string Name { get; set; }

    public void SomeImportantBehavior {}
}

public interface ICarModelRepository 
{
    CarModel FindByName(string name);
    CarModel Add(CarModel carModel);
}

Meanwhile another layer will hold the implementation of the interface:

// project Infrastructure or Persistence
public class CarModelRepository : ICarModelRepository
{
    public CarModel FindByName(string name)
    {
        return new CarModel { Name = name }; // the implementation is not really important here
    }

    public CarModel Add(CarModel carModel) {
        // somehow persist it here
        return carModel;
    }
}

So I've got a question: doesn't repository implementation violate the DiP principle? Since it not only depends on abstraction but also on concrete implementation (CarModel in this case)?

Another example of this is here.

P.S. CarModel is a domain model with behavior.

meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
hasrthur
  • 1,410
  • 15
  • 31
  • 1
    I would say not, from your example, `CarModel` is a simple data structure with no behavior, the notion of "concrete" and "abstraction" are not applicable to it. – Matthew Mar 12 '19 at 21:23
  • I'm voting to close this question as off-topic because it would seem to fit better on https://softwareengineering.stackexchange.com – Charles Mar 12 '19 at 21:33
  • 1
    abstractions are required for behaviour, not data – qujck Mar 12 '19 at 21:47
  • Previous comments have the right idea: abstraction principles apply to objects, which are conceptually separate from data structures. A more in-depth answer can be found in [How to eliminate hard dependencies](https://stackoverflow.com/a/55013810/1371329). – jaco0646 Mar 13 '19 at 01:07
  • @jaco0646 That was the simplest example - I now updated an entity with a behavior. These examples I see all over the internet and just wondering if it is ok or do we lack some abstraction? And if yes how that abstraction should be implemented – hasrthur Mar 13 '19 at 07:51

2 Answers2

1

You are missing a bit the point of Dependency Inversion principle. This principle is supposed to reflect the decouple between different modules. In other words, you shouldn't instantiate your objects where you need them, but receive them as parameters. This is the base principle for dependency injection.

To make things clear, let's suppose that you have a class Controller that uses your Repository. Without DI, at first it would look like this:

class Controller
{
    private CarModelRepository _repository;

    public Controller()
    {
        _repository = new CarModelRepository();
    }

    public void DoSomething()
    {
        //use repository here
    }
}

Looking in the constructor of this class, you can see that it creates its own dependency by doing

_repository = new CarModelRepository();

In this case, the Controller contains a dependency to the concrete CarModelRepository.

If you want to apply Dependency Inversion principle, then you will remove the instantiation there and inject the dependency as an abstraction. In this case, the controller will look like this:

class Controller
{
    private ICarModelRepository _repository;

    public Controller(ICarModelRepository repository)
    {
        _repository = repository;
    }

    public void DoSomething()
    {
        //use repository here
    }
}

Notice that now the repository is ICarModelRepository which is the interface, not the concrete type anymore and the Controller does not create it (as a concrete dependency), but it receives it as an abstract dependency (the interface).

This is an example of what Dependency Inversion principle means and in your case, you are not sending a dependency to the repository, but you are sending an object which it needs to save. Objects that represent modules of the application are things that you should consider as dependencies and inject them, as the case of a repository. Your domain objects are not the dependencies to be injected so, to answer your question:

doesn't repository implementation violate the DiP principle?

No, it doesn't.

meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
  • thanks for the response, but at some point repository will need to create an entity using new keyword like in FindByName method – hasrthur Mar 13 '19 at 18:29
  • 1
    @arthur.borisow that is the point where you will use a factory pattern, which will be injected also in the repository. – meJustAndrew Mar 13 '19 at 18:31
0

In your example, the Repository implementation (which is in infrasctructure layer, outer circle) creates an entity (domain layer, inner circle), so the lower level class,Repository (implementation,) depends on the entity class (higher level, inner circle). This is the right direction. DiP Principle says you cannot have the opposite, your entity class should not depend on an infrastructure class.

BUT, you missed another thing that uncle bob sad in his book. He says the data that cross boundaries between layers should be simple data structures, not object with logic. In others words, the repository should return an Data Transfer Object, not an entity object.

felipeaf
  • 377
  • 2
  • 11