Use when designing modules and components requiring Composition Over Inheritance, Law of Demeter, Tell Don't Ask, and Encapsulation principles that transcend programming paradigms.
View on GitHubSelect agents to install to:
npx add-skill https://github.com/TheBushidoCollective/han/blob/main/core/skills/structural-design-principles/SKILL.md -a claude-code --skill structural-design-principlesInstallation paths:
.claude/skills/structural-design-principles/# Structural Design Principles
These principles originated in object-oriented design but apply to **any
programming paradigm**
. They're about code structure, not paradigm.
## Paradigm Translations
In **functional programming** (Elixir), they manifest as:
- **Composition Over Inheritance** → Function composition, module
composition, pipe operators
- **Law of Demeter** → Minimize coupling between data structures,
delegate to owning modules
- **Tell, Don't Ask** → Push logic to the module owning the data type
- **Encapsulation** → Module boundaries, immutability, pattern matching,
opaque types
In **object-oriented programming** (TypeScript/React): Apply traditional OO
interpretations with classes, interfaces, and encapsulation.
**The underlying principle is the same across paradigms: manage dependencies,
reduce coupling, and maintain clear boundaries.**
---
## Four Core Principles
### 1. Composition Over Inheritance
**Favor composition (combining simple behaviors) over inheritance
(extending base classes).**
**Why:** Inheritance creates tight coupling and fragile hierarchies.
Composition provides flexibility.
### Elixir Approach (No Inheritance)
Elixir doesn't have inheritance - it uses composition naturally through:
- Module imports (`use`, `import`, `alias`)
- Function composition (`|>` pipe operator)
- Struct embedding
- Behaviour protocols
```elixir
# GOOD - Composition with pipes
def process_payment(order) do
order
|> validate_items()
|> calculate_total()
|> apply_discounts()
|> charge_payment()
|> send_receipt()
end
# GOOD - Compose behaviors
defmodule User do
use YourApp.Model
use Ecto.Schema
import Ecto.Changeset
# Composes functionality from multiple modules
end
# GOOD - Struct embedding
defmodule Address do
embedded_schema do
field :street, :string
field :city, :string
end
end
defmodule User do
schema "users" do
embeds_one :address, Address
end
end
```
### TypeScript Examples
```typescript
//