Chapter 18

반응형 아키텍처와 어니언 아키텍처

  • 18.1 반응형 아키텍처
  • 18.2 ValueCell
  • 18.3 FormulaCell
  • 18.4 어니언 아키텍처
  • 18.5 어니언 아키텍처의 세 계층

어니언 아키텍처는 "액션에서 계산을 빼내라"의 아키텍처 버전이야 — 1장에서 시작한 아이디어가 시스템 설계로 확장된 거지.

18장은 이 책의 마지막 기술 챕터로, 두 가지 큰 아키텍처 패턴을 다뤄. 첫 번째는 **반응형 아키텍처(reactive architecture)**야. 핵심 아이디어는 값이 바뀌면 그에 의존하는 것들이 자동으로 업데이트된다는 거거든. MegaMart에서 장바구니가 바뀔 때마다 합계 업데이트, 세금 업데이트, 배송비 업데이트를 수동으로 호출해야 했잖아. 하나라도 빠뜨리면 화면이 일치하지 않는 상태가 돼. 반응형으로 바꾸면 — "장바구니가 바뀌면 합계가 자동으로 다시 계산되고, 합계가 바뀌면 세금이 자동으로 다시 계산"되는 거야.

이걸 구현하기 위한 도구가 ValueCellFormulaCell이야. ValueCell은 **감시 가능한 값(observable value)**이야. 값이 바뀌면 등록된 감시자(watcher)에게 알리지.

function ValueCell(initialValue) {
  var currentValue = initialValue;
  var watchers = [];

  return {
    val: function() {
      return currentValue;
    },
    update: function(f) {
      var oldValue = currentValue;
      var newValue = f(oldValue);
      if (oldValue !== newValue) {
        currentValue = newValue;
        forEach(watchers, function(watcher) {
          watcher(newValue);
        });
      }
    },
    addWatcher: function(f) {
      watchers.push(f);
    }
  };
}

update에 전달하는 함수가 계산이라는 점이 중요해. 카피-온-라이트 패턴과 자연스럽게 결합되거든. FormulaCell은 다른 셀에서 파생된 값이야. 의존하는 셀이 바뀌면 자동으로 재계산되고, 읽기 전용이지.

var shoppingCart = ValueCell({});
var cartTotal = FormulaCell(shoppingCart, calc_total);
var cartTax = FormulaCell(cartTotal, calc_tax);

cartTotal.addWatcher(update_total_dom);
cartTax.addWatcher(update_tax_dom);

// 장바구니 변경 → 합계 자동 계산 → 세금 자동 계산 → DOM 자동 업데이트
shoppingCart.update(function(cart) {
  return add_item(cart, newItem);
});

스프레드시트를 떠올리면 이해하기 쉬워 — ValueCell은 사용자가 직접 값을 입력하는 셀(A1에 숫자 입력), FormulaCell은 수식으로 계산되는 셀(B1에 =A1*1.1). 이 패턴이 React, Vue, MobX 같은 프레임워크의 반응형 상태 관리와 정확히 같은 아이디어라는 걸 눈치챈 사람도 있을 거야.

두 번째 큰 패턴은 **어니언 아키텍처(onion architecture)**야. 이름이 양파인 이유는 계층이 양파 껍질처럼 동심원으로 쌓여 있어서야.

┌─────────────────────────┐
│    인터랙션 계층         │
│  ┌───────────────────┐  │
│  │  도메인 계층       │  │
│  │  ┌─────────────┐  │  │
│  │  │ 언어 계층    │  │  │
│  │  └─────────────┘  │  │
│  └───────────────────┘  │
└─────────────────────────┘

안쪽에서 바깥쪽으로 언어 계층(프로그래밍 언어의 기본 기능), 도메인 계층(비즈니스 로직, 계산), 인터랙션 계층(외부 세계와의 상호작용, 액션)이야. 핵심 규칙은 안쪽 계층은 바깥 계층을 모른다는 것이고, 의존성 방향은 항상 안쪽을 향해.

이게 왜 좋으냐면, 도메인 계층이 순수 계산이라 테스트하기 매우 쉽고, 데이터베이스를 바꾸거나 UI 프레임워크를 바꿔도 도메인 로직은 안 건드려도 되고, 비즈니스 규칙이 한 곳에 모여 있어서 이해하기 쉬워. 사실 이건 이 책 전체에서 반복한 **"액션에서 계산을 빼내라"**의 아키텍처 버전이야. 계산을 안쪽에 모으고, 액션을 바깥쪽에 모으는 것.


정리

18장 읽고 기억할 거 세 가지:

  1. ValueCell = 감시 가능한 값, FormulaCell = 파생 값. 값이 바뀌면 의존하는 것들이 자동으로 업데이트되는 반응형 패턴
  2. 어니언 아키텍처 = 언어/도메인/인터랙션의 세 계층. 안쪽은 계산, 바깥쪽은 액션. 의존성은 항상 안쪽을 향한다
  3. 어니언 아키텍처는 "액션에서 계산을 빼내라"의 아키텍처 버전. 1장의 핵심 아이디어가 시스템 설계로 확장된 것