Soyeon Park 님의 블로그
전통적인 설계 원리 본문
1. 추상화
추상화는 컴포넌트 구현에 대한 자세한 사항을 고려하지 않고, 추상적인 수준으로 컴포넌트를 다루는 도구이다. 컴포넌트는 외부에 서비스를 제공하는데, 이때 내부가 어떻게 동작하는지 상세한 사항에 구애 받으면 안된다. 단지 외부에 보이는 동작을 나타내면 된다.
즉, 추상화란 특정한 목적에 관련된 정보에 집중하고, 나머지 정보는 무시하는 관점이다. 예를 들어, 자동차에 추상화를 적용해보자. 엑셀을 밟으면 속도가 올라가고, 브레이크를 밝으면 멈추는 객체로 추상화할 수 있다. 내부적으로 엑셀과 브레이크가 어떤 구조를 가지고 어떻게 구현되는지는 관심이 없다. "자동차의 동작"이라는 특정한 목적에 집중한 것이다. 추상화는 복잡한 것을 줄이고, 시스템을 효율적으로 다룰 수 있게 해준다. 외부에 보이는 동작을 잘 나타내는 추상화가 중요하다.
조금 더 개발 관점에서 바라보면, 추상화는 컴포넌트의 인터페이스는 해당 구현과 독립적이어야 한다는 뜻이다. 자동차의 인터페이스는 페달, 기여변속 스틱 등이 있다. 이들이 전기차로 구현되건, 내연기관차로 구현되건 인터페이스와는 독립적인 관계이다.
*컴포넌트: 명백한 역할을 가지고 있으며 독립적으로 존재할 수 있는 시스템의 부분. 같은 기능을 가진 다른 컴포넌트로 대체 가능
2. 캡슐화
캡슐화는 추상화된 대상이 제공하는 서비스를 쉽게 접근하기 위한 개념이다. 특정한 목적만 노출시키고 어떻게 제공하는지는 숨긴다. 자세한 내부 구현(데이터 저장, 처리, 기능 구현 등)을 외부에 드러내지 않고 캡슐 안에 숨기는 것이다. 정보은닉이라고 한다.
정보은닉이 잘되면 모듈의 숨겨진 부분에 대한 변경사항이 모듈 외부의 내용에 영향을 미치지 않게 된다. 따라서 정보은닉을 통하여 더 높은 수준의 추상화를 유지할 수 있다. 소프트웨어 변경 요구에 탄력적으로 대처할 수 있는 것이다.
3. 모듈화
모듈화는 문제를 소프트웨어 구성요소가 될 만한 수준을 분할하는 과정이다. 복잡한 시스템을 세분화된 구성요소로 정의하면 더 잘 이해할 수 있다. 소프트웨어를 패키지 또는 클래스로 나누는 것으로 볼 수 있다. 너무 많은 모듈로 분할한다면 응집력이 낮아지고, 서로 상호작용이 더 복잡해질 수 있다. 재사용성을 극대화하면서, 의존성을 최소화할 수 있는 균형을 찾는 것이 중요하다.
3.1. 추상화 - 캡슐화 - 모듈화의 관계
추상화는 시스템의 핵심 특성에 초점을 두어 하나의 큰 시스템을 분할하는 원리이다. 캡슐화는 분할된 핵심 정보만을 노출시켜 내부 변경에 대한 영향을 최소화로 한다. 추상화와 캡슐화 원리에 의하여 큰 시스템이 잘 모듈화된 시스템으로 완성된다.
모듈을 추상화한 인터페이스와 실제 구현 모듈은 별개로 생각한다. 인터페이스는 컴포넌트에 대한 사용자의 뷰이다. 구현은 개발자의 뷰이다. 사용자는 이 컴포넌트를 사용할 때 캡슐화된 모듈의 내부가 어떻게 생겼는지는 관심없고, 개발자는 사용자에게 알리지 않고 구현을 수정할 수 있게 되는 것이다.
4. 결합
모듈 간 의존도이다. 결합도는 낮을 수록 좋다.
- 내용 결합: 한 모듈이 다른 모듈의 내용을 직접 찹조하는 경우
ex. 모듈P가 모듈Q의 문장을 조작 / P가 Q의 로컬 데이터 값 참조 / P가 Q 내부로 분기하는 경우 - 공통 결합: 한 모듈이 다른 모듈이 읽은 전역 변수 값을 쓰거나 변경하는 경우
모듈이 매개변수 대신에 "전역 변수"를 이용하여 데이터를 교환하는 경우를 공통 결합이라고 한다. - 제어 결합: 한 모듈이 다른 모듈의 제어흐름 경로를 결정하는 경우
모듈A가 모듈B에게 매개변수를 넘겨주는데, 그 값이 모듈B 내부의 if-else, switch 문을 작동시키는 플래그로 쓰인다는 뜻이다.
print(milesTraveled, displayMetricValues)
...
public void print(int miles, bool displayMetric) {
if (displayMetric) {
System.out.println(...);
}
else {...}
}- 스탬프 결합: 복합 데이터 구조의 일부만 사용하는 모듈에 복합 데이터 구조를 전달하는 경우
3개의 필드가 있는 레코드를 처음 2개 필드만 필요한 모듈에 매개변수로 전달하는 경우이다.
ex. 편의점 알바가 나이를 물었을 때 → 신분증을 보여준다. - 데이터 결합: 모듈들이 주고받는 매개변수가 간단한 타입이거나 레코드 안의 필드라도 단순 타입인 경우
ex. 편의점 알바가 나이를 물었을 때 → 나이만 알려준다.
5. 응집
하나의 모듈 내 작업들이 서로 관련된 정도이다. 응집도는 높을 수록 좋다.
- 우연적 응집: 단위 안의 요소들이 의미적으로 아무런 관계가 없다.
- 논리적 응집: 본질적으로 다르더라도 같은 범주의 기능을 수행하므로 논리적으로 분류되기 때문에 그룹으로 묶인 경우
ex. 마우스/키보드 입력 처리 루틴을 한 모듈 안에 넣었다면 "입력"이라는 논리로 분류한 것이다. - 순차적 응집: 모듈 내부 요소가 프로그램이 실행되는 특정한 시간에 처리되므로 한 그룹 안에 모여 있는 경우
ex. 열린 파일 닫고 → 오류 로그 생성하고 → 사용자에게 통보하는 예외 처리 함수. 기능이 다 다른데, 예외 처리하는 시점에 발생한다는 이유로 모여있는 것이다. - 절차적 응집: 모듈 안에서 수행되는 연산이 프로그램에서 수행되는 순서와 관련이 있는 경우
ex. 키보드 입력 → 확인하고 전역 변수에 답을 저장하다.
operationA(){
// 각각 다른 기능인데, 하나의 모듈 안에 모여있음
readData(data,filename1);
processAData(data);
storeData(data,filename2);
}- 교환적 응집: 모듈 내부 요소들이 동일한 데이터를 조작하기 때문에 모아진 경우
- 기능적 응집: 모듈에 대하여 정의된 하나의 기능에 모두 기여하고 밀접하게 관련되어 모아진 경우
- 정보적 응집: 데이터 구조 하나를 중앙에 두고, 그 데이터를 조작하는 여러 개의 독립적인 기능(메서드)들을 하나의 모아둔 경우
객체지향에서는 자연스럽게 정보적 응집을 갖도록 설계한다. 각 객체는 객체 안에 정의된 데이터를 조작하며, 객체의 각 멤버함수는 하나의 고유한 동작, 오퍼레이션, 함수를 수행한다.
class Airplane {
private double speed, altitude;
public void takeoff() {...}
public void fly() {...}
public void land() {...}
}
'소프트웨어공학' 카테고리의 다른 글
| GoF Design Pattern (0) | 2026.04.18 |
|---|---|
| SOLID - 코드로 이해하기 (0) | 2026.04.14 |
| 객체지향 설계 원리 (0) | 2026.04.14 |
| 결합도와 응집도 (Coupling and Cohension) (0) | 2026.04.14 |