agentleFS
JordanCoinJordanCoin/codingskills/skills/law-of-demeter/SKILL.md

law-of-demeter

Skill10 starsChanged 9 months agoMITView on GitHub

When reviewing code for excessive coupling and deep object chains. Use when the user says "too coupled," "train wreck," "chained calls," "feature envy," "mocking is painful," or "this reaches too deep." For broader structural coupling, see solid.

The file

We split this skill into the rules it gives an agent

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

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If .agents/stack-context.md exists, read it first.

    line 12
  2. Very specific:

    Every chain of access (order.customer.address.city) is a chain of coupling.

    line 22
  3. Very specific:

    Don't chain through objects: If you need data from deep inside a structure, ask the immediate owner to provide it.

    line 30
  4. Distinctive:

    Tell, don't ask: Instead of reaching into an object to get data and make a decision, tell the object what you need done.

    line 31
  5. Distinctive:

    Flatten data for consumers: When passing data across boundaries (to templates, to frontends, to other services), flatten the nested …

    line 33
  6. Very specific:

    Deep mocking in tests: If you need to mock order.customer.address just to test order processing, the code is reaching too deep

    line 41
  7. Distinctive:

    LoD does not mean wrap everything: Don't create a wrapper method for every single access pattern.

    line 71
  8. Distinctive:

    kiss: When wrapping becomes more complex than the chain

    line 87

≈ “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

LoD — Law of Demeter (Principle of Least Knowledge)

Before Applying

If .agents/stack-context.md exists, read it first. Apply this principle using idiomatic patterns for the detected stack. For framework-specific details, use context7 MCP or web search — don't guess.

Principle

A component should only talk to its immediate collaborators. Don't reach through an object to access its internals, its children's internals, or anything deeper.

More precisely: a method should only call methods on (1) itself, (2) its own fields, (3) its parameters, (4) objects it creates, and (5) global/singleton services.

Why This Matters in Production

Every chain of access (order.customer.address.city) is a chain of coupling. If any link in that chain changes — the customer model gets restructured, address becomes optional, city moves to a sub-object — every caller breaks.

LoD violations create fragile systems where a seemingly small refactor triggers cascading failures across unrelated code. They also make testing painful: to test a function that reaches through 4 layers, you must mock all 4 layers.

In production, LoD violations are a leading cause of NullPointerException and undefined is not an object errors. Each . in a chain is a potential null/undefined dereference point.

Rules

  1. Don't chain through objects. If you need data from deep inside a structure, ask the immediate owner to provide it. order.shipping_city() not order.customer.address.city.
  2. Tell, don't ask. Instead of reaching into an object to get data and make a decision, tell the object what you need done. Let it use its own internals.
  3. Wrap external APIs at the boundary. Third-party SDKs and API responses often expose deep structures. Create a thin wrapper that exposes only what your code needs, in the shape your code needs.
  4. Flatten data for consumers. When passing data across boundaries (to templates, to frontends, to other services), flatten the nested structure into a purpose-built shape rather than exposing your internal model.
  5. Limit parameter knowledge. A function that receives an object should only use the fields it directly needs. If it only needs the user's email, accept the email — not the entire user object.

Anti-Patterns

  • Train wrecks: app.config.database.connection.pool.max_size — any change to the config structure breaks this
  • Feature envy: A function that uses more data from another object than from its own — it probably belongs on that other object
  • Transparent wrappers: Objects that expose their internals via getters, making every consumer dependent on the internal structure
  • Deep mocking in tests: If you need to mock order.customer.address just to test order processing, the code is reaching too deep

Examples

-- LoD violation: reaching through the chain
def get_shipping_label(order):
    name = order.customer.name
    street = order.customer.address.street
    city = order.customer.address.city
    zip = order.customer.address.zip_code
    return format_label(name, street, city, zip)

-- LoD-compliant: ask the order for what you need
def get_shipping_label(order):
    info = order.shipping_info()  # order knows how to assemble this
    return format_label(info)
-- LoD violation: reaching into config internals
timeout = app.config.services.payment.timeout_ms

-- LoD-compliant: config provides what you need
timeout = config.payment_timeout()

Boundaries

  • LoD does not apply to pure data structures. Accessing fields of a DTO, dictionary, or value object is fine — these exist specifically to carry data. LoD applies to objects with behavior.
  • LoD does not mean wrap everything. Don't create a wrapper method for every single access pattern. Apply it at meaningful boundaries where the internal structure is likely to change.
  • Fluent/builder APIs are an exception. Chaining like query.select("name").where(active=true).limit(10) is not a LoD violation because each method returns self — you're talking to the same object.
  • Tension with KISS: Sometimes a direct chain is clearer than an intermediary method. Apply LoD where the coupling risk is real (across module boundaries, through unstable structures), not within tightly-coupled internals.

Code Review Checklist

  • Are there chains of 3+ property/method accesses reaching through object boundaries?
  • Does any function access more internals of another object than its own? (Feature envy)
  • Are external API responses wrapped at the boundary rather than leaked into business logic?
  • Can the internal structure of passed objects change without breaking this code?
  • Are tests forced to build deep object graphs just to exercise simple logic?

Related Skills

  • solid: For dependency inversion and interface segregation (structural decoupling)
  • separation-of-concerns: For keeping layers independent
  • kiss: When wrapping becomes more complex than the chain

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.