소프트웨어 엔지니어링 및 시스템 설계 표준
소프트웨어 엔지니어링 우수성, 시스템 아키텍처, 저수준 설계 및 분산 시스템을 위한 엄격하고 실전에서 검증된 운영 가이드입니다.
1. 핵심 운영 원칙
- 독단보다 트레이드오프: 보편적인 "최선의 방법"은 없으며 오직 트레이드오프만 존재합니다. 모든 아키텍처 선택은 특정 비용(지연 시간, 일관성, 운영 복잡성 또는 인지 부하)을 지불함으로써 일련의 이점을 얻습니다. 항상 무엇이 희생되는지 명시하십시오.
- 가역성 우선: 단방향(되돌릴 수 없는) 결정보다 양방향(되돌릴 수 있는) 결정을 우선시하십시오. 특정 벤더, 프레임워크 또는 분산 토폴로지에 대한 조기 결합을 피하십시오.
- 아키텍처 우주 공학 금지: 모든 추상화, 인터페이스 및 계층은 추측적인 미래 요구 사항(YAGNI 원칙)이 아니라 구체적인 기존 요구 사항에 대해 그 무게를 정당화해야 합니다.
- 증거 기반 설계: 가정이 아닌 구체적인 프로파일, 측정값, 쿼리 계획(
EXPLAIN ANALYZE) 및 용량 한계에 기반하여 결정을 내리십시오. - 빠른 실패 및 명시적 경계: 하위 시스템, 도메인 또는 네트워크 홉 간의 경계에는 명시적이고 강력한 타입의 계약, 유효성 검사, 타임아웃, 차단기(Circuit Breaker) 및 멱등성 보장이 있어야 합니다.
2. 고수준 설계(HLD) 및 아키텍처 워크플로
시스템을 설계하거나, 아키텍처를 평가하거나, 주요 하위 시스템을 리팩터링하라는 요청을 받으면 다음 6단계 프레임워크를 실행하십시오:
flowchart TD
Step1["1. 요구 사항 및 범위 명확화<br>(기능적, 비기능적, 지연 시간, 가용성, 일관성)"]
Step2["2. 용량 및 규모 추정<br>(DAU, QPS, 처리량, 네트워크 대역폭, 스토리지, 캐시 RAM)"]
Step3["3. 고수준 아키텍처 (C4 L1/L2)<br>(서비스 경계, 스토리지 선택, 인그레스, 캐싱)"]
Step4["4. 데이터 모델 및 인터페이스 계약<br>(엔터티, 스키마, 기본 키, 인덱스, REST/gRPC API)"]
Step5["5. 심층 분석 및 병목 지점 격리<br>(복제, 샤딩, 동시성, 캐싱 병리 현상, 핫스팟)"]
Step6["6. 복원력 및 SRE 전략<br>(SLO, 차단기, 지터 포함 재시도, 멱등성, DLQ)"]
Step1 --> Step2 --> Step3 --> Step4 --> Step5 --> Step6
상세 HLD 참고 자료
분산 시스템 정리(CAP, PACELC), 일관성 계층 구조, 합의(Raft/Paxos), 샤딩, 복제, Saga 패턴 및 트랜잭션 아웃박스(Transactional Outbox) 패턴에 대해서는 다음을 참조하십시오: 👉 고수준 시스템 설계 및 분산 시스템 참고 자료
3. 저수준 설계(LLD) 및 클린 코드 표준
코드를 작성, 검토 또는 리팩터링할 때 다음 표준을 준수하십시오:
3.1 SOLID 규칙
- SRP(단일 책임): 모듈은 응답해야 할 하나의 행위자/이해관계자를 가집니다. 지속성, HTTP 직렬화 및 비즈니스 로직을 별도의 관심사로 추출하십시오.
- OCP(개방-폐쇄): 광범위한
switch/if-else유형 디스패치 문보다 다형성, 전략(Strategy) 또는 방문자(Visitor) 패턴을 선호하십시오. - LSP(리스코프 치환): 서브타입은 부모의 모든 행동 불변성을 만족해야 합니다.
NotImplementedException을 던지도록 메서드를 재정의하는 것은 LSP를 위반합니다. - ISP(인터페이스 분리): 광범위한 "신(God) 인터페이스"보다 작고 클라이언트에 특화된 역할 인터페이스를 선호하십시오.
- DIP(의존성 역전): 핵심 비즈니스 규칙은 추상화(포트)에만 의존하고 외부 데이터베이스 라이브러리, UI 프레임워크 또는 네트워크 드라이버에 직접 의존해서는 안 됩니다.
3.2 모듈 캡슐화(Parnas 및 커네센스)
- 모듈 비밀: 모듈은 기본 비밀(내부 알고리즘/데이터 구조)과 보조 비밀(외부 환경/파일 형식)을 완전히 숨겨야 합니다.
- 커네센스: 동적 커네센스(실행 순서, 타이밍, 값 제약 조건)를 최소화하고 정적 이름/유형 계약에 대한 결합도를 줄이십시오.
상세 LLD 참고 자료
GoF 디자인 패턴 필드 가이드, 도메인 주도 설계(DDD) 전술적 구성 요소(엔터티, 값 객체, 애그리게이트, 도메인 이벤트) 및 리팩터링 기술에 대해서는 다음을 참조하십시오: 👉 저수준 설계 및 클린 코드 참고 자료
4. API 및 데이터 지속성 표준
- RESTful API:
- HTTP 메서드 의미를 엄격히 준수하십시오(
GET은 안전하고 멱등적,PUT/DELETE는 멱등적,POST는 생성). - 구조화된 오류 응답을 위해 **RFC 7807(Problem Details)**을 사용하십시오.
- 대량 컬렉션의 경우 오프셋/제한(Offset/Limit) 페이지네이션보다 키셋/커서(Keyset/Cursor) 페이지네이션을 사용하십시오.
- HTTP 메서드 의미를 엄격히 준수하십시오(
- 데이터베이스 인덱싱 (E-R-S 규칙):
- 복합 인덱스 컬럼 순서: [동등성 컬럼] $\to$ [범위 컬럼] $\to$ [정렬 컬럼].
- 커버링 인덱스(인덱스 전용 스캔) 및 부분 인덱스를 사용하여 핫 쿼리의 디스크 페이지 조회를 제거하십시오.
- 항상
EXPLAIN QUERY PLAN또는EXPLAIN ANALYZE로 쿼리를 검증하십시오.
- 비동기 메시징 및 이벤트:
- 적어도 한 번(at-least-once) 브로커 전달과 소비자 측 멱등성(저장소에서 중복 제거된 고유 메시지 ID)을 결합하여 사실상 한 번(effectively-once) 처리를 보장하십시오.
- 처리 불가능한 독성 메시지(Poison Pill)를 데드 레터 큐(DLQ)로 라우팅하여 파티션 중단을 방지하십시오.
상세 API 및 데이터 참고 자료
5. 성능, 용량 및 안정성 엔지니어링
- 어림셈 추정:
- $1\text{일} \approx 10^5\text{초}$ ($86,400\text{초}$). $1\text{M 요청/일} \approx 12\text{ RPS}$.
- 피크 QPS = 평균 QPS $\times$ $3$.
- 캐시 RAM = $20% \times (\text{일일 읽기 볼륨} \times \text{항목 크기})$ (파레토 80/20 법칙).
- 리틀의 법칙: $L = \lambda W$ (처리 중 동시성 = 도착률 $\times$ 지연 시간).
- 캐싱 규율:
- 정상 운영 시간 동안 만료되는 측정되지 않은 임의의 인메모리 TTL을 설정하지 마십시오.
- 데이터 버전/지문 또는 세션 타임스탬프를 기반으로 무효화하십시오.
- 캐시 스탬피드(뮤텍스/분산 잠금 사용), 캐시 침투(블룸 필터) 및 캐시 눈사태(TTL 지터)를 방어하십시오.
- 사이트 안정성 엔지니어링(SRE):
- 명시적인 SLO 및 지연 시간 예산($p50$, $p95$, $p99$)을 적용하십시오.
- 차단기(Circuit Breaker), 격리(Bulkhead) 및 전체 지터가 있는 지수 백오프(Exponential Backoff)를 구현하십시오.
상세 안정성 및 성능 참고 자료
6. 아키텍처 결정 기록(ADR)
표준 ADR 형식을 사용하여 중요하지 않은 기술적 선택을 문서화하십시오:
- 컨텍스트 및 동기: 문제, 운영 제약 조건 및 지연 시간/규모 목표.
- 고려된 옵션: 구조적 대안 및 그 트레이드오프.
- 결정 및 결과: 결정 동기와 연결되는 구체적인 근거.
- 결과: 명시적인 긍정적 이점과 수용된 부정적 비용.