e2c5471046
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.5 KiB
6.5 KiB
id, title, category, status, verification_status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, created_at, updated_at, review_reason, merge_history, tags, raw_sources, applied_in, github_commit
| id | title | category | status | verification_status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | created_at | updated_at | review_reason | merge_history | tags | raw_sources | applied_in | github_commit | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| anti-patterns-catalog | 안티패턴 카탈로그 | Software_Engineering | draft | applied |
|
A | 0.9 | 2026-06-13 | 2026-06-13 |
|
|
|
안티패턴 카탈로그
🎯 한 줄 통찰 (One-line insight)
안티패턴은 "처음엔 그럴듯하지만 시간이 지나면 버그·복잡도를 부르는 습관" 이며, ConnectAI 가 실제로 겪고 고친 사례에서 추출한 것이라 작은 모델이 회피해야 할 1순위 목록이다.
🧠 핵심 개념 (Core concepts)
각 안티패턴: 설명 / 왜 위험한가 / 증상 / 더 나은 대안 / 이 프로젝트의 사례(있으면).
📖 세부 내용 (Details · 안티패턴 모음)
A-01. 무음 빈 catch (Silent swallow)
- 설명:
try { ... } catch {}로 에러를 이유 없이 삼킴. - 왜 위험: 실패가 숨겨져 디버깅 불가, 잘못된 상태로 진행.
- 증상: "왜 아무 일도 안 일어나지?", 로그 없는 실패.
- 더 나은 대안: 본류 에러는 throw/처리. 부가 작업만 삼키되 이유 주석 필수.
- 사례: ConnectAI 는 부가 작업에 한해
catch { /* should never break main flow */ }로 정당화 [S2].
A-02. Promise/객체 동일성에 로직 걸기
- 설명:
===로 Promise·새 객체를 비교해 분기. - 왜 위험:
.then()/.map()등은 매번 새 인스턴스 → 비교 항상 false. - 증상: cleanup 안 됨, 메모리 누수, 간헐 race.
- 더 나은 대안: 명시적 토큰/ID 비교.
- 사례: lock.ts 의 옛 버그 → Symbol 토큰으로 수정 [S1].
A-03. || 로 기본값 — 의미 있는 0/''/false 삼킴
- 설명:
limit || 8처럼 falsy 전체를 대체. - 왜 위험: 0/''/false 가 유효값인데 기본값으로 둔갑.
- 증상: "검색 끄기(0)" 가 무시되는 류의 미묘한 버그.
- 더 나은 대안:
??(nullish) 사용. - 사례:
brainFileLimit ?? 8[S3].
A-04. 에이전트 남발 (Multi-agent over-engineering)
- 설명: 문제마다 새 persona/에이전트를 추가.
- 왜 위험: hop 마다 컨텍스트 누적·원본 손실, 자원 폭증, 디버깅 난해.
- 증상: "분석 방법론" 만 나오고 실제 결과 없음, OOM.
- 더 나은 대안: 단일 작성자 다중 역할, 정말 필요한 협업만 순차.
- 사례: 5-persona → ChunkedWriter 전환 [S4].
A-05. 거대 god-class (흐름·구현 한 덩어리)
- 설명: 모든 로직을 한 클래스/파일에.
- 왜 위험: 테스트 불가, 병합 충돌, 변경 두려움.
- 증상: 수천 줄 파일, "여길 고치면 저기가 깨짐".
- 더 나은 대안: 흐름 골격만 남기고 구현을 순수 모듈로 추출(ADR-0010 오케스트레이터 골격 모듈추출).
A-06. 이유 없는 동적 require/import
- 설명: 습관적으로
await import()를 핫패스에서 반복. - 왜 위험: 흐름 불명확, 불필요 오버헤드, 진짜 이유가 사라져도 잔존.
- 증상: 같은 모듈을 매 호출 동적 로드.
- 더 나은 대안: 순환이 없으면 정적 import. 동적은 진짜 무거운/드문 기능에만 + 이유 주석.
- 사례: dispatcher 의 require 8회 → 정적 promote [S4].
A-07. 형식만 믿는 LLM 출력 파싱
- 설명: "JSON 만 출력" 을 믿고
JSON.parse(raw)직접. - 왜 위험: 작은 모델은 코드펜스·잡설을 섞어 파싱 실패.
- 증상: 간헐 파싱 예외, 빈 결과.
- 더 나은 대안: 균형 괄호 스캔 추출 + fallback. "프롬프트와 파서를 함께 설계".
- 사례: criticAgent 의 균형
{}파서 [참조: Intelligence 검증 레이어].
A-08. 점수 부분 정규화 (편향 융합)
- 설명: 여러 신호를 합치며 일부만 정규화.
- 왜 위험: 정규화 안 된 신호가 스케일로 상위 독식.
- 증상: 새 신호를 더했는데 품질이 나빠짐.
- 더 나은 대안: 모든 신호를 동일 스케일로 정규화 후 가중 합.
- 사례: 하이브리드 검색 [S3].
A-09. 환경 무시한 동시성 가정
- 설명: "병렬이 빠르니 무조건 병렬".
- 왜 위험: 자원(RAM/GPU)을 넘으면 OOM·스왑으로 더 느려지거나 죽음.
- 증상: 로컬에서 멀티모델 로드 실패.
- 더 나은 대안: 타깃 하드웨어 기준으로 동시성 결정(ADR-0004 순차 디스패치 채택).
A-10. 만료 없는 영구 메모리
- 설명: 모든 기억을 영구 저장.
- 왜 위험: 시한부 사실(분기 계획)이 만료 후에도 검색돼 오답 유발.
- 증상: "지난 분기 계획" 을 현재처럼 답함.
- 더 나은 대안: temporal marker(
expiresAt)로 자동 제외 + 증류 보존 [참조: 5계층 메모리 시스템].
⚖️ 모순 및 업데이트 (Contradictions & updates)
일부 "안티패턴" 은 맥락에 따라 정당하다 — god-class(흐름 가독성), 빈 catch(부가 작업), 동적 import(무거운 기능). 핵심은 이유를 명시하고 의식적으로 쓰는가다. 무의식적 습관일 때만 안티패턴.
🛠️ 적용 사례 (Applied in summary)
모두 ConnectAI 가 실제로 마주쳐 고치거나 의식적으로 관리하는 사례. 교훈 라이브러리 Lessons Learned 와 짝을 이룬다.
🔗 지식 그래프 (Knowledge Graph)
- 상위/루트: ConnectAI 아키텍처 개요
- 관련 개념: 교훈 라이브러리 Lessons Learned, 아키텍처 휴리스틱, 디버깅 플레이북, 코딩 컨벤션과 주석 철학
- 참조 맥락: 로컬 LLM 이 코드 작성/리뷰 시 회피 목록으로 참조.
📚 출처 (Sources)
- [S1] ConnectAI/src/core/lock.ts — 동일성 비교 안티패턴
- [S2] ConnectAI/src/memory/index.ts — 빈 catch(정당화된 형태)
- [S3] ConnectAI/src/retrieval/index.ts — ?? vs ||, 부분 정규화
- [S4] ConnectAI/src/features/company/dispatcher.ts, AgentWorkflowManager.ts — 에이전트 남발, 동적 require
📝 변경 이력 (Change history)
- 2026-06-13: ConnectAI 사례 기반 안티패턴 카탈로그 초안.