CommunityCoding & Developmentgithub.com

yutna/oo-design

Use when starting a new module, feature or system in an object-oriented codebase, sizing design, or unsure which object rule applies.

What is oo-design?

oo-design is a Claude Code agent skill that use when starting a new module, feature or system in an object-oriented codebase, sizing design, or unsure which object rule applies.

Works with✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/yutna/object-oriented-design-skills/tree/HEAD/plugins/core/skills/oo-design

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Object-Oriented Design

Overview

The pack is design rules for codebases written in an object-oriented style, not universal advice. A project's own written conventions win over the pack. Follow the idiom of the module being changed. This skill sizes the task and names the skill that fits.

Load the skill this index names before you answer: its rules and examples live there, not here.

How much design a task warrants

TaskUseSkip
An answer used once, then thrown awayNothingEverything
One method in a class that existsIts name and its contractRemodelling
A feature inside an existing flowThe idiom that flow usesNew boundaries
A new class or moduleThe design loopNothing
A new contextThe loop, then its boundariesNothing
A new system from nothingThe loop, contexts, then structureNothing

Before designing

Before designing, state the gate: one rule the software must follow, with one example it accepts and one it rejects. For example, "A slot can hold at most one appointment." It accepts booking a second patient into a different slot and rejects booking a second patient into the same slot. If you can write the rule down, start. If you cannot, what is missing is not design, and this pack cannot supply it.

The design loop

  1. Say what the software must do in the domain's words (speaking the domain language), and find the object that knows what each behaviour needs (assigning responsibilities).
  2. Find the consistency boundary: what must be true together in one transaction (designing aggregates).
  3. Decide where each rule lives: an entity, a value object, or a domain service (placing domain logic).
  4. Design the messages each object answers (encapsulating state and behaviour), and make illegal states impossible to construct (making illegal states impossible).
  5. Invert dependencies so the domain knows nothing of the database or the framework (inverting dependencies, layering the system).
  6. Name things in the domain's words, and comment only what the code cannot say (naming classes and methods, commenting what code cannot say).
  7. Check the result against the red flags below (reviewing object design).

How strictly a rule is meant

Every core rule in this pack carries one of three labels, and the label says how strictly it is meant.

  • Rule. Breaking it is a defect. No framework excuses it.
  • Default. Do this unless a stated condition holds. The condition is its own sentence, never a trailing clause.
  • Judgement. Two answers are defensible. The skill says what tips the balance.

Symptoms to skills

Symptoms point to the skill that treats them, and this table grows as skills land.

SymptomSkill
Which class should do this?Assigning responsibilities
This class does too muchAssigning responsibilities
A change ripples through many classesDiagnosing coupling
How tightly are these two parts tied?Diagnosing coupling
Is this an object or just data?Deciding object or data
Our domain model is anemicDeciding object or data
Other code decides for this objectEncapsulating state and behaviour
Setters let this object break its rulesEncapsulating state and behaviour
This object can exist half-builtConstructing valid objects
This constructor takes too many argumentsConstructing valid objects
Every new case means editing working codeEncapsulating what varies
How much flexibility should this have?Encapsulating what varies
Is this a value or an entity?Modeling values and entities
Raw strings and numbers carry domain rulesModeling values and entities
Should this extend that class or hold it?Choosing composition over inheritance
Changing a base class breaks its subclassesChoosing composition over inheritance
A subclass breaks what its parent promisesHonouring substitutability
Code checks which subtype it holdsHonouring substitutability
The same switch on a type keeps coming backReplacing conditionals with polymorphism
Subclasses or pattern matching?Replacing conditionals with polymorphism
Code reaches through a chain of objectsLimiting what an object knows
This class only forwards callsLimiting what an object knows
What should this class or method be called?Naming classes and methods
Names like Manager, Helper or UtilNaming classes and methods
Callers depend on interface methods they never useDesigning interfaces
Interface or abstract base class?Designing interfaces
Domain code depends on a database or frameworkInverting dependencies
Where are objects created and wired together?Inverting dependencies
Callers know how another class stores or formats dataHiding implementation
A class leaks its internal errors or stepsHiding implementation
Flags or optional fields allow impossible combinationsMaking illegal states impossible
A type admits values the domain never hasMaking illegal states impossible
The code's words differ from the staff'sSpeaking the domain language
One word means different things to two teamsSpeaking the domain language
Which objects must change together?Designing aggregates
Saves collide or one load pulls in too muchDesigning aggregates
Which status changes are allowed?Modeling lifecycles
A cancelled or closed object changes againModeling lifecycles
How should domain objects be stored and found?Designing repositories
The repository has a find method per screenDesigning repositories
Use cases repeat the same business checkPlacing domain logic
Domain service, entity method or application service?Placing domain logic
Other parts must react after a change is savedPublishing domain events
A message went out for a change that rolled backPublishing domain events
Where does one team's model end and another's begin?Bounding contexts
Which parts are core, and which can we buy?Bounding contexts
Which way should the layers depend?Layering the system
A screen or job cannot be tested without its frameworkLayering the system
Modules depend on each other in a cycleOrganising modules
Modular monolith or separate services?Organising modules
A change to our API breaks the apps that call itCrossing system boundaries
How should we version this API or message?Crossing system boundaries
The mapping tool shapes our domain classesTaming persistence
A list runs one query per rowTaming persistence
Screens need data shaped unlike the modelSeparating reads from writes
Read model, projection or event sourcing?Separating reads from writes
MVC, MVP or MVVM for this screen?Separating presentation from domain
A screen edits domain objects directlySeparating presentation from domain
Which design pattern fits this problem?Choosing a pattern
A pattern was added before its problemChoosing a pattern
These pattern classes could be a functionPatterns the language provides
Visitor, or a closed set with matching?Patterns the language provides
A method returns null when it finds nothingDesigning failure behaviour
Refusals come back as codes callers ignoreDesigning failure behaviour
Threads share an object and lose or mix its changesManaging shared state
A lock or a single owner for this state?Managing shared state
A call to another system hangs or fails midwayMaking work reliable
A retry did the work twiceMaking work reliable
We cannot explain an incident from our recordsDesigning what to record
What should we log, count or audit?Designing what to record
A review found a god class or lava flowRecognising antipatterns
Which antipattern should we fix first?Recognising antipatterns
Tests break although behaviour did not changeTesting object-oriented code
Mock, stub or fake for this collaborator?Testing object-oriented code
Tests depend on the time or random valuesDesigning for testability
Code is made public only so tests can reach itDesigning for testability
How do we restructure this code safely?Refactoring toward object design
A refactoring grew too big to finishRefactoring toward object design
We must change code that has no testsWorking with legacy code
Replace an old system piece by pieceWorking with legacy code
What should this review check?Reviewing object design
Which review findings block a merge?Reviewing object design
Nobody remembers why the code is shaped this wayDocumenting design decisions
What should we draw, and at what level?Documenting design decisions
Comments repeat the code or contradict itCommenting what code cannot say
Where do we explain why this code looks odd?Commenting what code cannot say
A framework hook or marker holds a business ruleWorking within a framework
How far should we go along with the framework?Working within a framework
A calculation also saves, sends or changes its inputsApplying functional techniques
Which functional techniques fit object code?Applying functional techniques

Language skills

A language skill keeps the core rules in one language and never replaces them. A base language skill is for code with no framework.

  • oo-java, from object-oriented-design-java: records, sealed types, equals and hashCode, checked exceptions, Optional, and classes closed to extension.
  • oo-kotlin, from object-oriented-design-kotlin: data classes, sealed types, nullable types, delegation with by, and extension functions.
  • oo-typescript, from object-oriented-design-typescript: branded identifiers, #private state, abstract classes, decorators, discriminated unions, and a composition root.
  • oo-javascript, from object-oriented-design-javascript: contract tests, #private state, frozen values, and classes rather than edited prototypes.
  • oo-csharp, from object-oriented-design-csharp: records whose copies keep their checks, structs, nullable reference types, default interface members, and async kept in the shell.
  • oo-python, from object-oriented-design-python: protocols and abstract base classes, frozen dataclasses, properties without setters, mixins and the method resolution order, and final.
  • oo-ruby, from object-oriented-design-ruby: contract tests, messages instead of class checks, readers without writers, values with Data, held objects instead of mixins, and methods defined where a reader finds them.
  • A language with no skill of its own reads the nearest shipped one: Scala and Groovy read oo-java, and PHP reads oo-python.

In Claude Code, install a language plugin beside the core one: /plugin install object-oriented-design-java@object-oriented-design-skills

Quick reference

Common design questions, each with the answer this pack gives and the rule it rests on.

QuestionAnswerSkillRule
How many reasons to change per class?One kind of change request.Assigning responsibilities7
Command/query?Writes, no return; reads, no change.Encapsulating state and behaviour4
Return its list?No; methods or a read-only view.Encapsulating state and behaviour5
How do I keep a value from changing?Make it immutable.Modeling values and entities2
Should this class allow extension?No, unless built for it.Honouring substitutability5
Should an aggregate hold another aggregate?No; hold its identity.Designing aggregates3
Where should input checks live?At the edge; domain decides.Placing domain logic5
How much should a module expose?A small public interface.Organising modules6
How do outside types reach the domain?Map at the boundary.Crossing system boundaries2
Where should repository interfaces go?In the domain, types only.Designing repositories2
How do I name a test?For the behaviour it checks.Testing object-oriented code3
When should preconditions be checked?Before any change.Designing failure behaviour4

Red flags

Places to look, not verdicts. A red flag becomes a finding only with evidence: a measurement, a reproducible bug, or a failing test.

  • A class named Manager, Helper or Util.
  • A method that asks another object for its data and then decides for it.
  • A constructor that leaves the object unusable until a setter runs.
  • One business rule whose change touches many classes.
  • A test that needs many mocks to check one decision.

Further reading

Related Skills