어떻게 실현할 것인가 (<-> 요구분석: 무엇을 만들 것인가)
- 문제를 해결하여 솔루션을 구축해가는 과정
- 기본 구조 설계; 아키텍처 설계로 각 모듈의 역할과 인터페이스를 정의
- 상세 설계: 모듈 내부의 알고리즘, 데이터를 명세화
- 전통적 방법
- 분할 정복, top-down, 추상화 등
- 기능 실현에 중점
- 최근 방법
- 아키텍처 기반의 설계 방법 (복잡한 문제 처리, 변경에 대처)
- 품질 중심 설계
시스템을 구성하는 컴포넌트와 컴포넌트 상호작용의 집합
-
독립적으로 취급될 수 있는 단위 (서브시스템 or 모듈)
-
재사용 가능하게 설계
-
서브시스템
-
시스템의 복잡도를 줄이기 위해 분할한 것
-
분업, 커뮤니케이션 줄임, 서브시스템끼리 영향 덜 받음
예) java에서는 패키지로 구현
-
-
모듈
-
프로그래밍 언어의 문법 구조에서 정의된 컴포넌트
예) 메서드, 클래스, 패키지, 파일, 함수 등
-
- 소프트웨어 구조 (컴포넌트와 그것들의 관계)를 바라보는 일관된 방법
- 과거와는 달리 관점에 근거한 품질 중심 설계로 변화됨
- 종류
측면 | 모듈 관점(정적) | 컴포넌트 관점(동적) | 할당 관점 |
---|---|---|---|
내용 | 일정한 책임을 구현한 코드 단위인 모듈과 그 관계 | 실행될 떄 동작하는 요소들과 상호작용 | 소프트웨어의 하드웨어 설치, 작업 할당 , 구현, 데이터 저장에 대한 관점 |
설계 스타일 | 분할, 사용 관계, 계층구조, 데이터 모델 | 클라이언트 서버, 파이프, 출판 구독, 이벤트, 저장소 | 배치, 설치, 작업할당, 데이터 저장 |
-
의사 결정 과정이면서 동시에 시스템을 알아가는 과정
-
개발될 시스템의 유형이 중요 -> 아키텍처 스타일에 많은 영향을 줌
예) 대화형 시스템 -> 계층 구조 스타일
예) 임베디드 시스템 -> event-driven 스타일
예) 기존 시스템에 속하지 않는 시스템 -> 맞춤형 아키텍처 스타일
-
설계 목적 -> 설계 결과(품질)에 영향을 줌
예) 보안이 주요 목적이라면 인증 모듈, 정보보호 인터페이스 고려
- 비기능적 요구
- 설계에 대한 목표가 될 수 있음 -> 구체적으로 명시
- 이 설계 목표를 위한 설계안을 만들고 최적안을 골라내는 작업
- 서로 상충되는 요구(예: 성능 <-> 안정성)가 있을 때 최적안 선택
- ISO 25010 품질 특성 모델
- 성능: 단위시간당 처리량이 높은가, 트랜잭션당 응답 시간이 짧은가
- 상호운영성: 외부 시스템과의 데이터 전송/교환이 용이한다
- 사용용이성: 시스템의 효율적 사용으로 인해 사용자가 만족하는가
- 신뢰성: 시스템이 정의된 조건 아래 계속 동작할 수 있는가
- 보안성: 악의적, 우발적 행동으로부터 시스템을 보호하는가
- 유지보수성: 변경을 시스템이 얼마나 잘 수용할 수 있는가
- 이식성: HW, SW, 사용 환경을 다른 곳으로 쉽게 변환할 수 있는가
단순성 | 효율성 | 분할, 계층화 | 추상화 | 모듈화 |
---|---|---|---|---|
복잡한 여러가지 요소를 교통 정리하여 단순화 하거나 복잡함을 최소화 한다. | 사용하는 자원이 적정하고 효과적이도록 한다. | 다루기 쉬운 덩어리로 분리하여 계층화 한다. | 자세한 부분에 좌우되지 않게 컴포넌트를 정의한다. | 각 모듈이 외부와의 결합이 낮고 내부 요소가 응집되도록 한다. |
-
단순성
유지보수성에 영향을 주는 가장 중요한 특성
-
효율성
시스템 자원(처리시간, 기억공간)이 적정하고 효과적 -> 비용 절약
-
추상화
-
특정 목적에 관한 정보에 집중
-
구현에 대한 자세한 사항을 고려하지 않음
예) 자동차를 추상화하면, 엑셀 밟으면 가속하고 브레이크 밟으면 감속하는 객체
-
데이터나 절차적인 동작 관점으로 정의
예) 클라이언트와 서버의 정보교환을 주고받은 메시지의 추상화
-
-
캡슐화
- 추상화된 대상이 제공하는 서비스를 쉽게 접근하게 하는 개념
- 자세한 구현 내용을 숨김 -> 정보 은닉 (information hiding)
- 더 높은 수준의 추상화 유지
-
모듈화 -> 외부 결합은 낮고, 내부 응집은 높게 설계함
- 문제를 작은 요소로 분할 (패키지, 클래스 등)
- 재사용 가능성 극대화
- 의존성 최소화
The degree of interdependence between two modules
- 모듈 간에 서로 의존하는 정도
- 모듈 간 인터페이스 수
- 각 인터페이스의 복잡성(통신 유형에 따라 결정됨)
- 낮은 결합이 바람직함
The measure of the strength of functional relatedness of elements within a module
- 하나의 모듈 안에서 수행되는 작업들이 서로 관련된 정도
- 모듈 안의 여러 요소들이 하나의 목적을 위하여 유기적으로 관련되어 있는 것이 좋음
- 높은 응집이 바람직함
- 재사용 쉬움
- 이해하기 쉬움
- 수정에 의하여 받는 영향이 적음
숫자가 작을수록 결합도 높음.
-
내용 결합
한 모듈이 다른 모듈 내부의 내용을 직접 참조
예: 모듈 a가 모듈 b의 상태 변경
-
공통 결합
한 모듈이 다른 모듈이 읽은 전역 변수 값을 쓰거나 변경
예: 두 모듈이 같은 전역변수 접근
-
제어 결합
한 모듈이 다른 모듈의 제어흐름 경로(어떤 동작을 해야하는지)를 결정
예: function A calls B with a 'flag' saying what to do
-
스탬프 결합
여러 모듈이 복합 데이터 구조(구조체)를 공유하고 각기 일부만 사용함
구조체를 분해해서 각 모듈에 요구되는 최소 데이터 구조를 사용함
-
데이터 결합
모듈들이 주고받는 매개변수가 간단한 타입이거나 레코드 안의 필드이더라도 단순 타입인 경우
예: display time of arrival (w/ flight number)
숫자가 작을수록 낮은 응집
-
우연적 응집: 단위 안의 요소들이 의미적으로 아무 관계가 없음
-
논리적 응집: 본질적으로 다르더라도 같은 범주의 기능을 수행하므로 논리적으로 분류
예: 마우스 및 키보드 입력 처리 루틴을 모듈로 묶음
-
시간적 응집: 시간의 흐름에 따라 수행되는 동작을 묶음
-
절차적 응집: 모듈 안에서 수행되는 연산이 프로그램에서 수행되는 순서와 관련
-
교환적 응집: 동일한 데이터를 조작하는 것끼리 그룹화
예: DB record read/write
-
기능적 응집: 단 하나의 기능에 모두 기여하고 밀접하게 관련
예: XML 문자열의 어휘 분석에 관련된 기능들 모음
-
정보적 응집: 여러 동작이 고유한 시작점, 독립된 코드가 있고, 같은 데이터에 대해 실행하며, 각 기능이 정확히 한가지 동작만 해야 함
객체지향 개념(상속과 인터페이스 등)의 발전 -> 재사용, 수정용이성 상승
-
인터페이스(interface)와 구현(implementation)의 분리
-
단일 책임의 원칙 (Single Responsibility Principle)
Class는 하나의 기능만 가지며, 그 Calss가 제공하는 모든 서비스는 그 기능을 수행하는 데 집중되어야 한다.
-
개방/폐쇄의 원칙 (Open/Close Principle)
소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에 대해 열려있어야하고, 수정에 대해서는 닫혀 있어야 한다.
-
리스코프 치환 원칙 (Liskov Substitution Principle)
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
-
인터페이스 분리의 원칙 (Interface Segregation Principle)
클라이언트는 자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안된다.
-
의존관계 역전의 원칙 (Dependency Inversion Principle)
구체화가 아닌 추상화에 의존해야 한다.
클래스의 역할과 책임을 단일화
-> 클래스를 변경해야 할 이유를 하나로 제한
- 수정에 영향을 받지 않아야 함
- 쉽게 확장하여 재사용 가능하게 함
- 상속 (다형성) 이용
- Class B 가 Class A 를 상속했을 때
- 프로그램의 동작을 방해하지 않고 A를 B로 대체 가능
- B는 A의 기능을 손상시키면 안됨
사용하지 않는 인터페이스를 강제로 구현해서는 안됨
- Dummy 메서드 구현을 강제하는 상황을 만들면 안됨 -> 'fat interface' or 'polluted interface'
- 예: eat(), slepp(), walk(), fly() 메소드를 가진 하나의 Animal Interface
- CanEat, CanSleep, CanWalk, CanFly 라는 4개의 Interface 로 쪼개어 정의함
- 그러면, 각 동물은 위 Interface를 선택적으로 상속하여 정의 할 수 있음
- 높은 수준의 모듈이 낮은 수준의 추상화된 인터페이스에 의존하게 설계함
- 높은 수준의 모듈이 낮은 수준의 모듈에 종속되어서는 안됨
설계 모델에 대한 측정방법
-
크기 - 시스템 규모 (모듈, 인터페이스, 클래스, 메서드 개수)
-
복잡도 - 시스템 복잡한 정도 (모듈, 데이터, 시스템 등)
-
결합도 - 모듈 사이의 연결된 정도 (매개변수, 전역변수, 호출 함수 수)
-
응집도 - 단일 목적을 위해 얼마나 잘 협동하는지
-
정보흐름 - 얼마나 많은 정보가 흘러가는지
(전달하는 매개변수, 전역변수, 입출력의 수, 모듈 호출 수 등)
설계 메트릭 | 타입 | 설명 |
---|---|---|
클래스 당 가중 메소드 (WMC) | 복잡도 | 클래스 안에 있는 메소드의 복잡도 메트릭스의 합 |
상속 트리의 깊이 (DIT) | 상속 깊이 | 상속 트리의 루트로부터 해당 클래스까지 가장 깊은 상속 경로 |
지식 노드의 개수 (NOC) | 상속 너비 | 클래스의 상속 구조에서 직계 자식 클래스의 수 |
클래스 사이의 결합 (CBO) | 결합도 | 당 클래스가 의존하고 있는 클래스의 개수 |
클래스의 책임 (RFC) | 크기 | 클래스의 메소드 개수에 그 클래스의 메소드가 호출하는 메소드의 개수 |
메소드의 응집 결핍 | 응집도 | 소속된 클래스의 속성을 공유하지 않는 메소드 쌍의 수 |