카테고리 없음

소개론 ch.9 모듈화 설계

신지아 2025. 12. 2. 20:35

모듈화(Modularity): 소프트웨어 공학 원리 중 가장 근간이 되는 개념으로, 시스템의 독립적인 기능을 가진 부분들을 각각의 논리적 묶음(모듈)으로 구성하여 개발하는 것을 의미한다.

 

장점

- 모듈의 독립적인 기능 단위이므로, 해당 기능이 수행할 작업이 무엇인지 이해하기 쉬움.

- 팀 단위 개발 시, 모듈을 기준으로 할당하기 쉬움.

- 변경 사항이 있을 시, 영향을 받는 모듈만 수정하면 되기에 용이함.

- 독립적인 기능이 있으므로 다른 소프트웨어 개발 시 쉽게 재사용할 수 있음.

- 추적성이 높음 - 요구사항 분석부터 설계, 구현까지 일관성 있고 체계적인 모듈 간 연결 구조를 제공함.

 

좋은 설게를 수행한 소프트웨어의 특성 (모듈 개념이 실질적으로 적용되는 단계)

- 계층적 구조: 시스템은 서브 시스템으로, 서브 시스템은 하위 기능 영역으로, 기능 영역은 모듈들로 구성됨 - ex. 책장이 여러 개의 칸(서브 시스템)으로 나뉘어져 있고, 각 칸에는 주제별로 묶인 책(모듈)들이 정리되어 있음. 체계적.

- 모듈로 구성된 설계 결과: 아키텍처 및 상세 설계의 구성 요소는 모듈 개념을 포함하는 독립적인 컴포넌트들로 이루어져야 함. 즉, 각각의 구분된 모듈로서 존재해야 함.

- 관심사 분할: 데이터와 처리 절차가 구분 가능하고 분리된 표현으로 나타나야 함 - ex. UI 계층, 처리 계층, 데이터 계층, ... / 데이터를 관리하는 부분, 데이터를 실제로 처리하는 부분, 사용자에게 보여 주는 부분이 명확하게 나뉘어 있어야 함. 주방(데이터), 요리사(처리), 식탁(UI)처럼 역할이 분리되어야 효율적임.

- 독립적인 기능 단위 구현: 설계 결과는 독립적인 특성을 가진 기능 단위로 구현하며, 모듈 간 상호작용 및 소프트웨어와 외부의 상호작용을 최소화해야 함


결합력(Coupling): 모듈 간의 의존성 관계를 측정하는 적도

핵심 원칙: 결합력이 작을수록(느슨할수록) 좋은 설계임.

목표: 모듈이 독립적인 기능을 가지도록 설계하고, 불필요한 중복을 제거하며, 가능한 모듈 간의 상호작용을 줄여야 함.

모듈 간 커플링을 최소화할 시 장점:
- 시스템 구성 요소 간 결합이 느슨해짐

- 변경에 의한 파동 효과(Ripple Effect)를 막을 수 있음

- 소프트웨어에 대한 이해도를 높임

- 모듈의 인터페이스가 단순해짐

 

결합력 = 의존성

즉, 모듈들이 얼마나 서로 꽉 엮여 있는지를 나타냄

높은 결합력: 모듈 A를 고침 -> 모듈 B, C, D가 줄줄이 고장남 = 나쁜 설계

낮은 결합력: 모듈 A만 독립적으로 고칠 수 있음 - 수정이 쉽고, 오류가 전파되지 않아 안정적임

 

커플링의 목표는 의존성을 최소화하여 느슨한 결합을 만드는 것


모듈 간 결합력 유형 및 스케일

1. 메시지 결합력

특징: 결합의 정도가 가장 느슨한 유형, 객체지향에서 클래스 개념을 사용함

상호작용: 객체 간 상호작용은 메시지 전달이라는 한 가지 개념에 의해서만 이뤄짐

캡슐화: 객체 내 변수들은 Public 및 Private을 통해 캡슐화됨

객체지향에서 서로 메시지를 보내 대화하는 방식. 상대방의 내부를 모르고, 정해진 방법으로만 소통하기에 독립성이 완벽히 보장됨.

 

2. 데이터 결합력

특징: 2개의 모듈이 정수형, 문자형 등 단순한 기본 데이터 타입을 갖는 변수들에 이해 상호작용하는 경우

관계: main() 함수를 제외한 대부분의 함수 호출 관계는 데이터 결합력에 해당함 (피할 수 없는 관계)

*참고: 매개변수가 많아지는 Wide Interface를 지양하고, 관련 데이터를 구조화하여 매개변수를 줄이는 것이 좋음

단순히 숫자나 문자 같은 기본 정보를 주고받는 관계임. 아주 기본적인 함수 호출 관계이므로 피할 수 없음.

ex. add(10, 20) 이렇게 단순 데이터만 전달

 

3. 스탬프 결합력

특징: 두 모듈이 구조체와 같은 복합 데이터를 이용해 상호작용하는 경우.

문제점: 구조체 전체가 전달되기 때문에, 호출받는 모듈에서 구조체의 일부 멤버만 필요하더라도 불필요한 데이터까지 모두 전달되어 손실 발생할 수 있음 ex. 실행 시간, 메모리

개선 방안: 필요한 정보만 전달하도록 함수 선언하기, 서로 관련 없는 데이터를 인위적으로 하나의 구조체로 묶지 않도록 주의하기 - 관련성이 적은 경우, 2개 이상의 구조체로 분리 선언해야 함.

쉽게 설명하자면 통째로 스탬프(도장)을 찍어 보내는 것과 같음. 고객 정보가 담긴 거대한 봉투(구조체)를 통째로 전달하는데, 받는 모듈은 그 중에서 전화번호만 필요하다고 가정한다면, 그 외의 정보들(이름, 주소, SSN 등)까지 다 받게 되므로 비효율적임. 이럴 경우 필요한 데이터만 따로 전달하러간, 구조체를 의미 있는 단위로 쪼개야 함.

 

4. 제어 결합력

특징: 한 모듈에서 다른 모듈로 전달되는 매개변수(주로 Flag 변수)가 호출되는 함수의 내부 행위를 제어하는 역할을 할 때 발생함.

문제점: 호출하는 모듈이 호출되는 모듈의 내부 로직을 알아야 함 -> 독립성 저해됨

쉽게 설명하자면 리모컨을 넘겨 주는 것과 같음. 모듈 A가 모듈 B를 호출할 때, "1번 플래그를 줄 테니 넌 읽기 기능을 실행해"라고 명령한다고 생각해 보자. 모듈 A가 모듈 B의 내부 행동(읽을지 쓸지)을 제어하고 있음을 알 수 있다.

좋은 설게의 조건은 각 모듈이 스스로 일을 결정하도록 해야 하기 때문에, 이에 대한 개선 방법은 모듈 A가 직접 doRead()를 호출하거나, doWrite()를 호출하도록 로직을 분리하는 것이다.

 

5. 외부 결합력

2개의 모듈이 외부에 존재하는 다른 정보(파일, 디바이스 인터페이스, 프로토콜)를 공유하고 상호작용하는 경우.

위험: 다른 모듈이 변수 변경이나 동시 접근으로 인한 데드락(Deadlock) 등의 문제가 발생할 수 있음.

쉽게 설명하자면 외부 장치(프린터 등)를 같이 사용하는 상황. 내가 프린터를 쓰고 있는데, 다른 모듈이 설정값을 갑자기 바꿔버리면 오류가 날 것. 이것이 외부 결합력.

 

6. 공유 결합력

특징: 2개의 모듈이 글로벌 변수를 공유하는 관계

문제점: 모듈 간 의존성을 높임 -> 독립성 저해됨, 한 모듈의 공유 변수 수정이 다른 모듈에 영향을 줄 수 있음 (외부 결합력과 비슷함)

장점: 메모리 사용량을 줄이고, 프로그램 작성을 간단하게 할 수 있으나, 독립성 보장을 위해 꼭 필요한 변수만 글로벌 변수(광역 변수)로 선언해야 함

개선 방안: 글로벌 변수의 범위를 줄이기 위해 관련 변수들을 모듈 내 static 변수로 분리하여 선언하는 것을 고려해야 함

쉽개 설명하자면 글로벌 변수라는 공용 메모리를 같이 사용하는 상황이라 생각하면 됨. 모듈 A가 전역 변수 X = 10이라 설정했는데, 모듈 B가 갑자기 X = 20으로 값을 업데이트하면 모듈 A는 예측할 수 없는 결과를 얻게 됨. -> 모듈의 독립성이 훼손됨.

 

7. 내용 결합력

특징: 한 모듈이 다른 모듈의 내부(데이터나 코드)를 직접 참조하는 경우.

등급: 가장 나쁜 형태의 결합력

ex. 기존 절차적 언어에서 사용되던 goto가 대표적. 절대 피해야 하는 최악의 설계.


응집력(Cohesion): 응집력은 모듈을 구성하는 내적 요소(명령어, 변수 정의, 함수 호출 등) 간의 기능적 관련성의 강도를 측정하는 척도 (= 똘똘 뭉침의 정도)

모듈의 응집력을 최대화하는 것이 목표로 하며,

소프트웨어 설계 과정에서 독립적인 기능을 갖춘 모듈을 식별하는 것이 설계 목표이다.

높은 응집력을 가질수록 좋은 설게라고 평가한다. 유지보수가 쉽기 때문이다. 예를 들어 모듈 A의 모든 기능이 '로그인'이라는 단 하나의 목표를 존재하는 상황일 때 응집력이 높다고 할 수 있다.

낮은 응집력을 가질 때는 나쁜 설계라고 평가한다. 유지보수가 쉽지 않기 때문이다. 모듈 A가 로그인, 결제, 데이터베이스 백업 등 서로 관련 없는 기능들을 뒤섞어 가지고 있어 응집력이 낮다. 

좋은 설계의 기준은 응집력은 높고, 결합력은 낮은 상태이다. 

 

1. 기능 응집력

모듈을 구성하는 모든 요소가 단지 하나의 기능을 구현하기 위해 구성되었으며, 다른 추가 연산이나 기능 수행 없이 하나의 기능만 수행한 후 종료함.

ex. CalculateTax() 함수는 오로지 세금 계산한 수행함.

 

2. 순차 응집력

모듈을 구성하는 문장 관계에서, 한 문장의 실행 결과가 다음 문장의 입력으로 사용되는 경우임. (순차적인 입출력 관계)

순차 응집력을 구성하는 모든 문장이 기능 응집력을 만족하도록 정의하는 것이 중요함. 마지막 문장이 기능 응집력을 충독하지 못하면 응집력의 효과가 저해될 수 있음.

ex. 성적 읽음 -> 총점 구함 -> 평균 구함 (순차적으로 앞 단계의 결과가 뒷 단계에 사용됨)

 

3. 교환 응집력

모듈을 구성하는 모든 요소가 동일한 입력 또는 출력을 사용한다면 교환 응집력이 있다고 정의함.

문제점: 연산 결과의 반환(Return)에서 호출 모듈이 필요 없는 정보까지 모두 반환하면 의미 없는 부가 연산이 됨.

개선 방안: 모듈을 분리하여 필요한 정보만 반환하도록 만듦

e/x. 고객 이름, 잔고, 개설일 정보를 모두 반환하는 모듈이 있다면 -> 이를 이름만 반화하는 모듈, 잔고만 반환하는 모듈, 개설일만 반환하는 모듈로 분리 - 호출자가 하나의 정보만 원할 시, 다른 정보들까지 반환하는 것은 불필요한 낭비(부가 연산)이기 때문

 

4. 절차 응집력

모듈을 구성하는 문장들이 의미상 서로 관련이 없지만, 제어 흐름의 순서가 있는 경우

ex. 지난 학기 총점과 이번 학기 총점을 비교한다. 라는 문장은 성적 계산이라는 주 기능과 의미상 관련이 없지만, 절차상 순서는 정해져 있을 수 있음.

성적 읽기 -> 평균 계산 -> 지난 학기 성적 비교 -> 석차 부여 단계를 거쳐야 하므로 순서는 있지만 관련성은 약함.

위 단계에서 지난 학기 성적 비교는 필수 절차가 아님 - 단순히 실행 순서만 따라 묶여 있기에 유지보수가 어려움.

 

5. 시간 응집력

모듈을 구성하는 각 문장이 소프트웨어 실행의 특정 시간과 관련이 있는 것으로만 구성된 경우

ex. 데이터 사용 전 모든 변수를 처음에 초기화,

파일 사용 전 모든 파일을 오픈,

사용자에게 알림 정보를 제공하기 위한 모든 메시지를 처리

특정 시간에 실행해야 하는 것들을 모아 둔 것이다. 예르 ㄹ들어 프로그램이 시작될 때 실행해야 하는 변수 초기화, 파일 오픈, 로그인 설정 등을 하나의 모듈에 모아 둔다. 기능적으로는 관련이 없지만, 실행 시간이 같다는 이유로 묶여 있기 때문에 독립성이 매우 낮다.

 

6. 논리 응집력

모듈을 구성하는 모든 요소가 논리적으로 같은 유형의 외부 동작들로 구성되는 경우.

ex. 입력 플래그에 따라 read, write, update 중 하나를 수행하는 모듈

하나의 모듈이 여러 비슷한 기능을 if-else 구문이나 플래그를 사용해 선택적으로 수행함.

ex. 모듈이 플래그 값에 따라 읽기. 쓰기, 업데이트 기능을 모두 가지는 경우, 새로운 기능을 추가하려면 기존 모듈을 수정해야 하고, 그렇게 한다면 불필요한 코드가 많아지므로 기능 응집력을 사용해 개선해야 함.

 

7. 우연 응집력

모듈을 구성하는 모든 요소가 아무런 관련성이 없는 것으로 묶인 경우

가장 나쁜 형태의 응집력이며, 절대 작성되어서는 안 될 모듈 구성임

ex. 사과 계산, 로그인 처리, 프린터 드라이브 등 관련 없는 것들이 하나에 다 들어 있다고 생각하면 됨

 

 

좋은 설계는 결합력이 낮고 응집력이 높은 모듈 구성으로 이루어져야 한다.

(기능 응집력, 순차 응집력, 교환 응집력 지향)