높은 응집도 낮은 결합도

코드의 유지보수성에 대해서 이야기할 때 꼭 나오는 단어가 있습니다. 바로 응집도와 결합도 입니다. 유지 보수는 소프트웨어 생명 주기의 가장 큰 부분을 차지합니다. 요구사항에 따라 소프트웨어는 계속해서 변경되기 때문이죠. 우리는 코드의 변경에 유연하게 대처할 수 있는 코드를 작성해야 합니다.

응집도, 결합도의 개념과 함께 설계 시 두가지 개념을 고려해야 하는 이유에 대해서 이야기 해보려 합니다. 자바의 클래스를 예로 들어 설명하고 있지만, 모듈과 동일하게 생각하셔도 괜찮습니다.

응집도란?

응집도(Cohesion)는 하나의 클래스에 모여있는 데이터와 메서드가 밀접하게 관련되어 있는 정도를 말합니다.

높은 응집도의 장점

같은 목적을 가진 데이터와 메서드가 하나의 클래스에 모여있을수록 응집도가 높다고 할 수 있습니다. 클래스의 책임이 명확해지므로 코드를 분석하고 이해하기 쉬워집니다. 재활용이 쉬워지므로 코드 중복을 줄이는 데 큰 도움이 됩니다.

높은 응집도
낮은 응집도
  • 클래스의 책임이 명확함 → 코드 분석 및 수정이 쉬움
  • 재활용이 쉬움 → 코드 중복 감소

이런 이점들을 최대한 누리기 위해서 클래스와 메서드의 이름을 잘 지어주는 것이 중요합니다. 좋은 클래스 이름은 역할을 파악하기 쉽고, 좋은 메서드 이름은 로직을 파악하기 쉽습니다.

응집도와 SRP

응집도는 SOLID 원칙 중 S(Single Responsibility Principle), 단일 책임 원칙과도 관련이 있습니다. 응집도가 높은 클래스는 하나의 목적을 위한 데이터와 메서드를 가집니다. 즉 책임이 명확합니다.

높은 응집도 코드 예시

어떤 결과에 대한 보고를 위해 성공 횟수, 실패 횟수, 전체 횟수에 대해 카운팅하는 목적의 클래스입니다. ResultReport 인터페이스를 구현하고 있습니다.

interface ResultReport {
  public void increaseSuccessCount();
  public void increaseFailureCount();
  public long totalCount();
}

class DefaultResultReport implements ResultReport {
  private int successCount;
  private int failureCount;

  public ResultReport(int successCount, int failureCount) {
    this.successCount = successCount;
    this.failureCount = failureCount;
  }

  public void increaseSuccessCount() {
    this.successCount += 1;
  }

  public void increaseFailureCount() {
    this.failureCount += 1;
  }

  public int successCount() {
    return this.successCount;
  }

  public int failureCount() {
    return this.failureCount;
  }

  public long totalCount() {
    return this.successCount + this.failureCount;
  }
}

결합도란?

결합도(Coupling)는 하나의 클래스가 다른 클래스에 대해서 알고 있는 정도를 말합니다. A클래스가 B클래스에 대해 많이 알고 있는 것은 A가 B와 강하게 결합되었음을 의미합니다.

낮은 결합도의 장점

클래스 A가 클래스 B에 의존하고 있을 때 A와 B 사이의 결합도가 낮다는 것은 클래스 B가 변경되었을 때 클래스 A에는 영향을 주지 않는다는 것을 의미합니다. B의 코드를 수정해도 A는 영향을 받지 않습니다. 따라서 나도 모르게 다른 클래스를 고장낼 확률이 낮아집니다.

결합도가 낮은 코드는 인터페이스나 추상 클래스 등으로 느슨하게 결합되어 있습니다. 다형성을 통해 코드 중복이 줄어드는 효과도 있고, 유닛 테스트를 작성할 때 메서드를 Stub으로 대체할 수도 있습니다.

높은 결합도
낮은 결합도
  • 코드 수정 시 다른 클래스에 영향을 주지 않음 → 예상치 못한 버그를 줄일 수 있음
  • 다형성 적용 → 코드 중복 감소, 유닛 테스트 시 Stub으로 대체 가능

결합도가 높으면 클래스 A 코드 수정 시 여러 클래스에 영향을 줄 수 있습니다. 흩어진 코드를 확인하여 확실히 이해해야 버그를 줄일 수 있습니다. 나도 모르게 버그를 만들지 않기 위해서 결합도를 줄이는 노력이 필요합니다.

결합도와 OCP & DIP

결합도는 SOLID 원칙 중 O(Open/Closed Principle), 개방-폐쇄 원칙, D(Dependency Inversion Principle), 의존 관계 역전 원칙과 관련이 있습니다. 불필요한 결합을 줄이기 위해 다형성을 적용하고 의존 관계를 역전하는 방법을 고려해야 합니다.

낮은 결합도 코드 예시

ResultReportPrinter는 ResultReport 인터페이스에 의존하며, 의존 관계를 주입 받고 있습니다.

class ResultReportPrinter {
  private ResultReport resultReport;

  public ResultReportPrinter(ResultReport resultReport) {
    this.resultReport = resultReport;
  }

  public void printTotalCount() {
    System.out.println(resultReport.totalCount());
  }
}

관련 키워드

응집도에 대하여

  • SRP (Single Responsibility Principle)
  • 책임 주도 설계
  • 리팩터링
    • 메서드 추출
    • 클래스 추출

결합도에 대하여

  • 묻지 말고 시켜라
  • 디미터 법칙
  • OCP (Open/Closed Principle)
  • DIP (Dependency Inversion Principle)

참고 자료

  • 오브젝트 : 코드로 이해하는 객체지향 설계 – 조영호
스스로 경험하며 얻은 깨달음을 공유하기 좋아하며, 세상이 필요로 하는 코드를 작성하기 위해 노력하는 개발자입니다.

“유지보수와 결합/응집의 관계 (OOP)”의 한가지 생각

  • 항상 잘 보고 있습니다.
    첫 번째 예시에서 사용하는 이름인 ResultReport를 ResultCounter로 변경하는게 이름이 더 찰지지 않을까 하는 생각이 들었습니다 ㅎㅎ

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다