Java Omnibus
OOAD & Architecture / Architectural Styles / When to Use Which Architecture
Decision Guide Java Architecture Choice Trade-offs
Architectural Styles

Choosing an architecture is mostly about recognizing forces, not declaring allegiance to a style.

Teams usually do not fail because they chose the wrong fashionable label. They fail because they ignored the forces acting on the system: rate of change, infrastructure volatility, operational complexity, team structure, domain complexity, and testing needs.

Why This Topic Matters

Why it matters in real Java systems

A payment-heavy, integration-rich commerce platform has different forces than an internal catalog management app. The first might need stronger boundary isolation and asynchronous flows. The second might be better served by a modular monolith with disciplined packages. The architecture choice should match those forces.

Core Explanation

The main architectural idea

The best architecture choice usually emerges from a sequence of questions. How volatile is the infrastructure? How complex is the domain? How many teams will work in the codebase? Are deployments independent or coordinated? Do you need synchronous request-response most of the time, or is asynchronous collaboration central?

This page gives a practical guide: start simple, choose only the extra structure you can justify, and prefer internal modularity before external distribution unless the system clearly needs separate deployment and operational independence.

Concept Breakdown

Key ideas to keep in mind

Concept

If the domain is moderate and the team is small

A layered or modular monolith usually gives the best clarity-to-complexity ratio.

Concept

If infrastructure churn is high

Hexagonal, onion, or clean architecture can help keep the core insulated from frameworks and transport mechanisms.

Concept

If collaboration is asynchronous and decoupled

Event-driven architecture becomes more useful when events are a real coordination mechanism rather than decoration.

Decision table

Decision table

Situation Usually start with Why
Internal business app, one team, moderate domainLayered or modular monolithFastest path to clarity without operational overreach
Business core must survive framework churnHexagonal / Onion / CleanProtect dependency direction and testability
Heavy asynchronous flows and loose coupling needsEvent-drivenEvents become the coordination model, not just notifications
Streaming transformation pipelinePipes and FiltersProcessing stages are naturally sequential and composable
Multiple teams need independent deploymentModular monolith first, then microservices if justifiedInternal boundaries should prove themselves before distribution
Java Example

Java example in the Order Management domain

Java example: choosing a stable application boundary before choosing distribution
package org.javaomnibus.ecommerce.architecture;

public final class ArchitectureForces {
    private final boolean manyIndependentTeams;
    private final boolean highInfrastructureVolatility;
    private final boolean eventDrivenCollaboration;

    public ArchitectureForces(
        boolean manyIndependentTeams,
        boolean highInfrastructureVolatility,
        boolean eventDrivenCollaboration
    ) {
        this.manyIndependentTeams = manyIndependentTeams;
        this.highInfrastructureVolatility = highInfrastructureVolatility;
        this.eventDrivenCollaboration = eventDrivenCollaboration;
    }

    public String recommend() {
        if (manyIndependentTeams) return "Start modular, distribute only when boundaries prove stable";
        if (highInfrastructureVolatility) return "Protect the core with ports and inward dependencies";
        if (eventDrivenCollaboration) return "Design events as real business contracts";
        return "Use the simplest style that keeps dependencies honest";
    }
}
Code Walkthrough

Step by step

  1. This is not a production decision engine. It illustrates that architecture follows forces.
  2. The first question is not framework preference. It is what pressure the system is under.
  3. Strong boundaries matter more than clever naming.
  4. Good teams often arrive at good architecture by choosing one force at a time and designing for it explicitly.
Real-World Usage

Where this helps in practice

  • Architecture reviews before large refactors
  • Selecting the initial style for a new Java platform
  • Explaining to stakeholders why a microservice split may or may not be justified
Trade-Offs

Trade-offs and when not to overuse it

  • Decision guides help, but they cannot replace judgment about team maturity and domain complexity.
  • Over-optimizing for future scale can produce needless architecture today.
Common Mistakes

Frequent mistakes to watch for

  • Choosing microservices because growth might happen someday
  • Choosing layered architecture while ignoring dependency erosion between layers
  • Choosing event-driven architecture without clear event ownership or idempotency thinking
  • Treating architectural style as fixed forever instead of evolvable
Related Pages

Related concepts


What To Read Next