# Senior Dev Principles

> STRICT structure-and-complexity layer for non-trivial code work: designing systems, writing new modules, refactoring, implementing algorithms, or making structural decisions. Complements code-style-defaults (form of the output) and python-native (Python stdlib): this skill decides how code is structured and how fast it runs — target big-O before writing, single-responsibility grain, policy constants, testability, and per-language defaults for TypeScript, C, C++, and SQL. Triggers: "design X", "refactor this", "implement an algorithm/feature/service", "optimize this", "review this code", "what's the best way to structure X", or any task involving architecture, complexity reasoning, or multi-file changes. SKIP for trivial edits (rename, typo, single-line fix), config tweaks, and documentation edits.

- Skill: `crag666/senior-dev-principles` (Agent Skill)
- Install (CLI): `npx skillmds@latest add crag666/senior-dev-principles`
- Raw SKILL.md: https://api.skillmd.com/api/skills/crag666/senior-dev-principles/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: crag666 (https://skillmd.com/u/crag666)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/crag666/senior-dev-principles

---


# Senior Dev Principles

Structure and complexity layer. `code-style-defaults` governs the form of the output; `python-native` governs Python stdlib usage; this skill governs how code is structured and how fast it runs. Every rule is a requirement, not a suggestion.

Precedence: user's explicit instruction > convention of the file being edited > this list.

## 1. Algorithmic complexity — reason before writing

Mandatory for algorithmic code, hot paths, and anything touching unbounded or user-controlled input size. Skip for glue code, CRUD handlers, and transforms over known-small data.

| Problem                  | Naive      | Target       | Technique                |
|--------------------------|------------|--------------|--------------------------|
| Membership test          | O(n)       | O(1) amort.  | set / dict               |
| Find duplicates          | O(n²)      | O(n)         | hash set                 |
| Pair matching            | O(n²)      | O(n)         | hash map                 |
| Sorted lookup            | O(n)       | O(log n)     | binary search            |
| Shortest path (single-source, non-negative weights) | O(V²) | O((V+E) log V) | Dijkstra + min-heap; for negative edges use Bellman-Ford, or Johnson for all-pairs |
| Substring search         | O(nm)      | O(n+m)       | KMP (worst-case O(n+m)); Rabin-Karp (expected O(n+m), worst-case O(nm) on hash collisions) |
| Top-K elements           | O(n log n) | O(n log k)   | min-heap of size k       |
| Range sum queries        | O(n) each  | O(1) each    | prefix sum array         |
| Repeated subproblem      | O(2ⁿ)      | states × transition cost | memoization / DP (e.g. matrix-chain O(n³), 0/1 knapsack pseudo-polynomial O(nW)) |

- Do NOT use nested loops when a hash map flattens them.
- Do NOT sort inside a loop when one sort outside suffices.
- Do NOT use `in list` membership when n is unbounded — use `set`/`dict`.
- Do NOT accept O(n²) or worse on unbounded input without stating why in one line.
- DO note complexity in a comment only when non-obvious (recursive DP, custom structures, early exits) — never on obvious linear scans.

## 2. Structure

- Do NOT put two reasons-to-change in one unit — DB access + business rules + serialization is three units.
- Do NOT split a unit that reads top-to-bottom cohesively just to make files smaller.
- Do NOT create names nobody would search for (`OrderHelperUtils`, `ProcessingManagerImpl`) — if the split forces one, the split is wrong.
- Do NOT judge by size: a 50-line cohesive function is fine; a 30-line file mixing two domains is not. Split concerns, keep cohesion.
- Do NOT inline a literal that encodes policy — `MAX_RETRIES`, not `3`. DO inline intrinsic literals (`bytes[0]`, `len(parts) == 2`).
- Do NOT bury I/O inside logic when tests exist — pure functions where natural, I/O at the edges.
- Do NOT restructure working code purely to enable tests nobody will write.

## 3. Per-language

Python lives in `python-native`.

### TypeScript
- `const` by default, `let` only on mutation, never `var`.
- Explicit return types on exported functions.
- `strict: true`; `unknown` + narrowing over `any`.
- `async`/`await` over raw `.then` chains.

### C
- Every allocation has an owner and a matching free; verify with Valgrind or ASan.
- No implicit `switch` fallthrough — `break` or `/* fallthrough */`.
- `size_t` for sizes and indices; never mix signed/unsigned.
- Header guards on every `.h`.

### C++
- RAII: resources owned by objects, never managed manually.
- `unique_ptr`/`shared_ptr` over raw owning pointers.
- `const` on non-mutating methods; `const&` for non-trivial parameters.
- `std::vector`/`std::array` over raw arrays; Rule of Zero; `explicit` on single-argument constructors.

### SQL
- Explicit column lists, never `SELECT *` in production paths.
- Consider an index for new WHERE/JOIN columns; do NOT over-index write-heavy tables.
- Run `EXPLAIN` on queries that will scan large tables.

## Self-review before presenting

- State each unit's purpose in one sentence — if you can't, restructure.
- Is the complexity acceptable for realistic input sizes?
- Edge cases handled, or explicitly out of scope?
- Correct > clear > efficient > maintainable — in that order.

