Skip to content

Separation Of Concerns

Definition

Separation of Concerns Definition


Classic Example: MVC

MVC Pattern


Layered Architecture

Layered Architecture


Code Example

// BAD: All concerns mixed together
public class OrderController {
    public String placeOrder(HttpRequest request) {
        // Concern 1: Input parsing
        String json = request.getBody();
        JSONObject data = new JSONObject(json);
        String productId = data.getString("productId");
        int quantity = data.getInt("quantity");

        // Concern 2: Validation
        if (quantity <= 0) {
            return "{\"error\": \"Invalid quantity\"}";
        }

        // Concern 3: Business logic
        double price = 0;
        try (Connection conn = DriverManager.getConnection(URL)) {
            // Concern 4: Data access mixed in
            PreparedStatement ps = conn.prepareStatement(
                "SELECT price FROM products WHERE id = ?");
            ps.setString(1, productId);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                price = rs.getDouble("price");
            }

            double total = price * quantity;
            if (total > 1000) {
                total = total * 0.9;  // 10% discount
            }

            // Concern 5: More data access
            PreparedStatement insert = conn.prepareStatement(
                "INSERT INTO orders (product_id, quantity, total) VALUES (?, ?, ?)");
            insert.setString(1, productId);
            insert.setInt(2, quantity);
            insert.setDouble(3, total);
            insert.executeUpdate();

            // Concern 6: Response formatting
            return "{\"orderId\": 123, \"total\": " + total + "}";
        } catch (SQLException e) {
            // Concern 7: Error handling
            return "{\"error\": \"Database error\"}";
        }
    }
}

Properly Separated

// GOOD: Concerns separated into distinct classes

// Controller: Handles HTTP concerns only
@RestController
public class OrderController {
    private final OrderService orderService;

    @PostMapping("/orders")
    public ResponseEntity<OrderResponse> placeOrder(
            @Valid @RequestBody OrderRequest request) {
        Order order = orderService.placeOrder(
            request.getProductId(),
            request.getQuantity()
        );
        return ResponseEntity.ok(OrderResponse.from(order));
    }
}

// Service: Business logic concern
@Service
public class OrderService {
    private final ProductRepository productRepo;
    private final OrderRepository orderRepo;
    private final PricingService pricingService;

    @Transactional
    public Order placeOrder(String productId, int quantity) {
        Product product = productRepo.findById(productId)
            .orElseThrow(() -> new ProductNotFoundException(productId));

        Money total = pricingService.calculateTotal(product, quantity);

        Order order = new Order(product, quantity, total);
        return orderRepo.save(order);
    }
}

// Domain: Business rules concern
@Service
public class PricingService {
    private static final Money DISCOUNT_THRESHOLD = Money.of(1000);
    private static final BigDecimal DISCOUNT_RATE = new BigDecimal("0.10");

    public Money calculateTotal(Product product, int quantity) {
        Money subtotal = product.getPrice().multiply(quantity);
        if (subtotal.isGreaterThan(DISCOUNT_THRESHOLD)) {
            return subtotal.subtract(subtotal.multiply(DISCOUNT_RATE));
        }
        return subtotal;
    }
}

// Repository: Data access concern
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
}

// DTO: Presentation concern
public record OrderRequest(
    @NotBlank String productId,
    @Positive int quantity
) {}

public record OrderResponse(Long id, BigDecimal total) {
    public static OrderResponse from(Order order) {
        return new OrderResponse(order.getId(), order.getTotal().getAmount());
    }
}

Cross-Cutting Concerns

Cross-Cutting Concerns


SoC in Different Contexts

SoC Across Contexts


Tips & Tricks

SoC Tips