Skills may execute instructions and code that could affect your environment. Marketplace scans reduce risk but do not guarantee safety. Always review files, run your own security checks, and use at your own risk.
software-design-philosophy
Security Scan Summary
Status: Safe
Source: Syntic Skills registry
Automated security scan completed with no high-risk patterns detected. Manual review is still required.
About This Skill
Use when managing software complexity: module design, deep vs. shallow modules, information hiding, over-engineering, or strategic vs. tactical programming tradeoffs.
Downloadable SKILL.md
Download SKILL.md and place it in your Syntic skills folder. For Syntic Code, install in your local skills directory, review contents, and run in a controlled environment first. Acknowledge the risk notice above to enable the download.
---
name: software-design-philosophy
description: Use when managing software complexity: module design, deep vs. shallow modules, information hiding, over-engineering, or strategic vs. tactical programming tradeoffs.
category: Design
version: 1.0.0
tools: []
---
# A Philosophy of Software Design Framework
A practical framework for managing the fundamental challenge of software engineering: complexity. Apply these principles when designing modules, reviewing APIs, refactoring code, or advising on architecture decisions.
## Core Principle
**The greatest limitation in writing software is our ability to understand the systems we are creating.** Complexity is the enemy: it makes systems hard to understand, hard to modify, and a source of bugs. Evaluate every design decision by asking "Does this increase or decrease the overall complexity of the system?" — the goal is not zero complexity, but minimizing unnecessary complexity and concentrating the necessary kind where it can be managed.
## Scoring
**Goal: 10/10.** Score a design by counting how many of the eight Quick Diagnostic rows it satisfies (≈1.25 points each). Bands: **9-10** = all eight pass (deep modules, no leakage, interface comments capture design intent, design improvement routine); **6-8** = 5-6 pass (mostly deep, one or two leaks or undocumented abstractions); **3-5** = 2-4 pass (classitis, temporal decomposition, comments that only restate code); **≤2** = 0-1 pass (tactical-tornado: shallow modules, pervasive leakage, no design intent recorded). State the score, the failed rows, and the fix for each.
## The Software Design Framework
### 1. Complexity and Its Causes
Complexity is anything about a system's structure that makes it hard to understand and modify. Three symptoms — **change amplification** (a simple change requires edits in many places), **cognitive load** (a developer must hold too much in mind), and **unknown unknowns** (unclear what must change or what's relevant — the worst symptom) — stem from two causes: dependencies and obscurity. Complexity is incremental, accumulating from hundreds of small decisions ("death by a thousand cuts"), so every decision matters.
**Code applications:** centralize shared knowledge (extract color constants instead of hardcoding `#ff0000` in 20 files); hide detail to cut cognitive load (`open(path)` instead of requiring buffer size, encoding, lock mode); make dependencies explicit via types/interfaces; name precisely (`numBytesReceived` not `n`) to fight obscurity.
### 2. Deep vs Shallow Modules
The best modules are **deep**: powerful functionality behind a simple interface. **Shallow modules** have complex interfaces relative to their functionality — they add complexity rather than hiding it. The interface is the *cost* a module imposes; the implementation is the benefit, so a method harder to learn than to re-implement is net-negative. Depth = functionality provided / interface complexity imposed (Unix file I/O is deep; thin Java I/O wrappers are shallow). **Classitis** is the disease of too many small, shallow classes, each adding cognitive load without adding depth. Small methods aren't inherently good — depth matters more than size.
**Code applications:** hide complexity behind a simple API (`file.read(path)` hides disk blocks, caching, buffering, encoding); merge related shallow classes (`RequestParser` + `RequestValidator` + `RequestProcessor` → one `RequestHandler`); favor fewer parameters and sensible defaults over 15-parameter constructors.
### 3. Information Hiding and Leakage
Each module should encapsulate knowledge not needed by other modules. **Information leakage** — one design decision reflected in multiple modules — is a key red flag: a decision in one module can change there alone, while the same decision leaked into N modules turns one edit into N edits no compiler will remind you to make. **Temporal decomposition** causes leakage: splitting code by *when* things happen forces shared knowledge across phases — organize by knowledge instead. Back-door leakage through data formats, protocols, or shared assumptions is the subtlest form; decorators frequently leak by exposing the decorated interface. If two modules share knowledge, merge them or create a module that encapsulates it.
**Code applications:** centralize serialization (one module owns JSON encoding, not `json.dumps` everywhere); combine "read config" and "apply config" into one module instead of splitting by phase; abstract transport details (`MessageBus.send(event)` hides HTTP vs. gRPC vs. queue).
### 4. General-Purpose vs Special-Purpose Modules
Design modules that are "somewhat general-purpose": an interface general enough for multiple uses, with an implementation that handles current needs. Ask: "What is the simplest interface that covers all my current needs?" Counterintuitively, the general interface is usually the *simpler* one — special-case methods multiply as requirements grow, while one general method absorbs them. The trap runs the other way too: generality current needs don't demand is speculative complexity paid for a use case that may never arrive. Push complexity downward: lower-level modules handle hard cases so upper levels stay simple. Configuration parameters often represent a failure to decide — each one pushes complexity onto the caller.
**Code applications:** design for the concept, not one use case (`text.insert(position, string)` instead of `text.addBulletPoint()`); auto-detect behavior instead of adding parameters (file encoding, not an `encoding` param); one general method over many specific ones (`store(key, value, options)` instead of `storeUser()`, `storeProduct()`, `storeOrder()`).
### 5. Comments as Design Documentation
Comments should describe what is not obvious from the code: design intent, abstraction rationale, invariants, and assumptions. "Good code is self-documenting" is a myth beyond low-level detail — code records *what* it does, never why this approach over the alternatives or what it silently assumes. That rationale lives only in the author's head and is gone once they move on. Four comment types: interface comments (most important — they define the abstraction), data structure member comments, implementation comments, cross-module comments. Write comments first (comment-driven design) to clarify thinking before code; if a comment is hard to write, the design may be too complex.
**Code applications:** interface comment describes the abstraction, not the implementation ("Returns the widget closest to position, or null if none within threshold"); data structure comment explains invariants ("List sorted by priority descending; ties broken by insertion order"); implementation comment explains why, not what ("// Binary search: list always sorted, can hold 100k+ items").
### 6. Strategic vs Tactical Programming
**Tactical programming** gets features working quickly and accumulates complexity with each shortcut. **Strategic programming** invests 10-20% extra effort in good design, treating every change as an opportunity to improve structure — tactical speed is borrowed, while strategic investment compounds into systems that are faster to work with within months. The "tactical tornado" is a developer who ships fast but leaves wreckage — celebrated short-term, destructive long-term. Startups need strategic programming most, since early shortcuts compound into crippling debt as the team grows. Your primary job is a great design that happens to work, not working code that happens to have a design.
**Code applications:** resist quick-and-dirty fixes (no boolean parameter for "just this one special case"); refactor an awkward interface while adding a feature, not as a separate event; evaluate reviews on structure ("does this make the system simpler?"), not just correctness.
## Common Mistakes
| Mistake | Why It Fails | Fix |
|---------|-------------|-----|
| **Creating too many small classes** | Classitis adds interfaces without depth | Merge related shallow classes into deeper modules |
| **Splitting modules by temporal order** | "Read, then process, then write" forces shared knowledge across modules | Group code that shares knowledge into one module |
| **Exposing implementation in interfaces** | Callers depend on internals; changes propagate | Design interfaces around abstractions; hide formats and protocols |
| **Treating comments as optional** | Design intent and assumptions are lost | Write interface comments first; maintain with the code |
| **Configuration parameters for everything** | A parameter offloaded to the caller is a decision declined | Determine behavior automatically; provide sensible defaults |
| **Quick-and-dirty tactical fixes** | Shortcuts compound until the system is unworkable | Invest 10-20% extra; treat every change as a design opportunity |
| **Pass-through methods** | Forwards arguments, adds an interface but no functionality | Merge the pass-through into the caller or the callee |
## Quick Diagnostic
| Question | If No | Action |
|----------|-------|--------|
| Can you describe each module in one sentence? | Modules do too much or lack purpose | Split into coherent, describable responsibilities |
| Are interfaces simpler than implementations? | Modules are shallow — complexity leaks outward | Hide more; merge shallow classes into deeper ones |
| Can you change an implementation without affecting callers? | Information is leaking across boundaries | Encapsulate the leaked decision in one module |
| Is the interface general enough for current needs, no more? | Either special-cased or speculatively generic | Ask "simplest interface for all current needs?" |
| Do interface comments capture design intent? | Newcomers must reverse-engineer the abstraction | Write interface comments before or during implementation |
| Are configuration parameters minimized? | Callers carry decisions the module should make | Auto-detect behavior; supply sensible defaults |
| Is the team investing 10-20% in design, not just shipping features? | Tactical debt compounds silently | Budget refactoring time into every change |
| Are pass-through methods and pure delegation absent? | Extra interface layers with no added depth | Merge pass-throughs into caller or callee |
Based on John Ousterhout's *A Philosophy of Software Design*.
Bundle Download
Includes SKILL.md and bundled support files where provided. Risk acknowledgement is required.
Install Targets
Syntic App
- 1. Create a dedicated folder for this skill in your local skills library.
- 2. Place SKILL.md into that folder.
- 3. Restart Syntic and invoke this skill on matching tasks.
Syntic Code (CLI)
- 1. Save SKILL.md in your local Syntic Code skills directory.
- 2. Keep related files in the same skill folder.
- 3. Run in a safe environment and validate outputs.
Source
https://github.com/wondelai/skills/blob/main/software-design-philosophy/SKILL.md
Open Source LinkRelated Skills
design-everyday-things
Use when a product feels confusing or unintuitive — apply affordances, signifiers, constraints, feedback, and...
Designdesign-sprint
Use when the user wants to prototype and test a product idea with real users fast, mentions a "design...
Designdomain-driven-design
Use when modeling software around the business domain: bounded contexts, aggregates, ubiquitous language...
Designhooked-ux
Use when designing habit-forming product loops (Trigger, Action, Variable Reward, Investment), re-engagement...