Skip to main content
Clean Code 60 XP · 6 min

System Boundaries

Third-party code belongs at the edge — wrap it so it never pollutes your business logic.

Showing
Ad (728×90)

The Clean Boundary

When you use a third-party API (a Map, a logging library, an HTTP client) directly throughout your codebase, every change to that API affects your entire system. Instead, wrap it in a class you control. The wrapper speaks your language, and you can replace the underlying library in one place.

Raw dict leaking everywhere

sensors = {}
sensors["t1"] = new Sensor("t1")
temp = sensors["t1"].read()
sensors.clear()   // intentional?
remove sensors["t1"]  // scattered 40+ files

Wrap it — you control the interface

class SensorRegistry:
    sensors = {}

    function register(sensor):
        sensors[sensor.id] = sensor

    function reading(sensorId):
        return sensors[sensorId].read()

    function remove(sensorId):
        remove sensors[sensorId]

Learning Tests

When adopting a third-party library, write focused tests that explore its behavior — not to test the library (it has its own tests), but to document your understanding of it. These tests become a safety net: if the library upgrades with a breaking change, your learning tests fail first, before your production code breaks.

// Learning tests for a fictional cache library
function test_cache_returns_null_for_missing_key():
    cache = new Cache(maxSize: 10)
    assert cache.get("missing") == null

function test_cache_evicts_oldest_when_full():
    cache = new Cache(maxSize: 2)
    cache.set("a", 1)
    cache.set("b", 2)
    cache.set("c", 3)    // "a" should be evicted
    assert cache.get("a") == null
    assert cache.get("c") == 3

function test_cache_ttl_expires_entries():
    cache = new Cache(maxSize: 10, ttlSeconds: 1)
    cache.set("key", "value")
    wait(1.1 seconds)
    assert cache.get("key") == null

Using What Doesn't Exist Yet

Sometimes you need to integrate with a component that hasn't been built yet. Define the interface you wish you had, write your code against it, then build an adapter when the real thing arrives. This lets both teams work in parallel and keeps your code clean regardless of the external API's design.

// ✓ Step 1: Define the interface you wish existed
interface Transmitter:
    function transmit(frequency, stream): void

// ✓ Step 2: Build against your ideal interface
class CommunicationController:
    transmitter = null

    function send(data):
        transmitter.transmit(COMM_FREQUENCY, data)

// ✓ Step 3: When the real API ships, write one adapter
class RealTransmitterAdapter implements Transmitter:
    realApi = null

    function transmit(frequency, stream):
        realApi.sendOnFreq(frequency, stream.toBytes())

Code Challenge

Wrap the Third-Party Map — the raw Map is spreading everywhere. Wrap it with intent-revealing method names.

Key takeaway

You don't own third-party code. Wrap it at the boundary — your domain speaks your language, not theirs.

Done with this lesson?

Mark it complete to earn XP and track your progress.