소프트웨어 공학 — 2강: 요구사항 분석과 소프트웨어 설계
요구사항 공학
요구사항의 정의:
→ 시스템이 충족해야 하는 조건이나 능력
요구사항의 분류:
기능적 요구사항 (Functional Requirements):
→ 시스템이 무엇을 해야 하는가
→ "사용자는 로그인할 수 있어야 한다"
→ "결제 후 이메일 확인서를 받아야 한다"
비기능적 요구사항 (Non-Functional Requirements):
→ 시스템이 어떻게 동작해야 하는가
→ 성능: "페이지 로딩 3초 이내"
→ 보안: "패스워드 암호화 저장"
→ 가용성: "99.9% 업타임"
→ 확장성: "동시 사용자 10,000명"
요구사항 수집 기법:
→ 인터뷰, 설문 조사
→ 워크숍, 브레인스토밍
→ 프로토타이핑
→ 유스케이스 분석
→ 사용자 스토리 (애자일)
요구사항 명세서 (SRS):
→ IEEE 830 표준
→ 모든 요구사항 공식 문서화
→ 완전성, 일관성, 검증 가능성 중요
유스케이스와 UML
유스케이스 (Use Case):
→ 시스템과 외부 행위자(Actor) 간의 상호작용
→ 기능적 요구사항을 사용자 관점으로 기술
유스케이스 다이어그램 요소:
→ Actor: 시스템 외부 사용자/시스템 (사람 모양)
→ Use Case: 타원 (동사구)
→ System Boundary: 사각형 경계
→ 관계: 연관(선), 포함(<<include>>), 확장(<<extend>>)
사용자 스토리 (User Story):
→ As a [사용자], I want to [기능] so that [목적]
→ "온라인 쇼핑 고객으로서, 장바구니에 상품을 담을 수 있어서 나중에 구매할 수 있다"
UML 다이어그램 분류:
구조 다이어그램:
→ 클래스 다이어그램: 클래스·관계 (가장 중요)
→ 객체 다이어그램: 특정 시점 인스턴스
→ 컴포넌트 다이어그램: 소프트웨어 컴포넌트
→ 배포 다이어그램: 하드웨어 배치
행동 다이어그램:
→ 유스케이스 다이어그램: 기능 범위
→ 시퀀스 다이어그램: 시간 순서 상호작용
→ 상태 다이어그램: 객체 상태 전이
→ 활동 다이어그램: 워크플로우 (순서도 유사)
소프트웨어 설계 원칙 (SOLID)
SOLID 원칙 (Robert Martin, 객체지향):
S — 단일 책임 원칙 (Single Responsibility Principle):
→ 클래스는 하나의 이유로만 변경되어야 함
→ 하나의 클래스 = 하나의 책임
→ 예: UserDB 클래스는 DB 저장만, 이메일 발송 X
O — 개방-폐쇄 원칙 (Open/Closed Principle):
→ 확장에는 열려 있고, 수정에는 닫혀 있어야 함
→ 새 기능 추가 시 기존 코드 변경 최소화
→ 추상화, 인터페이스, 상속 활용
L — 리스코프 치환 원칙 (Liskov Substitution Principle):
→ 자식 클래스는 부모 클래스 자리를 대체 가능해야 함
→ 상속 관계가 의미 있는 IS-A 관계인지 확인
I — 인터페이스 분리 원칙 (Interface Segregation Principle):
→ 클라이언트는 사용하지 않는 인터페이스에 의존 금지
→ 큰 인터페이스 → 작은 인터페이스 분리
D — 의존성 역전 원칙 (Dependency Inversion Principle):
→ 고수준 모듈이 저수준 모듈에 의존 금지
→ 둘 다 추상화에 의존
→ 의존성 주입(DI) 패턴과 연결
디자인 패턴 (GoF)
GoF(Gang of Four) 디자인 패턴:
→ 23가지 패턴 (생성, 구조, 행위)
생성 패턴 (Creational):
싱글톤 (Singleton):
→ 클래스 인스턴스 하나만 생성 보장
→ 전역 접근점 제공
→ 예: DB 연결, 로그 매니저
팩토리 메서드 (Factory Method):
→ 객체 생성을 서브클래스에 위임
→ 어떤 클래스를 생성할지 런타임에 결정
빌더 (Builder):
→ 복잡한 객체를 단계별로 생성
→ 같은 생성 과정, 다른 결과물
구조 패턴 (Structural):
어댑터 (Adapter):
→ 호환 안 되는 인터페이스를 변환
→ 기존 코드 수정 없이 호환성 확보
데코레이터 (Decorator):
→ 객체에 동적으로 기능 추가
→ 서브클래싱 대안
행위 패턴 (Behavioral):
옵저버 (Observer):
→ 이벤트 발생 시 구독자에게 자동 알림
→ 이벤트 시스템, 반응형 프로그래밍
전략 (Strategy):
→ 알고리즘을 클래스로 캡슐화하여 교체 가능
→ if-else 대신 전략 교체
커맨드 (Command):
→ 요청을 객체로 캡슐화
→ 실행 취소(Undo), 큐, 로깅 가능
소프트웨어 아키텍처 패턴
계층형 아키텍처 (Layered):
→ 프레젠테이션 → 비즈니스 로직 → 데이터 접근
→ 각 계층은 아래 계층만 사용
→ 가장 일반적, 유지보수 용이
→ 단점: 모든 요청이 전 계층 통과 → 성능
MVC (Model-View-Controller):
→ Model: 데이터·비즈니스 로직
→ View: 화면 표현
→ Controller: 입력 처리·모델-뷰 조정
→ Django, Spring MVC 등에서 활용
마이크로서비스 아키텍처:
→ 애플리케이션을 독립적 서비스로 분해
→ 각 서비스: 독립 배포, 독립 DB
→ 장점: 확장성, 기술 독립성
→ 단점: 복잡한 통신, 분산 시스템 과제
이벤트 드리븐 아키텍처:
→ 이벤트 발행·구독으로 서비스 간 통신
→ 느슨한 결합, 비동기 처리
→ Kafka, RabbitMQ 활용
자주 묻는 질문
Q. SOLID 원칙을 실제 코드에 어떻게 적용하나요? A. 시작은 단일 책임 원칙부터입니다. 새 메서드/기능을 추가할 때 “이 클래스의 본래 목적과 관련 있는가?”를 물어보세요. 관련 없다면 새 클래스를 만드세요. 개방-폐쇄는 새 요구사항이 생겼을 때 기존 코드를 수정하지 않고 새 클래스를 추가하거나 인터페이스를 활용하는 방식입니다. 완벽하게 모든 원칙을 동시에 적용하기보다 점진적으로 리팩토링하는 것이 현실적입니다.
Q. 디자인 패턴을 반드시 사용해야 하나요? A. 아닙니다. 패턴은 도구이지 규칙이 아닙니다. 단순한 문제에 복잡한 패턴을 적용하는 ‘과설계(Over-engineering)‘는 오히려 코드를 복잡하게 만듭니다. 패턴은 특정 문제가 반복적으로 발생하여 추상화가 필요할 때 적용하는 것이 좋습니다. “지금 이 문제를 패턴으로 해결하면 미래에 변경이 쉬운가?”를 기준으로 판단하세요.
O
OIYO 편집부
Content Editor지식 인큐베이터이자 전문 콘텐츠 크리에이터. 경영, 경제, 법률 및 실생활에 유용한 실무/자격증 중심의 깊이 있는 정보를 연구하고 공유합니다.