Lately for the Flutter projects I have been working on, I have decided to adopt a feature-driven architecture using Clean Architecture. With a software design done in great detail it turns out to be very suitable in the division of logic.
These days, however, a question has arisen for me regarding the use of repositories. In an application where Firestore is used and repositories are the layer where I interact with such data is it right to have a division of them on the various features while still going to work on the same collections? (Different parts consisting of different features but touching the same collection of data). At the end of the work I might find several repository classes with the same code even though they belong to different features.
Clarification would be greatly appreciated! Thanks in advance
The repository is a great model to retrieve/manage data from an external data source.
This model is entity oriented. Maybe that’s what prompted you to ask this question.
I think feature-driven design doesn’t dictate keeping everything feature-oriented.
I mean this design determines your domain layer classification, but not everything.
Just because you have one handler per feature doesn’t mean you have to recode the repository multiple times.
The repository is part of the infrastructure layer. Its interface can be shared by several projects/modules if you have several domains on your application.
Somewhere in the domain layer (in a feature class manager) you will use a repository to load some data.
What you need to make sure is that you use an interface and don’t depend on the repository implementation (maybe this is already clear to you, just a point for other readers).
For example, you can use an IClientRepository in OrderReservationHandler to load customer data.
The difficulty you will face regardless of which design you use is:
- What this repository will return as a result?
- Should I load only the entity itself or even its relationships?
Regarding the first point, there are several ways:
- The first and my favorite is to return a DTO object (classes that only contain properties, no methods). And if necessary, convert these classes to a domain model (a class under your domain layer).
- The second: some developers prefer to return the Domain Model directly to reduce data mapping.
For the second point I think that whatever the design used, it is always the same difficulty:
- Should I load the entity and its associated entities?
- Should I only load the identifiers of the associated entities and do a lazy loading?
- Can I load an aggregation of entities (arbitrary joins) to reduce data loading time and make things simpler?
My opinion is that it depends on the context.
A design is used to make things simple, not to complicate things.
If I’m using a repository model entirely in a system and faced with a screen implementation for data searching using many filters, I will
Feel free to use a custom query or stored procedure to load aggregated data, I won’t complicate the implementation or make loading very slow because of the model.
I think a very important point here is knowing when to break the rules. There is no model that solves all problems.
Additionally, a model usually only solves one problem.
The conclusion, in a software project we will always need:
- Full loading of the entity => slow mode
- Loading the entity without associated data (only the relationship identifiers) => quick mode
- Custom data loading (arbitrary joins) => custom mode
Good design will help you easily distinguish these 3 uses.
Answered By – hatem87
Answer Checked By – Gilberto Lyons (FlutterFixes Admin)