2025년 6월 21일 작성
응집도 - Module 내부의 연관성
응집도는 module 내부 구성 요소 간의 연관 정도를 나타내는 지표이며, 가능한 높은 응집도를 유지하는 것이 좋습니다.
응집도 : 소프트웨어 설계의 핵심적인 품질 지표
- 응집도(Cohesion)는 module 내부 구성 요소 간의 연관 정도를 나타내는 software 설계의 핵심 품질 지표입니다.
- module이 독립적인 기능을 수행하는지, 하나의 기능을 중심으로 책임이 잘 뭉쳐있는지를 측정하는 개념입니다.
- 정보 은닉 개념의 확장으로, 하나의 module은 하나의 기능을 수행해야 한다는 원칙을 구체화합니다.
응집도의 기본 특징
- 유사 기능 영역 구성을 통해 관련된 기능들을 논리적으로 grouping합니다.
- 동일한 목적을 가진 요소들을 하나의 module에 배치합니다.
- 서로 다른 목적을 가진 요소들은 별도의 module로 분리합니다.
- 단일 책임 할당으로 각 module이 명확한 하나의 역할만 담당하도록 설계합니다.
- module의 존재 이유가 명확하고 단순해집니다.
- 변경이 필요한 이유도 하나로 제한됩니다.
- 함수 간 상호 협력을 통해 module 내부 요소들이 공통 목표를 위해 함께 동작합니다.
- 각 요소가 전체 기능 완성에 필수적인 역할을 담당합니다.
응집도의 유형과 품질 순서
- 응집도는 7가지 유형으로 분류되며, 품질 순서는 다음과 같습니다.
- 우연적 < 논리적 < 시간적 < 절차적 < 통신적 < 순차적 < 기능적 순으로 품질이 향상됩니다.
- 높은 응집도를 가질수록 좋은 설계이며, 기능적 응집도가 가장 이상적인 형태입니다.
기능적 응집도 (Functional Cohesion)
- module 내부의 모든 기능이 단일한 목적을 위해 수행되는 최고 품질의 응집도입니다.
- module 내의 모든 요소들이 하나의 기능을 수행하기 위해 구성됩니다.
- 각 요소는 전체 기능에 필수불가결한 역할을 담당합니다.
- 가장 높은 응집도를 가지며 가장 좋은 형태로 평가됩니다.
public class TriangleCalculator {
public double calculateSine(double angle) {
return Math.sin(angle);
}
public double calculateCosine(double angle) {
return Math.cos(angle);
}
public double calculateTangent(double angle) {
return Math.tan(angle);
}
}
- 삼각함수 계산이라는 단일 목적을 위해 모든 method가 협력하는 예시입니다.
순차적 응집도 (Sequential Cohesion)
- module 내에서 한 활동의 출력 값이 다른 활동의 입력으로 사용되는 응집도입니다.
- data가 순차적으로 처리되며 각 단계의 결과가 다음 단계로 전달됩니다.
- 처리 순서가 중요하며 pipeline 형태의 구조를 가집니다.
public class FileProcessor {
public void processFile(String fileName) {
String content = readFile(fileName);
String processedContent = transformContent(content);
writeFile(processedContent, fileName);
}
private String readFile(String fileName) {
// file 읽기 logic
return content;
}
private String transformContent(String content) {
// content 변환 logic
return processedContent;
}
private void writeFile(String content, String fileName) {
// file 쓰기 logic
}
}
통신적 응집도 (Communicational Cohesion)
- 동일한 입력과 출력을 사용하여 다른 기능을 수행하는 활동들이 모여 있는 응집도입니다.
- 모든 요소들이 동일한 입출력 data를 사용하지만 서로 다른 기능을 수행합니다.
- 순차적 응집도와 달리 처리 순서가 중요하지 않습니다.
public class CustomerReportGenerator {
public void generateCustomerReport(Customer customer) {
printCustomerInfo(customer);
validateCustomerData(customer);
updateCustomerStatistics(customer);
}
private void printCustomerInfo(Customer customer) {
// 고객 정보 출력
}
private void validateCustomerData(Customer customer) {
// 고객 data 검증
}
private void updateCustomerStatistics(Customer customer) {
// 고객 통계 정보 update
}
}
절차적 응집도 (Procedural Cohesion)
- module이 다수의 관련 기능을 순차적으로 수행하지만 data가 아닌 흐름 제어 요소가 전달되는 응집도입니다.
- 여러 기능 요소가 순차적으로 수행되지만 각 단계 간 data 전달은 없습니다.
- 업무 흐름이나 procedure를 따라 구성됩니다.
public class FileAccessManager {
public void accessFile(String fileName) {
checkPermission(fileName);
logAccess(fileName);
openFile(fileName);
}
private void checkPermission(String fileName) {
// 접근 권한 확인
}
private void logAccess(String fileName) {
// 접근 기록 남기기
}
private void openFile(String fileName) {
// file 열기
}
}
시간적 응집도 (Temporal Cohesion)
- 특정 시간에 처리되어야 하는 활동들을 한 module에서 처리하는 응집도입니다.
- 각 기능 요소들이 순서에 상관없이 특정 시점에 반드시 수행됩니다.
- 초기화, 종료, 예외 처리 등에서 주로 나타납니다.
public class SystemInitializer {
public void initializeSystem() {
loadConfiguration();
connectDatabase();
startLogService();
initializeCache();
}
private void loadConfiguration() {
// 설정 파일 로드
}
private void connectDatabase() {
// database 연결
}
private void startLogService() {
// log service 시작
}
private void initializeCache() {
// cache 초기화
}
}
논리적 응집도 (Logical Cohesion)
- 유사한 성격을 갖는 처리 요소들이 한 module에서 처리되지만 서로의 관계는 밀접하지 않은 응집도입니다.
- 논리적으로 비슷한 기능을 수행하지만 실제 처리 과정은 다릅니다.
- 주로 parameter에 따라 다른 기능을 수행하는 형태로 나타납니다.
public class MathOperations {
public double calculate(int operation, double a, double b) {
switch (operation) {
case 0:
return a + b; // 덧셈
case 1:
return a - b; // 뺄셈
case 2:
return a * b; // 곱셈
case 3:
return a / b; // 나눗셈
default:
throw new IllegalArgumentException("Unknown operation");
}
}
}
우연적 응집도 (Coincidental Cohesion)
- 서로 간에 어떠한 의미 있는 연관 관계도 없는 기능 요소로 구성된 가장 낮은 품질의 응집도입니다.
- module 내부의 각 구성 요소들이 아무런 관련 없이 구성된 형태입니다.
- module 수정이 side effect를 발생시킬 가능성이 매우 높습니다.
- 가장 좋지 않은 응집도로 반드시 피해야 하는 설계입니다.
public class MiscellaneousUtilities {
public void printMessage(String message) {
System.out.println(message);
}
public int calculateAge(Date birthDate) {
// 나이 계산 logic
return age;
}
public void sendEmail(String recipient, String subject) {
// email 전송 logic
}
public double convertCurrency(double amount, String from, String to) {
// 환율 변환 logic
return convertedAmount;
}
}
응집도를 높이는 설계 원칙
- 응집도를 높이기 위해 다양한 설계 원칙과 pattern을 적용할 수 있습니다.
단일 책임 원칙 적용
- 하나의 module은 하나의 변경 사유만 가져야 합니다.
- class나 module이 변경되는 이유가 오직 하나여야 합니다.
- 서로 다른 이유로 변경되는 기능들은 별도 module로 분리합니다.
기능 중심 설계
- 비즈니스 기능을 중심으로 module을 구성합니다.
- 기술적 계층보다는 업무 도메인을 기준으로 분리합니다.
- 관련된 data와 behavior를 함께 배치합니다.
Interface 분리
- 큰 interface를 작은 단위로 분리하여 각각이 특정 목적만 담당하도록 합니다.
- client가 사용하지 않는 method에 의존하지 않도록 설계합니다.
- 응집도가 높은 작은 interface들로 구성합니다.
공통 변경 원칙 활용
- 함께 변경되는 class들을 같은 package나 module에 배치합니다.
- 동일한 이유로 변경되는 요소들을 grouping합니다.
- 변경의 파급 효과를 최소화합니다.
응집도 측정하고 개선하기
- 응집도를 정량적으로 측정하고 개선하기 위한 방법론이 존재합니다.
응집도 측정 지표
- LCOM(Lack of Cohesion of Methods) metric을 활용하여 class의 응집도를 정량적으로 측정합니다.
- method 간 공유하는 instance variable의 개수를 기반으로 계산합니다.
- 값이 낮을수록 높은 응집도를 의미합니다.
응집도 개선 전략
- Extract Class refactoring을 통해 큰 class를 기능별로 분리합니다.
- 서로 다른 책임을 가진 기능들을 별도 class로 추출합니다.
- 각 class가 단일 책임을 갖도록 재구성합니다.
- Move Method refactoring으로 method를 적절한 class로 이동시킵니다.
- method가 사용하는 data가 위치한 class로 method를 이동합니다.
- data와 behavior의 결합도를 높입니다.