What a good layering solution should do
It must handle the following problems:
1. Dividing a system into layers based on modularization principles, such as single-direction dependency, limited entry of components and so on.
2. Compatible with modern dependency management tools such as Maven
3. Allowing for evolving into a distributed system in the future
Here I present my final version of layering after so many years’ development of java webapps.
Layers
Components’ Responsibilities
Component | Responsibility | Naming Conventions |
Biz Layer – Neutral Services | Most reusable core business logic(CRUD, Biz Modelling etc.) |
Bean: Xxx Facade: XxxService Repository: XxxRepos/ XxxDAO |
Application Layer – Front-End Managers | The complete logic of use cases for front end users (customers) |
Bean: FoXxx Facade: FoXxxManager |
Application Layer – Back-Office Managers | The complete logic of use case for back office users (admin, staff etc.) |
Bean: BoXxx Facade: BoXxxManager |
Application Layer – Partner System Service Providers | Remote services for partner systems which belong to the same company |
Bean: SsXxx(Ss= Some System) Facade: SsRpc |
Web Layer – Front-End Controllers |
Web MVC controllers to serve front end users with browsers Presentation only. No biz at all |
Bean: N/A Facade: FoXxxController |
Web Layer – Front-End Web Services |
Web Services to serve front end users’ rich clients (desktop/phone app) Presentation only. No biz at all |
Bean: N/A Facade: FoXxxResource/FoXxxSoap |
Web Layer – Back-Office Controllers |
Web MVC controllers to serve back office users with browsers Presentation only. No biz at all |
Bean: N/A Facade: BoXxxController |
(Continue)
Component | Bean | DTO | Dependency on Layer Below |
Biz Layer – Neutral Services |
Fine-grained entity Data oriented |
Beans as DTOs |
N/A |
Application Layer – Front-End Managers |
Very coarse-grained Crossing multiple biz entities User oriented |
Request/Response pairs as DTOs Response has error props |
Order order = convertSomehow(foNewOrderRequest); authService.permissionCheck(currentUserId…) ; orderService.saveNewOrder(order); itemService.doAnotherThing(…); FoOrder foOrder = combineSomehow(order, item, permission); return FoResponse.success(foOrder); |
Application Layer – Back-Office Managers |
Very coarse-grained Crossing multiple biz entities User oriented |
Similar with above |
Similar with above |
Application Layer – Partner System Service Providers |
Fairly fine-grained Partner system oriented |
Beans as DTOs |
Order order = convertSomehow(ssOrder); itemService.doAnotherThing(); SsOrder ssOrder = addOrRemoveProp(order); return ssOrder; |
Web Layer – Front-End Controllers | N/A | N/A |
FoNewOrderRequest foNewOrderRequest = webFormToObj(httpRequest); FoResponse foResponse = foOrderManager.doSth(currentUserId, foNewOrderRequest); httpResponse.putSomehow("data", foResponse.getData()); httpResponse.putSomehow("error", foResponse.getError()); |
Web Layer – Front-End Web Services | N/A | N/A |
FoNewOrderRequest foNewOrderRequest = jsonToObj(jsonRequest); FoResponse foResponse = foOrderManager.doSth(currentUserId, foNewOrderRequest); return toRestResponse(foResponse); |
Web Layer – Back-Office Controllers | N/A | N/A | Similar with "Front-End Controllers" |
Be Pragmatic (Anti-Patterns)
1. Managers are allowed to call repositories(DAOs) directly. It is annoying to have to have a same-name method in XxxService to wrap its counterpart in XxxRepo.
2. BoXxx/BoRequest/BoResponse should rely on and be allowed to extend FoXxx/FoRequest/FoResponse, and Back office Controllers should be allowed to call Front end managers. This is because back office users are also users. If you don’t allow this "slight violation", you may end up write tons of duplicate code in Bo Managers.
3. Web layer annotations such as @XmlElement should be allowed to put on application layer beans and DTOs. If not, you will have to create a lot of duplicate beans/DTOs on web layer.
Maven Projects
(Note: webapp must have "runtime" dependency on impl_fo and impl_bo, which has not been shown in the diagram.)
This is a ideal version of separation. The problem is it has too many maven projects.
A pragmatic version
Support for Distributed System Design
1. The maven project "intf-pso" is used as the RPC client stub for partner systems
2. The maven project "intf-fo" can be used as the RPC client stub for web service clients if they are also written in Java
3. The web layer can be an independent system immediately without any compilation error since they only rely on app-layer interfaces at compile time. Just let intf-fo and intf-bo be its client stub. In advance, the web layer’s components can each be an independent system.
If the web layer is transferred to another team
If the web layer is going to be transferred to another team in your organisation, the app layer should go with it. Otherwise, a small change will involve two team’s work, which is unbearable.
They will now be responsible for all the user-specific cases and considered as your partner system.
The original FO and BO managers should not rely on the biz services any more. Instead, you must create pso interfaces to wrap them and provide services to the original managers.
A demo webapp
For a demo webapp with most of the components describe, see this project on github.