0

Let's say there is a domain model:

 @Table(name = "room") @Getter @FieldNameConstants @AllArgsConstructor(onConstructor = @__({@PersistenceCreator})) public class HotelRoom extends AbstractEntity implements HotelAware, Sellable { @Id private final String id; @Column(value = "hotel_id") private final String hotelId; @Column(value = "name") private String name; @Column(value = "size") private RoomSize size; @Column(value = "sale_state") private SaleState saleState; @Embedded.Empty private Stock stock; @Embedded.Empty private RoomDesc desc; private HotelRoom(String roomId, String hotelId) { this.id = roomId; this.hotelId = hotelId; } public static HotelRoom create(String id, Hotel hotel, String name, RoomDesc desc, RoomSize size, Stock stock) { DomainUtils.must(stock.greaterTan(Stock.ZERO), () -> new IllegalArgumentException("stock must gather than zero")); var hotelId = hotel.getId(); var room = new HotelRoom(id, hotelId); room.name = name; room.size = size; room.stock = stock; room.desc = desc; room.saleState=SaleState.STOPPED; return room; } @Override public void startSale() { this.saleState = SaleState.STARTED; } @Override public void stopSale() { this.saleState = SaleState.STOPPED; } @Override public SaleState getSaleState() { return this.saleState; } @Override public boolean isOnSale() { return saleState.isOnSale(); } public void updateDesc(RoomDesc desc) { this.desc = desc; } public void updateName(String name) { this.name = name; } public void updateSize(RoomSize size) { this.size = size; } public void updateStock(Stock stock) { this.stock = stock; } } 

and it has updateDesc/updateName/updateSize/updateStock methods to call from service layer:

 @Override public void updateRoom(RoomUpdateCommand command) { var room = hotelRoomRepository.requireById(command.getRoomId()); room.updateDesc(RoomDesc.builder() .desc(command.getDesc()) .build()); room.updateName(command.getName()); room.updateSize(command.getSize()); room.updateStock(command.getStock()); hotelRoomRepository.save(room); } 

side note: those methods starting with update are no different than setter methods.

This is that simple, what it really means is that we eventually have a large model with a lot of fields i.e. customs declaration or some thing like this:

class ExampleModel{ field1:string field2:string field3:string ... field50:string ... state... money... } 

the fields1...50 are properties the user can freely change, just like a memo. How can it deal with this?

  1. create a patch class like HotelRoomPatch as a value bean under the domain layer, so the HotelRoom can handle it.
  2. define setter method with those fields so the service layer can call it.
  3. define updateXxx methods for them so the service layer can call it.

I think #1 is the same as #2, we can not protect our domain model.

I wonder how about your thinking?

1
  • 4
    What I’m thinking? Why this question has a domain-driven-design tag and even DDD in the title, when I only see the anti-patterns described in the books. Commented Oct 24, 2024 at 16:33

2 Answers 2

1

If you have a model containing fifty fields, start by refactoring the model in order to follow the single responsibility principle. For instance, a model from legacy code such as:

class Customer { firstName: string, lastName: string, middleName: string, title: string, // https://english.stackexchange.com/a/42603/10307 initials: string, phoneNumber: string, phoneNumber2: string, phoneNumber3: string, address1line1: string, address1line2: string, address1line3: string, address1line4: string, address1line5: string, address2line1: string, address2line2: string, address2line3: string, address2line4: string, address2line5: string, ... } 

should rather look like this:

class Customer { name: PersonName, phones: List<Phone>, addresses: List<Address>, ... } 

Once you do that:

  1. Use setters instead of updateSomething, i.e. setSomething to follow Java's conventions, or you can use a library such as Lombok, with specific annotations of the fields.
  2. If there is no need for your entity to be mutable, make it immutable.
  3. Even if the entity remains mutable, don't update the individual fields one by one when you need to update all of them. Call a constructor instead.
  4. Ensure that every piece of code that needs to work on all fields remains within the class. If those pieces of code escape the class, it becomes very difficult to track them and update them accordingly when you add a field. Although you may be able to do it through rigorous testing, it is not straightforward.
0
0

It looks like a large part of your model is a dumb flat data structure, not a rich domain model.

It can be perfectly fine not to use DDD patterns in a use case where HotelRoom is just a data bag that can be edited in a CRUD admin screen for instance.

On the other hand, the benefit of DDD is to model complex invariants and business rules in a domain model. It looks like startSale() could for example be rich - triggering some logic elsewhere, enforcing domain rules, maybe creating a whole other Sale aggregate, etc.

CRUD parts, implemented with minimal ceremony and vanilla code, and rich parts that use DDD patterns can be separated and coexist in an application. But you have to do a bit of analysis on your business domain and use cases to know where to draw the line.

Starting an implementation by applying DDD technical patterns everywhere without doing the necessary domain analysis is usually a bad idea.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.