소프트웨어 공학 [ 소프트웨어 공학 ] 17. 소프트웨어 디자인의 완전한 명세를 위한 4가지 디자인 모델저번에 컴퓨터 프로젝트로 SRS를 작성한 적이 있다. 그 때 하나씩 작성했던 기억이 나는데, 여기서 더욱 자세하게 적어볼 생각이다. 우선 소프트웨어 요구사항 명세를 할 때 흔히 4가지 모델을 사용할 수 있다는 점을 알아야 한다. 1. Data Design ( 데이터 설계 ) >> 흔히 ER 다이어그램과 같이 절차를 정의하고 문제를 해결하기 위해서 사용된다. 2. Architectural Design ( 방식 설계 ) >> 데이터 흐름도와 같이 일반적으로 소프트웨어 시스템 개발의 초기 단계에서 시스템의 개념적인 구조 없이 논리적인 시방만을 결정하는 작업을 말한다. 3. Procedural/Component Design ( 절차/기기 설계 ) >> 상태 다이어그램과 같은 것을 일컫는다. 시스템의 각 부분별 동작 특성을 고려하고 각 부분간의 상관 관계를 단계별로 규정해준다. 4. Interface Design ( 인터페이스 설계 ) >> 유즈케이스 다이어그램과 같은 것을 말한다. 일반 사용자들이 소프트웨어를 사용할 때 데이터 입력이나 동작을 제어하기 위해 사용하는 명령어 또는 기법 절차를 설계하는 것을 말한다. 사용자가 소프트웨어와 의사소통을 잘 할 수 있도록 하는 것이 목적이다. 포인트1. 설계 기본 개념과 과정은 무엇인가? 포인트2. 설계 작업에 고려하여야 할 품질 목표에는 어떤 것들이 있는가? 포인트3. 전통적인 설계 원리는 어떤 것들이 있는가? 포인트4. 객체지향 패러다임의 설계 원리(SOLID)는 무엇인가? 포인트5. 설계 결과를 객관적으로 측정하는 방법은 무엇인가? 요구 분석 - 무엇을 담을 것인가? 설계 - 요구사항을 어떻게 실현할 것인가? 기본 구조 설계 - 아키텍쳐 설계로 각 모듈의 역할과 인터페이스를 정의한다 상세 설계 - 모듈 내부의 알고리즘, 데이터를 명세화한다 분석과 설계 ( 출처 - 소프트웨어 공학의 모든 것 233page )6-1. 설계 기본 개념 설계 - 높은 수준의 의사 결정 과정의 연속 전통적 방법
최근의 방법
6-1-1. 서브시스템, 모듈 아키텍처 - 시스템을 구성하는 컴포넌트와 컴포넌트 상호작용의 집합 서브시스템 - 시스템의 복잡도를 줄이기 위해 분할한 것(개발자 커뮤니케이션, 수정에 대한 영향 감소) 서브시스템 ( 출처 - 소프트웨어 공학의 모든 것 235page )복잡한 시스템은 서브시스템을 반복적으로 분할하여 계층화 할 수 있음
6-1-2. 설계 관점 아키텍쳐 설계에서의 세 가지 관점
설계 관점과 표현 방법 ( 출처 - 소프트웨어 공학의 모든 것 237page )
6-1-3. 설계 작업 과정 설계 작업 - 의사 결정 과정이면서 동시에 시스템을 알아가는 과정 시스템 유형을 고려하는 것이 가장 중요 -> 아키텍처 스타일 선택에 영향을 주기 때문 아키텍처 설계 과정 ( 출처 - 소프트웨어 공학의 모든 것 238page )아키텍쳐 설계 과정 1. 설계 목표 설정
2. 스타일 결정
3. 서브시스템의 기능, 인터페이스 명세
4. 아키텍처 설계 검토
6-2. 품질 목표 기능 요구에 대한 요구 분석 모델은 하나이다. 비기능 요구(품질 요구사항)에 대한 설계안은 여러 가지가 있을 수 있다. 따라서 요구 분석에서 찾은 비기능적 요구를 설계 목표로 명시하고 이를 만족하기 위한 설계안을 만들고 그 중에 최적안을 골라내야 한다. 설계와 품질 목표 ( 출처 - 소프트웨어 공학의 모든 것 240page )품질 요구사항을 충족하게끔 설계할 때는 다른 속성에 미치는 영향을 고려하여 설계하여야 한다. 품질 속성의 우선순위를 정하고 상반되는 요구에 대한 절충안을 찾는 것이 중요함 ISO 25010에서 정의한 소프트웨어 기능 외적인 품질 ( 출처 - 소프트웨어 공학의 모든 것 240~241pages )
6-3. 전통적인 설계 원리 소프트웨어 설계에서 전통적으로 중요하게 생각하는 요소
6-3-1. 추상화 추상화
6-3-2. 캡슐화 추상화된 대상이 제공하는 서비스를 쉽게 접근하게 하는 개념 정보은닉
위 그림에서 TV 기능을 상호 작용할 수 있는 리모콘으로 추상화 했다고 해 보자 그림에서와 같이 신호 디코딩과 같은 자세한 정보를 나타낼 필요가 없다. 리모콘의 핵심 기능인 채널, 볼륨, 전원 상태를 나타내는 데이터 등을 묶어 캡슐화 하면 된다. 객체지향 언어를 사용하게 되면 정보를 접근할 수 있는 권한을 정의할 수 있다.(private,public,protected) 6-3-3. 모듈화 모듈화
장점
단점
+ 추상, 캡슐, 모듈화의 관계
6-3-4. 결합(Coupling) 모듈 간에 서로 의존하는 정도 결합이 강하면
모듈간 결합 정도 결정 요인
결합의 종류 - 내용 결합
- 공통 결합
- 제어 결합
- 스탬프 결합
- 데이터 결합
6-3-5. 응집(Cohesion) 하나의 모듈 안에서 수행되는 작업들이 서로 관련된 정도 = 모듈 안의 여러 요소들이 특정 작업을 수행하기 위해 함께 잘 모여 있는지를 나타냄 높은 응집일때는?
여러 가지 응집들 - 우연적 응집
- 논리적 응집
- 시간적 응집
- 절차적 응집
- 교환적 응집
- 기능적 응집
- 정보적 응집
+ 좋은 소프트웨어가 되려면? 좋은 소프트웨어가 되기 위해서는 모듈 간의 결합은 낮은 결합 형태를 가지며, 모듈 속에서는 높은 응집도를 가져야 한다. 높은 응집과 낮은 결합 응집 - 모듈, 클래스, 컴포넌트 안에 있는 요소들이 하나의 기능 단위로써 협동하는 정도 결합 - 둘 이상의 모듈, 클래스 컴포넌트 사이에 서로 의존하는 정도 높은 응집력 - 코드의 단위 안의 요소들이 서로 관련 있는 것을 한 곳에 넣고 유지하는 것을 의미함 낮은 결합력 - 코드의 단위 안에서 관련 없는 요소들을 가능한 많이 분리해 내는 것 그렇다면 응집력을 높게, 결합력을 낮게 하기 위해서는 어떻게 해야 되는가? - 응집을 높이는 방법 단일 책임을 가지게 하면 모듈 안의 응집력이 높아진다. 모듈의 기능을 한마디로 요약할 수 없다면 응집력이 떨어지는 것임 모듈의 기능을 정의한 문장을 밑에 있는 표로 분석하여 하나 이상의 기능을 수행한다는 결론이 나게 되면 분할을 진행하여 준다. 예를 들어 어떤 자료를 가지고 있는 모듈이 이미지를 처리하는 기능과 사운드를 처리하는 기능을 함께 가지고 있다고 하면 그 모듈은 응집력이 낮은 것이다. 따라서 자료를 보관하는 모듈을 분할하여 이미지 처리 모듈, 사운드 처리 모듈을 독립시킨다. 응집력을 판단하는 기준
- 결합을 낮추는 방법 결합을 낮추기 위해서는 모듈 사이의 인터페이스 수를 줄이고, 각 인터페이스의 복잡도를 낮추어야 한다. 그리고 간단한 정보를 파라미터로 넘겨야 하며, 데이터를 전달하는 커뮤니케이션을 진행하여야 한다.
6-4. 객체지향 설계 원리(SOLID) 전통적인 설계 원리는 객체지향 개념(상속, 인터페이스 등)이 추가 되어 재사용, 수정 용이성 등의 품질을 높일 수 있게 되었으며 이를 위해 지켜야 할 5가지의 원리가 있다.
6-4-1. 인터페이스와 구현의 분리 인터페이스 - 메서드의 프로토타입만을 정해 놓은 것 공개된 메서드를 인터페이스로 따로 정의 후 이를 구현, 상속한다. 인터페이스와 구현의 분리 원칙
6-4-2. 단일 책임의 원리 (Single Responsibility Principle) 클래스의 역할과 책임을 단일화 하여 클래스를 변경해야 할 이유를 하나로 제한시키는 원리 단일 책임의 원리 사례 ( 출처 - 소프트웨어 공학의 모든 것 253page )위 사례를 보자 Book에 책 이름, 저자, 내용을 관리하고 저장해야 하는 책임이 있다고 해 보자 여기서 Book은 다른 매체에 Print를 해 주면서 해상도 등을 고려해야 함 즉, Book은 내용을 관리하고 저장해야 하는 책임과 다른 곳에 Print를 하게 하는 두 가지의 책임이 있다. >> 책임 분리를 해 줘야됨! 6-4-3. 개방 폐쇄의 원리 (Open Close Principle) 소프트웨어 개체(클래스, 모듈, 기능 등) 가 확장을 위해서는 열려 있어야 하지만 수정을 위해서는 닫혀야 한다 상속을 이용하여 클래스가 정의되어 있을 때는 다형성이 적용되어 서로 대체할 수 있는 인터페이스를 구현 할 수 있다. 개방 폐쇄의 원리 사례 ( 출처 - 소프트웨어 공학의 모든 것 254page )위 그림을 한 번 보도록 하자 SortAlgorithm을 이용하는 Client 프로그램이 있다고 하면 SortAlgorithm을 상속 받은 여러 정렬 알고리즘들은 다형성을 이용하여 확장할 수 있도록 열려있다. 상속 관계가 아니라면 접근을 할 수 없기에 Client는 SortAlgorithm을 수정할 수 없음을 알 수 있다. ( 수정에 닫힘 ) 6-4-4. 리스코프 교체의 원리 (Liskov Substitution Principle) 클래스 B가 클래스 A에게서 상속받는 클래스라고 하면 A를 B로 대체할 수 있어야 한다는 원리이다. 즉, 파생 클래스가 부모 클래스로 대체 가능해야 한다.. 는 것이다. 리스코프 교체의 원리 "위반" 사례 ( 출처 - 소프트웨어 공학의 모든 것 255page )위 사례는 위반 사례이다. 여기서 리스코프 교체의 원리에 따르면 MuteMouse가 Animal을 대체 가능하다는 것인데 조건이 있다. 교체하려는 하위 클래스에서 오버라이딩 된 메서드들이 모두 타당하게 구현이 되어야 한다는 점이다. 예를 들어 위 사진처럼 MuteMouse의 makeNoise()가 IMakeNoiseException을 던지게 되면 리스코프 교체의 원리에 위배된다. ( 타당하게 구현되지 않은 것이다. ) 이 점을 주의할 것! 6-4-5. 인터페이스 분리의 원리 (Interface Segregation Principle) 클라이언트가 사용하지 않는 인터페이스를 강제로 구현해서는 안됨 > 당연한거 아닌가.. 필요 없는 것도 오버라이딩을 해 줘야 하기 때문 사용하지 않는 인터페이스를 비만 인터페이스(fat), 오염된 인터페이스(polluted) 라고 한다. 인터페이스 분리의 원리 사례 ( 출처 - 소프트웨어 공학의 모든 것 256page )왼쪽 그림에서 새는 필요없는 walk()를 만들어야 하는 사태가 발생한다. 이정도만 설명해도 어떤 느낌인지 알 것이다. 6-4-6. 의존 관계 역전의 원리 (Dependency Inversion Principle) 구체화 된 모듈이 추상화 된 모듈에게 의존이 역전되도록 설계하는 것 즉, 추상화 된 모듈이 구체화 된 모듈에 의존하면 안된다. 구체화 된 모듈이 추상화 된 모듈에 의존하게 해야 한다. 의존관계 역전 사례 ( 출처 - 소프트웨어 공학의 모든 것 256 page )그림에서 볼 수 있듯이 추상적인 Copy가 구체적인 Read KeyBoard 등에 의존하게 설계하면 문제가 생긴다. 오른쪽과 같이 추상적인 Copy에 의존하게 만들어야 한다. 6-5. 설계 메트릭 설계를 마친 뒤, 설계의 결과가 원리들을 잘 적용하여 좋은 설계가 되었는가를 따져 봐야 한다. 6-5-1. 전통적인 메트릭 설계 모델에 대한 전통적인 측정 방법
모듈의 구조적 복잡도 = (모듈의 팬 아웃 개수)^2 데이터 복잡도 = (입력 및 출력 변수의 개수) / (팬 아웃 + 1) 시스템 복잡도 = 구조적 복잡도 + 데이터 복잡도 6-5-2. 객체지향 메트릭 객체지향 설계 메트릭 ( 출처 - 소프트웨어 공학의 모든 것 258page ) |