<9. 소프트웨어 공학 설계원칙>
소프트웨어 아키텍처: 소프트웨어 아키텍처의 정의와 기본 개념.
아키텍처의 특징과 기능: 소프트웨어 아키텍처의 구성 요소와 설계 시 고려 사항.
아키텍처의 품질 속성: 품질 요구 사항과 이해 관계자들의 품질 속성.
아키텍처 구축 절차: 요구 사항 분석, 아키텍처 설계, 검증 및 승인 절차.
아키텍처의 4+1 관점: UML의 4+1 관점을 이용한 아키텍처 설계 방법.
아키텍처 스타일: 다양한 아키텍처 스타일과 그 특징.
데이터 중심형 모델: Repository 모델의 특징과 장단점.
클라이언트-서버 모델: 클라이언트-서버 모델의 특징과 설계 원리.
계층 모델: 계층 구조 모델의 설계 원리와 장단점.
MVC 모델: Model-View-Controller 모델의 구조와 장단점.
데이터 흐름 모델: Pipe and filter 구조와 그 설계 원리.
아키텍처 문서화: 설계 문서의 구조와 중요성.
단일 책임 원칙 (SRP): 소프트웨어 설계의 첫 번째 원칙과 책임 분리.
개방-폐쇄 원칙 (OCP): 확장에 대해서는 개방적이고, 변경에 대해서는 폐쇄적인 설계 원칙.
리스코프 치환 원칙 (LSP): 부모 클래스와 자식 클래스 사이의 행위 일관성.
의존 역전 원칙 (DIP): 변화가 적은 것에 의존하고, 변화를 쉽게 수용할 수 있는 설계 원칙.

1. 소프트웨어 아키텍처

정의

  • 소프트웨어 아키텍처는 시스템의 구조와 상호작용 방식을 정의하는 개념으로, 전체적인 설계 및 구성 요소 간의 관계를 관리합니다. 건물의 설계와 비슷하게 소프트웨어의 전체 구조를 관리합니다.

주요 개념

  • 구성 요소: 시스템을 이루는 서브시스템, 컴포넌트, 이들의 관계와 인터페이스.
  • 중요성: 시스템의 일관성 유지, 독립적인 작업, 확장성 준비, 재사용 용이성 등을 위해 필수적입니다.
  • 아키텍처 설계: 사용자 요구사항을 반영하여 시스템의 구조를 정의하고, 다양한 다이어그램(UML 등)을 사용하여 설계합니다.

2. 아키텍처의 특징과 기능

아키텍처의 정의

  • 구성 요소들의 구조와 이들 사이의 관계, 외부에 드러내는 속성 등을 정의합니다.
  • 구성 요소들이 제공하는 인터페이스와 상호작용 방식을 규정합니다.

아키텍처의 기능

  • 의사소통 도구: 다양한 이해 관계자들과의 소통을 원활하게 함.
  • 구현 제약 정의: 구현 시 필요한 제약 조건들을 명확히 함.
  • 품질 속성 결정: 시스템의 품질을 결정짓는 속성들을 정의함.
  • 재사용성: 아키텍처를 재사용 가능하게 설계해야 함.
  • 설계의 주요 원칙: 시스템 설계와 개발 시 적용되는 원칙과 지침을 제공함.

3. 아키텍처의 품질 속성

시스템 품질 속성

  • 가용성 (Availability): 시스템이 장애 없이 지속적으로 운영될 수 있는 능력.
    • 예: 하드웨어 이중화로 가용성을 높임.
  • 변경 용이성 (Modifiability): 변경 요구가 있을 때 쉽게 변경할 수 있는 능력.
    • 예: 자주 변경될 가능성이 높은 소프트웨어는 변경 용이성을 고려하여 설계.
  • 성능 (Performance): 이벤트 발생 시 빠르게 반응할 수 있는 능력.
    • 예: 공유 자원 사용, 알고리즘 선택 등과 밀접한 관련이 있음.
  • 보안성 (Security): 허용되지 않은 접근을 방지하는 능력.
    • 예: 계층 구조 아키텍처를 사용하여 중요한 데이터를 보호.
  • 사용성 (Usability): 사용자가 시스템을 쉽게 사용할 수 있는 편의성.
    • 예: 명확한 사용자 인터페이스 제공.
  • 테스트 용이성 (Testability): 시스템의 기능을 쉽게 테스트할 수 있는 능력.
    • 예: 테스트 케이스를 쉽게 작성하고 실행할 수 있도록 설계.

비즈니스 품질 속성

  • 시장 적시성 (Time to Market): 소프트웨어를 신속하게 출시하여 경쟁력을 높이는 능력.
    • 예: 삼성과 애플의 스마트폰 출시 시점 경쟁.
  • 비용과 이익 (Cost and Benefit): 비용 대비 효과를 고려한 설계.
    • 예: 유지보수 시 비용과 이익의 균형을 맞춤.
  • 예상 시스템 수명 (Predicted Lifetime): 시스템의 수명을 고려한 설계.
    • 예: 장기간 사용될 시스템의 경우 변경 용이성, 확장성, 이식성을 중요하게 고려.
  • 목표 시장 (targeted market)
    • 다양한 플랫폼에서도 잘 작동되어야 하므로, 이식성을 충분히 고려한 설계 필요
  • 신규 발매 일정 또는 공개 일정 (rollout schedule)
    • 현재 버전에서는 기본 기능만 제공하고 차기 버전에서 기능을 추가하여 완성도를 높일 예정이라면 유연성과 확장성을 고려한 설계 필요
  • 기존 시스템과의 통합 (integration with legacy system)
    • 아키텍쳐 설계 시 기존 시스템과의 통합 방법을 충분히 고려한 설계 필요

아키텍처 품질 속성

  • 개념적 무결성 (Conceptual Integrity): 시스템의 일관성을 유지하는 능력. 일관성.
    • 예: 전체 시스템과 구성 요소 간의 일관성 유지.
  • 정확성과 완전성 (Correctness and Completeness): 사용자의 요구를 충족시키는 정도.
    • 예: 요구 분석 명세서와의 일치.
  • 개발 용이성 (Buildability): 개발팀이 정해진 기간 내에 시스템을 완성할 수 있는 능력.
    • 예: 적절한 모듈로 분할하여 개발.

4. 아키텍처 구축 절차

요구 사항 분석

  • 기능적 요구 사항: 시스템이 수행해야 하는 기능을 정의.
  • 비기능적 요구 사항: 시스템의 성능, 보안, 가용성 등의 품질 요구 사항을 정의.
    • 요구 사항 취득, 식별, 명세, 분류, 검증 등의 과정을 거침.

아키텍처 분석 및 설계

  • 관점 정의: 이해 관계자를 파악하고, 각 이해 관계자별 관점을 정의.
  • 아키텍처 스타일 선택: 적절한 아키텍처 스타일을 선택 (예: MVC, Layered 등).
  • 후보 아키텍처 도출: 다이어그램 작성, 아키텍처 명세서 작성.

검증 및 승인

  • 아키텍처 평가: 아키텍처의 요구 사항 만족도, 적합성, 품질 속성 평가.
  • 아키텍처 상세화: 반복적인 설계를 통해 세부 사항을 결정.
  • 아키텍처 승인: 이해 관계자들의 최종 승인을 받음.
  • 우선순위 결정: 품질 속성 식별 및 반영 방법 개발.

5. 아키텍처의 4+1 관점

개요

  • 다양한 이해 관계자의 요구를 만족시키기 위해 소프트웨어 시스템을 여러 관점에서 분석하고 설계하는 방법입니다.
  • UML의 4+1 관점:
    • 논리적 관점 (Logical View): 시스템의 기능적 요구사항을 반영한 설계, 주요 클래스와 객체 간의 관계를 표현.
    • 개발 관점 (Development View): 개발 환경에서 시스템의 구조, 컴포넌트, 모듈 간의 관계를 표현.
    • 프로세스 관점 (Process View): 런타임 시의 동작 및 시스템 간의 상호작용을 표현.
    • 물리적 관점 (Physical View): 시스템의 배포, 하드웨어와 소프트웨어의 매핑을 표현.
    • 시나리오 (Use Case View): 사용자 요구사항을 중심으로 시스템이 어떻게 동작하는지 설명.

6. 아키텍처 스타일

정의

  • 아키텍처 스타일은 특정 문제를 해결하기 위해 반복적으로 사용되는 설계 패턴입니다.
  • 각 스타일은 특정 요구사항과 제약 조건에 맞추어 설계됩니다.

주요 아키텍처 스타일

  • 데이터 중심형 모델 (Repository Model):
    • 특징: 주요 데이터를 중앙에서 관리.
    • 구성: 중앙 저장소(repository)와 이 저장소에 접근하는 서브시스템.
    • 장점: 데이터 일관성 유지, 새로운 서브시스템 추가 용이.
    • 단점: 저장소의 병목 현상 발생 가능, 저장소와 서브시스템 간 강한 결합.
  • 클라이언트-서버 모델 (Client-Server Model):
    • 특징: 네트워크를 이용한 분산 시스템.
    • 구성: 서버(서비스 제공)와 클라이언트(서비스 요청).
    • 장점: 분할정복, 응집도 증진, 결합력 감소.
    • 단점: 네트워크 장애 시 전체 시스템 장애 가능.
  • 계층 모델 (Layered Model):
    • 특징: 기능을 여러 계층으로 나누어 배치.
    • 구성: 상위 계층(클라이언트), 하위 계층(서버).
    • 장점: 분할정복, 응집도 증진, 결합력 감소.
    • 단점: 계층 간의 통신 오버헤드 발생 가능.
  • MVC 모델 (Model-View-Controller Model):
    • 특징: 사용자 인터페이스와 데이터 처리를 분리.
    • 구성: 모델(데이터 처리), 뷰(사용자 인터페이스), 컨트롤러(사용자 입력 제어).
    • 장점: 관심사의 분리, 구조 변경 용이.
    • 단점: 클래스 수 증가로 인한 복잡성 증가.
  • 데이터 흐름 모델 (Pipe and Filter):
    • 특징: 데이터 스트림을 단계별로 처리.
    • 구성: 필터(데이터 변환), 파이프(데이터 전달).
    • 장점: 높은 재사용성, 융통성.
    • 단점: 각 필터 간의 강한 결합.


7. 아키텍쳐 모델

7-1. 데이터 중심형 모델

정의

  • 중앙 저장소(repository)에 데이터를 저장하고, 여러 서브시스템이 이 데이터를 공유하는 아키텍처 스타일입니다.

특징

  • 주요 데이터가 중앙 저장소에서 관리: 모든 데이터가 한곳에 모여 일관성 있게 관리됨.
  • 구성 요소: 중앙 저장소와 이 저장소에 접근하는 서브시스템.

장단점

  • 장점:
    • 데이터 일관성 유지.
    • 새로운 서브시스템의 추가가 용이.
  • 단점:
    • 중앙 저장소의 병목 현상 발생 가능.
    • 중앙 저장소와 서브시스템 간의 강한 결합.

7-2. 클라이언트-서버 모델

정의

  • 클라이언트와 서버로 나누어 데이터와 처리 기능을 분할하여 사용하는 분산 시스템 아키텍처입니다.

특징

  • 클라이언트: 서버에 서비스 요청.
  • 서버: 클라이언트에 서비스 제공.

장단점

  • 장점:
    • 분할정복: 클라이언트와 서버를 독립적으로 개발 가능.
    • 응집도 증진: 서버가 클라이언트에 높은 응집도의 서비스 제공.
    • 결합력 감소: 단순 메시지 교환을 통한 통신.
    • 융통성: 서버와 클라이언트를 추가하여 쉽게 재구성 가능.
    • 이식성: 서버를 변경하지 않고 클라이언트를 새 플랫폼에 적용 가능.
    • 테스트 가능성: 클라이언트와 서버를 독립적으로 테스트 가능.
  • 단점:
    • 네트워크 장애 시 전체 시스템 장애 가능.
    • 서버 과부하 시 성능 저하.

7-3. 계층 모델

정의

  • 시스템 기능을 여러 계층으로 나누어 상위 계층이 하위 계층의 서비스를 이용하는 구조입니다.

특징

  • 구성 요소: 상위 계층(클라이언트), 하위 계층(서버).
  • 계층 간 통신: 상위 계층은 하위 계층을 하나의 서비스로 여김.

장단점

  • 장점:
    • 분할정복: 각 계층을 독립적으로 설계.
    • 응집도 증진: 계층 내 관련 서비스가 응집.
    • 결합력 감소: 하위 계층이 상위 계층을 알 필요 없음.
    • 추상화 증진: 하위 계층의 구현 세부 사항을 알 필요 없음.
    • 재사용성 증진: 하위 계층은 범용적으로 설계 가능.
    • 융통성: 새로운 기능을 하위 계층에 추가하거나 상위 계층을 교체 가능.
    • 노후 대비: 특정 플랫폼에 의존된 부분을 격리하여 노후 대비 가능.
    • 이식성: 특정 플랫폼 의존 부분을 한 계층에 격리 가능.
    • 테스트 가능성: 각 계층을 독립적으로 테스트 가능.
    • 방어적 설계: 각 계층의 API를 엄격하게 검증 가능.
  • 단점:
    • 계층 간의 통신 오버헤드 발생 가능.
    • 각 계층의 변경이 전체 시스템에 영향을 미칠 수 있음.

7-4. MVC 모델 (Model-View-Controller 모델)

정의

  • 사용자 인터페이스와 데이터 처리를 분리하기 위한 소프트웨어 아키텍처 패턴입니다.
  • 목적: 변경에 대한 영향을 최소화하고, 시스템의 유연성을 높이는 것.

구성 요소

  • 모델 (Model): 데이터 상태와 로직을 처리하며, 뷰 및 컨트롤러와 독립적으로 작동.
  • 뷰 (View): 사용자 인터페이스를 담당하며, 모델의 데이터를 화면에 표시.
  • 컨트롤러 (Controller): 사용자의 입력을 받아 모델에 전달하고, 모델의 변화를 뷰에 반영.

장단점

  • 장점:
    • 관심사의 분리: 데이터 처리 로직과 사용자 인터페이스의 분리로 유지보수 용이.
    • 구조 변경 용이: UI 변경이 모델에 영향을 미치지 않음.
    • 재사용성: 동일한 모델에 대해 여러 뷰를 제공할 수 있음.
  • 단점:
    • 복잡성 증가: 클래스 수 증가로 인한 설계 및 유지보수의 복잡성 증가.
    • 성능 저하 가능성: 다수의 클래스와 인터페이스로 인해 성능 저하 가능.

7-5. 데이터 흐름 모델 (Pipe and Filter 모델)

정의

  • 데이터를 일련의 처리 단계(필터)로 전달하는 아키텍처 스타일입니다.
  • 목적: 데이터의 변환 및 처리를 쉽게 하고, 시스템의 모듈화를 촉진합니다.

구성 요소

  • 필터 (Filter): 데이터를 입력받아 처리하고, 처리된 데이터를 출력.
  • 파이프 (Pipe): 필터 간의 데이터 전달을 담당.

장단점

  • 장점:
    • 높은 재사용성: 각 필터는 독립적으로 설계되어 재사용 가능.
    • 유연성: 필터 추가, 삭제, 재배치가 용이.
    • 병렬 처리: 필터를 병렬로 실행 가능.
  • 단점:
    • 데이터 변환 오버헤드: 각 필터 간의 데이터 변환 오버헤드 발생.
    • 디버깅 어려움: 전체 데이터 흐름을 추적하는 디버깅이 어려울 수 있음.

8. 아키텍처 문서화

중요성

  • 설계 문서는 구현을 시작하기 전에 중요한 설계 이슈를 드러내고, 참여 그룹 간의 의사소통을 원활하게 함.
  • 목적: 시스템의 구조와 설계 의도를 명확히 하여, 현재와 미래의 개발자들이 시스템을 이해하고 유지보수할 수 있도록 지원.

문서 구조

  • 목적: 문서가 기술하는 대상 시스템의 정의.
  • 우선순위: 설계 작업 과정의 우선순위 기술.
  • 설계의 아웃라인: 최상위 추상화된 설계 제시.
  • 주요 설계 이슈: 해결되어야 할 중요한 이슈와 대안.
  • 설계 상세 사항: 독자가 알아야 할 중요한 사항 기술.

예시: 네비게이션 시스템

  • 목적: 자동차에 장착되어 목적지까지의 방향을 안내하는 시스템.
  • 우선순위: 성능, 의존성, 사용성, 유지보수성.
  • 설계 이슈: GIS 정보의 저장 방법, 통신 비용, 실시간 접근성.



9. 객체지향 개발의 원칙

바꾸기 쉽다, 이해하기 쉽다, 재사용하기 쉽다, 개발이 쉽다
나쁜 설계 - 경직성, 부서지기 쉬움(한부분 변경시 상관없는 부분 작동이 멈춤), 부동성(분해후 재사용 불가), 끈끈함(개발환경 의존적), 복잡함, 필요없는 반복, 불투명함(의도가)

의존관계 관리하기

잘못 관리된 의존관계가 설계의 품질을 저하 - 스파게티 코드

해결책

    인터페이스 활용 - 의존관계 끊거나 의존의 방향 바꾸기
    다형성 사용 - 함수를 포함한 모듈에 의존하지 않고도 그 함수를 호출할 수 있다

객체지향 언어의 사용

    의존관계를 원하는 모양대로 만들 수 있다
    5가지 원칙 - 단일책임, 개방폐쇄, 리스코프 치환, 의존역전, 인터페이스 분리


9-1. 단일 책임 원칙 (The Single Responsibility Principle, SRP)

정의

  • 클래스는 단 하나의 책임만 가져야 하며, 변경의 이유가 단 하나여야 한다는 원칙입니다.
  • 소프트웨어 설계의 첫번째 원칙, 절차적 프로그래밍 기법에도 적용
  • 목적: 클래스의 응집도를 높이고, 변경으로 인한 영향을 최소화.

주요 개념

  • 책임의 의미: 객체는 단 하나의 책임만 가져야 하며, 다양한 이유로 변경되지 않아야 함.
  • 변경 용이성: 예측 불가능한 변경 사항에도 유연하게 대처할 수 있어야 함.

책임 분리 방법

  • 회귀 테스트: 변경이 기존 시스템에 미치는 영향을 평가.
  • 산탄총 수술: 하나의 책임이 여러 곳에 분산되어 있을 때 발생. - 수술부위가 많다, 모든 환부를 빠짐없이 찾아야 한다(위험)
  • 관심 지향 프로그래밍: 횡단 관심사를 해결하기 위해 AOP(관심지향 프로그래밍)를 사용. 

SRP의 적용

- 결국 설계할때 기본 원칙인 응집도는 높고 결합도는 낮게 하는것, 관련된 것들을 한곳에 두어 응집도를 높이면, 자연스럽게 결합도는 낮아진다
  • 응집도 향상: 관련된 책임을 한 곳에 모아 응집도를 높임.
  • 결합도 감소: 독립적인 클래스로 분리하여 결합도를 낮춤. - 책임을 많이 질수록 클래스 내부에서 서로 다른 역할을 수행하는 코드끼리 강하게 결합될 가능성이 높다



9-2. 개방-폐쇄 원칙 (Open-Closed Principle, OCP)

정의

  • 소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해서는 개방적이어야 하지만, 변경에 대해서는 폐쇄적이어야 한다는 원칙입니다.

주요 개념

  • 확장에 개방적: 새로운 기능을 추가할 수 있도록 설계.
  • 변경에 폐쇄적: 기존 코드를 변경하지 않도록 설계.
  • 방법: 인터페이스와 추상 클래스를 사용하여 기능을 확장하고, 구체적인 구현은 변경하지 않도록 함.

예시

  • 템플릿 메소드 패턴: 상위 클래스는 알고리즘의 구조를 정의하고, 하위 클래스는 알고리즘의 세부 단계를 구현.
  • 전략 패턴: 특정 기능을 전략 인터페이스로 정의하고, 다양한 전략 구현체를 통해 기능을 확장.


9-3. 리스코프 치환 원칙 (Liskov Substitution Principle, LSP)

정의

부모 클래스와 자식 클래스 사이의 행위가 일관성이 있어야함, LSP 만족시 프로그램에서 부모 클래스 인스턴스 대신 자식 클래스 인스턴스로 대체해도 프로그램의 의미는 변화하지 않음
  • 자식 클래스는 부모 클래스의 기능을 대체할 수 있어야 하며, 부모 클래스에서 정의된 기능을 그대로 사용할 수 있어야 한다는 원칙입니다.

주요 개념

  • 행위 일관성: 자식 클래스는 부모 클래스의 행위를 일관되게 유지해야 함.
  • 재정의 최소화: 부모 클래스의 메서드를 재정의하지 않도록 설계.
  • 계약에 의한 설계: 부모 클래스와 자식 클래스 간의 계약을 명확히 정의.

예시

  • 사각형-정사각형 문제: 정사각형이 사각형을 상속받으면, 정사각형의 특성으로 인해 사각형의 특성을 위반할 수 있음.
  • 인터페이스 분리: 특정 기능을 수행하는 작은 인터페이스로 분리하여, 자식 클래스가 필요 없는 기능을 구현하지 않도록 함.


9-4. 의존 역전 원칙 (Dependency Inversion Principle, DIP)

정의

의존관계를 맺을때 변화하기 쉬운것보다 변화가 없는 것에 의존하라는 원칙, 추상적인 것은 변하기 어려운것에 해당

고차원 모듈은 저차원 모듈에 의존하면 안 되며, 이 둘은 모두 추상화에 의존해야 한다는 원칙입니다. 추상화는 구체적인 것에 의존하면 안 됩니다.

주요 개념

  • 고차원 모듈: 시스템의 중요한 정책이나 전략을 구현하는 모듈.
  • 저차원 모듈: 시스템의 세부 사항을 구현하는 모듈.
  • 추상화 의존: 구체적인 클래스 대신 인터페이스나 추상 클래스에 의존.

의존성 주입 (Dependency Injection)

  • 정의: 외부에서 의존 객체를 주입하여 객체 간의 의존성을 낮추는 기법.
  • 유형: 생성자 주입, 세터 주입, 인터페이스 주입.

예시

  • 서비스 로케이터 패턴: 특정 서비스를 필요로 하는 객체가 서비스 로케이터를 통해 의존 객체를 얻음.
  • 팩토리 패턴: 객체 생성을 위한 인터페이스를 정의하고, 실제 객체 생성은 팩토리 클래스에서 처리.

9-5. 인터페이스 분리 원칙 (Interface Segregation Principle, ISP)

인터페이스를 클라이언트에 특화되도록 분리시키라는 설계 원칙

  • 클라이언트는 자신이 사용하지 않는 메서드에 의존관계를 맺으면 안된다

  • 클라이언트의 관점에서 클라이언트 자신이 이용하지 않는 기능에는 영향을 받지 않아야 한다는 내용이 담겨 있다
  • 인터페이스를 클라이언트에 특화되도록 분리시키는 설계 원칙