agentleFS
kayamankayaman/skills/object-oriented-programming/SKILL.md

object-oriented-programming

Skill3 starsChanged 8 months agoCC0-1.0View on GitHub

Enforces object-oriented programming principles including encapsulation, composition over inheritance, GRASP patterns, message passing, and CRC-driven design. Use when designing class hierarchies, assigning responsibilities to objects, evaluating cohesion and coupling, refactoring toward better OO design, or reviewing code for OOP anti-patterns like God Objects and Anemic Domain Models.

2 other projects use a version of this.

Adopted by

Most recently taken up by

The file

Show its rules and text

We split this skill into the rules it gives an agent

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

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈18

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    MUST design public interfaces (messages) before internal implementation

    line 27
  2. Distinctive:

    MUST treat objects as black boxes — interact only through their public protocol

    line 28
  3. Distinctive:

    SHOULD ask "what message should I send?" before "what data do I need?"

    line 29
  4. Distinctive:

    When deciding which object should handle a responsibility, apply these patterns in order of priority (Larman):

    line 44
  5. Distinctive:

    MUST apply Information Expert as the default responsibility assignment strategy

    line 58
  6. Distinctive:

    MUST use Polymorphism instead of type-checking conditionals

    line 59
  7. Distinctive:

    SHOULD evaluate Low Coupling and High Cohesion when choosing between alternative designs

    line 60
  8. Distinctive:

    SHOULD introduce Pure Fabrication only when Expert creates cohesion problems

    line 61
  9. Distinctive:

    MUST NOT introduce content coupling — never reach into another object's internals

    line 114
  10. Distinctive:

    MUST NOT use global mutable state as a communication channel between objects

    line 115
  11. Distinctive:

    SHOULD prefer data coupling — pass only the specific values needed

    line 116
  12. Distinctive:

    SHOULD eliminate control coupling by replacing flag parameters with polymorphism

    line 117
  13. Very specific:

    MUST NOT chain through intermediaries: a.getB().getC().doSomething()

    line 138
  14. Very specific:

    MUST send messages only to: self, parameters, instance variables, objects you create, or direct collaborators

    line 139
  15. Distinctive:

    If you need to reach deep, the intermediate object is missing a responsibility

    line 140
  16. Distinctive:

    Use when discovering object roles in design sessions.

    line 144
  17. Distinctive:

    SHOULD prefer immutable value objects over mutable entities where possible

    line 171
  18. Very specific:

    SHOULD use traits/mixins/protocols for behavior sharing instead of inheritance

    line 172
  19. Distinctive:

    SHOULD use higher-order functions (lambdas, closures) where Strategy or Command patterns add unnecessary ceremony

    line 173
  20. Distinctive:

    SHOULD consider the Actor Model (Erlang, Akka, Swift concurrency) for concurrent message-passing systems

    line 174
  21. Distinctive:

    Before finalizing an object-oriented design, verify:

    line 180

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

Object-Oriented Programming

Reference: Practical Object-Oriented Design (Metz), Object Thinking (West), Applying UML and Patterns (Larman)

When to Apply

  • Designing new classes or assigning responsibilities to existing ones
  • Evaluating whether inheritance or composition is appropriate
  • Reviewing code for cohesion, coupling, or responsibility assignment
  • Refactoring God Objects, Anemic Domain Models, or deep hierarchies
  • Deciding between Tell Don't Ask and query-based approaches
  • Modeling a problem domain with objects, roles, and collaborations

Core Design Principles

Message-Passing First

Objects are autonomous agents communicating via messages. Design starts with what messages are sent, not what data is stored. Alan Kay's definition: "OOP means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things."

  • MUST design public interfaces (messages) before internal implementation
  • MUST treat objects as black boxes — interact only through their public protocol
  • SHOULD ask "what message should I send?" before "what data do I need?"

The Four Pillars — Applied

PillarDesign RuleViolation Signal
AbstractionHide complexity behind intention-revealing interfacesCallers need to understand implementation to use the object
EncapsulationBundle data and behavior; restrict direct access to statePublic getters/setters exposing internal structure
InheritanceUse ONLY for stable "is-a" where Liskov Substitution holdsSubclass overrides methods to do nothing, or breaks parent contracts
PolymorphismVary behavior through interchangeable objects sharing an interfaceif/else or switch chains checking object type

Responsibility Assignment — GRASP Patterns

When deciding which object should handle a responsibility, apply these patterns in order of priority (Larman):

PatternRuleApply When
Information ExpertAssign to the class that has the data neededDefault starting point for any responsibility
CreatorAssign creation to the class that aggregates, contains, or closely uses the targetDeciding where to put new/factory calls
Low CouplingAmong alternatives, choose the design that reduces dependenciesComparing two valid designs
High CohesionKeep classes focused on a single purposeA class is growing responsibilities beyond its core concern
ControllerA non-UI object receives and coordinates system eventsHandling user actions or external triggers
PolymorphismUse polymorphic dispatch instead of conditionals on typeif/switch testing object type to decide behavior
Pure FabricationCreate a non-domain service class when Expert leads to poor cohesionExpert assignment would bloat a domain object
IndirectionIntroduce a mediating object to decouple two othersTwo objects are too tightly coupled but need to collaborate
Protected VariationsWrap predicted variation points behind stable interfacesA known requirement may change in the future
  • MUST apply Information Expert as the default responsibility assignment strategy
  • MUST use Polymorphism instead of type-checking conditionals
  • SHOULD evaluate Low Coupling and High Cohesion when choosing between alternative designs
  • SHOULD introduce Pure Fabrication only when Expert creates cohesion problems

Composition vs Inheritance

Default to composition. Use inheritance only when ALL of these hold:

  1. The relationship is genuinely, permanently "is-a" (not "has-a" or "behaves-like-a")
  2. The subclass is a true specialization — it uses everything from the parent
  3. Liskov Substitution holds: substituting the subclass for the parent breaks nothing
  4. The hierarchy is shallow (SHOULD NOT exceed 2–3 levels)

Composition advantages:

  • Black-box reuse — no exposure of internal implementation
  • Runtime flexibility — swap collaborators without changing class structure
  • Avoids the fragile base class problem — base changes don't silently break subclasses
TechniqueUse ForExample
DelegationForwarding behavior to a collaboratorclass Order { private pricing: PricingPolicy }
Traits / MixinsSharing behavior across unrelated types without inheritanceRust traits, Kotlin interfaces with default methods, PHP traits
Strategy / PolicyVarying one algorithm dimensionInterchangeable ShippingCalculator implementations
DecoratorAdding behavior dynamicallyWrapping a Logger around a Repository

Cohesion and Coupling

Cohesion (aim for the top)

TypeQualityDescription
FunctionalBestAll elements serve a single, well-defined task
SequentialGoodOutput of one element feeds the next
CommunicationalAcceptableElements operate on the same data
ProceduralWeakElements follow a sequence but share no data
TemporalWeakElements run at the same time (e.g., initialization)
LogicalPoorElements are grouped by category, not purpose
CoincidentalWorstRandom grouping — utility grab-bags

Coupling (aim for the bottom)

TypeQualityDescription
ContentWorstOne module modifies another's internals directly
CommonPoorModules share global mutable state
ExternalWeakModules depend on the same external format or protocol
ControlWeakOne module passes a flag controlling another's behavior
StampAcceptableModules share a composite data structure but use different parts
DataBestModules exchange only the parameters they need
  • MUST NOT introduce content coupling — never reach into another object's internals
  • MUST NOT use global mutable state as a communication channel between objects
  • SHOULD prefer data coupling — pass only the specific values needed
  • SHOULD eliminate control coupling by replacing flag parameters with polymorphism

Object Thinking — Tell, Don't Ask

Design objects as autonomous virtual persons (West). Command them to act rather than querying their state and deciding externally.

Tell, Don't Ask:

# BAD — Ask: querying state, deciding externally
if order.status == "paid" and order.items_in_stock():
    warehouse.ship(order)

# GOOD — Tell: the object decides internally
order.fulfill()  # Order knows its own rules

Law of Demeter — only talk to immediate collaborators:

  • MUST NOT chain through intermediaries: a.getB().getC().doSomething()
  • MUST send messages only to: self, parameters, instance variables, objects you create, or direct collaborators
  • If you need to reach deep, the intermediate object is missing a responsibility

CRC Cards (Class-Responsibility-Collaboration):

Use when discovering object roles in design sessions. Each card lists:

  • Class name — a noun representing a domain concept
  • Responsibilities — what the object knows and does (verbs)
  • Collaborators — other objects it needs to fulfill responsibilities

Walk through use cases, role-playing objects. Missing responsibilities reveal missing objects.


Anti-Patterns and Remedies

Anti-PatternSignalRemedy
God ObjectOne class knows and does too much; most other classes are data holdersExtract responsibilities using Information Expert; apply SRP
Anemic Domain ModelObjects are data bags with getters/setters; all logic in service classesMove behavior into domain objects — Tell, Don't Ask
Deep Hierarchy4+ inheritance levels; changes at the top cascade unpredictablyFlatten to max 2–3 levels; replace inheritance with composition
Getter/Setter ProliferationEvery field has public get/set; encapsulation is brokenRemove getters; ask the object to perform the operation instead
Primitive ObsessionUsing raw strings, ints for domain concepts (email, money, ID)Introduce Value Objects: EmailAddress, Money, OrderId
Feature EnvyA method uses more data from another class than its ownMove the method to the class whose data it uses
Refused BequestSubclass overrides inherited methods to do nothing or throwReplace inheritance with composition; the relationship isn't "is-a"

Modern OO — Multi-Paradigm Pragmatism

Pure OO dogma has given way to blending OO encapsulation with FP immutability and higher-order functions. Apply these guidelines:

  • SHOULD prefer immutable value objects over mutable entities where possible
  • SHOULD use traits/mixins/protocols for behavior sharing instead of inheritance
  • SHOULD use higher-order functions (lambdas, closures) where Strategy or Command patterns add unnecessary ceremony
  • SHOULD consider the Actor Model (Erlang, Akka, Swift concurrency) for concurrent message-passing systems

Checklist

Before finalizing an object-oriented design, verify:

  • Responsibilities are assigned using Information Expert as the default
  • Public interfaces are defined before internal implementation
  • Inheritance is used only for stable, shallow "is-a" with Liskov Substitution
  • Composition is used for "has-a", "behaves-like-a", and cross-cutting behavior
  • No God Objects — every class has a single, focused purpose
  • No Anemic Domain Models — objects contain behavior, not just data
  • Law of Demeter is respected — no method chain trains
  • No type-checking conditionals — polymorphism handles variation
  • Value Objects replace primitive types for domain concepts
  • Coupling is at the data or stamp level, never content or common

Key References

BookAuthor(s)PublisherYear
Practical Object-Oriented Design (2nd ed.)Sandi MetzAddison-Wesley2018
Head First Object-Oriented Analysis and DesignMcLaughlin, Pollice, WestO'Reilly2006
Growing Object-Oriented Software, Guided by TestsFreeman & PryceAddison-Wesley2009
Design Patterns: Elements of Reusable OO SoftwareGamma, Helm, Johnson, VlissidesAddison-Wesley1994
Object ThinkingDavid WestMicrosoft Press2004
Elegant Objects Vol 1 & 2Yegor BugayenkoSelf-published2016–2017
Applying UML and Patterns (3rd ed.)Craig LarmanPrentice Hall2004
Object-Oriented Software ConstructionBertrand MeyerPrentice Hall1997
Balancing Coupling in Software DesignVlad KhononovAddison-Wesley2024
A Philosophy of Software Design (2nd ed.)John OusterhoutStanford2021

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.