"매 type-tagged switch 의 polymorphism 의 missed opportunity". 매 classic code smell 의 — 매 type 의 switch 의 새 type 의 추가 시 매 모든 switch 의 update 의 필요. 2026 의 modern lang 의 sealed types + pattern matching 의 acceptable.
매 핵심
매 왜 smell 인가
OCP 위반: 매 새 type 의 추가 의 매 switch 의 modify 의 필요.
Shotgun surgery: 매 동일 switch 의 codebase 의 scatter.
Type safety hole: 매 default 의 fallthrough — 매 unhandled case 의 silent.
doublearea(Shapes){returnswitch(s){caseCirclec->Math.PI*c.r()*c.r();caseSquaresq->sq.side()*sq.side();caseTrianglet->0.5*t.base()*t.h();// no default — compiler proves exhaustive};}
Kotlin — sealed when
sealedclassEventdataclassClick(valx:Int,valy:Int):Event()dataclassKey(valcode:Int):Event()objectClose:Event()funhandle(e:Event)=when(e){isClick->"click at ${e.x},${e.y}"isKey->"key ${e.code}"Close->"bye"}// exhaustive — no else needed
Rust — match
enumMsg{Quit,Move{x: i32,y: i32},Write(String)}fnprocess(m: Msg){matchm{Msg::Quit=>println!("quit"),Msg::Move{x,y}=>println!("move to {x},{y}"),Msg::Write(s)=>println!("write {s}"),}}
Replace with map (data dispatch)
// BAD
functionfmt(t: string,v: number):string{switch(t){case"usd":return`$${v}`;case"eur":return`€${v}`;case"krw":return`₩${v}`;}}// GOOD
constPREFIX: Record<string,string>={usd:"$",eur:"€",krw:"₩"};constfmt=(t: string,v: number)=>`${PREFIX[t]??""}${v}`;
Replace with strategy
classDiscount(Protocol):defapply(self,price:float)->float:...classPct(Discount):def__init__(self,p):self.p=pdefapply(self,price):returnprice*(1-self.p)classFixed(Discount):def__init__(self,amt):self.amt=amtdefapply(self,price):returnmax(0,price-self.amt)# caller injects Discount, no switch
매 결정 기준
상황
Approach
Type dispatch (open set)
Polymorphism
Type dispatch (closed set)
Sealed + pattern match
Data lookup
Map / dict
Complex behavior swap
Strategy pattern
AST / state machine
Switch (legitimate)
기본값: 매 sealed types + exhaustive pattern matching — 매 modern lang 의 ergonomic + safe.