Software Design Reference System Designer · Designing Systems That Scale

Lesson 0026 · System Designer · Module 3

Libraries and Packages vs Building It Yourself

Every dependency you skip is code you maintain forever. Every dependency you take is a contract you must follow. This lesson gives you the decision procedure.

Mission tie-in: "understand when to use libraries/packages vs building solutions yourself" — the last System Designer skill, and the bridge to Phase III's first trade-off, Build vs Buy.

Knowledge: three questions decide

Ask three questions about the problem you're about to solve:

  1. Is it generic or is it yours? Serialization, auth, date math, HTTP — generic problems with mature solutions. Pricing logic, fraud rules, workflow semantics — your domain. Generic → library. Yours → build.
  2. Is the library boring? Mature, widely used, slowly changing (Dan McKinley's "choose boring technology"). A library three days old, or a fashionable rewrite every quarter, is a dependency you'll maintain at its pace, not yours.
  3. Can you wrap it? Any dependency worth taking is worth hiding behind a port (lessons 0009, 0023) so its churn never reaches your domain.
# take: JSON Schema validation? mature, generic, boring — take it
import jsonschema
jsonschema.validate(payload, schema)

# hide: the schema library's version churn stays inside the adapter
class PayloadValidator:
    def validate(self, payload: dict) -> None:
        try:
            jsonschema.validate(payload, self._schema)
        except jsonschema.ValidationError as e:
            raise InvalidPayload(str(e))

The cost of building: you own every bug, every missing edge case, every security review forever. The cost of taking: an external contract, upgrade cadence, and supply-chain surface. The tie-breaker is always the same — is this problem your business's differentiator? If yes, build (and own it deliberately). If no, take (and wrap it).

The AI special case: AI will happily "write a small library" for you instead of taking one — the generated code then becomes your hand-maintained dependency with zero of the library's maturity. Prefer the real library; use AI on your domain.
Field notes · take, build, or neither
The thing you needVerdictBecause
JWT signing, password hashingtakeA subtle bug here is a breach, not a defect.
date, timezone and currency arithmetictakeThe edge cases are a decade of other people’s bugs.
your pricing or matching rulesbuildIt is the product; a library makes you a reseller.
an AI’s 60-line retry helpertake the librarytenacity is battle-tested; the copy is not.
a wrapper over one library callneitherIt adds a name and contains nothing.

Skill: take, build, or wrap?

JWT authentication for your API is:

Your pricing engine is your business's edge. The right call is:

Every external library you take should be:

Practice on your own code

List the last three "small utilities" you (or an AI) hand-wrote. Run the three questions on each: generic or yours? boring available? wrapable? Replace at least one hand-rolled utility with the mature library — and wrap it.

Reveal: a hand-rolled utility audit

An AI-generated "retry helper" with 60 lines of exponential backoff — hand-maintained, untested. The audit: generic (yes), boring (tenacity is battle-tested), wrapable (yes). Replaced with the library behind a RetryPolicy port; the AI's version went to the graveyard with its bugs.

Your win

You can run the three-question procedure on any build-vs-take decision, and you know the wrap rule that contains whatever you take. Phase II complete — on to Master Designer.

Read and watch deeper

Bring your hand-rolled utilities to your agent-teacher and run the three questions on each.