Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Dependency

Concept

A foundational idea to recognize and understand.

Context

No component exists in a vacuum. To do its work, it relies on other pieces: libraries, services, frameworks, data sources, or tools. A dependency is anything a component needs to function. The concept operates at the architectural scale and is central to understanding both the structure and the fragility of a system.

Dependencies come in many forms: a Python package imported from PyPI, a database a service connects to, an API a frontend calls, or a tool an AI agent is given access to. Some dependencies are chosen; others are inherited.

Problem

How do you rely on things you don’t control without becoming hostage to them?

Forces

  • Using existing libraries and services saves enormous effort. No one should rewrite a JSON parser.
  • Every dependency is a bet that the depended-upon thing will continue to work, be maintained, and remain compatible.
  • Transitive dependencies (dependencies of your dependencies) multiply risk invisibly.
  • Removing or replacing a dependency after the fact can be expensive, especially if your code is tightly coupled to it.

Solution

Treat dependencies as conscious decisions, not accidents. For each dependency, ask: what does this give us? What does it cost? What happens if it disappears or changes?

Practical strategies for managing dependencies:

  • Minimize. Don’t depend on things you don’t need. A dependency that saves ten lines of code but adds a maintenance burden isn’t worth it.
  • Isolate. Wrap external dependencies behind your own interfaces. If you access a database through a Repository interface, swapping databases is a local change.
  • Pin. Specify exact versions so that updates are deliberate, not surprises.
  • Audit. Periodically review your dependency tree for abandoned, vulnerable, or bloated packages.

In agentic workflows, the tools you give an AI agent are its dependencies. If an agent depends on a deploy tool that silently changes its behavior, the agent’s workflow breaks, just as a library upgrade with breaking changes breaks your build. Treat agent tool definitions with the same care you give code dependencies.

How It Plays Out

A Node.js project installs a popular date library. A year later, the library is abandoned and a security vulnerability is discovered. Because the team imported the library directly in dozens of files, replacing it touches the entire codebase. A team that had wrapped it behind a DateService interface would only need to change the wrapper.

An AI agent relies on a search_code tool to work with a repository. When the tool’s output format changes (line numbers are no longer included), the agent’s parsing logic breaks. The developer who maintains the agent’s configuration updates the tool description and adjusts the prompt, treating the tool dependency the same way they’d treat a library upgrade.

Note

The node_modules folder — or its equivalent in any ecosystem — is a dependency graph made visible. Glancing at its size can be a useful gut check: if your project has 400 transitive dependencies, you are standing on a tower of other people’s decisions.

Example Prompt

“We use the moment library in dozens of files. Wrap it behind a DateService interface so that if we need to replace it later, we only change the wrapper.”

Consequences

Well-managed dependencies let you benefit from the broader ecosystem without being trapped by it. Isolation through interfaces makes dependencies swappable. Version pinning makes updates predictable.

The cost is vigilance. Dependencies require ongoing maintenance: updates, security patches, compatibility checks. Ignoring them creates a growing liability. But obsessing over “zero dependencies” leads to reinventing well-solved problems. The balance is having the dependencies you need, wrapped behind stable interfaces, with a clear plan for maintaining them.

  • Is a form of: Coupling — every dependency couples you to the thing you depend on.
  • Managed via: Interface, Abstraction — wrapping dependencies behind interfaces reduces direct coupling.
  • Crosses: Boundary — dependencies reach across boundaries.
  • Relevant to: Composition — composing systems from parts means managing dependencies between those parts.