숏컷 코드
text
이벤트 이름
-> 무슨 일이 끝났는지 말해야 함
payload
-> 수신자가 실제로 필요한 만큼만
generic event 하나
-> 결국 분기와 캐스팅 증가문법과 예시
event contract는 "누가 무엇을 알면 되는가"로 좁게 잡는 편이 낫다
이벤트는 발행자 내부 상태를 다 노출하는 통로가 아니라, 구독자가 필요한 사실만 전달하는 계약입니다. 그래서 이름은 "무슨 일이 일어났는가"를 분명히 말하고, payload는 그 사실을 처리하는 데 필요한 최소 정보만 담는 편이 안정적입니다.
text
좋은 예
- QuestCompleted { questId, rewardIds }
- InventoryChanged { itemId, delta, reason }
나쁜 예
- GameEvent { type, object, data1, data2, data3 }broad event보다 narrow event contract가 추적과 리팩터링에 유리하다
generic bus 하나에 type과 임의 payload를 얹으면 처음엔 유연해 보입니다.
하지만 시간이 지나면 구독자마다 분기와 캐스팅이 늘고, 어떤 필드가 실제 계약인지 알기 어려워집니다.
가장 흔한 실패는 미래 확장을 걱정해 payload를 과도하게 크게 만드는 것이다
아직 쓰이지 않는 sender, context, snapshot, raw model을 전부 payload에 담아두면 수신자가 발행자 내부 구조에 묶입니다. 이벤트 계약은 넓게 열기보다 필요한 경우에 새 계약을 추가하는 쪽이 보통 더 안전합니다.
event contract를 고를 때 핵심
| 상황 | 더 자연스러운 선택 |
|---|---|
| 한 사건을 여러 수신자가 독립적으로 처리할 때 | 명시적 event contract |
| 수신자가 실제로 필요한 정보가 명확할 때 | narrow payload |
| 분기와 캐스팅이 늘어나기 시작할 때 | broad event 분해 |
| 발행자 내부 모델이 자주 바뀔 때 | raw model 대신 안정적 DTO |
| 모든 사건을 하나의 bus 타입으로만 보내고 있을 때 | contract 재설계 |
특이 케이스와 주의할 점
흔한 실패는 "일단 범용으로 만들어 두자"며 generic event 하나에 모든 사건을 태우는 것입니다. 이 방식은 확장보다 결합을 더 빨리 늘립니다.
text
실패 예시
- AppEvent { type, sender, payload, metadata, context, rawObject }
- 구독자마다 type switch와 cast 반복
결과
- 계약이 아니라 약속 없는 메시지 전달로 변함
- 추적과 리팩터링 비용 증가