Back to blog
Dec 02, 2025
6 min read

[번역] Cohesion and Coupling: the difference

응집도와 결합도: 차이점, 소프트웨어 개발에서 가장 가치 있는 원칙 중 하나에 대한 글입니다.

원문 : https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/

소프트웨어 개발에서 가장 가치 있는 원칙 중 하나에 대한 글입니다.

코드베이스를 작업할 때 낮은 결합도(low coupling)와 높은 응집도(high cohesion)를 달성해야 한다는 가이드라인을 들어보셨을 것입니다. 이 글에서는 이 가이드라인이 실제로 무엇을 의미하는지 논의하고, 이를 설명하는 코드 예제를 살펴보겠습니다. 또한 이 두 개념의 차이점을 명확히 구분하고자 합니다.

1. 응집도와 결합도: 차이점

결합도는 거의 모든 사람이 이해하는 데 어려움이 없는 직관적인 개념입니다. 반면 응집도는 이해하기 더 어렵습니다. 게다가 두 개념의 차이점은 종종 모호하게 보입니다. 놀라운 일은 아닙니다. 이 용어들의 기본 개념은 실제로 비슷하기 때문입니다. 그럼에도 불구하고 두 개념은 분명히 다릅니다.

응집도는 코드베이스의 한 부분이 논리적으로 단일하고 원자적인 단위를 형성하는 정도를 나타냅니다.

이는 어떤 코드 단위 내부의 연결 수로 표현할 수도 있습니다. 연결 수가 적다면 해당 단위의 경계가 잘못 선택된 것이며, 단위 내부의 코드가 논리적으로 연관되어 있지 않다는 것을 의미합니다.

여기서 단위는 반드시 클래스일 필요는 없습니다. 메서드, 클래스, 클래스 그룹, 심지어 모듈이나 어셈블리일 수도 있습니다. 응집도(및 결합도)의 개념은 다양한 레벨에서 적용 가능합니다. 이에 대해서는 잠시 후에 이야기하겠습니다.

반면 결합도는 단일 단위가 다른 단위들로부터 독립적인 정도를 나타냅니다. 다시 말해, 두 개 이상의 단위 간의 연결 수입니다. 연결 수가 적을수록 결합도가 낮아집니다.

2. 높은 응집도, 낮은 결합도 가이드라인

본질적으로 높은 응집도는 서로 관련된 코드베이스의 부분들을 한 곳에 유지하는 것을 의미합니다. 동시에 낮은 결합도는 관련 없는 코드베이스의 부분들을 가능한 한 많이 분리하는 것입니다.

이론적으로는 이 가이드라인이 꽤 단순해 보입니다. 그러나 실제로는 소프트웨어의 도메인 모델을 충분히 깊이 파고들어 코드베이스의 어떤 부분들이 실제로 관련되어 있는지 이해해야 합니다.

이는 순환 복잡도(cyclomatic complexity)와 같은 메트릭과 달리, 코드가 높은 응집도와 낮은 결합도를 가진 정도를 직접 측정할 수 없다는 것을 의미합니다. 이는 코드의 의미론에 크게 의존하며, 이는 도메인 모델의 속성입니다.

아마도 이 가이드라인의 객관성 부족이 이를 따르기 어려운 이유일 것입니다.

이 가이드라인과 밀접하게 관련된 원칙이 하나 있습니다: 관심사의 분리(Separation of Concerns). 두 가지는 제안하는 베스트 프랙티스 측면에서 매우 유사합니다.

3. 응집도와 결합도 관점에서 본 코드 유형

높은 응집도와 낮은 결합도를 가진 코드 외에도, 스펙트럼의 다른 부분에 속하는 최소 세 가지 유형이 있습니다. 총 4가지 유형입니다:

각 유형을 하나씩 살펴보겠습니다.

1. 이상적인 코드는 가이드라인을 따르는 코드입니다. 느슨하게 결합되어 있고 높은 응집도를 가집니다:

여기서 같은 색의 원은 서로 관련된 코드베이스의 조각들을 나타냅니다.

2. God Object는 높은 응집도와 높은 결합도를 도입한 결과입니다. 이는 안티패턴이며 기본적으로 모든 작업을 한 번에 수행하는 단일 코드 조각을 나타냅니다:

이런 종류의 코드를 Big Ball of Mud라고도 부릅니다.

3. 세 번째 유형은 서로 다른 클래스나 모듈 간의 경계가 잘못 선택된 경우 발생합니다:

God Object와 달리 이 유형의 코드는 경계가 있습니다. 여기서 문제는 경계가 부적절하게 선택되어 도메인의 실제 의미를 반영하지 못한다는 것입니다. 이런 코드는 단일 책임 원칙(Single Responsibility Principle)을 위반하는 경우가 많습니다.

**4. 파괴적 분리(Destructive decoupling)**는 가장 흥미로운 유형입니다. 프로그래머가 코드베이스를 너무 분리하려다 코드가 완전히 초점을 잃을 때 발생합니다:

마지막 유형은 더 자세한 논의가 필요합니다.

4. 응집도와 결합도: 함정

개발자가 낮은 결합도, 높은 응집도 가이드라인을 구현하려고 할 때 종종 결합도 측면에만 너무 많은 노력을 기울이고 다른 한쪽은 완전히 잊어버립니다. 이는 코드가 실제로 분리되어 있지만 동시에 명확한 초점이 없는 상황으로 이어집니다. 코드의 부분들이 서로 너무 분리되어 의미를 파악하기 어렵거나 심지어 불가능해집니다. 저는 이런 상황을 파괴적 분리라고 부릅니다.

예제를 살펴보겠습니다:

public class Order
{
    public Order(IOrderLineFactory factory, IOrderPriceCalculator calculator)
    {
        _factory = factory;
        _calculator = calculator;
    }

    public decimal Amount
    {
        get { return _calculator.CalculateAmount(_lines); }
    }

    public void AddLine(IProduct product, decimal price)
    {
        _lines.Add(_factory.CreateOrderLine(product, price));
    }
}

이 코드는 파괴적 분리의 결과입니다. 한편으로는 Order 클래스가 Product와 심지어 OrderLine으로부터 완전히 분리되어 있습니다. 계산 로직을 특별한 IOrderPriceCalculator 인터페이스에 위임하고, 라인 생성은 팩토리에서 수행됩니다.

동시에 이 코드는 완전히 비응집적입니다. 의미론적으로 밀접하게 관련된 클래스들이 이제 서로 분리되어 있습니다. 이것은 꽤 간단한 예제이므로 여기서 무슨 일이 일어나고 있는지 이해할 수 있을 것입니다. 하지만 익숙하지 않은 도메인 모델을 설명하는 이런 코드를 이해하는 것이 얼마나 어려울지 상상해보세요. 대부분의 경우 응집도 부족은 코드를 읽을 수 없게 만듭니다.

파괴적 분리는 종종 “모든 곳에 인터페이스” 태도와 함께 나타납니다. 즉, 인터페이스가 추상화를 나타내지 않더라도 모든 구체 클래스를 인터페이스로 대체하려는 유혹입니다.

그렇다면 위의 코드를 어떻게 다시 작성할까요? 다음과 같습니다:

public class Order
{
    public decimal Amount
    {
        get { return _lines.Sum(x => x.Price); }
    }

    public void AddLine(Product product, decimal amount)
    {
        _lines.Add(new OrderLine(product, amount));
    }
}

이렇게 하면 Order, OrderLine, Product 간의 연결을 복원했습니다. 이 코드는 간결하고 응집력이 있습니다.

응집도와 결합도 간의 관계를 이해하는 것이 중요합니다. 일관성을 해치지 않고 코드베이스를 완전히 분리하는 것은 불가능합니다. 마찬가지로 불필요한 결합을 도입하지 않고 완전히 응집력 있는 코드를 만드는 것도 불가능하지만, 응집도와 달리 결합도의 개념은 어느 정도 직관적이기 때문에 이러한 태도는 드문 경우입니다.

둘 사이의 균형이 높은(하지만 완전하지 않은) 응집도와 느슨하게 결합된(하지만 완전히 분리되지 않은) 코드베이스를 만드는 핵심입니다.

5. 다양한 레벨에서의 응집도와 결합도

앞서 언급했듯이 응집도와 결합도는 다양한 레벨에서 적용될 수 있습니다. 클래스 레벨이 가장 명확하지만 유일한 것은 아닙니다. 프로젝트 내의 폴더 구조가 한 예입니다:

언뜻 보면 프로젝트가 잘 구성되어 있습니다: 엔티티, 팩토리 등을 위한 별도의 폴더가 있습니다. 그러나 응집도가 부족합니다.

이는 다이어그램의 3번째 카테고리에 해당합니다: 잘못 선택된 경계. 프로젝트 내부가 실제로 느슨하게 결합되어 있지만, 경계가 의미론을 반영하지 못합니다.

높은 응집도(그리고 낮은 결합도)를 가진 버전은 다음과 같습니다:

이렇게 하면 관련된 클래스들을 함께 유지할 수 있습니다. 게다가 프로젝트의 폴더가 이제 유틸리티 목적이 아닌 도메인 모델 의미론으로 구조화됩니다. 이 버전은 첫 번째 카테고리에 속하며, 솔루션에서 이런 종류의 파티셔닝을 유지하는 것을 강력히 권장합니다.

6. 응집도와 단일 책임 원칙

응집도의 개념은 단일 책임 원칙(Single Responsibility Principle)과 유사합니다. SRP는 클래스가 단일 책임(변경해야 할 단일 이유)을 가져야 한다고 명시하는데, 이는 높은 응집도를 가진 코드가 하는 것과 비슷합니다.

차이점은 높은 응집도가 코드가 유사한 책임을 가져야 함을 의미하지만, 반드시 하나만 가져야 한다는 것은 아니라는 점입니다. SRP가 그런 의미에서 더 제한적이라고 말할 수 있습니다.

7. 요약

다음과 같이 요약해보겠습니다:

  • 응집도는 코드베이스의 한 부분이 논리적으로 단일하고 원자적인 단위를 형성하는 정도를 나타냅니다.

  • 결합도는 단일 단위가 다른 단위들로부터 독립적인 정도를 나타냅니다.

  • 응집도를 해치지 않고 완전한 분리를 달성하는 것은 불가능하며, 그 반대도 마찬가지입니다.

  • 코드베이스의 모든 레벨에서 “높은 응집도와 낮은 결합도” 가이드라인을 따르도록 노력하세요.

  • 파괴적 분리의 함정에 빠지지 마세요.