Good fit
Most internal business systems, especially when team familiarity and readability matter more than infrastructure isolation.
Layered architecture is often treated as boring compared to trendier styles, but for many Java business systems it remains the best default. It is understandable, teachable, and well-suited to teams that need clear boundaries between web, application, domain, and data access concerns.
Order entry, payment handling, catalog management, and shipment planning often need a straightforward structure that many developers can navigate. Layered architecture gives that clarity when the layers stay honest and the domain does not get buried under procedural glue.
The core idea of layered architecture is simple: each layer owns a certain kind of work and depends only in an allowed direction. A presentation layer handles HTTP or UI concerns. An application layer coordinates use cases. A domain layer owns business concepts and rules. A persistence or infrastructure layer handles storage and external integrations.
The danger is not the style itself. The danger is allowing layers to become only a packaging convention while dependencies leak everywhere. Good layered architecture is disciplined dependency direction, not just folders named controller, service, and repository.
Most internal business systems, especially when team familiarity and readability matter more than infrastructure isolation.
Easy to understand and onboard. Many developers can reason about the structure quickly.
Service layers become procedural dumping grounds and domain objects become passive.
package org.javaomnibus.ecommerce.web;
public final class CheckoutController {
private final CheckoutApplicationService checkoutApplicationService;
public CheckoutController(CheckoutApplicationService checkoutApplicationService) {
this.checkoutApplicationService = checkoutApplicationService;
}
public CheckoutResponse checkout(CheckoutRequest request) {
return CheckoutResponse.from(
checkoutApplicationService.checkout(request.toCommand())
);
}
}
package org.javaomnibus.ecommerce.application;
public final class CheckoutApplicationService {
private final OrderRepository orderRepository;
private final PaymentGateway paymentGateway;
public CheckoutReceipt checkout(CheckoutCommand command) {
Order order = orderRepository.requireById(command.orderId());
order.markPaid(paymentGateway.capture(command.orderId(), command.amount()));
orderRepository.save(order);
return CheckoutReceipt.from(order);
}
}