Software Engineering
Engineering judgment - thoughtful decisions - quality code.
<when_to_use>
-
Making architectural or design decisions
-
Evaluating trade-offs between approaches
-
Determining appropriate level of thoroughness
-
Assessing when code needs refactoring
-
Deciding when to ask vs proceed independently
-
Balancing speed, quality, maintainability
NOT for: mechanical tasks, clear-cut decisions, following explicit instructions
</when_to_use>
Core engineering judgment framework.
User preferences trump defaults CLAUDE.md , project rules, existing patterns always override skill suggestions.
Simplest thing that works Start simple. Add complexity only when requirements demand.
-
Boring solutions for boring problems
-
Proven libraries over custom implementations
-
Progressive enhancement over rewrites
Read before write Understand existing patterns before modifying.
-
Check how similar features implemented
-
Follow established conventions
-
Maintain consistency
Small, focused changes One idea per commit, 20-100 LOC, 1-5 files.
-
Easy to review/understand
-
Lower bug risk
-
Simpler to revert
-
Faster feedback
Security awareness Don't introduce vulnerabilities.
-
Validate external input
-
Parameterized queries
-
Handle auth properly
-
No secrets in code/logs
Know when to stop Ship working code, don't gold-plate.
-
Implement requirements, not assumptions
-
No unrequested features
-
No speculative abstraction
<type_safety>
Type safety across languages.
Core principle: Make illegal states unrepresentable. Type system should prevent invalid data at compile time, not runtime.
Hierarchy: Correct (type-safe) - Clear (self-documenting) - Precise (not overly broad)
Key patterns:
-
Result types - Errors explicit in signatures, not hidden in exceptions
-
Discriminated unions - Mutually exclusive states with discriminator field
-
Branded types - Distinct types for domain concepts (user ID vs product ID)
-
Parse, don't validate - Transform untyped to typed at boundaries, trust types internally
See type-patterns.md for detailed concepts. Load typescript-dev/SKILL.md for TypeScript implementations.
</type_safety>
<decision_framework>
Systematic approach to engineering choices.
Understand before deciding
-
What problem being solved?
-
What constraints exist?
-
What's already in codebase?
-
What patterns does project use?
Consider trade-offs No perfect solutions:
-
Speed vs robustness
-
Simplicity vs flexibility
-
Consistency vs optimization
-
Implement time vs maintain time
Recognize good-enough Perfect is enemy of shipped:
-
Meets requirements?
-
Maintainable by team?
-
Tested adequately?
-
Can improve incrementally?
If yes to all - ship it.
Document significant choices Non-obvious decisions: comment why, note trade-offs, link discussions, flag assumptions.
</decision_framework>
<when_to_ask>
Balance autonomy with collaboration.
Proceed independently:
-
Task clear and well-defined
-
Approach follows existing patterns
-
Changes small and localized
-
Requirements fully understood
-
No security/data integrity risks
Ask questions:
-
Requirements ambiguous
-
Multiple approaches, unclear trade-offs
-
Changes affect architecture
-
Security/compliance implications
-
Unfamiliar domain/technology
Escalate immediately:
-
Security vulnerabilities discovered
-
Data corruption/loss risk
-
Breaking changes to public APIs
-
Performance degradation detected
Don't guess on high-stakes decisions.
</when_to_ask>
<code_quality>
Standards separating good from professional code.
Type safety: Make illegal states unrepresentable via discriminated unions, branded types.
Error handling: Every error path needs explicit handling. No silent failures.
Naming: Functions=verbs (calculateTotal ), variables=nouns (userId ), booleans=questions (isValid ).
Function design: One thing well. 10-30 lines typical, max 50. 3 params ideal, max 5. Pure when possible.
Comments: Explain why, not what.
See code-quality-patterns.md for examples.
</code_quality>
When and how to improve existing code.
Refactor when:
-
Adding feature reveals poor structure
-
Code duplicated 3+ times
-
Function exceeds 50 lines
-
Naming unclear/misleading
-
Tests difficult to write
Don't refactor when:
-
Code works and won't be touched
-
Time-critical delivery in progress
-
No test coverage to verify
-
Scope creep from main task
-
Just preference, no clear benefit
Guidelines:
-
Have tests first (or write them)
-
One refactoring at a time
-
Keep tests passing throughout
-
Commit refactors separately from features
-
Don't change behavior
Testing philosophy.
Test the right things:
-
Public interfaces, not implementation
-
Edge cases and error paths
-
Critical business logic
-
Integration points
-
Security boundaries
Don't over-test:
-
No tests for trivial getters/setters
-
Don't test framework behavior
-
Avoid brittle implementation-coupled tests
Coverage targets:
-
Critical paths: 90%+
-
Business logic: 80%+
-
Utility functions: 80%+
-
Overall: 70%+
Low coverage acceptable for: config, type definitions, framework boilerplate.
Balance optimization with delivery.
Premature optimization is root of evil
-
Make it work first
-
Make it right second
-
Make it fast only if needed
Optimize when:
-
Measured performance issue exists
-
User experience degraded
-
Resource costs excessive
-
Profiler shows clear bottleneck
Before optimizing:
-
Measure current performance
-
Set target metrics
-
Profile to find bottleneck
-
Optimize specific bottleneck
-
Measure improvement
-
Document trade-offs
Don't optimize based on gut feeling or without measurement.
Security mindset for all code.
Input validation: Validate all external input, sanitize before processing, allowlists over blocklists.
Auth: Never trust client-side checks, verify on server, use proven libraries, don't roll your own crypto.
Data handling: Never log sensitive data, hash passwords (bcrypt/argon2), parameterized queries, strict file upload validation.
Dependencies: Keep updated, review advisories, minimize count, audit before adding.
Red flags to escalate: Payment info, user credentials, health/financial data, encryption implementation, session management.
<anti_patterns>
Common mistakes to avoid.
Over-engineering: Building "might need" features, premature abstraction, excessive config, enterprise patterns for simple problems. Fix: YAGNI. Build for today.
Under-engineering: No error handling, no input validation, ignoring edge cases, copy-paste over functions. Fix: Basic quality isn't optional.
Scope creep: "While I'm here...", refactoring unrelated code, adding unrequested features. Fix: Stay focused. File issues for unrelated work.
Guess-and-check: Random solutions, copying without understanding, no root cause investigation. Fix: Systematic debugging. Understand before changing.
Analysis paralysis: Endless design discussions, researching every option, waiting for perfect. Fix: Good enough + shipping > perfect + delayed.
</anti_patterns>
Senior engineer collaboration.
Clear issues/PRs: Context (problem), approach (solution), trade-offs (alternatives), testing (verification), impact (risks).
Code review: Focus on correctness/clarity/security. Suggest, don't demand perfection. Approve when good enough.
When blocked: Try 30 min self-unblock, gather context, ask specific question with context, propose solutions.
Saying no: "That would work, but have you considered X?" / "This introduces Y risk. Can we mitigate with Z?"
Back opinions with reasoning. Stay open to being wrong.
<workflow_integration>
Connect with other baselayer skills.
With TDD: Senior judgment decides what's worth testing. TDD skill provides how.
With debugging: Senior judgment decides if worth fixing now. Debugging skill provides systematic investigation.
With dev- skills*: Software engineering provides the "why" and "when". dev-* skills provide the "how" for specific technologies (typescript-dev, react-dev, hono-dev, bun-dev).
</workflow_integration>
ALWAYS:
-
Read CLAUDE.md and project rules first
-
Follow existing codebase patterns
-
Make small, focused changes
-
Validate external input
-
Handle errors explicitly
-
Test critical paths
-
Document non-obvious decisions
-
Ask when uncertain on high-stakes
NEVER:
-
Add features not in requirements
-
Ignore error handling
-
Skip input validation
-
Commit secrets or credentials
-
Guess on security decisions
-
Refactor without tests
-
Optimize without measuring
-
Over-engineer simple solutions
Complements other baselayer skills:
Core Practices:
-
test-driven-development/SKILL.md - TDD methodology
-
debugging-and-diagnosis/SKILL.md - systematic debugging
-
pathfinding/SKILL.md - requirements clarification
Development Skills (load for implementation patterns):
-
typescript-dev/SKILL.md - TypeScript, Zod, modern features
-
react-dev/SKILL.md - React 18-19, hooks typing
-
hono-dev/SKILL.md - Hono API framework
-
bun-dev/SKILL.md - Bun runtime, SQLite, testing
Detailed Patterns:
-
type-patterns.md - language-agnostic type patterns
-
code-quality-patterns.md - code examples
Standards:
- FORMATTING.md - formatting conventions