[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -2,102 +2,148 @@
|
||||
id: wiki-2026-0508-소프트웨어-아키텍처-베스트-프랙티스
|
||||
title: 소프트웨어 아키텍처 베스트 프랙티스
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AUTO-FDDA7F]
|
||||
aliases: [Architecture Best Practices, SW Architecture Patterns]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
tags: [auto-reinforced]
|
||||
verification_status: applied
|
||||
tags: [architecture, best-practices, patterns]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
github_commit: "[P-Reinforce] Continuous Worker - 소프트웨어 아키텍처 베스트 프랙티스"
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: agnostic
|
||||
framework: agnostic
|
||||
---
|
||||
|
||||
# [[소프트웨어 아키텍처 베스트 프랙티스|소프트웨어 아키텍처 베스트 프랙티스]]
|
||||
# 소프트웨어 아키텍처 베스트 프랙티스
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> 소프트웨어 아키텍처 베스트 프랙티스는 회복성, 확장성, 그리고 유지보수성이 뛰어난 시스템을 구축하기 위한 핵심 원칙과 설계 청사진입니다 [1]. 이는 단순한 이론적 지침을 넘어, 기능의 추가 및 수정을 용이하게 하고 기술 부채를 최소화하여 애플리케이션의 장기적인 비즈니스 가치를 보존하는 근본적인 철학입니다 [1, 2]. 관심사의 분리(SoC), 클린 아키텍처, 도메인 주도 설계(DDD) 등의 원칙을 통해 시스템의 결합도를 낮추고 응집도를 높여 복잡성을 통제하는 것을 궁극적인 목표로 합니다 [3-5].
|
||||
## 매 한 줄
|
||||
> **"매 best practice는 매 context-bound이며, 매 trade-off 의 명시 없이 적용 시 매 cargo cult로 전락한다"**. Fowler / Vernon / Newman의 매 distillation은 매 boundary 의 명확화, 매 dependency 의 inversion, 매 deployment 의 independence를 매 핵심으로 본다.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
성공적인 소프트웨어 아키텍처를 구현하기 위한 핵심 프랙티스들은 다음과 같습니다.
|
||||
## 매 핵심
|
||||
|
||||
* **관심사의 분리 ([[_뇌와 팔다리의 분리_ - 관심사의 분리 (Separation of Concerns)|Separation of Concerns]], SoC)**
|
||||
소프트웨어 설계에서 가장 중요한 원칙 중 하나로, 프로그램을 서로 겹치지 않는 뚜렷한 기능(관심사)별로 나누는 것을 의미합니다 [6, 7]. 비즈니스 로직(뇌)과 인프라/프레임워크(팔다리)를 엄격히 분리함으로써 높은 응집도(High Cohesion)와 낮은 결합도(Low Coupling)를 달성할 수 있습니다 [8-10]. 이를 통해 하나의 모듈을 변경할 때 다른 모듈이 받는 영향을 최소화하여 유지보수성과 재사용성을 극대화합니다 [11].
|
||||
* **클린 아키텍처 및 의존성 규칙**
|
||||
비즈니스 규칙과 애플리케이션 로직을 시스템의 중심에 두고, 프레임워크, UI, 데이터베이스 등의 외부 세부 사항을 바깥 계층으로 밀어내는 철학입니다 [12, 13]. 핵심은 '의존성 규칙(Dependency Rule)'으로, 소스 코드의 의존성은 항상 외부에서 내부(고수준의 비즈니스 정책)를 향해야 합니다 [14]. 이로 인해 인프라가 변경되더라도 핵심 업무 로직은 영향을 받지 않습니다 [15].
|
||||
* **객체 지향 및 모듈화 원칙 (SOLID & DRY)**
|
||||
클래스는 단 하나의 변경 이유만 가져야 한다는 단일 책임 원칙(SRP)을 비롯한 SOLID 원칙은 낮은 결합도와 높은 테스트 가능성을 제공합니다 [16, 17]. 또한, 동일한 로직이나 지식을 여러 곳에 중복하지 않는 DRY(Don't Repeat Yourself) 원칙을 통해 시스템 내 단일 진실 공급원([[Single_Source_of_Truth|Single Source of Truth]])을 유지해야 합니다 [18].
|
||||
* **도메인 주도 설계 (Domain-Driven Design, DDD)**
|
||||
복잡한 시스템을 다루기 위해 비즈니스 도메인 전문가와 개발자가 '보편적 언어(Ubiquitous Language)'를 공유하며 모델링하는 기법입니다 [19]. 거대한 도메인을 '바운디드 컨텍스트(Bounded Context)'로 나누어 각 영역이 독립적인 모델을 가지게 함으로써 복잡성을 관리합니다 [20, 21].
|
||||
* **마이크로서비스 (Microservices) 및 이벤트 기반 아키텍처**
|
||||
거대한 모놀리식 구조를 탈피하여, 단일 비즈니스 역량을 수행하며 독립적으로 배포 및 확장이 가능한 작은 서비스들의 집합으로 시스템을 구성합니다 [22]. 서비스 간의 느슨한 결합을 위해 메시지 브로커를 활용한 비동기식 이벤트 기반 아키텍처(Event-Driven [[Architecture|Architecture]])를 함께 적용하는 것이 권장됩니다 [23]. 프론트엔드 영역에서도 이를 적용한 '마이크로 프론트엔드' 기술이 사용됩니다 [24, 25].
|
||||
* **테스트 주도 개발(TDD) 및 테스트 경계**
|
||||
아키텍처는 초기부터 테스트 가능성을 고려하여 설계되어야 합니다. TDD는 모듈화와 명확한 인터페이스 생성을 강제하므로 결합도를 낮추는 데 기여합니다 [26, 27]. 테스트 또한 시스템의 일부로 간주되며, 변동성이 큰 GUI 등을 거치지 않고 업무 규칙을 직접 검증할 수 있는 테스트 API를 구축하는 것이 중요합니다 [27, 28].
|
||||
### 매 SOLID at architecture level
|
||||
- **SRP**: 매 service 매 single business capability.
|
||||
- **OCP**: 매 plugin / 매 extension point.
|
||||
- **LSP**: 매 contract-based versioning.
|
||||
- **ISP**: 매 client-specific API (BFF).
|
||||
- **DIP**: 매 ports & adapters.
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
|
||||
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
|
||||
### 매 Cloud-native principles (12-factor + extensions)
|
||||
- 매 stateless processes.
|
||||
- 매 config via env.
|
||||
- 매 backing services as attached resources.
|
||||
- 매 disposability (fast startup, graceful shutdown).
|
||||
- 매 logs as event streams.
|
||||
- 매 health endpoints (`/healthz`, `/readyz`).
|
||||
- 매 telemetry by default (OpenTelemetry).
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- **Related Topics:** [[관심사의 분리 (SoC)|관심사의 분리(SoC]], 클린 아키텍처, 마이크로서비스 아키텍처, 도메인 주도 설계(DDD), [[SOLID 원칙|SOLID 원칙]]
|
||||
- **Projects/Contexts:** 넷플릭스(Netflix)의 코스모스 플랫폼 및 마이크로서비스 전환, 스포티파이(Spotify)의 마이크로 프론트엔드 및 스쿼드 모델
|
||||
- **Contradictions/Notes:** 소스에 따르면 완벽한 형태의 아키텍처 경계(예: 완벽한 관심사 분리와 다형성 인터페이스의 전면적 도입)는 유지보수성과 독립성을 극대화하지만, 초기 구현 비용과 성능 오버헤드, 인지적 부하(Over-engineering)를 초래할 수 있습니다. 따라서 아키텍트는 YAGNI(You Aren't Gonna Need It) 철학을 기반으로 "[[Rule of Three|Rule of Three]](세 번 이상 중복 시 추상화)" 등을 활용해 부분적 경계만을 도입하는 등 실무적인 타협을 지속적으로 판단해야 한다고 지적합니다 [29-32].
|
||||
### 매 응용
|
||||
1. 매 deployment 독립성으로 매 release cadence 향상.
|
||||
2. 매 boundary 명확화로 매 team autonomy.
|
||||
3. 매 observability 매 ship-time guarantee.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-18*
|
||||
## 💻 패턴
|
||||
|
||||
---
|
||||
### Health endpoint (Spring Boot)
|
||||
```java
|
||||
@RestController
|
||||
class HealthController {
|
||||
@GetMapping("/healthz") // liveness
|
||||
ResponseEntity<?> live() { return ResponseEntity.ok().build(); }
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
@GetMapping("/readyz") // readiness
|
||||
ResponseEntity<?> ready(DataSource ds) {
|
||||
try (var c = ds.getConnection()) {
|
||||
c.prepareStatement("SELECT 1").execute();
|
||||
return ResponseEntity.ok().build();
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.status(503).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### Circuit breaker (Resilience4j)
|
||||
```java
|
||||
CircuitBreaker cb = CircuitBreaker.of("payment",
|
||||
CircuitBreakerConfig.custom()
|
||||
.failureRateThreshold(50)
|
||||
.slowCallDurationThreshold(Duration.ofSeconds(2))
|
||||
.waitDurationInOpenState(Duration.ofSeconds(30))
|
||||
.build());
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
Supplier<Receipt> guarded = CircuitBreaker
|
||||
.decorateSupplier(cb, () -> paymentClient.charge(req));
|
||||
return Try.ofSupplier(guarded).recover(t -> Receipt.queued()).get();
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Outbox pattern (Postgres + Debezium)
|
||||
```sql
|
||||
BEGIN;
|
||||
INSERT INTO orders (id, status) VALUES ($1, 'CONFIRMED');
|
||||
INSERT INTO outbox (aggregate_id, type, payload)
|
||||
VALUES ($1, 'OrderConfirmed', $2);
|
||||
COMMIT;
|
||||
-- Debezium reads outbox table → publishes to Kafka
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### Idempotency key (REST)
|
||||
```python
|
||||
@app.post("/payments")
|
||||
def charge(req: ChargeReq, idempotency_key: str = Header(...)):
|
||||
cached = redis.get(f"idem:{idempotency_key}")
|
||||
if cached:
|
||||
return json.loads(cached)
|
||||
result = process(req)
|
||||
redis.setex(f"idem:{idempotency_key}", 86400, json.dumps(result))
|
||||
return result
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### Feature flag (LaunchDarkly-style)
|
||||
```typescript
|
||||
if (await flags.isEnabled("new-checkout", { userId })) {
|
||||
return newCheckout(cart);
|
||||
}
|
||||
return legacyCheckout(cart);
|
||||
```
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| 매 cross-service consistency | Outbox + Kafka |
|
||||
| 매 retry safety | Idempotency key |
|
||||
| 매 cascading failure 방지 | Circuit breaker |
|
||||
| 매 zero-downtime release | Feature flag + blue/green |
|
||||
| 매 schema evolution | Backward-compatible (additive) only |
|
||||
|
||||
**기본값**: 매 12-factor + OpenTelemetry + idempotency.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[소프트웨어 아키텍처 설계]]
|
||||
- 변형: [[Microservices]] · [[Modular Monolith]]
|
||||
- 응용: [[Outbox Pattern]] · [[Circuit Breaker]] · [[Saga]]
|
||||
- Adjacent: [[12-Factor App]] · [[OpenTelemetry]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 best practice 의 trade-off 설명 / 매 idempotency key generation.
|
||||
**언제 X**: 매 specific SLA tuning — 매 production data 기반 결정 필요.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Cargo cult microservices**: 매 boundary 없이 매 split.
|
||||
- **Distributed transaction**: 매 2PC across services.
|
||||
- **Shared database**: 매 service 간 매 schema 공유.
|
||||
- **Dual write**: 매 outbox 없이 매 DB + Kafka 동시 write.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Newman, *Building Microservices 2e*; Vernon, *Implementing DDD*; Fowler, *Patterns of Enterprise Application Architecture*).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — 매 outbox / circuit breaker / idempotency 추가 |
|
||||
|
||||
Reference in New Issue
Block a user