refactor(topics): 멀티 에이전트용 지식 재편 — _Common(공통 기본기) + Domain_* 구조
에이전트 8종(대화형/프로그래머 C·S/디자이너/설계자/기획자/QA/PD/PM)에게 [공통 기본 능력 + 롤별 Specialty] 2층으로 지식을 주입하기 위한 재분류. 문서 내용·포맷은 무수정, 폴더 이동만 (6,372개 문서 수 보존 확인). - Topic_Programming → Domain_Programming (내부 구조 보존) - Topic_Graphic → Domain_Design - Topic_Business → Domain_Product - Topic_General → Domain_General - _Common 신설: Math(구 Topic_Math_Specialty), Reasoning(구 General/From_Thinking & Reasoning), Reasoning_Creativity(구 General/From_창의성), Communication(Poetic_Blog_Writing + From_writing) - 타 도메인의 From_* 폴더는 유지 (출처 표기일 뿐, 이미 도메인에 맞게 분류된 문서) - 빈 폴더 정리 (memory/procedures) - 에이전트→폴더 매핑은 workspace의 .astra/agent-knowledge-map.json (9개 에이전트) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
---
|
||||
id: wiki-2026-0508-aspect-oriented-programming-aop
|
||||
title: Aspect Oriented Programming (AOP)
|
||||
category: 10_Wiki/Topics
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [AOP, Aspect Programming, Cross-cutting Concerns]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.9
|
||||
verification_status: applied
|
||||
tags: [architecture, paradigm, spring, decorator]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-05-10
|
||||
github_commit: pending
|
||||
tech_stack:
|
||||
language: Java / TypeScript / Python
|
||||
framework: Spring AOP / AspectJ / NestJS
|
||||
---
|
||||
|
||||
# Aspect-Oriented Programming (AOP)
|
||||
|
||||
## 매 한 줄
|
||||
> **"매 cross-cutting concern을 separate aspect로 modularize."**. 1997년 Gregor Kiczales (Xerox PARC) 의 AspectJ 가 시초. 2026 현재 Spring AOP 6.x, NestJS interceptor, Python decorator 가 주류 — logging/transaction/security 같이 매 객체 가로지르는 logic을 매 한 곳에 모음.
|
||||
|
||||
## 매 핵심
|
||||
|
||||
### 매 용어
|
||||
- **Aspect**: 매 cross-cutting concern 의 modular 단위 (e.g. `LoggingAspect`).
|
||||
- **Join Point**: 매 program execution 의 한 지점 (method call, field access).
|
||||
- **Pointcut**: 매 join point 의 selection expression.
|
||||
- **Advice**: 매 pointcut 매칭 시 실행할 code (`@Before`, `@After`, `@Around`).
|
||||
- **Weaving**: 매 aspect 와 base code 결합 — compile-time / load-time / runtime.
|
||||
|
||||
### 매 cross-cutting concerns
|
||||
- Logging / tracing
|
||||
- Transaction management
|
||||
- Security / authorization
|
||||
- Caching
|
||||
- Performance monitoring
|
||||
- Error handling / retry
|
||||
- Audit trail
|
||||
|
||||
### 매 응용
|
||||
1. Spring `@Transactional` — DB transaction 자동 commit/rollback.
|
||||
2. NestJS `@UseInterceptors` — request/response transform.
|
||||
3. Python `@functools.lru_cache` — pure caching aspect.
|
||||
4. OpenTelemetry auto-instrumentation — runtime byte-code weaving.
|
||||
|
||||
## 💻 패턴
|
||||
|
||||
### Spring AOP — @Around aspect
|
||||
```java
|
||||
@Aspect
|
||||
@Component
|
||||
public class LoggingAspect {
|
||||
|
||||
@Around("execution(* com.example.service.*.*(..))")
|
||||
public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
Object result = pjp.proceed();
|
||||
long elapsed = System.currentTimeMillis() - start;
|
||||
log.info("{} took {} ms", pjp.getSignature(), elapsed);
|
||||
return result;
|
||||
} catch (Throwable t) {
|
||||
log.error("{} threw {}", pjp.getSignature(), t.getMessage());
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Spring — @Transactional declarative TX
|
||||
```java
|
||||
@Service
|
||||
public class OrderService {
|
||||
|
||||
@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
|
||||
public Order placeOrder(OrderRequest req) {
|
||||
Order order = orderRepo.save(new Order(req));
|
||||
inventoryRepo.decrement(req.getItems());
|
||||
// Any RuntimeException → automatic rollback via AOP proxy
|
||||
return order;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### NestJS — Interceptor (AOP-style)
|
||||
```typescript
|
||||
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
|
||||
import { Observable, tap } from 'rxjs';
|
||||
|
||||
@Injectable()
|
||||
export class TimingInterceptor implements NestInterceptor {
|
||||
intercept(ctx: ExecutionContext, next: CallHandler): Observable<unknown> {
|
||||
const start = Date.now();
|
||||
return next.handle().pipe(
|
||||
tap(() => console.log(`${ctx.getHandler().name} took ${Date.now() - start}ms`)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Controller('orders')
|
||||
@UseInterceptors(TimingInterceptor)
|
||||
export class OrdersController { /* ... */ }
|
||||
```
|
||||
|
||||
### Python — Decorator as aspect
|
||||
```python
|
||||
import functools, time, logging
|
||||
|
||||
def timed(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
start = time.perf_counter()
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
finally:
|
||||
elapsed = time.perf_counter() - start
|
||||
logging.info(f"{func.__name__} took {elapsed*1000:.1f}ms")
|
||||
return wrapper
|
||||
|
||||
@timed
|
||||
def expensive_calc(n: int) -> int:
|
||||
return sum(i * i for i in range(n))
|
||||
```
|
||||
|
||||
### Python — Class-based retry aspect
|
||||
```python
|
||||
def retry(times: int = 3, on: tuple = (Exception,)):
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
last = None
|
||||
for attempt in range(times):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except on as e:
|
||||
last = e
|
||||
time.sleep(2 ** attempt)
|
||||
raise last
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@retry(times=5, on=(httpx.HTTPError,))
|
||||
def fetch_remote(url: str) -> dict:
|
||||
return httpx.get(url).json()
|
||||
```
|
||||
|
||||
### AspectJ pointcut DSL
|
||||
```java
|
||||
@Pointcut("execution(public * com.example.repo.*.find*(..))")
|
||||
public void anyFinder() {}
|
||||
|
||||
@Pointcut("@annotation(com.example.Audited)")
|
||||
public void auditedMethod() {}
|
||||
|
||||
@Before("anyFinder() && auditedMethod()")
|
||||
public void audit(JoinPoint jp) {
|
||||
auditService.log(jp.getSignature().toShortString(), Instant.now());
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript — method decorator
|
||||
```typescript
|
||||
function Cached(ttlMs: number): MethodDecorator {
|
||||
const cache = new Map<string, { value: unknown; exp: number }>();
|
||||
return (_t, _k, desc: PropertyDescriptor) => {
|
||||
const original = desc.value;
|
||||
desc.value = function (...args: unknown[]) {
|
||||
const key = JSON.stringify(args);
|
||||
const entry = cache.get(key);
|
||||
if (entry && entry.exp > Date.now()) return entry.value;
|
||||
const value = original.apply(this, args);
|
||||
cache.set(key, { value, exp: Date.now() + ttlMs });
|
||||
return value;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
class Pricing {
|
||||
@Cached(60_000)
|
||||
fetchRate(currency: string) { /* ... */ }
|
||||
}
|
||||
```
|
||||
|
||||
## 매 결정 기준
|
||||
| 상황 | Approach |
|
||||
|---|---|
|
||||
| Java enterprise, declarative TX | Spring AOP (proxy-based) |
|
||||
| 매 method 매칭 + field access weaving | AspectJ (compile/load-time) |
|
||||
| Node.js HTTP layer | NestJS Interceptor / Guard |
|
||||
| Python script / function-level | Decorator |
|
||||
| Cross-language tracing | OpenTelemetry auto-instrumentation |
|
||||
|
||||
**기본값**: framework-native (Spring AOP / NestJS interceptor / decorator). 매 raw AspectJ 는 매 매우 specific 한 경우만.
|
||||
|
||||
## 🔗 Graph
|
||||
- 부모: [[Object-Oriented-Programming]] · [[Software-Architecture]]
|
||||
- 변형: [[Middleware]]
|
||||
- 응용: [[Spring Framework]] · [[NestJS]] · [[OpenTelemetry]]
|
||||
- Adjacent: [[Dependency_Injection_(DI)|Dependency-Injection]] · [[Cross-Cutting Concerns]]
|
||||
|
||||
## 🤖 LLM 활용
|
||||
**언제**: cross-cutting concern (logging/TX/security/caching) 이 매 여러 service 에 반복, declarative style 선호, framework 가 AOP 지원.
|
||||
**언제 X**: 매 한두 곳만 쓰는 logic (직접 호출이 명확), 매 magic 회피 culture, 매 debug 어려움 감수 못할 때.
|
||||
|
||||
## ❌ 안티패턴
|
||||
- **Aspect 안 business logic**: 매 aspect 는 매 cross-cutting 만 — 매 domain rule 넣지 X.
|
||||
- **너무 broad pointcut**: `execution(* *.*(..))` — 매 unintended weaving.
|
||||
- **Self-invocation 의 proxy bypass**: 매 같은 class 안 method call 은 매 proxy 통과 안 함 (Spring).
|
||||
- **Order 의존**: 매 multiple aspect 매 ordering 명시 X 면 매 비결정적.
|
||||
- **Aspect explosion**: 매 100+ aspect → 매 control flow 추적 불가.
|
||||
|
||||
## 🧪 검증 / 중복
|
||||
- Verified (Spring Framework 6.x docs, AspectJ programming guide, NestJS docs).
|
||||
- 신뢰도 A.
|
||||
|
||||
## 🕓 Changelog
|
||||
| 날짜 | 변경 |
|
||||
|---|---|
|
||||
| 2026-05-08 | Phase 1 |
|
||||
| 2026-05-10 | Manual cleanup — AOP full content with Spring/NestJS/Python patterns |
|
||||
Reference in New Issue
Block a user