1

I hope you are all doing well. I am currently working on a multi-layered application and have encountered a few challenges that I would appreciate your input on.

Here's the situation:

I have an application with the following layers: Domain, Application, Infra.Data, Infra.IoC, and WebUI (MVC), with the appropriate project references.

I have an action in a controller that needs to display various pieces of information about a course, for example: course name, number of students enrolled, creation date, and whether it is active. Additionally, it should display information about the course enrollments, such as student name, enrollment date, start date, percentage completed (which I get from another entity), etc. It is an overview of the course.

This is where my questions start. How do I get this information as needed? For example, various entities are used to populate the view, but I don't want to have to load all the information from all the entities, just the necessary ones. In this case, I would need a DTO, but the DTOs should be in the Application layer.

Since the interfaces are in the Domain layer, how would I declare, for example, the following signature in an interface: Task GetDashboardByCourseIdAsync(Guid courseId);

The above approach would allow me to have a LINQ select statement in the Infra.Data layer that fetches only the information I need, avoiding bringing in a lot of unnecessary data.

This DTO could be the representation of my view, containing properties from more than one entity and only those that I actually need. However, according to my research, it is not correct to have a DTO in the Domain layer.

I'd really appreciate the help, guys.

With this question, I hope to gain insights and guidance on structuring my application effectively, particularly regarding the handling of data retrieval and presentation in a multi-layered architecture. Specifically, I seek advice on optimizing the retrieval of specific information without unnecessary overhead, while adhering to best practices and maintaining a clean architectural design.

1 Answer 1

0

Disclaimer: I'm not an expert in "Clean Architecture" as a named thing, but I have a lot of experience with the ideas behind it.

In these types of architecture you have the layers of the architecture and the technical roles and responsibilities assigned to them. You do have some latitude to choose how rigidly you enforce the architecture, or the finer points in how you choose to implement it.

How do I get this information as needed? For example, various entities are used to populate the view, but I don't want to have to load all the information from all the entities, just the necessary ones. In this case, I would need a DTO, but the DTOs should be in the Application layer.

Design Considerations

When designing layers (i.e. domain, etc) - meaning the actual programmable interface they presents to the other layer(s) that will consume them (e.g. the UI) - there will be tensions between them: your UI will want methods and data structures that are ideally suited to it, where as your logic layers may try to be more agnostic and reusable. This is where that latitude comes in. Here are some approaches, and keep in mind that they do not have to be mutually exclusive.

  • Backend-For-FrontEnd (BFF). In this approach the backend lives to service the frontend. Therefore you would design and implement methods and data structures that were fine-tuned to what the UI needs. This can makes sense if the UI is quite complex and/or has functional and non-functional needs which tend towards the more extreme; it possibly also assumes that the logic layer will never need to be reused by other UIs.
  • Purely Agnostic / Domain Driven. In this approach the UI (and its designers & developers) just have to suck it up, and use whatever methods the logic layers choose to expose. You would only want to rigidly enforce this approach if knew you'd have to support many different UI's (consumers of the logic layers) overtime, and therefore showing favoritism to one would be a nightmare.
  • A pragmatic mix of both - perhaps agnostic methods and data structures for anything that is basic/core/common type functionlaity - like simple CRUD etc; plus BFF type methods and data structures for more specialised functionality.

Qualities like performance are useful to keep in mind; you probably don't want to create methods that place emphasis on being agnostic or "reusable" at the expense of bad performance (e.g. bringing back way too much data, or forcing the UI to iterate through loops generating many requests).

I once worked on a project where the dev team for the legacy backend system insisted on providing only one integration method, which provided "all" the data they thought the mobile team would ever need. The issue was that most of the time the mobile team only needed 5-10% of the data being returned, and the backend process was trying to fetch so much data it often timed out. This was not using Clean Architecture but the trap applies universally.

DTO Considerations

In simple and smaller scale solutions (home projects) I often have one set of DTOs which are used for moving data between all layers - not just the database to logic (& IoC).

This works well in situations where the logic layer is largely pass-through and the data structures are never overly complex. It means I'm choosing to code and reuse one object rather than create and maintain two which in practical terms do exactly the same thing.

I'm banking on the assumption that this approach will work 90% of the time, that I can still create more specialized DTOs if needed, and that if things radically need to change I can still refactor my way out of trouble. In these situations it's also expected that the one code-base and technology stack is all that will be needed.

There are definitely cases where the DTO's that provide data into the logic layers are different from those used by the logic to provide data to the UI. I would think that approach would be useful in situations that were larger, multi-technology and more complex, rather than simple and small scale solutions.

The Design consideration further above are also relevant. For example, in a BFF situation the data objects are more likely to be different from the Infra ones - You challenge is to determine if that justifies having them in separate layers, with the inter-layer visibility constraints that brings. If you have a large dev team - e.g. with an infra/app/UI split - it might make perfect sense to keep them separate.

Key takeaway:

Remember that styles of architecture are there as a starting point, but you always have to decide how you will interpret and apply them to your real-world situation.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

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.