2026 소프트웨어 아키텍처 완전 가이드

모놀리스·마이크로서비스·DDD·BFF

by AI개발자
소프트웨어엔지니어링_0.png
이 장을 읽기 전에: 백엔드(4장)와 데이터베이스(5장)의 기초를 이해하고 있을 것.


아키텍처는 "나중에 깔끔하게 하기 위한 장식"이 아니라, 팀이 어떤 속도로 변경을 계속할 수 있는지를 결정하는 설계다. 중요한 것은 유행하는 이름을 아는 것이 아니라, 요건과 운용 능력에 대해 과불급 없는 구조를 선택하는 것이다.

� 한국 시장 맥락: 국내 주요 IT 기업(카카오·네이버·라인·쿠팡)은 대부분 모놀리스에서 시작해 성장 후 마이크로서비스로 전환했다. 토스는 모듈러 모놀리스를 거쳐 점진적으로 분리하는 사례를 기술 블로그에서 공개했다. 공공·금융 SI 환경은 여전히 대규모 모놀리스가 표준인 경우가 많다.



1. 모놀리스, 모듈러 모놀리스, 마이크로서비스

이 섹션이 답하는 질문: 어디까지 분할해야 하는가. 언제 나누어야 하는가.


왜 필요한가

분할은 자유도를 늘리는 한편, 통신, 감시, 배포, 장애 구분의 비용도 늘린다. "작게 나눌수록 좋다"는 것은 잘못이며, 실제로는 팀의 운용 능력이 상한이 된다.

swe-2026-14-01.png


판단기준

swe-2026-14-02.png
swe-2026-14-03.png
⚠️ 막히면 모놀리스 또는 모듈러 모놀리스에서 시작한다. 먼저 분산하면, 조직이 다룰 수 없는 복잡성만 늘어나기 쉽다.


단계적인 진행 방법

처음에는 모놀리스로 신속하게 사양을 굳힌다

변경이 빈번한 영역마다 모듈 경계를 명확화한다

독립 배포가 필요해진 부분만 외부로 분리한다


� 국내 기업 사례: 토스는 "마이크로서비스 아키텍처 전환기" 블로그에서 모놀리스→모듈러 모놀리스→마이크로서비스의 점진적 전환 과정을 공개했다. 배달의민족도 "배민 마이크로서비스 여행기"에서 도메인 주도 분리 경험을 공유했다.


정리

분할은 목적이 아니라 수단이다. 팀의 독립성과 운용 능력이 갖춰질 때까지는, 일체로 동작하는 구조 쪽이 강하다.



2. 레이어 설계와 의존 방향

이 섹션이 답하는 질문: 코드를 어떻게 정리하면 변경에 강해지는가.


왜 필요한가

기능이 늘어나면 화면, 업무 규칙, 데이터 접근, 외부 API 호출이 섞이기 쉽다. 이 혼재를 방치하면 작은 변경에도 부작용을 읽을 수 없게 된다.


클린 아키텍처, 헥사고날 아키텍처, 어니언 아키텍처는 이름은 달라도 목표는 가깝다.

공통된 요점:

비즈니스 규칙을 중심에 둔다

DB나 외부 API 등의 세부 사항은 바깥쪽에 둔다

의존 방향을 안쪽으로 향한다


구현의 최소형 — TypeScript(Node.js/Next.js)

소~중규모에서는, 다음 3계층으로 충분한 경우가 많다.

swe-2026-14-04.png
swe-2026-14-05.png

구현의 최소형 — Kotlin(Spring Boot)


// 국내 Spring Boot 표준 레이어 구조

// 입구층 (Controller)

@RestController

@RequestMapping("/api/v1/orders")

class OrderController(private val orderService: OrderService) {


@PostMapping

fun createOrder(

@AuthenticationPrincipal user: UserDetails,

@RequestBody @Valid request: CreateOrderRequest

): ResponseEntity<OrderResponse> {

val order = orderService.createOrder(user.userId, request)

return ResponseEntity.status(HttpStatus.CREATED).body(order.toResponse())

}

}


// 업무층 (Service) — 비즈니스 규칙 중심

@Service

@Transactional

class OrderService(

private val orderRepository: OrderRepository,

private val paymentGateway: PaymentGateway, // 외부 의존은 인터페이스로

private val stockChecker: StockChecker,

) {

fun createOrder(userId: Long, request: CreateOrderRequest): Order {

// 비즈니스 규칙: 재고 확인 후 결제

stockChecker.check(request.productId, request.quantity)

val payment = paymentGateway.charge(userId, request.amount)

return orderRepository.save(Order.create(userId, request, payment))

}

}


// 데이터층 (Repository) — DB 접근

지금 바로 작가의 멤버십 구독자가 되어
멤버십 특별 연재 콘텐츠를 모두 만나 보세요.

brunch membership
AI개발자작가님의 멤버십을 시작해 보세요!

AI Workflow Architect, LLM Engineer, Vibe Engineering, Claude Code, AI 업무 자동화 컨설팅/AI강의

104 구독자

오직 멤버십 구독자만 볼 수 있는,
이 작가의 특별 연재 콘텐츠

  • 최근 30일간 77개의 멤버십 콘텐츠 발행
  • 총 106개의 혜택 콘텐츠
최신 발행글 더보기
이전 13화2026 웹 보안 완전 가이드