I usually structure my codebase following Clean Architecture principles, which helps ensure scalability.
If you look at the root folder structure of the projects I work on, you’d see something like this (for more complex projects, it might vary, but the general idea remains the same):
- 📂 /presentation → UI code
- 📂 /domain → Business logic (core functionality)
- 📂 /data → Data access & communication
Beyond keeping things organized, it’s crucial to enforce dependency rules.
The key rule is:
✅ presentation & data → Can depend on domain
❌ domain → Must NOT depend on anything
The challenge is that it’s relatively easy to break this dependency scheme if not careful, so having mechanisms to prevent violations is essential.
Alternatives to Enforce Dependency Rules
One approach I’ve seen in some projects is defining a separate module for each layer (presentation, domain, and data). This prevents the project from compiling if the rules are broken, making it an effective safeguard. However, this approach comes with some drawbacks:
⚠️ It increases complexity and boilerplate, as multiple modules need to be managed.
⚠️ It significantly impacts compilation times and memory consumption.
I still remember a particular project where the build used 19GB of RAM. Insane!
A Better Alternative? ArchUnit 🛠️
ArchUnit lets you define architecture rules as tests. If a dependency violation occurs, the test fails—helping maintain structure without compromising performance.
✅ Works with Java/Kotlin (similar tools exist for other languages).
✅ No need for separate modules—faster builds!