Use when designing modules, APIs, and system architecture requiring independent, non-overlapping components where changes in one don't affect others.
View on GitHubSelect agents to install to:
npx add-skill https://github.com/TheBushidoCollective/han/blob/main/core/skills/orthogonality-principle/SKILL.md -a claude-code --skill orthogonality-principleInstallation paths:
.claude/skills/orthogonality-principle/# Orthogonality Principle
Build systems where components are independent and changes don't ripple
unexpectedly.
## What is Orthogonality?
**Orthogonal** (from mathematics): Two lines are orthogonal if they're
at right angles - changing one doesn't affect the other.
**In software**: Components are orthogonal when changing one doesn't
require changing others. They are independent and non-overlapping.
### Benefits
- Changes are localized (less debugging)
- Easy to test in isolation
- Components are reusable
- Less coupling = less complexity
- Easier to understand and maintain
## Signs of Non-Orthogonality
### Red flags indicating components are NOT orthogonal
1. **Change amplification**: Changing one thing requires changing many others
2. **Shotgun surgery**: One feature scattered across many files
3. **Tight coupling**: Components know too much about each other
4. **Duplicate logic**: Same concept implemented multiple ways
5. **Cascading changes**: Change in A breaks B, C, D unexpectedly
## Achieving Orthogonality
### 1. Separation of Concerns
### Keep unrelated responsibilities separate
### Elixir Example
```elixir
# NON-ORTHOGONAL - Mixed concerns
defmodule UserController do
def create(conn, params) do
# Validation
if valid_email?(params["email"]) do
# Database
user = Repo.insert!(%User{email: params["email"]})
# External API
Stripe.create_customer(user.email)
# Notification
Email.send_welcome(user.email)
# Logging
Logger.info("Created user #{user.id}")
# Response
json(conn, %{user: user})
end
end
end
# Changing email format affects validation, database, Stripe, email!
# ORTHOGONAL - Separated concerns
defmodule UserController do
def create(conn, params) do
with {:ok, command} <- build_command(params),
{:ok, user} <- UserService.create(command) do
json(conn, %{user: user})
end
end
end
defmodule UserService do
def create(command) do
with {: