At my work we follow this layered architecture: http://www.oracle.com/technetwork/java/dataaccessobject-138824.html
We have the following:
Spring Data Repositories - Custom @Query methods that run custom SQL
Database Services - Calls the repository interfaces to persist or get JPA model data from the database
JPA Models - Contains our Hibernate JPA models that just have getters and setters
DAOs - calls the database services to get data and convert them to DTO objects or convert our DTO objects to JPA models to pass to the database service to save
Business Objects (BO) - Contains our business logic and calls DAOs to save or get data (DTOs)
DTOs - Same as the JPA models but with properties that might not be in the database
These projects have separate purposes:
- One project is an internal support tool
- Another is a monitoring tool for our customers
- Another is an custom engine that drives the purpose of the business
My issue with this architecture is if I want to add new functionality like getMostRecentOrder() to a module that depends on our Common project, I have to create 4 methods instead of 1. Also we have another layer for one of our applications that abstracts Spring as engineers don't want/need to know about it which creates 5 methods total.
Has anyone followed a similar layered architecture like this and was able to resolve or find a better solution?
The architect that I work with likes this structure but I am starting to really dislike it as it is tedious for me to add all these methods just to get data out and it seems like I am writing a lot of duplicate code with just data type changes because of the layers that are in place.
The architect wants our BOs to be generic like WeatherBO that has all the business logic for weather, EventBO for all the logic for events, etc. My issue with that is our BOs are starting to be 1000 lines of code and I feel depressed when we have large classes.
Can anyone provide some insights on some successful Java layered architectures that is simple (3 layer vs my 4 or 5 layer), maintainable, flexible, scalable, etc (basically a developer's number 1 dream haha)?
Update: Providing pseudo code of the layers
Repository
public interface IOrderRepository extends JpaRepository {
@Query("FROM Order o WHERE o.time = Max Time")
Order getMostRecentOrder();
}
Database Service
public interface IOrderService extends IService<Entity ID, Entity> {
Order getMostRecentOrder();
}
@Service
@Transactional
public final class OrderServiceImpl implements IOrderService {
@Autowired
private IOrderRepository repository;
@Override
public Order getMostRecentOrder() {
return repository.getMostRecentOrder();
}
}
DAO
public interface IOrderDAO extends IDAO<DTO Key, DTO> {
OrderDTO getMostRecentOrder();
}
@Service
@Transactional
public final class OrderDAOImpl implements IOrderDAO {
@Autowired
private IOrderService service;
// Spring Conversion Service that uses Dozer to convert JPA model to DTO
@Autowired
private ConversionService conversionService;
@Override
public OrderDTO getMostRecentOrder() {
Order order = service.getMostRecentOrder();
return conversionService.convert(order, OrderDTO.class);
}
}
BO
@Service
public final class OrderBO {
@Autowired
private IOrderDAO orderDAO;
public OrderDTO getMostRecentOrder() {
return orderDAO.getMostRecentOrder();
}
}
Web Service Call
@PATH("/orders")
@Service
public class OrderResource {
@Autowired
private OrderBO orderBO;
@GET
@PATH("/getMostRecentOrder")
@Produces(APPLICATION_JSON)
public Response getMostRecentOrder() {
Response response = Response.ok().build();
OrderDTO orderDTO = orderBO.getMostRecentOrder();
response.withEntity(orderDTO).build();
return response;
}
}
This is just an example but the BOs are a lot bigger than my provided example and some almost 1000 lines of code or close. Also I'm afraid that the DAOs could get pretty big as well. We have a DAO, Service and Repository, for each DTO and JPA model. The BOs usually are a collection of common DAOs, for example, an OrderBO could have an order DAO, invoice DAO, customer DAO, etc.
I don't think there is a right or wrong answer here but what I usually do is...
I'd create a "database" project. This project would have all database interactions.
Then I'd create a "service" project, this project would contain all business/service operations. This one also interacts directly to the "database" project. This project would expose all business methods such as saveClient(Client client), deleteClient(Client client), updateProjects(List projects) and so on.
Then I create N "client" projects than will interact with my "service" project calling the interface methods.
Just a couple of side notes. 1- Clients are client applications like a web application or a desktop or mobile app. They all "could/should" interact with the same service layer depending on the requirements. 2- This is a conceptual overview.
I try to keep everything pretty standard. However, your "complaining" is that if you have a new "client" requirement like "display the projects in a certain order", you need 3 or 4 new methods. Yes, you will need to write 3 or 4 new methods, depending on the number of layers you have. I remember projects using the whole J2EE stack where a simple CRUD operation would require 12 classes from DAO's, facades, interceptors and a few others.
Personally, I try to follow the KISS principle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With