응집도 완벽정리 - 기능적·순차적·교환적·절차적·시간적·우연적 응집도 예제 코드로 이해하기

응집도란?

응집도는 모듈(함수, 클래스 등) 내부의 구성 요소들이 서로 얼마나 밀접하게 관련되어 있는지를 나타내는 개념입니다.


응집도 종류 영문명 설명

우연적 응집 Coincidental Cohesion 관련 없는 기능들이 모여 있음
논리적 응집 Logical Cohesion 논리적으로 관련된 기능을 묶음
시간적 응집 Temporal Cohesion 같은 시(예: 초기화)에 수행되는 기능을 묶음
절차적 응집 Procedural Cohesion 순서에 따라 수행되는 기능을 묶음
통신적 응집 Communicational Cohesion 동일 데이터를 처리하는 기능을 묶음
기능적 응집 Functional Cohesion 하나의 명확한 기능을 수행
내용적(정보적) 응집 Informational Cohesion 여러 기능이 공통 데이터를 공유

① 우연적 응집 (Coincidental Cohesion)

서로 아무 관련없고 상관이 없는 기능들이 하나의 모듈에 들어 있는 형태를 의미합니다.

이렇게되면 유지보수도 어렵고 코드의 목적도모르게 됩니다.

// ============================================
// 1. 우연적 응집도 (Coincidental Cohesion) - 최악
// ============================================
// 모듈의 구성 요소들이 아무런 관련이 없음
// 단지 같은 파일에 있다는 이유로 묶여있음

class CoincidentalCohesion {
  // 전혀 관련 없는 기능들이 한 클래스에 존재
 
  printReport() {
    console.log("리포트 출력");
  }

  calculateTax(amount: number): number {
    return amount * 0.1;
  }

  sendEmail(to: string, message: string) {
    console.log(`이메일 전송: ${to}`);
  }

  validatePassword(password: string): boolean {
    return password.length >= 8;
  }
}

② 논리적 응집 (Logical Cohesion)

논리적으로 관련된 기능들을 하나의 모듈에 묶은 형태입니다.
논리적으로는 유사하지만 실제로 동작은 서로 다릅니다.
예) 모든 입력 처리 라는 주제만 같고 나머지로직은 다릅니다.

// ============================================
// 2. 논리적 응집도 (Logical Cohesion)
// ============================================
// 유사한 성격의 작업들을 묶었지만, 실제로는 다른 작업을 수행
// flag나 매개변수로 어떤 작업을 할지 결정

class LogicalCohesion {
  // 입력을 처리하지만, 각각 다른 타입의 입력을 처리
  handleInput(type: 'mouse' | 'keyboard' | 'touch', data: any) {
    switch(type) {
      case 'mouse':
        this.handleMouseInput(data);
        break;
      case 'keyboard':
        this.handleKeyboardInput(data);
        break;
      case 'touch':
        this.handleTouchInput(data);
        break;
    }
  }

  private handleMouseInput(data: any) {
    console.log("마우스 입력 처리");
  }

  private handleKeyboardInput(data: any) {
    console.log("키보드 입력 처리");
  }

  private handleTouchInput(data: any) {
    console.log("터치 입력 처리");
  }
}

③ 시간적 응집 (Temporal Cohesion)

같은 시점에 실행되는 기능들을 묶은 형태의 응집도입니다.
실행 시점이 비슷하지만 기능과 목적은 다릅니다.
예) 프로그램의 시작 또는 종료

// ============================================
// 3. 시간적 응집도 (Temporal Cohesion)
// ============================================
// 특정 시점에 함께 실행되어야 하는 기능들을 묶음
// 초기화나 종료 시에 관련 없는 작업들을 함께 처리

class SystemInitializer {
  // 시스템 시작 시 실행되어야 하는 것들을 모아놓음
  // 각 작업은 서로 직접적인 관련이 없음
 
  initialize() {
    this.connectToDatabase();
    this.loadConfiguration();
    this.startLogging();
    this.initializeCache();
    this.setupEventHandlers();
  }

  private connectToDatabase() {
    console.log("데이터베이스 연결");
  }

  private loadConfiguration() {
    console.log("설정 로드");
  }

  private startLogging() {
    console.log("로깅 시작");
  }

  private initializeCache() {
    console.log("캐시 초기화");
  }

  private setupEventHandlers() {
    console.log("이벤트 핸들러 설정");
  }
}

④ 절차적 응집 (Procedural Cohesion)

특정 순서에 따라 처리되어야 하는 기능들을 묶은 형태입니다.
순서는 있지만 데이터의 전달이 없이 각각 따로 실행되며 작업이 절차적으로만 이루어 집니다.

// ============================================
// 4. 절차적 응집도 (Procedural Cohesion)
// ============================================
// 순차적으로 실행되는 작업들을 묶음
// 작업들이 순서대로 실행되지만, 데이터를 공유하지 않을 수 있음

class FileProcessor {
  // 파일 처리 절차를 순차적으로 실행
 
  processFile(filename: string) {
    this.openFile(filename);
    this.readData();
    this.validateData();
    this.closeFile();
  }

  private openFile(filename: string) {
    console.log(`파일 열기: ${filename}`);
  }

  private readData() {
    console.log("데이터 읽기");
  }

  private validateData() {
    console.log("데이터 검증");
  }

  private closeFile() {
    console.log("파일 닫기");
  }
}

⑤ 통신적 응집 (Communicational Cohesion)

같은 데이터를 처리하거나 동일한 입력/ 출력 데이터를 사용하는 기능들을 묶은 형태입니다. 공통 데이터의 중심이고 데이터처리 단계들이 하나로 묶여있습니다.

// ============================================
// 5. 통신적 응집도 (Communicational Cohesion)
// ============================================
// 같은 데이터를 사용하는 작업들을 묶음
// 여러 기능이 같은 입력 데이터나 출력 데이터를 공유

class CustomerReport {
  // 같은 고객 데이터를 사용하는 여러 작업
 
  generateCustomerReport(customerId: string) {
    const customer = this.getCustomerData(customerId);
   
    this.printCustomerInfo(customer);
    this.printOrderHistory(customer);
    this.printPaymentInfo(customer);
  }

  private getCustomerData(customerId: string) {
    return {
      id: customerId,
      name: "홍길동",
      orders: [],
      payments: []
    };
  }

  private printCustomerInfo(customer: any) {
    console.log(`고객 정보: ${customer.name}`);
  }

  private printOrderHistory(customer: any) {
    console.log(`주문 내역: ${customer.orders.length}건`);
  }

  private printPaymentInfo(customer: any) {
    console.log(`결제 정보: ${customer.payments.length}건`);
  }
}

⑥ 순차적 응집 (Sequential Cohesion)

한 기능의 출력이 다음 기능의 입력으로 사용되는 기능들을 묶은 형태입니다.
기능들이 순서대로 실행되고 데이터의 흐름(Data Flow)을 중심으로 연결되어 있습니다.

// ============================================
// 6. 순차적 응집도 (Sequential Cohesion)
// ============================================
// 한 작업의 출력이 다음 작업의 입력으로 사용되는 경우
// 데이터가 파이프라인처럼 흘러감

class DataPipeline {
  // 각 단계의 출력이 다음 단계의 입력이 됨
 
  processData(rawData: string): number {
    const cleaned = this.cleanData(rawData);
    const parsed = this.parseData(cleaned);
    const validated = this.validateData(parsed);
    const result = this.calculateResult(validated);
    return result;
  }

  private cleanData(raw: string): string {
    console.log("데이터 정제");
    return raw.trim().toLowerCase();
  }

  private parseData(cleaned: string): string[] {
    console.log("데이터 파싱");
    return cleaned.split(',');
  }

  private validateData(parsed: string[]): string[] {
    console.log("데이터 검증");
    return parsed.filter(item => item.length > 0);
  }

  private calculateResult(validated: string[]): number {
    console.log("결과 계산");
    return validated.length;
  }
}

⑦ 기능적 응집 (Functional Cohesion)

모든 기능이 하나의 명확한 목적 그리고 단일책임 원칙인 SRP를 잘 이행하고 있는 수준이고 유지보수성과 재사용성이 가장 좋습니다.

// ============================================
// 7. 기능적 응집도 (Functional Cohesion) - 최고
// ============================================
// 모든 구성 요소가 하나의 잘 정의된 작업을 수행
// 단일 책임 원칙(Single Responsibility Principle)을 따름

class EmailValidator {
  // 이메일 유효성 검사라는 단일 기능만 수행
 
  validate(email: string): boolean {
    return this.hasValidFormat(email) &&
           this.hasValidDomain(email) &&
           this.hasValidLength(email);
  }

  private hasValidFormat(email: string): boolean {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }

  private hasValidDomain(email: string): boolean {
    const domain = email.split('@')[1];
    return domain !== undefined && domain.length > 0;
  }

  private hasValidLength(email: string): boolean {
    return email.length >= 5 && email.length <= 255;
  }
}

class PasswordHasher {
  // 비밀번호 해싱이라는 단일 기능만 수행
 
  hash(password: string): string {
    const salt = this.generateSalt();
    const hashed = this.computeHash(password, salt);
    return this.formatResult(hashed, salt);
  }

  private generateSalt(): string {
    return Math.random().toString(36).substring(7);
  }

  private computeHash(password: string, salt: string): string {
    // 실제로는 bcrypt 같은 라이브러리 사용
    return `hashed_${password}_${salt}`;
  }

  private formatResult(hash: string, salt: string): string {
    return `${salt}:${hash}`;
  }
}

class PriceCalculator {
  // 가격 계산이라는 단일 기능만 수행
 
  calculateTotal(basePrice: number, quantity: number, discountRate: number = 0): number {
    const subtotal = this.calculateSubtotal(basePrice, quantity);
    const discount = this.calculateDiscount(subtotal, discountRate);
    const total = this.applyDiscount(subtotal, discount);
    return this.roundPrice(total);
  }

  private calculateSubtotal(price: number, quantity: number): number {
    return price * quantity;
  }

  private calculateDiscount(amount: number, rate: number): number {
    return amount * rate;
  }

  private applyDiscount(amount: number, discount: number): number {
    return amount - discount;
  }

  private roundPrice(amount: number): number {
    return Math.round(amount * 100) / 100;
  }
}

예제를 통해서 응집도를 알아봤습니다.

제가 작성한 코드들도 응집도가 무조건적으로 기능적으로 응집한 코드만 있는게 아니여서 무조건 적으로 기능적 응집도만 고집 할수는 없고 대신 예외 상황이 아니라면 최대한 기능적 응집도 즉 srp를 잘 이루는 코드를 짜도록 하는것을 목적으로 두고 코드를 작성해야 품질 좋은 코드를 작성 할 수 있을것 같습니다.

반응형