d8a80f6272
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해 끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은 과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업. 도구: Datacollect/scripts/link_reconcile_apply.mjs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.2 KiB
7.2 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-aspect-oriented-programming-aop | Aspect Oriented Programming (AOP) | 10_Wiki/Topics | verified | self |
|
none | A | 0.9 | applied |
|
2026-05-10 | pending |
|
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
매 응용
- Spring
@Transactional— DB transaction 자동 commit/rollback. - NestJS
@UseInterceptors— request/response transform. - Python
@functools.lru_cache— pure caching aspect. - OpenTelemetry auto-instrumentation — runtime byte-code weaving.
💻 패턴
Spring AOP — @Around aspect
@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
@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)
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
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
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
@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
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) · 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 |