--- id: wiki-2026-0508-object-seam-객체-접점 title: Object Seam (객체 접점) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Object Seam, OO Seam, Polymorphic Seam] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [legacy-code, refactoring, testability, seams, oop] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: java framework: junit-mockito --- # Object Seam (객체 접점) ## 매 한 줄 > **"매 OO 언어에서 다른 코드 변경 없이 동작을 바꿀 수 있는 분기점 — 매 polymorphism이 enabling point."**. Michael Feathers의 *Working Effectively with Legacy Code* (2004) 에서 정의된 3개 seam (preprocessing, link, object) 중 가장 강력. 2026 현재 mock framework · DI container의 핵심 메커니즘. ## 매 핵심 ### 매 3 seam types - **Preprocessing seam**: C/C++ macro 치환 — enabling point는 build flag. - **Link seam**: linker가 symbol을 binding — enabling point는 link order. - **Object seam**: virtual dispatch — enabling point는 object instantiation. ### 매 Object Seam 작동 원리 - Polymorphic type (interface, abstract class, base class with virtual) - Caller가 abstract type 사용 - Subtype 선택은 외부 (constructor, factory, DI container) - 매 단순 if/else 분기 vs polymorphism 분기 ### 매 응용 1. Test에서 real DB → in-memory fake 교체. 2. HTTP client → mock으로 network 차단. 3. Strategy pattern으로 algorithm swap. ## 💻 패턴 ### Java — interface seam ```java public interface PaymentGateway { PaymentResult charge(Money amount, Card card); } public class CheckoutService { private final PaymentGateway gateway; // ← seam public CheckoutService(PaymentGateway g) { this.gateway = g; } public Order checkout(Cart cart, Card card) { var result = gateway.charge(cart.total(), card); return result.success() ? Order.confirmed(cart) : Order.failed(); } } // Test: enabling point = constructor arg @Test void rejects_failed_payment() { var fake = (amount, card) -> PaymentResult.failed("declined"); var svc = new CheckoutService(fake); assertEquals(OrderStatus.FAILED, svc.checkout(cart, card).status()); } ``` ### TypeScript — class hierarchy seam ```typescript abstract class Notifier { abstract send(msg: string): Promise; } class EmailNotifier extends Notifier { /* SMTP */ } class TestNotifier extends Notifier { sent: string[] = []; async send(msg: string) { this.sent.push(msg); } } // Production: new EmailNotifier() // Test: new TestNotifier() — same caller ``` ### C++ — virtual function seam ```cpp class Clock { public: virtual ~Clock() = default; virtual std::chrono::system_clock::time_point now() const = 0; }; class SystemClock : public Clock { auto now() const override { return std::chrono::system_clock::now(); } }; class FakeClock : public Clock { std::chrono::system_clock::time_point t_; public: void advance(std::chrono::seconds s) { t_ += s; } auto now() const override { return t_; } }; ``` ### Introducing seam to legacy code (Extract Interface) ```java // Before: hard dependency on concrete class public class Report { public void generate() { var db = new MySQLConnection(); // ← no seam // ... } } // After: introduced object seam public class Report { private final Database db; public Report(Database db) { this.db = db; } public void generate() { /* uses db */ } } public interface Database { ResultSet query(String sql); } public class MySQLConnection implements Database { /* ... */ } ``` ### Testing legacy code with subclass-and-override ```java public class LegacyService { public Report run() { var data = fetchData(); // ← protected, override in test return process(data); } protected Data fetchData() { /* real network */ } } // Test class TestableService extends LegacyService { @Override protected Data fetchData() { return Data.fixture(); } } ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | New code, OO language | Constructor injection + interface | | Legacy class, can't refactor much | Extract Interface + DI | | Sealed legacy class | Subclass and Override Method | | C/C++ no virtual overhead | Link seam (selective compilation) | | Functional language | Higher-order function = seam | **기본값**: interface + constructor injection — 매 가장 explicit · testable. ## 🔗 Graph - 부모: [[Seam (접점)]] · [[Seams (이음새)]] - 변형: [[Link Seam (링크 접점)]] · [[Preprocessing Seam (전처리 접점)]] - 응용: [[Dependency Injection (의존성 주입)]] · [[Mock Objects (가짜 객체)]] · [[Test Doubles (테스트 대역)]] - Adjacent: [[Polymorphism (다형성)]] · [[Hexagonal_Architecture_Ports_and_Adapters]] ## 🤖 LLM 활용 **언제**: legacy code testability 도입, mock framework 설계, plug-in architecture, strategy swap. **언제 X**: pure functional code (no objects), one-shot script, performance-critical hot loop (virtual call overhead). ## ❌ 안티패턴 - **Concrete class 직접 new**: 매 seam 없음 — Test 어려움. - **`static` method 의존**: 매 polymorphism 불가 — wrap with instance method. - **Final/sealed class without interface**: 매 subclass override seam도 막음. - **Service Locator** (anti): 매 hidden dependency — explicit constructor injection 권장. ## 🧪 검증 / 중복 - Verified (Feathers *WELC* 2004, Fowler *Refactoring* 2nd ed., Meszaros *xUnit Patterns* 2007). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — Object seam definition + 3 language patterns |