A class handles multiple variants of an external concern — different library versions, vendor APIs, transport protocols — branching internally with `if (version === 1)` or `if (vendor === 'X')`. Adding or upgrading a variant touches the host class even though the variant logic is fundamentally external.
Host class methods the agent must scan twice — once for the host logic, once for each variant branch — to determine what executes in a given environment. Library-version edits ripple to host class methods even when host behaviour is unchanged.
Each variant lives in its own Adapter class wrapping the external API. The host class holds a reference to one adapter and delegates; switching variants is a constructor argument, not an internal branch.
One adapter file per variant; the agent verifies each adapter independently against the external API. The host class becomes a thin delegator the agent reads once and trusts thereafter.
Before the refactoring
// One class branches on library version internally.class ChartGenerator {draw(data, libraryVersion) {if (libraryVersion === 1) {const ctx = OldChartLib.createContext();ctx.setData(data.map(d => ({ x: d.label, y: d.value })));ctx.setTitle(this.title);ctx.render();return ctx;}if (libraryVersion === 2) {const renderer = new NewChartLib.Renderer({ data, title: this.title });renderer.render();return renderer;}throw new Error(`unsupported version ${libraryVersion}`);}}
After the refactoring
// One adapter per version; ChartGenerator no longer knows the library.class ChartGenerator {constructor(chartAdapter) {this.chartAdapter = chartAdapter;}draw(data) {return this.chartAdapter.draw(data, this.title);}}class V1ChartAdapter {draw(data, title) {const ctx = OldChartLib.createContext();ctx.setData(data.map(d => ({ x: d.label, y: d.value })));ctx.setTitle(title);ctx.render();return ctx;}}class V2ChartAdapter {draw(data, title) {const renderer = new NewChartLib.Renderer({ data, title });renderer.render();return renderer;}}
Mixing variant-specific code with host logic produces Divergent Change — the class changes for unrelated reasons (host behaviour evolves; library upgrades). Test setup must mock the external library, which couples host tests to the library's surface area.
Mixed variant + host code consumes context budget on every host-class edit. The agent must hold all variant branches in working memory to verify that a host change doesn't break a variant code path; cross-variant invariants are easy to miss.
Each adapter is one more file; the host class gives up direct knowledge of the external API and must define a clean wrapping interface. Mapping a host concept to an adapter API forces design choices that don't pay until the second adapter exists.
Adapter extraction multiplies file count and may obscure the agent's static call-graph view of how data flows from host through to external API. Mocking adapters in host tests requires duplicating the adapter interface in the test setup.
Adapters can be swapped per environment, tested in isolation against the real external API, and replaced when the external library is replaced. The host class stops paying the variant-knowledge tax on every read.
Host class tests load the adapter's interface instead of the external library; adapter tests load the vendor surface in isolation; a library upgrade touches the one adapter file rather than every host call site.
Extracting an adapter for a single, stable external system buys nothing — the wrapper is just one more layer the reader hops through. The pattern pays when there are multiple variants or when the external API is unstable enough that wrapping it earns testability.
An adapter for a single, stable variant is dead weight — one extra file the agent must learn before reading the host. The pattern pays only when adapter count > 1 or when adapter-level test isolation buys verifiability the host couldn't achieve alone.