Monolith — a single, unified application where all components (UI, business logic, data access) are built, deployed, and scaled as one unit. Microservices — an architecture where the application is split into small, independent services that communicate over the network.
System Design Context: The choice between monolith and microservices is one of the most consequential architectural decisions. The "monolith first" approach (advocated by Martin Fowler) suggests starting with a well-structured monolith and extracting services only when clear boundaries emerge.
Monolith — Detailed Characteristics:
1// Monolith — everything in one application2@SpringBootApplication3public class MonolithApp {4 public static void main(String[] args) {5 SpringApplication.run(MonolithApp.class, args);6 }7}89// User, Order, Payment — all in one JVM10@Service11public class OrderService {12 @Autowired private UserService userService; // direct call13 @Autowired private PaymentService paymentService; // direct call14 @Autowired private InventoryService inventoryService; // direct call1516 @Transactional // ACID across all tables17 public Order createOrder(OrderRequest req) {18 User user = userService.findById(req.userId());19 inventoryService.reserve(req.items());20 Payment payment = paymentService.charge(user, req.total());21 return orderRepo.save(new Order(user, req.items(), payment));22 }23}
Microservices — Detailed Characteristics:
1// Each service is a separate Spring Boot application2@SpringBootApplication3public class UserServiceApp {4 public static void main(String[] args) {5 SpringApplication.run(UserServiceApp.class, args);6 }7}89@SpringBootApplication10public class OrderServiceApp {11 public static void main(String[] args) {12 SpringApplication.run(OrderServiceApp.class, args);13 }14}1516// OrderService calls UserService via HTTP (not direct)17@Service18public class OrderService {19 private final WebClient webClient;20 private final CircuitBreaker circuitBreaker;2122 public Order createOrder(OrderRequest req) {23 User user = Decorators.ofCallable(24 () -> webClient.get()25 .uri("http://user-service/api/users/{id}", req.userId())26 .retrieve()27 .bodyToMono(User.class)28 .block()29 ).withCircuitBreaker(circuitBreaker)30 .decorate().execute();3132 // Publish event instead of direct call33 kafkaTemplate.send("order-events", new OrderCreatedEvent(req));34 return orderRepo.save(new Order(user, req.items()));35 }36}
Production Configuration Comparison:
Common Pitfalls:
Monitoring Differences:
When to Use Which: