DDD + Clean Architecture: Stop Putting Business Logic in the Application Layer
Your Clean Architecture isn’t clean if the domain is anemic
When people try Clean Architecture… they often end up with bloated application layers and empty domain layers.
Application Layer:
- Validate input
- Load entities
- Perform business logic
- Call repositories
- Call gateways
- Publish events
Domain Layer:
- Entity with getters and settersThat’s an anemic domain, not a rich domain.
The domain doesn’t actually do anything. All the rules are in the application layer.
In Clean Architecture, we’re supposed to have a rich domain, which fits in with DDD.
❌Empty Domain
Many developers are used to CRUD. They think of entities as just data structures
You’re used to CRUD. You think of entities as just data structure, with public getters and setters:
class Order {
private int id;
private List<Item> items;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
class Item {
private String sku;
private int quantity;
private boolean expired;
public String getSku() {
return sku;
}
public void setSku(String sku) {
this.sku = sku;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public boolean isExpired() {
return expired;
}
public void setExpired(boolean expired) {
this.expired = expired;
}
}Looks fine… but the business rules live elsewhere (application layer).
Your application service does this:
public void addItemToOrder(Order order, Item item) {
if (item.isExpired()) {
throw new ExpiredException();
}
List<Item> items = order.getItems();
if (items == null) {
items = new ArrayList<>();
}
if (items.size() > 10) {
throw new LimitExceededException();
}
items.add(item);
order.setItems(items);
orderRepository.save(order);
}All the rules (expiration check, limit check) live in the application layer.
The entity is just a data container.
Basically, you’ve moved all the complexity into a layer that’s supposed to orchestrate, not decide.

