In Java language, we have encapsulation at many levels. First, is the class, as it may has private data
members and methods. It has the benefits of hiding complexity and provides a layer of abstraction.
Second is the package. It provides access rights to sibling classes inside it. Classes defined without being public are private to the same package classes and not exposed outside the package. So, packages in Java provide a means of encapsulation and details hiding inside it. There are also other means of encapsulation in Java, but I am not concerned about them in this post.
For more details about controlling access to class members for class, package, subclass and the world, see: https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
After this introduction, my question is, how can we organize project classes into packages? I am describing here two ways and comparing them. I will provide example product that is related to finance. I will assume both ways are using the same famous separation of concerns such as having separate layers for entities, data access repositories, business logic and web layer.
1) Organize Packages based on Layer:
- com.finance.entity: stores all data bases entity classes.
- com.finance.repository: contains all data access classes.
- com.finance.business: contains all business classes.
- com.finance.web: stores all web layers that include controllers and rest classes.
2) Organize Packages based on business domain :
- com.finance.user: includes all classes from all layers that are related to user.
- com.finance.account: includes all classes from all layers that are related to account.
- com.finance.transaction: contains everything related to transaction.
- com.finance.charts: contains everything related to charts.
Each package has separate classes for each layer. As example in account package we will have:
- AccountEntity
- AccountRepository
- AccountService
- AccountRest
- Any other classes related to Account
In approach 1:
- All applications folder/package structure will look the same as long as they use the same described architecture. There is no identity exposed in package names.
- The utilization of java package encapsulation is almost eliminated or ignored.
- This thinking may be imposed by functional devision of code that match organizing your teams to Functional Teams rather than Cross-Functional Teams.
In approach 2:
- We utilized the package as a component concept, that you can have private classes to the package.
- You will have a unique identity for each application that matches its domain.
- Each package can be easily separated into micro-service.
- Encourage or at least consistent with cross-functional teams organizations.
Modifiability:
Assume you want to change the transaction date to be transaction date and time. This change will required you to change all layers to accommodate this change.
In approach one: you have to navigate to 4 different packages to change them. I found this navigation tedious and distracting.
In approach two: all your changes are contained in one package only. Other packages will not be affected at all, except in case you will change a public class-method.
This is why I prefer approach two and see it consistent with Java package concept as well as Agile cross functional teams and micros-services.