소프트웨어 설계 (Software Design)

핵심 인사이트 (3줄 요약)

요구사항을 구현 가능한 구조로 변환하는 핵심 활동으로, 아키텍처 설계(전체 구조)와 상세 설계(모듈 내부)로 분류된다. 응집도는 높게, 결합도는 낮게, 모듈화·추상화·정보 은닉이 핵심 원칙이다. 기술사 시험에서는 SOLID 원칙, GoF 패턴, UML 표기법이 핵심이다.


Ⅰ. 개요 (필수: 200자 이상)

개념: 소프트웨어 설계(Software Design)는 요구사항 명세서를 기반으로 소프트웨어의 구조, 구성요소, 인터페이스, 특성을 정의하는 활동으로, "어떻게 만들 것인가"를 결정하는 단계다.

💡 비유: 소프트웨어 설계는 "건축 설계도면 작성" 같아요. "방 3개짜리 집 주세요"(요구사항)라는 말만으로는 집을 지을 수 없어요. 어떤 구조로, 어떤 자재로, 어떻게 지을지 설계도면이 필요하죠!

등장 배경 (필수: 3가지 이상 기술):

  1. 기존 문제점 - 무계획 개발: 요구사항만 있고 설계 없이 바로 코딩 시작 → 스파게티 코드, 유지보수 불가능

  2. 기술적 필요성 - 복잡성 관리: 현대 소프트웨어는 수백만 라인 코드. 체계적 구조 없이는 이해·변경 불가능. 추상화·모듈화 필수

  3. 시장/산업 요구 - 유지보수 비용: 소프트웨어 수명 주기 중 유지보수 비용이 60~80%. 좋은 설계로 유지보수 비용 절감

핵심 목적: 요구사항을 만족하는 유지보수 가능한 소프트웨어 구조 정의


Ⅱ. 구성 요소 및 핵심 원리 (필수: 가장 상세하게)

구성 요소 (필수: 최소 4개 이상):

구성 요소역할/기능특징비유
아키텍처 설계시스템 전체 구조 정의컴포넌트, 인터페이스건물 골조
상세 설계모듈 내부 구조 정의알고리즘, 자료구조인테리어
데이터 설계DB 스키마, 데이터 모델ERD, 정규화배관 설계
인터페이스 설계모듈 간 통신 방식API, 프로토콜출입구
UI/UX 설계사용자 인터페이스와이어프레임창문·문

구조 다이어그램 (필수: ASCII 아트):

┌─────────────────────────────────────────────────────────────────────────┐
│              소프트웨어 설계 단계                                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   ┌─────────────────────────────────────────────────────────────────┐  │
│   │                   아키텍처 설계 (Architectural Design)           │  │
│   │                                                                 │  │
│   │   • 시스템 전체 구조 정의                                       │  │
│   │   • 주요 컴포넌트 식별                                          │  │
│   │   • 컴포넌트 간 인터페이스 정의                                  │  │
│   │   • 기술 스택 선정                                              │  │
│   │   • 비기능 요구사항(성능, 보안, 확장성) 반영                     │  │
│   │                                                                 │  │
│   │   산출물: 아키텍처 문서(SAD), 컴포넌트 다이어그램               │  │
│   └─────────────────────────────────────────────────────────────────┘  │
│                              │                                          │
│                              ▼                                          │
│   ┌─────────────────────────────────────────────────────────────────┐  │
│   │                   상세 설계 (Detailed Design)                    │  │
│   │                                                                 │  │
│   │   • 모듈 내부 구조 정의                                         │  │
│   │   • 알고리즘, 자료구조 설계                                      │  │
│   │   • 클래스, 함수 설계                                           │  │
│   │   • DB 스키마 설계                                              │  │
│   │   • UI/UX 설계                                                  │  │
│   │                                                                 │  │
│   │   산출물: 설계 문서(SDD), 클래스 다이어그램, 시퀀스 다이어그램   │  │
│   └─────────────────────────────────────────────────────────────────┘  │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│              응집도와 결합도                                              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   [응집도 (Cohesion) - 높을수록 좋음]                                   │
│                                                                         │
│   ┌────────────────────────────────────────────────────────────────┐   │
│   │  기능적 > 순차적 > 교환적 > 절차적 > 시간적 > 논리적 > 우연적  │   │
│   │    (最强)                                            (最弱)    │   │
│   └────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│   기능적 응집도: 모든 요소가 단일 기능 수행 (이상적)                   │
│   우연적 응집도: 공통점 없는 요소들이 모임 (피해야 함)                 │
│                                                                         │
│   [결합도 (Coupling) - 낮을수록 좋음]                                   │
│                                                                         │
│   ┌────────────────────────────────────────────────────────────────┐   │
│   │  자료 < 스탬프 < 제어 < 외부 < 공통 < 내용                     │   │
│   │   (最弱)                                         (最强)         │   │
│   └────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│   자료 결합도: 단순 데이터만 주고받음 (이상적)                         │
│   내용 결합도: 다른 모듈의 내부 데이터 직접 접근 (피해야 함)           │
│                                                                         │
│   ┌─────────────────────────────────────────────────────────────────┐  │
│   │                      Good Design                                │  │
│   │                  높은 응집도 + 낮은 결합도                       │  │
│   │                                                                 │  │
│   │    ┌─────┐      ┌─────┐      ┌─────┐                          │  │
│   │    │  A  │──▶──▶│  B  │──▶──▶│  C  │                          │  │
│   │    └─────┘      └─────┘      └─────┘                          │  │
│   │    (자료 결합도: 데이터만 전달)                                 │  │
│   └─────────────────────────────────────────────────────────────────┘  │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│              SOLID 원칙 (객체지향 설계 5원칙)                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   S - Single Responsibility (단일 책임 원칙)                           │
│       클래스는 하나의 책임만 가져야 한다                               │
│       예: User 클래스는 사용자 정보만, 이메일 발송은 EmailService      │
│                                                                         │
│   O - Open/Closed (개방-폐쇄 원칙)                                     │
│       확장에는 열려 있고, 수정에는 닫혀 있어야 한다                     │
│       예: 새로운 결제수단 추가 시 기존 코드 수정 없이 확장              │
│                                                                         │
│   L - Liskov Substitution (리스코프 치환 원칙)                         │
│       하위 타입은 상위 타입을 대체할 수 있어야 한다                     │
│       예: Bird → Penguin 치환 시 fly() 오류 (펭귄은 못 날아!)          │
│                                                                         │
│   I - Interface Segregation (인터페이스 분리 원칙)                     │
│       인터페이스를 작게 분리하여 클라이언트마다 필요한 것만 구현        │
│       예: Worker 인터페이스를 Workable, Eatable로 분리                 │
│                                                                         │
│   D - Dependency Inversion (의존성 역전 원칙)                          │
│       고수준 모듈이 저수준 모듈에 의존하지 말고 추상화에 의존           │
│       예: OrderService → PaymentInterface ← CreditCardPayment          │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

동작 원리 (필수: 단계별 상세 설명):

① 요구사항 분석 → ② 아키텍처 설계 → ③ 상세 설계 → ④ 설계 검토 → ⑤ 구현
  • 1단계 (요구사항 분석): 기능적/비기능적 요구사항 파악, 제약사항 식별
  • 2단계 (아키텍처 설계): 시스템 구조 정의, 컴포넌트 식별, 인터페이스 정의, 아키텍처 패턴 선택
  • 3단계 (상세 설계): 모듈 내부 설계, 알고리즘/자료구조, 클래스 설계, DB 설계
  • 4단계 (설계 검토): 설계 리뷰, 인스펙션, 프로토타입 검증
  • 5단계 (구현): 코딩, 단위 테스트

핵심 알고리즘/공식:

[설계 품질 지표]

1. 응집도 측정
   LCOM (Lack of Cohesion of Methods)
   LCOM = |P| - |Q|
   P: 서로 공통 속성을 사용하지 않는 메서드 쌍 수
   Q: 서로 공통 속성을 사용하는 메서드 쌍 수
   LCOM이 높을수록 응집도 낮음 (나쁨)

2. 결합도 측정
   CBO (Coupling Between Objects)
   CBO = 다른 클래스와의 결합 수
   CBO가 낮을수록 좋음

3. 복잡도 측정
   사이클로매틱 복잡도 (Cyclomatic Complexity)
   V(G) = E - N + 2P
   E: 엣지 수, N: 노드 수, P: 연결 컴포넌트 수

   복잡도 기준:
   1-10: 단순 (좋음)
   11-20: 복잡 (주의)
   21+: 매우 복잡 (리팩토링 권장)

[설계 원칙 체크리스트]

✓ 모든 요구사항이 설계에 반영되었는가?
✓ 모듈 간 결합도가 낮은가?
✓ 모듈 내 응집도가 높은가?
✓ SOLID 원칙을 준수했는가?
✓ 중복 코드가 없는가? (DRY)
✓ 필요한 것만 구현했는가? (YAGNI)
✓ 인터페이스가 명확한가?
✓ 예외 처리가 적절한가?

코드 예시 (필수: Python SOLID 원칙):

"""
소프트웨어 설계 원칙 예시
- SOLID 원칙 구현
- 응집도/결합도 예시
"""

from abc import ABC, abstractmethod
from typing import List, Protocol
from dataclasses import dataclass

# ============================================================
# 1. Single Responsibility Principle (SRP)
# ============================================================

# Good: 각 클래스가 단일 책임
class User:
    """사용자 정보만 관리"""
    def __init__(self, name: str, email: str):
        self.name = name
        self.email = email


class UserRepository:
    """DB 저장 책임"""
    def save(self, user: User):
        print(f"[SRP] 사용자 저장: {user.name}")


class EmailService:
    """이메일 발송 책임"""
    def send(self, to: str, message: str):
        print(f"[SRP] 이메일 발송: {to}")


# ============================================================
# 2. Open/Closed Principle (OCP)
# ============================================================

class PaymentProcessor(Protocol):
    """결제 처리 인터페이스"""
    def pay(self, amount: float) -> bool:
        ...


class CreditCardPayment(PaymentProcessor):
    def pay(self, amount: float) -> bool:
        print(f"[OCP] 신용카드 결제: {amount}원")
        return True


class KakaoPayment(PaymentProcessor):
    def pay(self, amount: float) -> bool:
        print(f"[OCP] 카카오페이 결제: {amount}원")
        return True


class OrderService:
    """기존 코드 수정 없이 새 결제수단 사용 가능"""
    def __init__(self, payment: PaymentProcessor):
        self.payment = payment

    def checkout(self, amount: float):
        return self.payment.pay(amount)


# ============================================================
# 3. Liskov Substitution Principle (LSP)
# ============================================================

class Bird(ABC):
    @abstractmethod
    def move(self):
        pass


class FlyingBird(Bird):
    def move(self):
        return self.fly()

    @abstractmethod
    def fly(self):
        pass


class Sparrow(FlyingBird):
    def fly(self):
        print("[LSP] 참새가 날아갑니다")


class Penguin(Bird):
    def move(self):
        return self.swim()

    def swim(self):
        print("[LSP] 펭귄이 헤엄칩니다")


# ============================================================
# 4. Interface Segregation Principle (ISP)
# ============================================================

class Workable(Protocol):
    def work(self):
        ...


class Eatable(Protocol):
    def eat(self):
        ...


class HumanWorker:
    def work(self):
        print("[ISP] 사람이 일합니다")

    def eat(self):
        print("[ISP] 사람이 밥을 먹습니다")


class RobotWorker:
    """로봇은 일만 함 (eat 불필요)"""
    def work(self):
        print("[ISP] 로봇이 일합니다")


# ============================================================
# 5. Dependency Inversion Principle (DIP)
# ============================================================

class Switchable(Protocol):
    def turn_on(self):
        ...

    def turn_off(self):
        ...


class Lamp:
    def turn_on(self):
        print("[DIP] 전등 켜짐")

    def turn_off(self):
        print("[DIP] 전등 꺼짐")


class Switch:
    """고수준 모듈이 추상화(Switchable)에 의존"""
    def __init__(self, device: Switchable):
        self.device = device
        self.on = False

    def toggle(self):
        if self.on:
            self.device.turn_off()
        else:
            self.device.turn_on()
        self.on = not self.on


# ============================================================
# 6. 응집도/결합도 예시
# ============================================================

@dataclass
class OrderItem:
    product: str
    quantity: int
    price: float


class Order:
    """높은 기능적 응집도: 주문 관련 기능만 수행"""
    def __init__(self):
        self.items: List[OrderItem] = []

    def add_item(self, item: OrderItem):
        self.items.append(item)

    def calculate_total(self) -> float:
        return sum(item.price * item.quantity for item in self.items)


class OrderPrinter:
    """단일 책임: 출력만 담당"""
    def print_receipt(self, order: Order):
        print(f"\n[응집도/결합도] 영수증")
        for item in order.items:
            print(f"  {item.product} x {item.quantity}: {item.price}원")
        print(f"  합계: {order.calculate_total()}원")


# ============================================================
# 사용 예시
# ============================================================

if __name__ == "__main__":
    print("=" * 50)
    print("SOLID 원칙 예시")
    print("=" * 50)

    # SRP
    print("\n1. Single Responsibility Principle")
    user = User("홍길동", "hong@example.com")
    repo = UserRepository()
    email = EmailService()
    repo.save(user)
    email.send(user.email, "회원가입 축하!")

    # OCP
    print("\n2. Open/Closed Principle")
    order_service = OrderService(KakaoPayment())
    order_service.checkout(50000)

    # LSP
    print("\n3. Liskov Substitution Principle")
    birds: List[Bird] = [Sparrow(), Penguin()]
    for bird in birds:
        bird.move()

    # DIP
    print("\n4. Dependency Inversion Principle")
    switch = Switch(Lamp())
    switch.toggle()
    switch.toggle()

    # 응집도/결합도
    print("\n5. 높은 응집도 + 낮은 결합도")
    order = Order()
    order.add_item(OrderItem("사과", 3, 1000))
    order.add_item(OrderItem("바나나", 2, 1500))
    printer = OrderPrinter()
    printer.print_receipt(order)

Ⅲ. 기술 비교 분석 (필수: 2개 이상의 표)

장단점 분석 (필수: 최소 3개씩):

장점단점
유지보수성: 체계적 구조로 변경 용이시간 소요: 설계 단계에 시간 투자 필요
재사용성: 모듈화로 코드 재사용오버엔지니어링: 과도한 추상화 위험
품질 향상: 설계 단계 결함 조기 발견학습 곡선: 설계 기법·패턴 학습 필요
의사소통: UML 등으로 설계 공유문서 동기화: 코드 변경 시 문서 갱신

설계 방법론 비교 (필수: 2개 대안):

비교 항목구조적 설계객체지향 설계도메인 주도 설계
핵심 단위함수/모듈클래스/객체도메인 모델
데이터 처리데이터 중심캡슐화유비쿼터스 언어
접근 방식Top-DownBottom-Up도메인 중심
재사용함수 라이브러리상속/컴포지션바운디드 컨텍스트
적합 환경임베디드/시스템엔터프라이즈복잡한 비즈니스

★ 선택 기준: 하드웨어 제어 → 구조적, 일반 앱 → 객체지향, 복잡한 비즈니스 로직 → DDD


Ⅳ. 실무 적용 방안 (필수: 기술사 판단력 증명)

기술사적 판단 (필수: 3개 이상 시나리오):

적용 분야구체적 적용 방법기대 효과 (정량)
마이크로서비스도메인별 서비스 분리, API 설계배포 독립성 100%, 장애 격리
레거시 현대화점진적 리팩토링, Strangler Pattern리스크 70% 감소
임베디드하드웨어 추상화 계층, 인터페이스 설계하드웨어 교체 시 코드 변경 90% 감소

실제 도입 사례 (필수: 구체적 기업/서비스):

  • 사례 1: 구글 - 마이크로서비스 아키텍처로 설계. 각 서비스 독립 배포, 하루 4,000회 배포 가능

  • 사례 2: 우버 - DDD로 도메인별 서비스 분리. 드라이버, 라이더, 결제 등 독립적 개발

  • 사례 3: 삼성전자 - 임베디드 HAL(Hardware Abstraction Layer) 설계. 칩셋 교체 시 앱 코드 변경 0%

도입 시 고려사항 (필수: 4가지 관점):

  1. 기술적: 아키텍처 패턴 선택, 기술 스택, 성능 요구사항, 확장성
  2. 운영적: 팀 구조, 개발 프로세스, 코드 리뷰 문화
  3. 보안적: 보안 설계(Defense in Depth), 데이터 암호화, 접근 제어
  4. 경제적: 설계 시간 투자 vs 유지보수 비용 절감

주의사항 / 흔한 실수 (필수: 최소 3개):

  • 오버엔지니어링: 불필요한 추상화, "나중에 필요할지도" → YAGNI 위반
  • 설계 문서만 작성: 실제 코드와 다른 문서 → 동기화 필수
  • 저수준 설계 생략: 아키텍처만 하고 상세 설계 안 함 → 구현 단계 혼란

관련 개념 / 확장 학습 (필수: 최소 5개 이상 나열):

┌─────────────────────────────────────────────────────────────────┐
│  소프트웨어 설계 핵심 연관 개념 맵                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   [요구사항 공학] ←──→ [소프트웨어 설계] ←──→ [구현]             │
│        ↓                   ↓                 ↓                  │
│   [유스케이스]        [아키텍처]          [코딩]                 │
│        ↓                   ↓                 ↓                  │
│   [SRS]              [디자인 패턴]       [리팩토링]              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
관련 개념관계설명문서 링크
소프트웨어 아키텍처상위 개념전체 구조 설계[software_architecture](./software_architecture.md)
디자인 패턴설계 기법검증된 설계 템플릿[design_pattern](./design_pattern.md)
UML표현 도구설계 시각화[uml](./uml.md)
요구사항 공학선행 활동요구사항 도출[requirements_engineering](../methodology/requirements_engineering.md)
소프트웨어 테스트후속 활동설계 검증[software_testing](../testing/software_testing.md)

Ⅴ. 기대 효과 및 결론 (필수: 미래 전망 포함)

정량적 기대 효과 (필수):

효과 영역구체적 내용정량적 목표
유지보수성체계적 구조로 변경 용이변경 비용 50% 절감
재사용성모듈화로 코드 재사용개발 시간 30% 단축
품질설계 단계 결함 조기 발견결함 밀도 40% 감소
의사소통UML 등으로 설계 공유오해로 인한 이슈 60% 감소

미래 전망 (필수: 3가지 관점):

  1. 기술 발전 방향: AI 기반 설계 자동화, 모델 기반 개발(MDD), 로우코드 플랫폼

  2. 시장 트렌드: 마이크로서비스·클라우드 네이티브 설계, 이벤트 드리븐 아키텍처

  3. 후속 기술: AI Copilot과 결합한 설계 지원, 자동 리팩토링

결론: 소프트웨어 설계는 요구사항을 구현으로 변환하는 핵심 다리다. 좋은 설계는 "높은 응집도 + 낮은 결합도"를 달성하여 유지보수 가능한 코드를 만든다. 과도한 설계(Over-engineering)도 피해야 한다.

※ 참고 표준: IEEE 1016(SDD), ISO/IEC/IEEE 42010(아키텍처), UML 2.5, SOLID(Martin)


어린이를 위한 종합 설명

소프트웨어 설계는 마치 "레고 조립 설명서 만들기" 같아요!

레고로 멋진 성을 지으려면 어떻게 해야 할까요?

1. 그냥 만들기 (설계 없음): "대충 이거랑 이거 붙여볼까?" → 결과: 이상한 덩어리 😅

2. 설계도면 그리기: "탑은 여기, 문은 여기, 창문은 여기!" → 결과: 멋진 성 🏰

설계의 핵심 3가지:

① 모듈화 (블록 나누기)

  • 탑 블록, 문 블록, 지붕 블록
  • 각각 따로 만들어서 나중에 조립!

② 높은 응집도 (가족 같이)

  • 탑 블록에는 탑 관련 부품만
  • "엉뚱한 거 섞이지 마!"

③ 낮은 결합도 (이웃처럼)

  • 탑과 문은 딱 맞는 곳에만 연결
  • "너무 꽉 붙어 있으면 떼기 힘들어!"

SOLID 원칙:

  • S: 한 가지 일만 해요 (학생은 공부만!)
  • O: 새 기능은 추가로 (추가만 하고 수정은 NO)
  • L: 교체해도 잘 돼요 (부모 대신 자식이 일해도 OK)
  • I: 필요한 것만 (다 할 필요 없어!)
  • D: 약속만 지키면 돼요 (인터페이스만 맞으면 OK)

이게 바로 소프트웨어 설계예요! 🏗️