BCE Pattern in a Monolith: Clean Architecture for Complex Systems
Many companies start with a monolith because it is simple and fast to implement in the beginning. Short development cycles, low infrastructure complexity, and a straightforward deployment process make it especially attractive in early project phases. However, as business complexity grows, typical challenges begin to appear:
- increasing coupling between components
- unclear responsibilities
- business logic that is difficult to test
- decreasing maintainability
The key question is therefore:
How can a monolith remain maintainable, modular, and future-proof in the long term?
The Boundary-Control-Entity (BCE) pattern provides a structured answer to this question. It creates clear responsibilities within a system and allows even large monoliths to grow in a controlled way. At the same time, it makes a later migration toward microservices significantly easier.
What is the BCE Pattern?
The BCE pattern divides software architecture into three clearly defined roles:
-
Boundary The interface to the outside world — for example REST APIs, messaging adapters, or external integrations.
-
Control Orchestrates use cases and controls the application flow. This is where the actual application logic lives.
-
Entity Represents business objects and business rules — independent of UI or infrastructure.
This separation is intentionally kept simple, but is extremely effective. It ensures that each layer has a clearly defined responsibility and does not mix concerns with other parts of the system.
Why is this important?
In many real-world projects, the boundaries between presentation, business logic, and persistence become blurred. This leads to typical problems:
- controllers contain business logic
- services directly access foreign domains
- entities know infrastructure details
- tests become complex and unstable
The BCE pattern directly counteracts these problems:
-
Clarity Developers immediately know where each kind of logic belongs.
-
Testability Each layer can be tested in isolation.
-
Maintainability Changes remain local and have only minimal impact on other areas.
-
Extensibility New features can be integrated in a structured way.
Why BCE in a Monolith?
A monolith is not bad by default. Quite the opposite: a well-structured monolith can be operated and evolved efficiently for many years.
The problem only starts when structure is missing.
The BCE pattern helps establish exactly this structure:
- clear separation of business domains
- defined dependency directions
- reduced coupling
Each domain organizes itself internally:
- its own boundaries for external communication
- its own control classes for use cases
- its own entities as the business model
This creates what is known as a modular monolith.
The key advantage:
A later split into microservices is not forced, but prepared.
Domains can be extracted when needed without having to rethink the entire system.
Our Approach: Domain-Based Structure
We structure the monolith strictly by business domains:
de.acmebank.person
de.acmebank.konto
de.acmebank.rechnung
de.acmebank.kredit
de.acmebank.buchungen
Within each domain, the same structure is used:
- Boundary → REST APIs, adapters, external interfaces
- Control → use-case logic and orchestration
- Entity → business models and rules
- Repository → persistence access
This repetition is intentional: It provides orientation and reduces cognitive load within the team.
Architectural Principle: Dependency Direction
One of the most important rules in the BCE pattern is:
Dependencies always point inward
Boundary → Control → Entity
In concrete terms, this means:
- Boundary knows Control
- Control knows Entity
- Entity knows nothing outside the domain
Cross-domain communication happens exclusively through boundaries.
This prevents hidden coupling and creates clear interfaces.
Optimized Architecture Sketch
BCE in Detail
Boundary
The boundary layer is the entry point into the system.
Typical responsibilities:
- receiving requests
- validating input
- mapping DTOs to domain objects
- returning responses
Important: No business logic!
Control
The control layer represents the application layer.
Responsibilities:
- implementing use cases
- orchestrating workflows
- coordinating multiple entities
- calling external boundaries
This is where the actual intelligence of the application lives.
Entity
Entities form the business core of the application.
Characteristics:
- contain business rules
- are independent of frameworks
- have no infrastructure dependencies
The goal is a stable, long-lived domain model.
Best Practices
Some proven rules for using BCE:
-
No business logic in the boundary
-
No direct coupling between domains
-
Entities remain free of technical dependencies
-
Model use cases clearly
-
Strictly follow dependency rules
-
Enforce communication through boundaries
These rules seem simple, but they have a huge impact in large systems.
Example with Spring Boot
// Boundary
@RestController
@RequestMapping("/api/konto")
public class KontoApi {
private final KontoService kontoService;
public KontoApi(KontoService kontoService) {
this.kontoService = kontoService;
}
@PostMapping
public ResponseEntity<KontoDto> create(@RequestBody KontoDto dto) {
Konto konto = kontoService.create(dto.getNummer(), dto.getSaldo());
return ResponseEntity.ok(KontoMapper.toDto(konto));
}
}
// Control
@Service
public class KontoService {
private final KontoRepository kontoRepository;
public KontoService(KontoRepository kontoRepository) {
this.kontoRepository = kontoRepository;
}
public Konto create(String nummer, BigDecimal saldo) {
Konto konto = new Konto(nummer, saldo);
konto.validate();
return kontoRepository.save(konto);
}
}
// Entity
public class Konto {
private final String nummer;
private BigDecimal saldo;
public Konto(String nummer, BigDecimal saldo) {
this.nummer = nummer;
this.saldo = saldo;
}
public void validate() {
if (saldo.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Balance must not be negative");
}
}
}
Conclusion
The BCE pattern is a simple but highly effective way to structure complex systems.
It helps to:
- keep monoliths maintainable
- make business boundaries visible
- reduce complexity
- prepare future migrations
The most important point:
BCE does not make your monolith smaller — but it structures it in a way that keeps it scalable in the long term.