agentleFS
vadimvitvickiyvadimvitvickiy/vv-agent-kit/skills/injecting-dependencies/SKILL.md

injecting-dependencies

Skill0 starsChanged 51 days agoMITView on GitHub

Use when writing a constructor or initialiser, when a type needs a collaborator to do its work, or when adding a parameter so something can be swapped in a test.

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    When a test needs to see something a type builds internally, move the construction to the call site.

    line 33
  2. Distinctive:

    When two collaborators must share the identical object — a cache for a reader and a writer, a session for two clients — bind it to a local …

    line 40
  3. Distinctive:

    Every dependency in the signature is one a reader sees, a test replaces and a change traces.

    line 54

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Injecting dependencies

A complex collaborator is a required parameter. Services, engines, controllers, coordinators, repositories, clients — whoever configures the object supplies them, not the object itself.

  • Defaults are for simple leaves: a scheduler, a clock, a timer source, a formatter — no dependencies of their own, and the default is the answer rather than a guess.

The sentinel default is the anti-pattern

init(engine: Engine? = nil) {
    self.engine = engine ?? Engine(...)     // ← this
}

nil here means "construct it yourself" — the one thing the parameter existed to prevent.

  • The dependency is invisible. Nothing at the call site says this type needs an Engine.
  • Two construction paths. Production takes one, tests the other, so the shipped path is the least exercised.
  • The default outlives its reason, and nothing fails when it stops being right.
  • The constraint is the signal. A default that would need another parameter's value to build is the language saying the object cannot construct this itself. Pass it in.

Move construction, do not add an escape hatch

  • When a test needs to see something a type builds internally, move the construction to the call site. Do not add a parameter only tests use — the test then verifies the path nobody ships.
  • Move the new/init to whoever already decides how the object is configured; test and production become one path.

Two parameters that must be one instance

When two collaborators must share the identical object — a cache for a reader and a writer, a session for two clients — bind it to a local at the call site and pass it to both:

let session = Session(...)
let reader = Reader(session: session)
let writer = Writer(session: session)

The sharing is visible where it is established. Constructing twice, or documenting the requirement in a comment, leaves it for a refactor to break silently.

What this buys

  • Every dependency in the signature is one a reader sees, a test replaces and a change traces.
  • Wiring moves out to a composition point — where that knowledge belongs.
  • A parameter list that feels too long is information: the type has too many responsibilities. Defaults hide the evidence, not the responsibilities.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.