1과목 - 소프트웨어 설계
3장. 애플리케이션 설계
20. 소프트웨어 아키텍처
소프트웨어 아키텍처의 설계
- 소프트웨어 아키텍처는 소프트웨어를 구성하는 요소들 간의 관계를 표현하는 시스템 구조
- 이해 관계자들의 의사소통 도구로 활용
- 기본 원리
- 모듈화
- 추상화
- 단계적 분해
- 정보은닉
모듈화 (Modularity)
- 소프트웨어 성능을 향상시키거나 유지 관리가 용이하도록 시스템의 기능들을 모듈 단위로 나누는 것
- 자주 사용되는 기능들을 공통 모듈로 구성하여 프로젝트의 재사용성 향상
추상화 (Abstraction)
- 문제의 포괄적인 개념을 설계한 후 차례로 세분화하여 구체화시켜 나가는 것
- 최소의 비용으로 실제 상황에 대처 가능
- 추상화의 유형
- 과정 추상화 : 전반적인 흐름만 파악
- 데이터 추상화 : 데이터의 세부적인 용도를 정의하지 않고, 데이터 구조를 대표할 수 있는 표현으로 대체
- 제어 추상화 : 이벤트 발생의 절차나 방법을 정의하지 않고, 대표할 수 있는 표현으로 대체
단계적 분해 (Stepwise Refinement)
- 문제를 상위 중요 개념으로부터 하위 개념으로 구체화시키는 하향식 설계 전략
- 추상화의 반복에 의해 세분화
정보 은닉 (Information Hiding)
- 다른 모듈이 접근하거나 변경하지 못하도록 하는 기법
- 정보 은닉된 모듈과 커뮤니케이션할 필요가 있을 때는 필요한 정보만 인터페이스를 통해 주고받음
- 모듈 변경 시 다른 모듈에 영향을 주지 않으므로 유지보수가 용이
소프트웨어 아키텍처의 품질 속성
- 시스템 측면
- 성능 : 사용자 요청 발생 시 빠르게 처리하는 것
- 보안 : 허용되지 않은 접근은 막고, 허용된 접근에는 적절한 서비스를 제공하는 것
- 가용성 : 장애 없이 정상적인 서비스를 제공하는 것
- 기능성 : 사용자가 요구한 기능을 구현하는 것
- 사용성 : 사용자가 소프트웨어를 잘 사용하도록 편리하게 구현하는 것
- 변경 용이성 : 소프트웨어가 다른 하드웨어나 플랫폼에서도 동작할 수 있도록 구현하는 것
- 확장성 : 시스템 용량이나 처리능력을 확장시켰을 때 이를 효과적으로 활용할 수 있도록 구현하는 것
- 비즈니스 측면
- 시장 적시성 : 정해진 시간에 맞춰 프로그램을 출시하는 것
- 비용과 혜택 : 개발 비용을 더 투자하여 유연한 아키텍처를 만들 것인지 결정하는 것
- 예상 시스템 수명 : 시스템을 얼마나 오랫동안 사용할 것인지를 고려하는 것
- 아키텍처 측면
- 개념적 무결성 : 전체 시스템과 시스템을 이루는 구성요소들 간의 일관성을 유지하는 것
- 정확성/완결성 : 요구사항을 모두 충족시키는 것
- 구축 가능성 : 모듈 단위로 구분된 시스템을 적절하게 배분하여 유연하게 일정을 변경할 수 있도록 하는 것
소프트웨어 아키텍처의 설계 과정
- 설계 목표 설정
- 요구사항을 분석하여 전체 시스템의 설계 목표 설정
- 시스템 타입 결정
- 시스템과 서브시스템 타입을 결정하고, 설계 목표와 함께 고려하여 아키텍처 패턴 선택
- 아키텍처 패턴 적용
- 시스템의 표준 아키텍처 설계
- 서브시스템 구체화
- 서브시스템 간 상호작용을 위한 동작과 인터페이스 정의
- 검토
21. 아키텍처 패턴
아키텍처 패턴의 개요
- 아키텍처를 설계할 때 참조할 수 있는 전형적인 해결 방식
- 소프트웨어 시스템의 구조를 구성하기 위한 기본적인 윤곽 제시
- 아키텍처 패턴의 장점
- 시행착오를 줄여 개발 시간 단축
- 검증된 구조로 개발하기 때문에 안정적인 개발 가능
- 시스템의 특성을 개발 전에 예측하는 것이 가능
- 아키텍처 패턴의 종류
- 레이어 패턴
- 클라이언트-서버 패턴
- 파이프-필터 패턴
- 모델-뷰-컨트롤러 패턴
레이어 패턴 (Layers Pattern)
- 시스템을 계층으로 구분하여 구성 (고전적인 방법)
- 상위 계층은 서비스 제공자가 되고, 하위 계층은 상위 계층의 클라이언트가 됨
- 서로 마주보는 두 계층 사이에서만 상호작용이 이루어지므로 변경 작업이 용이
- ex) OSI 참조 모델
클라이언트-서버 패턴 (Client-Sever Pattern)
- 서버 컴포넌트 : 클라이언트 컴포넌트 = 1 : N
- 사용자는 클라이언트와만 소통
- 서버는 클라이언트 요청에 대비해 항상 대기 상태 유지
- 클라이언트와 서버는 서로 독립적
파이프-필터 패턴 (Pipe-Filter Pattern)
- 데이터 스트림 절차의 각 단계를 필터 컴포넌트로 캡슐화하여 파이프를 통해 전송하는 패턴
- 필터 컴포넌트는 재사용성이 좋고 확장이 용이
- ex) UNIX shell
모델-뷰-컨트롤러 패턴 (Model-View-Controller Pattern)
- 각 부분은 별도의 컴포넌트로 분리되어 있어 서로 영향 받지 않고 개발 가능
- 모델 : 서브시스템의 핵심 기능과 데이터 보관
- 뷰 : 사용자에게 정보 표시
- 컨트롤러 : 사용자로부터 받은 입력 처리
기타 패턴
- 마스터-슬레이브 패턴 (Master-Slave Pattern)
- 마스터 컴포넌트는 모든 작업의 주체이고, 슬레이브 컴포넌트는 마스터 컴포넌트의 지시에 따라 작업 수행
- 브로커 패턴 (Broker Pattern)
- 사용자가 원하는 서비스를 요청하면 브로커 컴포넌트가 요청에 맞는 컴포넌트와 사용자를 연결
- 분산 환경 시스템에서 활용
- 피어-투-피어 패턴 (Peer-To-Peer Pattern)
- 각 피어는 클라이언트가 될 수도, 서버가 될 수도 있는 패턴
- 전형적인 멀티스레딩 방식 사용
- 이벤트-버스 패턴 (Event-Bus Pattern)
- 특정 채널에 이벤트 메시지를 발행하면 해당 채널을 구독한 리스너들이 이벤트를 처리하는 방식
- 블랙보드 패턴 (Blackboard Pattern)
- 모든 컴포넌트들이 공유 데이터 저장소와 블랙보드 컴포넌트에 접근 가능한 형태
- 인터프리터 패턴 (Interpreter Pattern)
- 프로그램 코드의 각 라인을 수행하는 방법을 지정
22. 객체지향 (Object-Oriented)
객체지향의 개요
- 객체지향은 소프트웨어의 재사용 및 확장이 용이하고, 유지보수가 쉬움
- 현실 세계를 모형화하므로 사용자와 개발자가 쉽게 이해 가능
- 주요 개념
- 객체 / 클래스 / 캡슐화 / 상속 / 다형성
객체 (Object)
- 객체는 데이터와 데이터를 처리하는 함수를 캡슐화한 하나의 소프트웨어 모듈
- 데이터 : 객체가 갖고 있는 정보 (속성이나 상태)
- 함수 : 객체가 수행하는 기능 (객체가 데이터를 처리하는 알고리즘)
- 객체의 특성
- 객체는 독립적으로 식별 가능한 이름을 가짐
- 객체는 행위의 특징을 나타내며 일정한 기억장소를 가짐
클래스 (Class)
- 클래스는 공통된 속성과 연산을 갖는 객체의 집합
- 인스턴스 (Instance) : 클래스에 속하는 각각의 객체
- 동일 클래스에 속한 인스턴스들은 공통된 속성과 행위를 가짐
캡슐화 (Encapsulation)
- 캡슐화는 데이터와 데이터를 처리하는 함수를 하나로 묶는 것
- 캡슐화된 객체는 재사용이 가능하고, 세부 정보를 은닉하여 외부 접근에 제한둠
상속 (Inheritance)
- 상속은 상위 클래스의 모든 속성과 연산을 하위 클래스가 물려받는 것
- 하위 클래스는 상위 클래스의 모든 속성과 연산을 재정의하지 않고 자신의 속성으로 사용 가능
- 소프트웨어의 재사용을 높이는 중요한 개념
다형성 (Polymorphism)
- 하나의 메시지에 대해 여러 가지 형태의 응답이 있다는 것을 의미
23. 모듈 (Module)
모듈의 개요
- 모듈은 단독으로 컴파일 할 수 있고, 재사용 가능
- 모듈의 독립성을 높이려면 결합도는 약하게, 응집도는 강하게, 모듈의 크기는 작게 만들어야 함
결합도 (Coupling)
- 모듈 간 상호 의존하는 정도 (두 모듈 사이의 연관 관계)
- 결합도가 약할수록 높은 품질, 강할수록 낮은 품질
- 자료 결합도 < 스탬프 결합도 < 제어 결합도 < 외부 결합도 < 공통 결합도 < 내용 결합도
응집도 (Cohesion)
- 모듈 내부 요소들의 서로 관련있는 정도, 즉 모듈이 독립적인 기능으로 정의되어 있는 정도
- 우연적 응집도 < 논리적 응집도 < 시간적 응집도 < 절차적 응집도 < 교환적 응집도 < 순차적 응집도 < 기능적 응집도
팬인 (Fan-In) / 팬아웃 (Fan-Out)
- 팬인 : 어떤 모듈을 제어하는 모듈의 수
- 팬아웃 : 어떤 모듈에 의해 제어되는 모듈의 수
- 팬인과 팬아웃을 분석하여 시스템 복잡도를 알 수 있음
- 시스템 복잡도를 최적화하려면 팬인은 높게, 팬아웃은 낮게 설계
24. 공통 모듈
공통 모듈의 개요
- 공통 모듈은 여러 프로그램에서 공통적으로 사용할 수 있는 모듈을 의미
- 모듈의 재사용성 확보와 중복 개발 회피를 위해 설계 과정에서 명세 작성 필요
- 명세 기법
- 정확성 (Correctness)
- 구현 시 해당 기능이 필요하다는 것을 알 수 있도록 정확히 작성
- 명확성 (Clarity)
- 해당 기능이 중의적으로 해석되지 않도록 명확하게 작성
- 완전성 (Completeness)
- 구현을 위해 필요한 모든 것을 기술
- 일관성 (Consistency)
- 공통 기능들 간 상호 충돌이 발생하지 않도록 작성
- 추적성 (Traceability)
- 기능에 대한 요구사항의 출처, 관련 시스템 등 관계를 파악할 수 있도록 작성
- 정확성 (Correctness)
재사용 (Reuse)
- 비용과 개발 시간을 절약하기 위해 이미 개발된 기능들을 파악하고 재구성하여 최적화시키는 작업
- 재사용을 위해서는 사용법을 공개해야 함
- 재사용되는 대상은 외부 모듈과의 결합도는 낮고, 응집도는 높아야 함
25. 코드
코드의 개요
- 코드는 특정 자료의 추출을 쉽게 하기 위해서 사용하는 기호
- 정보를 신속, 정확하게 전달할 수 있게 함
- ex) 주민등록번호, 학번, 전화번호
- 주요 기능
- 식별 기능 : 데이터 간의 성격에 따라 구분
- 분류 기능 : 특정 기준이나 동일한 유형에 해당하는 데이터를 그룹화
- 배열 기능 : 의미를 부여하여 나열
코드의 종류
- 순차 코드 (Sequence Code)
- 자료의 발생 순서, 크기 순서 등 일정 기준에 따라 차례로 일련번호 부여
- ex) 1, 2, 3, 4, …
- 블록 코드 (Block Code)
- 공통성이 있는 것끼리 블록으로 구분하고 각 블록 내에서 일련번호 부여
- ex) 1001 ~ 1100 : 총무부, 1101 ~ 1200 : 영업부
- 10진 코드 (Decimal Code)
- 도서 분류식 코드
- ex) 1000 : 공학, 1100 : 소프트웨어 공학
- 그룹 분류 코드 (Group Classification Code)
- 일정 기준에 따라 대분류, 중분류, 소분류 등으로 구분하고 각 그룹 안에서 일련번호 부여
- ex) 1-01-001 : 본사-총무부-인사계, 2-01-001 : 지사-총무부-인사계
- 연상 코드 (Mnemonic Code)
- 코드화 대상 항목의 명칭과 관계있는 숫자나 문자를 이용하여 코드 부여
- ex) TV-40 : 40인치 TV, L-15-220 : 15W 220V 램프
- 표의 숫자 코드 (Significant Digit Code)
- 대상 항목의 물리적 수치를 그대료 코드에 적용시키는 방법
- ex) 120-720-1500 : 두께 X 폭 X 길이가 120 X 720 X 1500인 강판
- 합성 코드 (Combined Code)
- 필요한 기능을 하나의 코드로 수행하기 어려운 경우 2개 이상의 코드를 조합하여 만드는 방법
- ex) 연상코드 + 순차코드
코드 부여 체계
- 이름만으로 개체의 용도와 적용 범위를 알 수 있도록 코드를 부여하는 방식
- 각 개체에 유일한 코드를 부여하여 개체 식별을 용이하게 함
26. 디자인 패턴 (Design Pattern)
디자인 패턴의 개요
- 디자인 패턴은 재사용할 수 있는 기본형 코드들이 포함되어 있음
- 생성 패턴 / 구조 패턴 / 행위 패턴
생성 패턴 (Creational Pattern)
- 객체의 생성과 참조 과정을 캡슐화하여 프로그램에 유연성을 더해줌
- 추상 팩토리 (Abstract Factory)
- 구체적인 클래스에 의존하지 않고 인터페이스를 통해 서로 의존하는 객체들의 그룹으로 생성
- 연관된 서브 클래스를 묶어 한 번에 교체하는 것이 가능
- 빌더 (Builder)
- 작게 분리된 인스턴스를 건축하듯이 조합하여 객체 생성
- 팩토리 메소드 (Factory Method)
- 객체 생성을 서브 클래스에서 처리하도록 분리하여 캡슐화
- 상위 클래스에서 인터페이스만 정의하고 실제 생성은 서브 클래스가 담당
- 프로토타입 (Prototype)
- 원본 객체를 복제하는 방법으로 객체를 생성하는 패턴
- 싱글톤 (Singleton)
- 하나의 객체를 생성하면 어디서든 참조할 수 있지만, 여러 프로세스가 동시에 참조하는 것은 불가능
- 클래스 내 인스턴스가 하나뿐임을 보장하여 불필요한 메모리 낭비 최소화
구조 패턴 (Structural Pattern)
- 클래스나 객체들을 조합하여 더 큰 구조로 만들 수 있게 해주는 패턴
- 구조가 복잡한 시스템을 개발하기 쉽게 도와줌
- 어댑터 (Adapter)
- 호환성이 없는 클래스들의 인터페이스를 다른 클래스가 이용할 수 있도록 변환해주는 패턴
- 브리지 (Bridge)
- 기능과 구현을 두 개의 별도 클래스로 구현
- 컴포지트 (Composite)
- 복합 객체와 단일 객체를 구분 없이 다루고자 할 때 사용
- 데코레이터 (Decorator)
- 객체 간 결합을 통해 능동적으로 기능들을 확장할 수 있는 패턴
- 퍼싸드 (Facade)
- 복잡한 서브 클래스들을 피해 더 상위에 인터페이스를 구성
- 서브 클래스들의 기능을 간편하게 사용할 수 있도록 도와줌
- 플라이웨이트 (Flyweight)
- 인스턴스가 필요할 때마다 매번 생성하는 것이 아닌 가능한 한 공유해서 사용함으로써 메모리 절약
- 프록시 (Proxy)
- 접근이 어려운 객체와 연결하려는 객체 사이 인터페이스 역할을 수행하는 패턴
- 네트워크 연결, 메모리 대용량 객체로의 접근 등에 주로 이용
행위 패턴 (Behavioral Pattern)
- 클래스나 객체들이 서로 상호작용하는 방법이나 책임 분배 방법을 정의하는 패턴
- 하나의 객체로 수행할 수 없는 작업을 여러 객체로 분배하면서 결합도를 최소화
- 책임 연쇄 (Chain of Responsibility)
- 한 객체가 요청을 처리하지 못하면 다음 객체로 넘어가는 형태
- 커맨드 (Command)
- 요청을 캡슐화하여 요청에 필요한 정보를 저장하거나 로그에 남기는 패턴
- 인터프리터 (Interpreter)
- 언어에 문법 표현을 정의하는 패턴
- 반복자 (Iterator)
- 접근이 잦은 객체에 대해 동일한 인터페이스를 사용하도록 하는 패턴
- 중재자 (Mediator)
- 객체 간 상호작용을 캡슐화하여 객체로 정의하는 패턴
- 메멘토 (Memento)
- 요청에 따라 객체를 해당 시점의 상태로 돌릴 수 있는 기능을 제공
- 옵저버 (Observer)
- 한 객체의 상태가 변하면 객체에 상속되어 있는 다른 객체들에게 변화된 상태를 전달
- 상태 (State)
- 객체 상태에 따라 동일한 동작을 다르게 처리해야 할 때 사용
- 전략 (Strategy)
- 동일한 계열의 알고리즘들을 개별적으로 캡슐화하여 상호 교환할 수 있게 정의
- 클라이언트 영향 업이 알고리즘 변경 가능
- 템플릿 메소드 (Template Method)
- 상위 클래스에서 골격을 정의하고, 하위 클래스에서 세부 처리를 구체화하는 구조
- 방문자 (Visitor)
- 각 클래스에서 처리 기능을 분리하여 별도 클래스로 구성하는 패턴