Reputation: 42957
I am developing a Spring application that use Spring Data JPA to access to the data layer.
So basically I have n entity classes and n related repository classes to access to the data of the database table associated to the entity classes, something like this:
@Repository
@Transactional(propagation = Propagation.MANDATORY)
public interface EntityType1DAO extends JpaRepository<EntityType1, Long> {
//@Query("FROM Room WHERE accomodation = :id")
List<EntityType1> findByEntityType1(EntityType1 entityType1);
}
@Repository
@Transactional(propagation = Propagation.MANDATORY)
public interface EntityType2DAO extends JpaRepository<EntityType2, Long> {
List<EntityType2> findByEntityType2(EntityType2 entityType2);
}
...........................................................................
...........................................................................
...........................................................................
@Repository
@Transactional(propagation = Propagation.MANDATORY)
public interface EntityTypeNDAO extends JpaRepository<EntityTypeN, Long> {
List<EntityTypeN> findByEntityTypeN(EntityTypeN entityTypeN);
}
So basically in this way I have n domain classes accessed by **n repository classes.
I can divide these n domain classes into subsets belonging to a common concept.
For example I can have entity classes like: Room, RoomTipology RoomRate and RoomPicture that all belong to the Room concept.
So I will have the following services classes: RoomDAO, RoomTipologyDAO, RoomRateDAO and RoomPictureDAO.
It works fine but I want adopt a more DOMAIN-DRIVEN DESIGN architecture.
So I have found this interesting article about how to obtain a DOMAIN-DRIVEN DESIGN in Spring application: http://static.olivergierke.de/lectures/ddd-and-spring/
Reading the previous article it says that:
Repository - Spring component, usually a Spring Data repository interface. Can depend on entities and value objects, are centered around entities that are aggregate roots.
What exactly means? It means that I can create an aggregate roots class (for example RoomAggregation that aggregate together my Room, RoomTipology RoomRate and RoomPicture entity classes) using the @Embedded annotation.
Or what?
What could be a good architectural solution to obtain a DOMAIN-DRIVEN DESIGN in my application using Spring Data JPA?
Upvotes: 2
Views: 2784
Reputation: 1196
As @Sebastian has elaborated it very well, when you are DDDing your application, persistance should be the last thing to worry about ever. You do not couple your entities with the database or else you will end up with a very database driven application messed up with ddd and it will not be presentable in terms of clean code and aesthetic sense. There is a good presentation on youtube named Domain Driven Design for Database Driven Mind please check it out.
Secondly most of your DAOs should be refactored to Value Objects and you dump al your business logic into Value Objects and Entities and in the end when you need to worry about storing the stuff, just go with a data mapper layer.
Speaking out of experience, value objects done right will offload your 90% weight of the proper app design.
Upvotes: 0
Reputation: 525
First of all, forget about Spring Data JPA or any other persistence mechanism. Domain Driven Design is about modelling the domain in analysis and your particular case is about modeling some kind of hotels sub-domain and do not worry about persistence at all. That is another completely different concern not related to hotels but to persistence (another domain or bounded context).
You must think in terms of use cases instead of concepts so we can identify behavior and this way detect invariants that allow us to think about establishing boundaries around what must remain consistent all the time.
Remember to model small aggregates as suggested by Vaughn so your idea of having a big aggregate does not sound good. The hotel manager might instantiate a Room to actually represent a Room and give it a number and some other stuff. Now what about the price and the pictures? Let's take the example of the price and let me ask you, does a Room actually know what its price is? Isn't the room price dynamic and totally affected by a lot of other variables such as dates? Then why to fix a rate inside the Room aggregate? We said a room is not responsable in the real world for such responsibility and the price is affected by several conditions that occur outside the boundary of a Room. So the Rate is totally accidental to a Room, not essential if we talk in philosophy terminology.
The other Aggregate is PriceList and it's Aggregate Root having the same name. So you can ask the price list, the price for an Room (standard, deluxe, ...) in a specific date and it will know the price :) Depending on how you model all these stuff this might belong to the Pricing Bounded Context exposed as a Microservice, but don't worry about it. The PriceList is another aggregate completely isolated from the Room and refering the rooms by its conceptual identity that is the Room Number.
The same applies for RoomPicture. In this particular case think that the department/area/employees dealing with the album picture might not be the Manager but someone else with a different role and creating a room album with its own lifecycle.
As conclusiong you would end up having these aggregates:
Room PriceList Album
And remember the all these have disconnected associations referring room numbers (not Rooms) and each having its own boundaries around invariants. In a huge app you might have each of these living in its own bounded context.
Remember Room does not enforce any invariant neither over its album of picture nor its price list.
Hope it helps, Sebastian.
Upvotes: 2
Reputation: 81882
You don't create a new class as the Aggregate. Instead you pick one of the exiting ones. Typically it presents itself, and in your example it might be the Room
So you would have a repository for rooms (RoomRepository
or Rooms
maybe). You use it to save and load rooms, including finding rooms by the various criteria you need.
In order to access (and manipulate) for example a RoomPicture
you load the Room
navigate to the RoomPicture
manipulate it and save your JPA session, which essentially means you are modifying the Room.
If you choose simple navigation between entities (@OneToMany and the gang) or @Embedded ist not affected by your choice of Aggregates, except, that you don't have direct references from on Aggregate to another. So if you also have Booking
as an AggregateRoot, that Booking
would contai a roomId
and you'd use the Room repository to look the Room up.
Upvotes: 3