Reputation: 3499
I have the following folder structure for my application
app
core
features
feature1
domain
entities
entity1
entity2
entity3
entity4
entity5
entity6
data
models
model1
model2
model3
model4
model5
model6
presentation
feature2
domain
entities
entity1
entity2
entity3
entity4
entity5
entity6
data
models
model1
model2
model3
model4
model5
model6
presentation
Model 1 to 6 for both features are exactly the same and more are coming as the application scales. This is becoming hard to maintain. Does clean architecture allow for sharing models and entities across the multiple features? Would that be done through the core folder?
Upvotes: 5
Views: 3318
Reputation: 3264
I'm assuming you're following the ResoCoder course. I did too. I used that design in our team for a few weeks before realizing there soon become problems with it (which ResoCoder himself realizes if you check the Github issues and responses for his repo):
Hence, for my team's app (getting quite complex now), we've adapted this which seems to work:
(ignore the 2 \core
directories, that's by mistake. There's meant to be only 1)
Then, inside all of these top-level directories (excluding /core
- that's specifically for things like API clients, routers, etc.), there's folders for each feature. Ex: authentication
, settings
, posting
, etc.
Then, here's the important bit, in each of these feature-split directories (ex: /domain
, /presentation
, etc.) we have a sub-directory called /shared
that resembles what each folder needs to look like, except it just contains functionality that's categorized as (example) domain or data. This stuff is then split between all features.
For example, if I have an app that allows users to post content, I'm going to create the post
entity (using ResoCoder terminology) inside the /posts
feature. Except, UH OH, I need to have it displayed inside the /feed
feature as well! This is then a perfect case for /shared
inside the general /domain
directory.
Let me know if this helps, or if you have any further questions!
Upvotes: 4
Reputation: 51363
Yes you can and you maybe should not do it.
Yes, because the clean architecture doesn't make a statement about this. As long as the dependency rule is honored you are compliant in terms of the clean architecture.
But you maybe should not do it, because there are other principles and considerations you should take into account.
First, you should ask your self if it would be a violation of the single responsiblility principle. Sometimes things look the same but are not really douplicated code. It's more an accident that they look the same. The question is "Who is the change trigger?". Usually the features change for different reasons and thus the features use cases and entities change for different reasons. If so you should not share the models between them.
Second, from a DDD (domain driven design) perspective the features can be in different bounded contexts. In this case you can have two entities with the same name, but they have different meanings in the differnt context. Therefore, the models have different properties and different methods.
If you decide to share the modles you should take a close look at them in intervalls and scan the properties and methods. Are there properties and methods that are exclusively dedicated to one feature? If so you are maybe mixing concerns.
Finally if you are facing problems like "Uhh, we changed someting here and broke something there", you should rethink if the sharing of some code is a good way to go. Sharing of code always couples code, because all clients depend on the shared code. It's a trade off between duplication (maintenance costs) and dependencies. Principles like the SRP help you to make an educated guess.
Upvotes: 4
Reputation: 190
Does clean architecture allow for sharing models and entities across the multiple features?
I think DRY principles should be applied whether you use clean architecture or not.
As for the answer:
I think you could abstract your shared models and entities into separate modules or packages. If it's all dart code, I suggest choosing packages. You can place it inside the root project (Monorepo) or separate it to another repository, this way you could achieve modularity by abstracting the all layer of shared dependency (abstract class, interface, clients, or maybe repositories) out of the main application
There is a good video about this topic on Google I/O'19, it is about Android but you can get great insight and applied to general mobile development. I suggest you give it a try
Upvotes: 1