4

This might be an easy question for experienced software engineers.

I'm currently reading the book Clean Architecture by Uncle Bob, and I'm trying to implement clean architecture in a Java project.

Now, in my project, I came across the exact same situation as described here in Chapter 17 of the book:

enter image description here

The red line is the boundary between the high-level business rules component and the low-level database component. Thanks to the DatabaseInterface, that is part of the high-level component, but implemented in the low-level component, the dependency rule is satisfied.

However, how can the BusinessRules get an instance of an object that implements DatabaseInterface without violating the dependency rule?

The implementing class DatabaseAccess is in the low-level component, and the high-level component is not supposed to know anything about the classes in the low-level component.

In other words, we can't instantiate a DatabaseAccess object inside BusinessRules, because this would violate the dependency rule.

How is this problem generally solved?

Note:

The same situation is also described in Chapter 18:

enter image description here

And here again, how can Client get an instance of ServiceImpl without violating the dependency rule?

The book doesn't give any hints about how this is done in practice. I would be very interested to know what's the correct strategy for solving this situation.

7

Your application structure should have one "Entry point" component(with main method), which will "know" about all other components/libraries.
Responsibility of entry point component will be to glue together high-level abstractions and low-level implementations.

.----------------.       .----------------<I>-.       .-----------------.   
| Business rules | ----> | Database interface | <|--- | Database access |  
'----------------'       '--------------------'       '-----------------'  
        ^                         ^                            ^  
        |                         |                            |  
        |                         |                            |  
        |                  .-------------.                     |  
         ----------------  | Entry point |  -------------------  
                           '-------------'  

In entry point you can instantiate business rules objects and pass database interface implementations without business rules to know about implementation details.

public void main()
{
    // MyDatabase implements IDataAccess
    IDataAccess dataAccess = new MyDatabase(connectionString); 

    // BusinessRules expect an instance of IDataAccess as constructor parameter
    MyBusinessRule rule = new MyBusinessRule(dataAccess);
}

This approach is well known as Dependency injection. There are a bunch of Dependency injection frameworks exists which will automate this process. But for sake of learning will be good to do it manually and solve possible problems by yourself.

  • 1
    I got it! Now I think I finally understood dependency injection, after several years of first hearing about it. In your above diagram, the middle box should be DatabaseInterface, right? – weibeld Jun 8 '18 at 20:55
  • @weibeld, correct, fixed diagram. – Fabio Jun 8 '18 at 21:12
1

A typical approach is to use some kind of factory (Wikipedia: Factory Method Pattern). Your high level code requests an object from the factory, and the factory knows from which concrete class the object has to be created.

Edit: The implementation of the factory (not its interface) is specific to the application, it is part of the configuration. It "glues" together business logic and lower layer, but is not part of either one.

The factory approach is useful if the decision, when and how often objects of the lower layer need to be constructed is in the business logic. In other cases, other inversion of control mechanisms can be used, like, providing the business logic the objects during business logic startup (see answer from Fabio).

  • Thanks. What about dependency injection? Could this be another approach to solve the same problem? – weibeld Jun 8 '18 at 20:42
  • In which layer this kind of Factory should exists? It cannot be in Business rules layer, because then Business rules should "know" about low-level implementation. – Fabio Jun 8 '18 at 20:48
  • I was thinking exactly the same thing. If this factory is part of the high-level business rules component, then this component as a whole would still have dependencies on the low-level implementations (which violates the dependency rule). On the other hand, if the factory is part of a low-level component, then the high-level business rules component would have a dependency on this low-level component since it uses the factory (which violates the dependency rule). – weibeld Jun 8 '18 at 21:01
  • So, it seems that it is dependency injection that goes very well together with Inversion of Control/Dependency Inversion, which is the backbone of Clean Architecture. – weibeld Jun 8 '18 at 21:03
  • @Fabio: The factory interface exists in business rules layer, the factory implementation (at least the part that contains the knowledge about which object to construct) belongs neither to business layer, nor to the lower layer. It is in fact part of the glue of the system (configuration) - similar to what you call entry point in your answer. – Dirk Herrmann Jun 8 '18 at 22:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.