0

I am trying to follow Clean Architecture by Uncle Bob. I have 3 layers:

  • Core (Hosts business logic, and is the central layer)
  • Application (Host application usecases, and is directly above the core)
  • Infrastructure

I know the responsibility of the Infrastructure layer is to host any external dependencies that our application needs. But I have few questions about Infrastructure layer:

  1. Is the Infrastructure layer responsible for fulfilling interfaces defined only in Core? Or is it supposed to fulfill the interfaces of any other layer that needs an external dependency. For example, Application or UI etc.

  2. Infrastructure layer is always depicted as the last layer in Onion Architecture, how come it can depend upon the Core? Aren't the layers supposed to directly depend on the layers immediately below them?

  3. Let's say I have an interface IExternalDep in the Core and I created its implementation in the Infrastructure layer. Now, how can my other layers use this implementation? What is the way to provide the implementation at runtime without directly depending upon the Infrastructure, as we know it is the outermost layer.

1

Your questions seem to be rooted in the assumption that there is only one way to skin this cat. There is more than one way, so most of your questions end up being answered as "it depends".


  1. Is the Infrastructure layer responsible for fulfilling interfaces defined only in Core? Or is it supposed to fulfill the interfaces of any other layer that needs an external dependency. For example, Application or UI etc.

There are plenty of examples where interfaces for services are defined outside of the Core/Domain/... project, e.g. Application. Similarly, your top-level application (e.g. web app) may have its own need on some external service in its middleware.

Where the contract is defined is not something Infrastructure cares about. It simply fulfills the contracts it can.

  1. Infrastructure layer is always depicted as the last layer in Onion Architecture, how come it can depend upon the Core? Aren't the layers supposed to directly depend on the layers immediately below them?

Based on 1 and 2, it seems like your Core is defined as the collection of your contracts (that is one way to do it, but not the only way). In that scenario, your Core project will permeate through your codebase, as it quite literally defines the contracts that facilitate the interaction between these layers.

In this approach, it is pretty much guaranteed that all other projects depend on your contracts project, which for you seems to be Core.

For reference, I often see a specific separation of the core logic (generally called Domain or Core) and the contracts (unsurprisingly called Contracts), specifically to prevent having the core logic permeate through the codebase because the contracts need to. But that is not a hard set requirement. I think there is some margin of contextuality here on how clean you have to keep this.

  1. Let's say I have an interface IExternalDep in the Core and I created its implementation in the Infrastructure layer. Now, how can my other layers use this implementation?

Generally speaking, your DI container handles this.

First of all, don't forget that even though your code is separated into layers, during actual runtime, these layers get chained together and work as a whole. Therefore, your DI container has access to each and every layer/project in your codebase, whether directly or indirectly.

In either case, it is the DI container who connects your layers. It will instantiate your FooController, pass it the needed IFooService dependency, and in doing so it will instantiate a FooService and pass it the needed IFooRepository dependency, and so on. However you've defined your dependencies, across layers, the DI container will stitch it all together based on how you've configure the DI container, i.e. having told it which implementation of an interface it should use when a dependency of that interface is requested.

What is the way to provide the implementation at runtime without directly depending upon the Infrastructure, as we know it is the outermost layer.

This all depends on how you structure your dependencies. Most commonly, the top-level application (e.g. web app) references all needed projects specifically so that it can configure the DI container (which stitches it all together).

However, it's also possible to delegate this through and let each layer perform its own DI configuration. In that case, the top-level application (e.g. web app) passes the DI config object to the layers, and the layers then register their needed configuration.
This way, it's possible that A passes the DI config object to B, who in turn passes it to C, without A needing to depend on (or even know about the existence of) C.

But more commonly, this level of secrecy isn't really necessary, and it's considered normal for the TLA to have access to all projects purely for the DI registration (nothing more).

3

how can my other layers use this implementation

At compile time all other layers can "use" (= "depend on" = "know the definition of") the interfaces that are defined in the the core (i.e. IExternalDep or ICustomerRepository).

What is the way to provide the implementation at runtime without directly depending upon the Infrastructure

The answer is Dependency injection.

Your busineslogic and uscases only depend on the interfaces in the core.

There is an initialisation module that wires up your application. This initialisation module also knows (depend on) the classes of the infrastructure layer. The wireup tells your usecase which implementations to use:

public void wireupMyApp() {
 ICustomerRepository customerRepositytory = new MyDatabaseCustomerRepository(....);
 MyCustomerUseCase customerUsecase = new MyCustomerUseCase(customerRepositytory, ....);

}
1

I get the feeling that you are forgetting one important principle that permeates all the Clean Architecture. The stable dependency principle. AKA SDP.

In few words, what SDP proposes is; make code that changes often depend on more stable code, not otherwise. Make stable code by making this one depending on abstractions not concrete implementations.

Applied to C.A, it could be translated into push concrete code outwards and make this code depend on inner layers. Make inner layers to be stable by adopting abstractions instead of concrete implementations.

So the answer to #1 and #2 is, not necessarily.

#1 The business could extend domain features by implementing domain ports designed to this end. Outer layers can do it too. Even replace adapters from inner layers if need it.

#2 I would dare to say that if it follows SDP, doesn't matter if the inner layer is the immediate one or the next.

The answer to #3 is rather simple. Follow the principle of dependency inversion. Applied to C.A, make outer layers inject concrete implementations downstream. Ideally, you will make the application layer to be the composite root.

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.