좋은 아키텍처란 무엇일까요?

우리는 종종 ‘좋은 아키텍처’ 또는 ‘유지보수하기 쉬운 코드’에 대해 이야기하지만, 이러한 평가는 주관적일 때가 많습니다. 그렇다면 코드의 구조적 건강 상태를 객관적으로 측정하고 평가할 방법은 없을까요? 로버트 C. 마틴(Robert C. Martin)은 그의 저서에서 이러한 질문에 대한 답으로 몇 가지 유용한 지표를 제시합니다.

그중에서도 메인 시퀀스로부터의 거리(Distance from the Main Sequence) 는 모듈(컴포넌트, 패키지 등)이 얼마나 이상적인 균형을 이루고 있는지를 평가하는 강력한 지표입니다. 이 지표를 이해하기 위해서는 먼저 추상도(Abstractness)불안정도(Instability) 라는 두 가지 핵심 개념을 알아야 합니다.

1. 추상도 (Abstractness): 얼마나 유연한가?

추상도(A) 는 모듈이 얼마나 많은 추상적인 요소(추상 클래스, 인터페이스)를 포함하고 있는지를 나타내는 척도입니다. 즉, 모듈의 ‘구현’ 대비 ‘추상화’의 비율을 측정합니다.

공식은 다음과 같습니다:

$$ A = \frac{\text{모듈 내 추상 클래스와 인터페이스의 수}}{\text{모듈 내 전체 클래스의 수}} $$
  • A = 0: 모듈에 추상 클래스나 인터페이스가 전혀 없고, 오직 구체적인 구현 클래스만 존재합니다. 이 모듈은 확장하기 어렵고 경직되어 있을 가능성이 높습니다.
  • A = 1: 모듈이 오직 추상 클래스와 인터페이스로만 구성되어 있습니다. 이 모듈은 매우 유연하고 확장성이 뛰어납니다.

추상도가 높을수록 모듈은 변화에 더 잘 적응할 수 있지만, 지나치게 추상적이면 실제 내용이 없는 껍데기가 될 수도 있습니다.

2. 불안정도 (Instability): 얼마나 쉽게 변하는가?

불안정도(I) 는 모듈이 다른 모듈의 변경에 얼마나 영향을 받기 쉬운지를 나타내는 척도입니다. 이는 모듈의 의존성 관계를 통해 계산됩니다.

이를 이해하기 위해 두 가지 커플링 개념이 필요합니다.

  • 구심 커플링 (Afferent Coupling, Ca): 들어오는 의존성. 얼마나 많은 외부 모듈이 이 모듈 에 의존하고 있는지를 나타냅니다. 이 값이 높을수록 모듈은 책임감 있고 안정적(stable) 이라고 말합니다. (변경 시 파급 효과가 크기 때문)
  • 원심 커플링 (Efferent Coupling, Ce): 나가는 의존성. 이 모듈 이 얼마나 많은 외부 모듈에 의존하고 있는지를 나타냅니다. 이 값이 높을수록 모듈은 변덕스럽고 불안정(instable) 하다고 말합니다. (외부의 변경에 쉽게 영향을 받기 때문)

불안정도를 계산하는 공식은 다음과 같습니다:

$$ I = \frac{C^e}{C^a + C^e} $$
  • I = 0: 모듈에 대한 들어오는 의존성만 있고 나가는 의존성은 없습니다. 이는 매우 안정적인 상태로, 다른 모듈에 영향을 줄 수는 있지만 자신은 외부로부터 영향을 거의 받지 않습니다.
  • I = 1: 모듈이 다른 모듈에 의존하기만 하고, 이 모듈에 의존하는 다른 모듈은 없습니다. 이는 매우 불안정한 상태로, 외부 모듈의 변경에 직접적으로 영향을 받습니다.

3. 메인 시퀀스로부터의 거리 (Distance from the Main Sequence)

드디어 핵심 지표입니다. 메인 시퀀스로부터의 거리(D) 는 위에서 설명한 추상도(A)와 불안정도(I)를 결합하여, 모듈이 얼마나 ‘이상적인’ 상태에 가까운지를 측정합니다.

공식은 다음과 같습니다:

$$ D = |A + I - 1| $$
  • D = 0: 모듈이 메인 시퀀스 위에 정확히 위치하며, 추상도와 안정성 간의 균형이 가장 이상적인 상태입니다.
  • D = 1: 모듈이 메인 시퀀스에서 가장 멀리 떨어져 있으며, 구조적으로 문제가 있을 가능성이 매우 높습니다.

이 관계를 그래프로 시각화하면 그 의미가 더욱 명확해집니다.

  • x축: 불안정도 (I) - 오른쪽으로 갈수록 불안정
  • y축: 추상도 (A) - 위로 갈수록 추상적
  • 메인 시퀀스: A + I = 1을 만족하는 대각선. 이 선 위에 있는 모듈들이 가장 바람직한 구조를 가집니다.

쓸모없는 구역과 고통의 구역

메인 시퀀스에서 멀리 떨어진 모듈들은 두 가지 위험 지대에 속하게 됩니다.

1. 고통의 구역 (Zone of Pain)

  • 위치: 그래프의 왼쪽 아래 (A=0, I=0 에 가까움)
  • 특징: 매우 안정적 이면서 동시에 매우 구체적 인 모듈입니다.
  • 문제점: 많은 다른 모듈들이 이 모듈에 의존하고 있어 변경하기가 매우 어렵지만(안정적), 추상화가 전혀 되어 있지 않아 확장도 불가능합니다(구체적). 이런 모듈은 시스템 전체를 경직되게 만드는 주범이 됩니다.
  • 예시: 데이터베이스 스키마와 강하게 결합된 구체적인 클래스(UserDAO)가 있고, 시스템의 50개 다른 클래스가 이 UserDAO를 직접 사용하고 있다고 상상해 보세요. UserDAO를 변경하는 것은 엄청난 고통을 수반할 것입니다.

2. 쓸모없는 구역 (Zone of Uselessness)

  • 위치: 그래프의 오른쪽 위 (A=1, I=1 에 가까움)
  • 특징: 매우 추상적 이면서 동시에 매우 불안정 한 모듈입니다.
  • 문제점: 이 모듈은 인터페이스와 추상 클래스로 가득 차 있지만(추상적), 아무도 이 모듈을 사용하지 않으며(들어오는 의존성 없음), 오히려 다른 여러 구체적인 모듈에 의존하고 있습니다(불안정). 즉, 아무에게도 쓰이지 않는 과도한 추상화의 결과물입니다.
  • 예시: 아무도 구현하지 않고 사용하지도 않는 수많은 인터페이스만 모아놓은 패키지를 생각할 수 있습니다.

결론: 균형을 향한 리팩토링

메인 시퀀스로부터의 거리 는 우리에게 중요한 교훈을 줍니다. 좋은 아키텍처는 단순히 추상적이거나 안정적이기만 한 것이 아니라, 두 특성 간의 적절한 균형 을 이루어야 한다는 것입니다.

  • 안정적인 모듈 은 변경하기 어려우므로, 변화에 유연하게 대처할 수 있도록 추상적이어야 합니다. (예: 프레임워크의 인터페이스)
  • 구체적인 모듈 은 자주 변경될 수 있으므로, 다른 모듈에 미치는 영향을 최소화하기 위해 불안정해야 합니다. (예: 비즈니스 로직 구현체)

소프트웨어 아키텍트는 이 지표를 활용하여 시스템의 각 모듈을 그래프에 배치해보고, ‘고통의 구역’이나 ‘쓸모없는 구역’에 위치한 모듈을 식별할 수 있습니다. 그리고 이들을 메인 시퀀스에 가깝게 이동시키는 방향으로 리팩토링 전략을 수립함으로써, 전체 시스템을 더 건강하고 유지보수하기 좋은 구조로 만들어갈 수 있습니다.