[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -1,128 +1,219 @@
|
||||
---
|
||||
id: wiki-2026-0508-architecture-anti-patterns
|
||||
title: Architecture Anti patterns
|
||||
title: Architecture Anti-patterns
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-REINFORCE-WIKI-72D5C126]
|
||||
aliases: [아키텍처 안티패턴, design anti-patterns, distributed monolith, big ball of mud]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.95
|
||||
tags: [architecture-anti-patterns, circuit-breaker-pattern, architecture-decision-record-(adr), anaemic-domain-model, software-architecture-erosion, architecture-principles]
|
||||
source_trust_level: B
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, anti-patterns, distributed-systems, microservices, adr, code-smell, technical-debt]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-02
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
|
||||
tech_stack:
|
||||
language: unspecified
|
||||
framework: unspecified
|
||||
language: language-agnostic
|
||||
framework: any
|
||||
---
|
||||
|
||||
# [[Architecture Anti-patterns]]
|
||||
# Architecture Anti-patterns
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
아키텍처 안티패턴(Architecture Anti-patterns)은 소프트웨어 시스템 설계 및 진화 과정에서 발생할 수 있는 비효율적이거나 잘못된 아키텍처 결정 및 관행을 의미합니다 [1, 2]. 분산 시스템에서의 잘못된 타임아웃 설정, 의사결정의 지연(분석 마비), 또는 문서화되지 않은 결정 등이 대표적인 사례입니다 [1, 2]. 이러한 안티패턴을 인지하고 해결하는 것은 시스템의 성능 저하와 커뮤니케이션 단절을 막는 데 필수적이지만, 하나의 안티패턴을 해결하는 과정이 연쇄적으로 또 다른 안티패턴을 유발할 수도 있으므로 주의가 필요합니다 [2].
|
||||
## 📌 한 줄 통찰
|
||||
> **"매 안 하면 좋은 것"**. 매 design 의 mistake catalog. 매 timeout misconfig, 매 distributed monolith, 매 big ball of mud. 매 anti-pattern 의 catalog 의 senior 의 첫 weapon.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
소스 데이터를 기반으로 확인된 주요 아키텍처 안티패턴은 다음과 같습니다.
|
||||
## 📖 핵심
|
||||
|
||||
- **타임아웃 안티패턴 (Timeout AntiPattern):** 분산 시스템에서 타임아웃 값을 설정할 때 발생하는 문제를 설명합니다 [1]. 타임아웃을 너무 짧게 설정하면 정상적인 요청도 조기에 실패 처리되어 복잡한 우회 방법이 필요해지며, 너무 길게 설정하면 오류 응답이 늦어져 사용자 경험이 심각하게 저하됩니다 [1].
|
||||
- **의사결정 지연 및 분석 마비 (Decision Delay & Analysis Paralysis):** 아키텍트가 잘못된 선택을 할 것을 두려워하여 아키텍처 결정을 지연시키거나 회피할 때 발생합니다 [2]. 이를 방지하려면 개발 팀과 긴밀하게 협력하고, 불필요한 지연으로 인한 분석 마비를 막기 위해 충분한 정보가 확보된 '마지막 책임 순간(last responsible moment)'에 결정을 내려야 합니다 [2].
|
||||
- **문서화되지 않은 결정 (Forgotten/Undocumented Decisions):** 아키텍처 결정이 이메일과 같은 휘발성 매체를 통해 소통되거나 제대로 기록되지 않아 잊혀지는 현상입니다 [2]. 이는 명확한 결론 없이 동일한 논의가 반복되는 결과를 초래합니다 [2].
|
||||
- **빈약한 도메인 모델 (Anaemic Model):** 전통적으로는 안티패턴으로 간주되지만, 마이크로서비스 아키텍처와 같이 단일 도메인의 기능만 포함하는 매우 작은 서비스에서는 이러한 트랜잭션 스크립트 기반의 단순한 모델이 오히려 효율적일 수 있다는 논의도 존재합니다 [3].
|
||||
### 매 카테고리
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- **안티패턴 해결의 연쇄 작용:** 아키텍처 안티패턴은 종종 점진적인 시퀀스를 따르기 때문에, 하나의 안티패턴을 해결하기 위한 조치가 또 다른 안티패턴의 출현으로 이어질 수 있는 제약 및 부작용을 동반합니다 [2].
|
||||
- **타임아웃 설정의 딜레마:** 타임아웃 안티패턴에서 짧은 타임아웃(정상 요청의 실패 위험)과 긴 타임아웃(느린 에러 응답) 사이의 타협점(Trade-off)을 찾는 것은 매우 어렵습니다 [1]. 이를 최적화하기 위해 서킷 브레이커(Circuit Breaker) 패턴을 도입할 수 있으나, 이는 서비스 상태를 실시간으로 모니터링해야 하는 시스템적 복잡성을 추가로 요구합니다 [1].
|
||||
- **문서화 오버헤드:** 문서화되지 않은 결정 안티패턴을 피하기 위해서는 기술적 및 비즈니스적(비용, 시장 출시 시간 등) 타당성을 명시한 아키텍처 결정 기록(ADR)을 위키와 같은 중앙 저장소에 엄격하게 관리해야 하는 관리적 반대 급부가 따릅니다 [2].
|
||||
- **결정 시점의 위험성:** 분석 마비를 피하기 위해 '마지막 책임 순간'까지 결정을 보류하는 것은 유연성을 유지하는 방법이지만, 시기를 잘못 조율하면 오히려 개발 진행을 방해하는 치명적인 병목이 될 수 있습니다 [2].
|
||||
#### Distributed system
|
||||
- **Distributed monolith**: 매 microservice 가 sync coupling — 매 worst of both.
|
||||
- **Chatty service**: 매 N+1 inter-service call.
|
||||
- **Wrong timeout**: 매 too short = false fail / too long = bad UX.
|
||||
- **Shared database**: 매 service 가 같은 DB → 매 coupling.
|
||||
- **No circuit breaker**: 매 cascading failure.
|
||||
- **Synchronous chain**: 매 5 service hop = 매 latency 합.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
### Related Concepts
|
||||
#### Decision-making
|
||||
- **Analysis paralysis**: 매 fear-driven indecision.
|
||||
- **Forgotten decision**: 매 email-only / 매 ADR 없음.
|
||||
- **Premature optimization**: 매 evidence X 의 optimize.
|
||||
- **Cargo cult**: 매 "Netflix 가 이렇게" 의 무비판 모방.
|
||||
|
||||
#### [아키텍처/기반 기술]
|
||||
- [[Circuit Breaker Pattern]]
|
||||
- 연결 이유: Timeout AntiPattern으로 인해 발생하는 분산 시스템의 오류 응답 및 지연 문제를 해결하기 위한 구조적 해결책입니다 [1].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 하트비트(heartbeat)나 실시간 사용량 모니터링을 통해 실패를 조기에 감지하고 분산 아키텍처의 복원력을 높이는 원리 [1].
|
||||
#### Code structure
|
||||
- **Big ball of mud**: 매 boundary X.
|
||||
- **God object**: 매 single class 의 모든 logic.
|
||||
- **Anaemic model**: 매 entity 가 data 만 (case-by-case).
|
||||
- **Spaghetti**: 매 control flow tangled.
|
||||
- **Lava flow**: 매 dead code + commented-out.
|
||||
|
||||
#### [구현/활용 도구]
|
||||
- [[Architecture Decision Record (ADR)]]
|
||||
- 연결 이유: 이메일 등을 통한 파편화된 소통으로 인해 결정이 잊혀지는 안티패턴을 방지하기 위한 구체적인 문서화 도구입니다 [2].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 아키텍처 결정의 배경, 대안, 위험 및 결과를 문서화하여 시간이 지나도 팀원 및 이해관계자들이 변경 사항을 추적할 수 있도록 돕는 방법 [4, 5].
|
||||
#### Microservice 특화
|
||||
- **Nano-service**: 매 너무 작 — 매 communication 의 logic 의 dominate.
|
||||
- **Entity service**: 매 1 entity = 1 service (vs business capability).
|
||||
- **Sync everywhere**: 매 async 의 부재.
|
||||
- **No bounded context**: 매 model 의 leak.
|
||||
- **Versioning chaos**: 매 breaking change 의 coordination X.
|
||||
|
||||
#### [설계 패러다임]
|
||||
- [[Anaemic Domain Model]]
|
||||
- 연결 이유: 일반적으로 안티패턴으로 불리나, 마이크로서비스 설계의 경계 내에서는 수용 가능 여부가 토론되는 핵심 개념입니다 [3].
|
||||
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 모놀리식 구조와 마이크로서비스 구조에서 비즈니스 로직의 복잡성을 다루는 관점의 차이 [3].
|
||||
#### Data
|
||||
- **Data in flight**: 매 in-memory 의 single source of truth.
|
||||
- **Eventual consistency 의 ignore**: 매 user 의 see stale.
|
||||
- **Cache stampede**: 매 expire 시 동시 fetch.
|
||||
- **Read-modify-write race**: 매 lost update.
|
||||
|
||||
### Deeper Research Questions
|
||||
- 분산 시스템에서 Timeout AntiPattern을 피하기 위해 Circuit Breaker 외에 어떠한 기술적 패턴들이 병행되어야 하는가?
|
||||
- '마지막 책임 순간(Last responsible moment)'에 도달했음을 객관적으로 판단할 수 있는 정량적 또는 정성적 기준은 무엇인가?
|
||||
- ADR(Architecture Decision Record)을 지속적으로 유지보수하기 위해 개발 조직의 문화나 파이프라인에 어떻게 통합하는 것이 가장 효과적인가?
|
||||
- Anaemic Model이 마이크로서비스 환경에서 수용될 수 있는 시스템적 한계점(크기나 복잡도 기준)은 어디까지인가?
|
||||
- 하나의 아키텍처 안티패턴을 해결했을 때 연쇄적으로 발생하는 다른 안티패턴들의 구체적인 실무 사례와 방어 전략은 무엇인가?
|
||||
### Sequence problem
|
||||
- 매 anti-pattern 의 fix 가 매 다른 anti-pattern 의 generate.
|
||||
- 매 distributed monolith 의 fix → 매 chatty / 매 sync chain.
|
||||
- 매 god object 의 split → 매 nano-service.
|
||||
|
||||
### Practical Application Contexts
|
||||
- **Implementation:** 마이크로서비스 간의 통신 시 타임아웃 안티패턴에 빠지지 않도록 적절한 서킷 브레이커 도구를 구현하여 장애 전파를 차단합니다.
|
||||
- **System Design:** 초기 시스템 설계 시 모놀리식과 마이크로서비스 간의 트레이드오프를 평가할 때, 무조건적인 도메인 모델의 복잡화(Anaemic Model 배제)가 항상 정답은 아님을 인지하고 서비스 크기에 맞게 설계합니다.
|
||||
- **Operation / Maintenance:** 이메일이나 채팅으로 결정된 주요 아키텍처 사항들을 위키 기반의 중앙화된 ADR 저장소로 이관하여 문서화 누락으로 인한 유지보수 병목을 방지합니다.
|
||||
- **Learning Path:** 분산 시스템이나 클라우드 네이티브 환경을 학습할 때, 성공적인 패턴뿐만 아니라 Timeout AntiPattern이나 의사결정 분석 마비와 같은 안티패턴을 먼저 인지하여 설계 실패를 조기에 예방합니다.
|
||||
- **My Project Relevance:** 현재 진행 중인 프로젝트에서 결정을 내리지 못해 일정이 지연되고 있다면, 그것이 정보 부족 때문인지 아니면 두려움으로 인한 '분석 마비' 안티패턴인지 진단하고, 마지막 책임 순간의 기준을 명확히 설정할 수 있습니다.
|
||||
→ 매 trade-off awareness 의 핵심.
|
||||
|
||||
### Adjacent Topics
|
||||
- [[Software Architecture Erosion]]
|
||||
- 확장 방향: 아키텍처 안티패턴이 장기적으로 방치되었을 때 시스템 아키텍처가 원래의 의도에서 벗어나 붕괴되거나 침식되는 과정과 그 복구 방법에 대한 연구로 확장할 수 있습니다 [6].
|
||||
- [[Distributed Systems Fallacies]]
|
||||
- 확장 방향: 이벤트 기반 아키텍처나 분산 시스템 설계 시, 타임아웃 문제나 데이터 손실과 같이 네트워크가 항상 신뢰할 수 있다는 오해(분산 컴퓨팅의 오류)에 대한 탐구로 이어질 수 있습니다 [7, 8].
|
||||
### 매 detect 방법
|
||||
- **Architecture test**: dependency-cruiser, ArchUnit.
|
||||
- **Dependency graph**: 매 cycle / 매 hub.
|
||||
- **Latency analysis**: 매 hop count.
|
||||
- **Code metric**: 매 cyclomatic / 매 LOC / 매 fan-out.
|
||||
- **Tracing**: 매 distributed trace 의 path.
|
||||
- **Postmortem catalog**: 매 incident pattern.
|
||||
|
||||
---
|
||||
*Last updated: 2026-05-02*
|
||||
### 매 modern catalog
|
||||
- Mark Richards 의 "Software Architecture: The Hard Parts".
|
||||
- Sam Newman 의 "Building Microservices".
|
||||
- Vaughn Vernon "Implementing DDD".
|
||||
- AWS / Azure architecture pattern.
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
## 💻 패턴 (응용 — detection / fix)
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(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
|
||||
### Architecture test
|
||||
```js
|
||||
// .dependency-cruiser.js
|
||||
module.exports = {
|
||||
forbidden: [
|
||||
{
|
||||
name: 'no-domain-to-infrastructure',
|
||||
severity: 'error',
|
||||
from: { path: '^src/domain' },
|
||||
to: { path: '^src/infrastructure' },
|
||||
},
|
||||
{
|
||||
name: 'no-circular',
|
||||
severity: 'error',
|
||||
from: {},
|
||||
to: { circular: true },
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### ADR (Architecture Decision Record) template
|
||||
```markdown
|
||||
# ADR-0042: Use Kafka for inter-service events
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
## Status
|
||||
Accepted (2026-05-10)
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
## Context
|
||||
3 services (order, billing, inventory) need to coordinate.
|
||||
Sync HTTP creates cascading failure risk.
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
## Decision
|
||||
Adopt Kafka for async event-driven coordination.
|
||||
Use Avro for schema evolution.
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
## Consequences
|
||||
+ Decoupling, scale, replay.
|
||||
- Operational complexity (Kafka cluster).
|
||||
- Debugging async harder.
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
## Alternatives considered
|
||||
1. RabbitMQ — simpler but less throughput.
|
||||
2. SQS — vendor lock-in.
|
||||
3. Sync HTTP — original problem.
|
||||
```
|
||||
|
||||
### Circuit breaker (anti-pattern fix)
|
||||
```ts
|
||||
class CircuitBreaker {
|
||||
state: 'closed' | 'open' | 'half-open' = 'closed';
|
||||
failures = 0;
|
||||
lastFailure = 0;
|
||||
|
||||
async call<T>(fn: () => Promise<T>): Promise<T> {
|
||||
if (this.state === 'open') {
|
||||
if (Date.now() - this.lastFailure > 30_000) this.state = 'half-open';
|
||||
else throw new CircuitOpen();
|
||||
}
|
||||
try {
|
||||
const result = await fn();
|
||||
if (this.state === 'half-open') this.state = 'closed';
|
||||
this.failures = 0;
|
||||
return result;
|
||||
} catch (e) {
|
||||
this.failures++;
|
||||
this.lastFailure = Date.now();
|
||||
if (this.failures > 5) this.state = 'open';
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Detect distributed monolith
|
||||
```python
|
||||
def detect_distributed_monolith(services, traces):
|
||||
"""매 sync coupling chain 의 detect"""
|
||||
for trace in traces:
|
||||
sync_chain = [s for s in trace.spans if s.kind == 'sync']
|
||||
if len(sync_chain) > 3:
|
||||
yield ('long sync chain', trace.id, sync_chain)
|
||||
|
||||
# 매 deploy coupling
|
||||
deploy_pairs = collections.Counter()
|
||||
for incident in incidents:
|
||||
if len(incident.affected_services) > 1:
|
||||
for pair in combinations(incident.affected_services, 2):
|
||||
deploy_pairs[pair] += 1
|
||||
|
||||
return deploy_pairs.most_common(5)
|
||||
```
|
||||
|
||||
## 🤔 결정 기준
|
||||
| 안티패턴 | 해결 |
|
||||
|---|---|
|
||||
| Distributed monolith | Async event + bounded context |
|
||||
| Wrong timeout | Tiered timeout + circuit breaker |
|
||||
| Forgotten decision | ADR + central wiki |
|
||||
| Analysis paralysis | Last responsible moment + spike |
|
||||
| God object | Refactor by responsibility |
|
||||
| Nano-service | Merge by business capability |
|
||||
| Cache stampede | Probabilistic refresh, lock |
|
||||
|
||||
**기본값**: 매 ADR + architecture test + tracing + postmortem.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Architecture-Styles]] · [[Software-Engineering]]
|
||||
- 변형: [[Big-Ball-of-Mud]] · [[Distributed-Monolith]] · [[Anaemic-Domain-Model]] · [[God-Object]]
|
||||
- 응용: [[Circuit-Breaker]] · [[ADR]] · [[Architecture-Test]] · [[Bounded-Context]]
|
||||
- Adjacent: [[Technical-Debt]] · [[Code-Smells]] · [[Refactoring]] · [[Postmortem]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: 매 architecture review. 매 design decision. 매 incident 의 root cause analysis.
|
||||
**언제 X**: 매 simple project (대부분 의 anti-pattern 의 N/A).
|
||||
|
||||
## ❌ 안티패턴 (meta)
|
||||
- **모든 anti-pattern 의 fix**: 매 trade-off 의 ignore.
|
||||
- **Cargo cult**: 매 "최선" 의 context 의 ignore.
|
||||
- **No ADR**: 매 future-self 의 confusion.
|
||||
- **Architecture astronaut**: 매 over-design.
|
||||
- **YAGNI 의 무시**: 매 future hypothetical 의 design.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Mark Richards, Sam Newman, AWS Well-Architected).
|
||||
- 신뢰도 B.
|
||||
- Related: [[Architecture-Styles]] · [[Anaemic-Domain-Model]] · [[Circuit-Breaker]].
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — 카테고리 + 매 distributed / decision / data + ADR + circuit breaker |
|
||||
|
||||
Reference in New Issue
Block a user