3

I'm starting a new project and I want to follow a Clean Architecture(ish) approach. I've modeled my projects in that manner (attached diagram).

enter image description here

For the API I'm using FastEndpoint since I like it, it's performance, and the pre-built tools it comes with (such as tokens, validations, mappings, bus and queues).

I'm used to N-Tier applications. Over the years been changing styles where I rely on interfaces I could easily swap part of the application or database if needed (to be honest never happens).

In the following case my endpoint has interfaces injected from the application project that contain the methods I need to perform an action (for instance I have an IUsersManagment that has methods for creating/updating/deleting/changing password/etc... for my users). Those also include needed validation to perform for handling user data. I would have something similar for other aspects of my application.

My dilemma is: should I use the interfaces as described, which I believe gives separation between the presentation and application layer (being careful that I have an implementation for everything and go though the application layer). Or should I use a Mediator approach? In such case the presentation sends a command that is handled by a handler - giving maybe better separation. In such case I saw that the handlers and commands are created in the application layer and that means that there is tight coupling between the layers - so does that no mean that the separation is not "clean" and I'm coupling the 2 layers? What about performance hits when using this approach? What I was thinking is maybe have another project that will contain the Mediator commands and will be referenced by the presentation and application layers. In any case when replacing or adding another presentation layer it would require that layer to call the same even handlers instead of using the interfaces?

I'm a bit confused... What am I missing here? What is the advantages and common scenario?

1 Answer 1

4

go away

Hard disagree here. Having your persistence layer accessed directly by your presentation layer is a recipe for disaster.

Architecture discussion can run long so I'll keep it to that mention, but I strongly urge you to revisit your idea of giving the presentation layer direct and unfettered access to your data store.

Or should I use a Mediator approach? In such case the presentation sends a command that is handled by a handler - giving maybe better separation.

You're crossing your wires.

When using an interface, lets say IPersonService, you interact with that interface using concrete models, e.g. Person in Person GetById(int id) or void Save(Person p).

When using a mediator pattern, your command (e.g. CreatePerson) is not the equivalent of the IPersonService, it's the equivalent of the Person model. It is your command handler (e.g. CreatePersonHandler) that is the equivalent of the IPersonService. Using the mediator pattern, that concrete command handler is hidden from the consumer (because the consumer only talks to the mediator), in the same way that an interface would hide the concrete implementation of that interface.

In such case I saw that the handlers and commands are created in the application layer and that means that there is tight coupling between the layers

More crossed wires leading to a problem that's not there. I can address this, but it would be helpful if you draw out both of your approaches. Plan what an interface-oriented approach would look like, and what a mediator oriented-approach would look like.

Wherever you put the interface and its models in the first approach, you would place the commands and the mediator; because they both represent the interaction between the consumer and the application layer. Obviously, the interaction itself must be publicly known outside of the application layer, by the very definition of what it is.

It is only the concrete implementation of the interface (e.g. class PersonService : IPersonService) and the command handlers (e.g. CreatePersonHandler) that would be kept private in the application layer, without a consumer being directly aware of it.

The conclusion to draw here is that in terms of "clean separation", the scenarios are identical. The difference between them is one of implementation, not a degree of separation.

What about performance hits when using this approach?

Performance is irrelevant when considering clean architectural approaches. You don't use a software architecture for its runtime performance. Don't confuse the benefits of clean coding and that of runtime optimization because they are two completely separate worlds with different goals.

Summarizing your overall question, I think you are dealing with a misinterpretation of the software architecture you've been learning about, and it's causing to you protect against phantom issues and focus on the wrong goals. I suggest you revisit your material on the subject because it's significantly harder to have to fix those misinterpretations by repeatedly learning the hard way.

3
  • Thanks. That helped me a lot. Especially understanding what is the role Mediator Handlers. A follow up question: you mentioned that the presentation should not reference the repository, but from everything I've see in Clean Architecture that is how it's done - separating the repository from the application and having it in the same level as presentation and the presentation is the glue that binds all DI together. Where would you put it? Commented Nov 27 at 13:06
  • @developer82 Usually, repositories are abstracted behind an interface. For example, you may have an IPersonRepository interface with an EntityFrameworkPersonRepository implementation. While the implementation lives in the infrastructure, the interface belongs to the Domain, the Application, or in-between. The diagram in your question already shows an Interface-layer, which looks suitable.
    – pschill
    Commented Dec 2 at 15:21
  • @pschill: I personally follow the architecture that you outline here but I just want to point out that domain-centric is not the only existing architecture. If you go N-tier (or layered, as some people prefer to call it), that would be a case where the persistence layer defined its own interface, to then be consumed by the application layer. This is a non-domain-centric architecture with some real world use cases. I do advocate for domain-centric - but sometimes context can change what's best for a particular situation.
    – Flater
    Commented Dec 3 at 0:54

Your Answer

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

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