opinionated-software-engineering/skills/object-oriented-programmer/SKILL.md
Object-oriented design principles, patterns, and practices. Use when working with object-oriented languages (Java, C#, C++, Python, Ruby, Swift, etc.) without language-specific skills available, or when applying OOP in multi-paradigm codebases.
npx skillsauth add pyroxin/opinionated-claude-skills object-oriented-programmerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill provides guidance on object-oriented programming principles, design patterns, and practices. Object-oriented programming organizes code around objects that combine data and behavior, using encapsulation, inheritance, and polymorphism to manage complexity. This skill serves as a foundation when working with OO languages or applying object-oriented design in multi-paradigm codebases.
Use this skill when:
Note: Language-specific skills (e.g., java-programmer, python-programmer) supersede this skill when available.
Object-oriented programming bundles data (state) with the operations (behavior) that act on that data. An object presents a clean interface while hiding implementation details. This encapsulation creates boundaries that limit coupling and enable local reasoning.
Quote to remember: "Bad programmers worry about the code. Good programmers worry about data structures and their relationships." — Linus Torvalds
Polymorphism allows treating different types uniformly through shared interfaces. This enables writing code against abstractions rather than concrete types, making systems more flexible and extensible.
Types of polymorphism:
Inheritance enables defining types in terms of other types, inheriting both interface and implementation. However, inheritance creates tight coupling between parent and child classes.
The inheritance trade-off: Inheritance is easy to add (create subclass) but hard to change (affects all subclasses). Composition is harder to add (requires more boilerplate) but easier to change (localized impact).
Modern wisdom: "Composition over inheritance" — prefer delegating to contained objects over inheriting from parent classes.
Encapsulation bundles related data and behavior while hiding internal implementation. Objects expose interfaces; internals are private.
Why encapsulation matters:
Encapsulation boundaries:
Abstraction focuses on essential characteristics while hiding incidental details. Interfaces and abstract classes define contracts without specifying implementation.
Why abstraction matters:
Abstraction levels:
Polymorphism allows uniform treatment of different types. Write code once that works with many implementations.
Why polymorphism matters:
Polymorphism trade-off: Indirection obscures flow. Reading polymorphic code requires knowing what implementations exist and which is active. Balance flexibility against clarity.
<solid_principles>
SOLID provides guidelines for object-oriented design. These are heuristics, not laws—apply them where they improve code, not dogmatically.
<single_responsibility>
A class should have one reason to change. Each class should do one thing well.
Good indicators:
When to violate:
Common mistake: Confusing "single responsibility" with "one method." Classes can have multiple methods serving one coherent purpose. </single_responsibility>
<open_closed>
Open for extension, closed for modification. Add new behavior without changing existing code.
Implementation strategies:
When to violate:
Staff insight: OCP assumes future requirements. Don't add extension points for hypothetical needs. Wait until you need to extend, then refactor to enable it. </open_closed>
<liskov_substitution>
Subtypes must be substitutable for their base types.[^1] Derived classes should strengthen (not weaken) base class contracts.
What LSP means:
Common LSP violations:
When inheritance violates LSP, use composition instead.
[^1]: Barbara Liskov and Jeannette Wing. 1994. A behavioral notion of subtyping. ACM Transactions on Programming Languages and Systems 16, 6 (Nov. 1994), 1811–1841. https://doi.org/10.1145/197320.197383 </liskov_substitution>
<interface_segregation>
Clients shouldn't depend on interfaces they don't use. Many specific interfaces beat one general interface.
Why ISP matters:
When to violate:
Staff insight: ISP fights "fat interfaces." If clients only use subset of methods, split the interface. But don't create explosion of single-method interfaces either. </interface_segregation>
<dependency_inversion>
Depend on abstractions, not concretions. High-level modules shouldn't depend on low-level modules.
Implementation:
Why DIP matters:
When to violate:
The Gang of Four patterns are valuable but often overused. Apply patterns to solve real problems, not to demonstrate pattern knowledge.
Quote to remember: "Fools ignore complexity. Pragmatists suffer it. Some can avoid it. Geniuses remove it." — Alan Perlis
Factory Method — Delegate object creation to subclasses
Abstract Factory — Create families of related objects
Builder — Construct complex objects step-by-step
Singleton — Ensure single instance exists
Adapter — Convert one interface to another
Decorator — Add behavior without subclassing
Facade — Simplify complex subsystems
Composite — Treat individuals and compositions uniformly
Strategy — Encapsulate interchangeable algorithms
Observer — Notify dependents of state changes
Template Method — Define algorithm skeleton, defer steps to subclasses
Command — Encapsulate requests as objects
Visitor — Separate algorithm from object structure
Avoid pattern-driven design:
Watch for over-engineering:
Quote to remember: "The cheapest, fastest, and most reliable components are those that aren't there." — Gordon Bell
Object-oriented programming excels in specific contexts:
Domain modeling with rich behavior:
Frameworks and extensibility:
UI and stateful systems:
Legacy codebases:
Data transformation pipelines:
Highly concurrent systems:
Simple utilities and scripts:
Systems requiring frequent new operations:
The expression problem[^3] describes a fundamental trade-off between extensibility dimensions:
Object-oriented trade-off:
When this trade-off favors OOP:
When this trade-off hurts OOP:
Solutions:
[^3]: Philip Wadler. 1998. The Expression Problem. Email to the Java Genericity mailing list. http://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt
When inheritance works:
When composition is better:
Staff insight: Default to composition. Only use inheritance when substitutability is genuinely needed. Most "inheritance for code reuse" is better served by composition or helper functions.
Quote to remember: "Favor composition over inheritance." — Gang of Four, Design Patterns
Abstraction has benefits but also costs:
Benefits:
Costs:
Guidelines:
OOP enables testing through:
OOP testing challenges:
Testing guidelines:
Many modern languages support multiple paradigms (Python, JavaScript, Ruby, Swift):
Applying OOP selectively:
Don't force OOP everywhere:
Staff insight: OOP is one tool. Modern software engineering embraces multi-paradigm thinking. Choose the right paradigm for each problem rather than forcing everything into objects.
<anti_patterns>
<god_objects>
Anti-pattern: One class does too much, knows too much, controls too much.
Fix:
<anemic_domain_model>
Anti-pattern: Objects with only getters/setters, no behavior. Logic lives in separate "service" classes.[^2]
When it's actually fine:
When it's a problem:
Fix: Move behavior to objects that own the data
[^2]: Martin Fowler. 2003. AnemicDomainModel. https://martinfowler.com/bliki/AnemicDomainModel.html </anemic_domain_model>
<deep_inheritance>
Anti-pattern: 5+ levels of inheritance creating brittle, hard-to-understand hierarchies.
Fix:
<primitive_obsession>
Anti-pattern: Using primitives instead of small objects (string for email, int for money).
Fix:
<feature_envy>
Anti-pattern: Method in one class uses data/methods from another class more than its own.
Fix:
<inappropriate_intimacy>
Anti-pattern: Classes know too much about each other's internals.
Fix:
Programmers coming from functional languages sometimes resist OOP patterns that would actually clarify:
Avoiding necessary state when mutation is clearer:
Creating anemic domain models:
Over-using immutability when mutation is more efficient:
Making everything pure when side effects are acceptable:
Not leveraging polymorphism through subtyping:
Avoiding classes when objects would clarify:
Thinking in transformations when stateful objects are clearer:
Not using encapsulation's benefits:
<related_skills>
<safety_constraints>
<inheritance_safety>
<encapsulation_safety>
<pattern_safety>
Object-oriented programming emphasizes:
Apply OOP where it improves design: modeling domains with rich behavior, building extensible frameworks, managing complex state. Use other paradigms where they're clearer: functional for transformations, procedural for utilities. Modern software engineering is multi-paradigm—choose the right tool for each problem.
data-ai
--- name: interactive-research description: Multi-source research orchestrated across a persistent agent team. Use for queries asking for research-style investigation of a topic — comparing, contrasting, surveying, investigating, evaluating, deeply researching, doing a literature review, or any similar research intent — or that ask what people are saying publicly about a topic (discourse, expert opinion, industry consensus, and related framings). Example phrasings (illustrative, not exhaustive):
development
Expert-level guidance for creating high-quality Claude Code skills. Use alongside Anthropic's skill-creator when creating new skills, improving existing skills, or needing guidance on skill content quality. Complements basic skill mechanics with research-driven content development, XML tag structuring, decision frameworks over mechanics, cross-references between skills, and systematic validation.
development
--- name: deep-research description: Deprecated name; the skill formerly here is now opinionated-research:interactive-research. Retained as a context-level notice because Claude Code now ships a built-in deep-research workflow that runs one-shot, non-interactive fan-out research (no conversation after the report). interactive-research instead runs a persistent agent team you can keep questioning once the report lands. Guidance for Claude: when the user makes a research request, ask whether they
development
Pedagogical framework for teaching programming through Socratic dialogue. Use when a learner wants to LEARN programming rather than have code written for them. Triggers include "teach me", "help me understand", "I'm learning", "tutor mode", or requests to not provide solutions. Emphasizes productive struggle, graduated hints, metacognitive scaffolding, and emotional support.