britter / bootify-testpyramid

Apache License 2.0
5 stars 2 forks source link

Why are not the entities from the persistence package directly used? #8

Open gerritsangel opened 6 years ago

gerritsangel commented 6 years ago

I really liked the presentation and have one question concerning the design of the classes:

Why is there an extra domain package? As far as I know, it should be possible to put the domain logic inside @Entity annotated POJOs - so why create new classes which basically seem to be just copies of the classes from the repository package? For example, the AddressEmbeddable is basically the same as the Address, and even the Order class is almost the same as the OrderEntity (except for the deliveryPrice attribute).

khmarbaise commented 6 years ago

One thing be the separation of concerns and the separate meaning. OrderEntity is a representation of how an Order is being persisted whereas the Order is the domain model...

gerritsangel commented 6 years ago

Well, yes, that I understand, but isn't the representation of how the Order is being persisted basically already defined in the annotations?

britter commented 6 years ago

Well, yes, that I understand, but isn't the representation of how the Order is being persisted basically already defined in the annotations?

Yes, you could implement an application using only a persistence model. As with all architecture decision, this depends a lot on the context. Are you implementing only a simple CRUD application that does not have a lot of business logic? Then you're probably better off without the overhead of maintaining a separate domain model.

In my project we need to implement a lot a calculations like price and weight calculations, business constaints (e.g. we only accept a new order if the delivery date is at least the day after tomorrow) and business rules (e.g. if the delivery date is tomorrow the order's state has to be changed to 'invalid'). There are two important arguments for separating the business logic from persistence:

  1. Level of abstraction: The persistence mechanism is a low level detail of how we chose to implement our application. It may change some time for example because we want to use a different persistence engine. Business rules are high level rules, which we expect are less likely to change then technical details.
  2. Separation of concerns: When it comes to JPA persistence there are a lot of specialities you need to take care of. Let me give you an example. Whenever you want to maintain a one-n relationship between two entities you need to setup a bidirectional relationship between the Java objects. This is needed because your persistence framework needs to insert the primary key of the owning entity as a foreign key in the child table. For this reason you can't implement simple setters for referenced collection. In my example maintaining the list of order items would look like this:
public class OrderEntity {

  @OneToMany(cascade = CascadeType.ALL, mappedBy = "order")
  private List<OrderItemEntity> items = new ArrayList<>();

  // ...

  public void setItems(List<OrderItemEntity> newItems) {
    items.clear()
    if(newItems != null) {
      this.items.addAll(newItems);
      this.items.forEach(OrderItemEntity::setOrder)
    }
  }
}

As you can see there is a lot a stuff going on for a simple setter, when working with ORMs like Hibernate. This code would be mixed with the business code I talked before. For this reason it's sometimes good to implement a dedicated persistence model to follow SCP.