pdd-skills 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1478 -0
- package/bin/pdd.js +354 -0
- package/config/bpmn-rules.yaml +166 -0
- package/config/checkstyle.xml +105 -0
- package/config/eslint.config.js +48 -0
- package/config/pmd.xml +91 -0
- package/config/prd-rules.yaml +113 -0
- package/config/ruff.toml +45 -0
- package/config/sqlfluff.cfg +82 -0
- package/hooks/hook-executor.js +332 -0
- package/index.js +43 -0
- package/lib/api-routes.js +750 -0
- package/lib/api-server.js +408 -0
- package/lib/cache/cache-config.js +209 -0
- package/lib/cache/system-cache.js +852 -0
- package/lib/config-manager.js +373 -0
- package/lib/generate.js +528 -0
- package/lib/grpc/grpc-routes.js +1134 -0
- package/lib/grpc/grpc-server.js +912 -0
- package/lib/grpc/proto-definitions.js +1033 -0
- package/lib/init.js +172 -0
- package/lib/iteration/auto-fixer.js +1025 -0
- package/lib/iteration/auto-reviewer.js +923 -0
- package/lib/iteration/controller.js +577 -0
- package/lib/list.js +130 -0
- package/lib/mcp-server.js +548 -0
- package/lib/openclaw/api-integration.js +535 -0
- package/lib/openclaw/cli-integration.js +567 -0
- package/lib/openclaw/data-sync.js +845 -0
- package/lib/openclaw/openclaw-adapter.js +783 -0
- package/lib/plugin/example-plugins/code-stats/index.js +332 -0
- package/lib/plugin/example-plugins/code-stats/plugin.json +1 -0
- package/lib/plugin/example-plugins/custom-linter/index.js +472 -0
- package/lib/plugin/example-plugins/custom-linter/plugin.json +1 -0
- package/lib/plugin/example-plugins/hello-world/index.js +86 -0
- package/lib/plugin/example-plugins/hello-world/plugin.json +1 -0
- package/lib/plugin/plugin-manager.js +655 -0
- package/lib/plugin/plugin-sdk.js +565 -0
- package/lib/plugin/sandbox.js +627 -0
- package/lib/quality/rules/maintainability.js +418 -0
- package/lib/quality/rules/performance.js +498 -0
- package/lib/quality/rules/readability.js +441 -0
- package/lib/quality/rules/robustness.js +504 -0
- package/lib/quality/rules/security.js +444 -0
- package/lib/quality/scorer.js +576 -0
- package/lib/report.js +669 -0
- package/lib/sdk-base.js +301 -0
- package/lib/sdk-js.js +446 -0
- package/lib/sdk-python/README.md +546 -0
- package/lib/sdk-python/examples/basic_usage.py +450 -0
- package/lib/sdk-python/pdd_sdk/__init__.py +180 -0
- package/lib/sdk-python/pdd_sdk/client.py +1170 -0
- package/lib/sdk-python/pdd_sdk/events.py +423 -0
- package/lib/sdk-python/pdd_sdk/exceptions.py +158 -0
- package/lib/sdk-python/pdd_sdk/models.py +518 -0
- package/lib/sdk-python/pdd_sdk/utils.py +759 -0
- package/lib/token/budget-alert.js +367 -0
- package/lib/token/budget-manager.js +485 -0
- package/lib/update.js +54 -0
- package/lib/utils/logger.js +88 -0
- package/lib/verify.js +741 -0
- package/lib/version.js +52 -0
- package/lib/vm/README.md +102 -0
- package/lib/vm/dashboard/api-routes.js +669 -0
- package/lib/vm/dashboard/server.js +391 -0
- package/lib/vm/dashboard/sse.js +358 -0
- package/lib/vm/dashboard/static/css/dashboard.css +1378 -0
- package/lib/vm/dashboard/static/index.html +118 -0
- package/lib/vm/dashboard/static/js/app.js +949 -0
- package/lib/vm/dashboard/static/js/charts.js +913 -0
- package/lib/vm/dashboard/static/js/kanban-view.js +1053 -0
- package/lib/vm/dashboard/static/js/pipeline-view.js +463 -0
- package/lib/vm/dashboard/static/js/quality-view.js +598 -0
- package/lib/vm/dashboard/static/js/system-view.js +1021 -0
- package/lib/vm/data-provider.js +1191 -0
- package/lib/vm/event-bus.js +402 -0
- package/lib/vm/hooks/extract-hook.js +307 -0
- package/lib/vm/hooks/generate-hook.js +374 -0
- package/lib/vm/hooks/hook-interface.js +458 -0
- package/lib/vm/hooks/report-hook.js +331 -0
- package/lib/vm/hooks/verify-hook.js +454 -0
- package/lib/vm/models.js +1003 -0
- package/lib/vm/reconciler.js +855 -0
- package/lib/vm/scanner.js +988 -0
- package/lib/vm/state-schema.js +955 -0
- package/lib/vm/state-store.js +733 -0
- package/lib/vm/tui/components/card.js +339 -0
- package/lib/vm/tui/components/progress-bar.js +368 -0
- package/lib/vm/tui/components/sparkline.js +327 -0
- package/lib/vm/tui/components/status-light.js +294 -0
- package/lib/vm/tui/components/table.js +370 -0
- package/lib/vm/tui/input.js +335 -0
- package/lib/vm/tui/renderer.js +548 -0
- package/lib/vm/tui/screens/kanban-screen.js +397 -0
- package/lib/vm/tui/screens/overview-screen.js +357 -0
- package/lib/vm/tui/screens/quality-screen.js +336 -0
- package/lib/vm/tui/screens/system-screen.js +379 -0
- package/lib/vm/tui/tui.js +805 -0
- package/package.json +1 -0
- package/scripts/cso-analyzer.js +198 -0
- package/scripts/eval-runner.js +359 -0
- package/scripts/i18n-checker.js +109 -0
- package/scripts/linter/activiti-linter.js +272 -0
- package/scripts/linter/prd-linter.js +162 -0
- package/scripts/linter/report-generator.js +207 -0
- package/scripts/linter/run-linters.js +285 -0
- package/scripts/linter/sql-linter.js +166 -0
- package/scripts/token-analyzer.js +162 -0
- package/scripts/vm-test.js +180 -0
- package/skills/core/official-doc-writer/LICENSE +21 -0
- package/skills/core/official-doc-writer/README.md +232 -0
- package/skills/core/official-doc-writer/SKILL.md +475 -0
- package/skills/core/official-doc-writer/_meta.json +1 -0
- package/skills/core/official-doc-writer/document_generator.py +580 -0
- package/skills/core/official-doc-writer/evals/default-evals.json +1 -0
- package/skills/core/official-doc-writer/examples.md +150 -0
- package/skills/core/official-doc-writer/fonts/FONTS_LIST.md +45 -0
- package/skills/core/official-doc-writer/fonts/README.md +141 -0
- package/skills/core/official-doc-writer/fonts/SIMFANG.TTF +0 -0
- package/skills/core/official-doc-writer/fonts/SIMHEI.TTF +0 -0
- package/skills/core/official-doc-writer/fonts/SIMKAI.TTF +0 -0
- package/skills/core/official-doc-writer/fonts/SIMSUN.TTC +0 -0
- package/skills/core/official-doc-writer/fonts//346/226/271/346/255/243/345/260/217/346/240/207/345/256/213GBK.TTF +0 -0
- package/skills/core/official-doc-writer/references/GBT_9704-2012_/345/205/232/346/224/277/346/234/272/345/205/263/345/205/254/346/226/207/346/240/274/345/274/217.md +422 -0
- package/skills/core/official-doc-writer/scripts/__pycache__/generate_official_doc.cpython-313.pyc +0 -0
- package/skills/core/official-doc-writer/scripts/dialog_manager.py +564 -0
- package/skills/core/official-doc-writer/scripts/generate_official_doc.py +252 -0
- package/skills/core/official-doc-writer/scripts/install_fonts.py +390 -0
- package/skills/core/official-doc-writer/scripts/smart_prompts.py +363 -0
- package/skills/core/pdd-ba/SKILL.md +305 -0
- package/skills/core/pdd-ba/_meta.json +1 -0
- package/skills/core/pdd-ba/evals/default-evals.json +1 -0
- package/skills/core/pdd-code-reviewer/SKILL.md +378 -0
- package/skills/core/pdd-code-reviewer/_meta.json +1 -0
- package/skills/core/pdd-code-reviewer/evals/default-evals.json +1 -0
- package/skills/core/pdd-doc-change/SKILL.md +350 -0
- package/skills/core/pdd-doc-change/_meta.json +1 -0
- package/skills/core/pdd-doc-change/evals/default-evals.json +1 -0
- package/skills/core/pdd-doc-gardener/SKILL.md +248 -0
- package/skills/core/pdd-doc-gardener/_meta.json +1 -0
- package/skills/core/pdd-doc-gardener/evals/default-evals.json +1 -0
- package/skills/core/pdd-entropy-reduction/SKILL.md +360 -0
- package/skills/core/pdd-entropy-reduction/_meta.json +1 -0
- package/skills/core/pdd-entropy-reduction/evals/default-evals.json +1 -0
- package/skills/core/pdd-entropy-reduction/references/entropy-report-template.md +287 -0
- package/skills/core/pdd-entropy-reduction/references/golden-principles.md +573 -0
- package/skills/core/pdd-entropy-reduction/scripts/entropy_scan.py +712 -0
- package/skills/core/pdd-extract-features/SKILL.md +320 -0
- package/skills/core/pdd-extract-features/_meta.json +1 -0
- package/skills/core/pdd-extract-features/evals/default-evals.json +1 -0
- package/skills/core/pdd-generate-spec/SKILL.md +418 -0
- package/skills/core/pdd-generate-spec/_meta.json +1 -0
- package/skills/core/pdd-generate-spec/evals/default-evals.json +1 -0
- package/skills/core/pdd-implement-feature/SKILL.md +332 -0
- package/skills/core/pdd-implement-feature/_meta.json +1 -0
- package/skills/core/pdd-implement-feature/evals/default-evals.json +1 -0
- package/skills/core/pdd-main/SKILL.md +540 -0
- package/skills/core/pdd-main/_meta.json +1 -0
- package/skills/core/pdd-main/evals/default-evals.json +1 -0
- package/skills/core/pdd-main/evals/evals.json +215 -0
- package/skills/core/pdd-verify-feature/SKILL.md +474 -0
- package/skills/core/pdd-verify-feature/_meta.json +1 -0
- package/skills/core/pdd-verify-feature/evals/default-evals.json +1 -0
- package/skills/core/pdd-vm/evals/default-evals.json +1 -0
- package/skills/core/traffic-accident-assessor/LICENSE +29 -0
- package/skills/core/traffic-accident-assessor/SKILL.md +439 -0
- package/skills/core/traffic-accident-assessor/evals/evals.json +1 -0
- package/skills/core/traffic-accident-assessor/references/accident-types.md +369 -0
- package/skills/core/traffic-accident-assessor/references/liability-rules.md +287 -0
- package/skills/core/traffic-accident-assessor/references/traffic-laws.md +226 -0
- package/skills/core/traffic-accident-assessor/references//351/253/230/345/260/224/345/244/253/350/257/264/346/230/216/344/271/246.pdf +32576 -106
- package/skills/core/traffic-accident-assessor/scripts/generate_official_statement.py +588 -0
- package/skills/core/traffic-accident-assessor/scripts/generate_report.py +495 -0
- package/skills/core/traffic-accident-assessor/scripts/generate_statement.py +528 -0
- package/skills/core/traffic-accident-assessor.zip +0 -0
- package/skills/entropy/expert-arch-enforcer/SKILL.md +292 -0
- package/skills/entropy/expert-arch-enforcer/_meta.json +1 -0
- package/skills/entropy/expert-arch-enforcer/evals/default-evals.json +1 -0
- package/skills/entropy/expert-auto-refactor/SKILL.md +327 -0
- package/skills/entropy/expert-auto-refactor/_meta.json +1 -0
- package/skills/entropy/expert-auto-refactor/evals/default-evals.json +1 -0
- package/skills/entropy/expert-code-quality/SKILL.md +468 -0
- package/skills/entropy/expert-code-quality/_meta.json +1 -0
- package/skills/entropy/expert-code-quality/evals/default-evals.json +1 -0
- package/skills/entropy/expert-code-quality/evals/evals.json +109 -0
- package/skills/entropy/expert-code-quality/references/code-smells.md +605 -0
- package/skills/entropy/expert-code-quality/references/design-patterns.md +1111 -0
- package/skills/entropy/expert-code-quality/references/refactoring-catalog.md +1281 -0
- package/skills/entropy/expert-code-quality/references/solid-principles.md +524 -0
- package/skills/entropy/expert-entropy-auditor/SKILL.md +276 -0
- package/skills/entropy/expert-entropy-auditor/_meta.json +1 -0
- package/skills/entropy/expert-entropy-auditor/evals/default-evals.json +1 -0
- package/skills/expert/expert-activiti/SKILL.md +497 -0
- package/skills/expert/expert-activiti/_meta.json +1 -0
- package/skills/expert/expert-mysql/SKILL.md +832 -0
- package/skills/expert/expert-mysql/_meta.json +1 -0
- package/skills/expert/expert-performance/SKILL.md +379 -0
- package/skills/expert/expert-performance/_meta.json +1 -0
- package/skills/expert/expert-performance/evals/default-evals.json +1 -0
- package/skills/expert/expert-ruoyi/SKILL.md +472 -0
- package/skills/expert/expert-ruoyi/_meta.json +1 -0
- package/skills/expert/expert-security/SKILL.md +1341 -0
- package/skills/expert/expert-security/_meta.json +1 -0
- package/skills/expert/expert-security/evals/default-evals.json +1 -0
- package/skills/expert/software-architect/SKILL.md +350 -0
- package/skills/expert/software-architect/_meta.json +1 -0
- package/skills/expert/software-engineer/SKILL.md +437 -0
- package/skills/expert/software-engineer/_meta.json +1 -0
- package/skills/expert/software-engineer/architecture.md +130 -0
- package/skills/expert/software-engineer/patterns.md +151 -0
- package/skills/expert/software-engineer/testing.md +135 -0
- package/skills/expert/system-architect/SKILL.md +628 -0
- package/skills/expert/system-architect/_meta.json +1 -0
- package/skills/expert/system-architect/assets/templates/ARCHITECTURE.md +25 -0
- package/skills/expert/system-architect/assets/templates/README.md +44 -0
- package/skills/expert/system-architect/references/js-ts-standards.md +18 -0
- package/skills/expert/system-architect/references/python-standards.md +19 -0
- package/skills/expert/system-architect/references/scaffolding.md +61 -0
- package/skills/expert/system-architect/references/security-checklist.md +21 -0
- package/skills/openspec/openspec-apply-change/SKILL.md +156 -0
- package/skills/openspec/openspec-apply-change/_meta.json +1 -0
- package/skills/openspec/openspec-archive-change/SKILL.md +114 -0
- package/skills/openspec/openspec-archive-change/_meta.json +1 -0
- package/skills/openspec/openspec-bulk-archive-change/SKILL.md +246 -0
- package/skills/openspec/openspec-bulk-archive-change/_meta.json +1 -0
- package/skills/openspec/openspec-continue-change/SKILL.md +118 -0
- package/skills/openspec/openspec-continue-change/_meta.json +1 -0
- package/skills/openspec/openspec-explore/SKILL.md +288 -0
- package/skills/openspec/openspec-explore/_meta.json +1 -0
- package/skills/openspec/openspec-ff-change/SKILL.md +101 -0
- package/skills/openspec/openspec-ff-change/_meta.json +1 -0
- package/skills/openspec/openspec-new-change/SKILL.md +74 -0
- package/skills/openspec/openspec-new-change/_meta.json +1 -0
- package/skills/openspec/openspec-onboard/SKILL.md +554 -0
- package/skills/openspec/openspec-onboard/_meta.json +1 -0
- package/skills/openspec/openspec-sync-specs/SKILL.md +138 -0
- package/skills/openspec/openspec-sync-specs/_meta.json +1 -0
- package/skills/openspec/openspec-verify-change/SKILL.md +168 -0
- package/skills/openspec/openspec-verify-change/_meta.json +1 -0
- package/skills/pr/pdd-multi-review/SKILL.md +534 -0
- package/skills/pr/pdd-multi-review/_meta.json +1 -0
- package/skills/pr/pdd-pr-batch/SKILL.md +303 -0
- package/skills/pr/pdd-pr-batch/_meta.json +1 -0
- package/skills/pr/pdd-pr-create/SKILL.md +344 -0
- package/skills/pr/pdd-pr-create/_meta.json +1 -0
- package/skills/pr/pdd-pr-merge/SKILL.md +286 -0
- package/skills/pr/pdd-pr-merge/_meta.json +1 -0
- package/skills/pr/pdd-pr-review/SKILL.md +217 -0
- package/skills/pr/pdd-pr-review/_meta.json +1 -0
- package/skills/pr/pdd-task-manager/SKILL.md +636 -0
- package/skills/pr/pdd-task-manager/_meta.json +1 -0
- package/skills/pr/pdd-template-engine/SKILL.md +306 -0
- package/skills/pr/pdd-template-engine/_meta.json +1 -0
- package/templates/behavior-shaping/iron-law-template.md +87 -0
- package/templates/behavior-shaping/rationalization-template.md +62 -0
- package/templates/behavior-shaping/red-flags-template.md +70 -0
- package/templates/bilingual-template.md +139 -0
- package/templates/config/default.yaml +47 -0
- package/templates/project/default/README.md +31 -0
- package/templates/project/frontend/README.md +46 -0
- package/templates/project/java/README.md +48 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: software-engineer
|
|
3
|
+
description: "Production-grade Software Engineer writing clean code with proper error handling. Call when implementing features or writing business logic."
|
|
4
|
+
license: "MIT"
|
|
5
|
+
author: "neuqik@hotmail.com"
|
|
6
|
+
version: "2.0"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Software Engineer
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
This skill focuses on:
|
|
14
|
+
- Class/function level code implementation
|
|
15
|
+
- Business logic and domain models
|
|
16
|
+
- Unit testing and integration testing
|
|
17
|
+
- Error handling and validation
|
|
18
|
+
- Code refactoring and optimization
|
|
19
|
+
|
|
20
|
+
**Note**: This is a code implementation skill, focusing on specific business functionality implementation. For architecture design, use **software-architect**; for project initialization, use **system-architect**.
|
|
21
|
+
|
|
22
|
+
## Directory Structure
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
software-engineer/
|
|
26
|
+
├── SKILL.md # Skill definition file
|
|
27
|
+
└── LICENSE # MIT License
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Trigger Conditions
|
|
31
|
+
|
|
32
|
+
**Auto-trigger:**
|
|
33
|
+
- Implementing specific features or functions
|
|
34
|
+
- Writing business logic or service layer code
|
|
35
|
+
- Creating repositories, controllers, or handlers
|
|
36
|
+
- Writing unit tests or integration tests
|
|
37
|
+
- Refactoring existing code
|
|
38
|
+
- Fixing bugs or code quality issues
|
|
39
|
+
|
|
40
|
+
**Manual trigger:**
|
|
41
|
+
- User inputs commands like `/implement`, `/code`, `/refactor`, etc.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Core Rules
|
|
46
|
+
|
|
47
|
+
### 1. Read Before Write
|
|
48
|
+
- Check existing code style, patterns, and conventions before writing new code
|
|
49
|
+
- Respect current tech stack — do not switch libraries without explicit request
|
|
50
|
+
- Match existing naming conventions, formatting, and project structure
|
|
51
|
+
|
|
52
|
+
### 2. Compilable Code
|
|
53
|
+
Every code block must:
|
|
54
|
+
- Use correct imports for actual library versions
|
|
55
|
+
- Use APIs that exist in project dependency versions
|
|
56
|
+
- Pass basic syntax checks — no placeholders `// TODO: implement`
|
|
57
|
+
|
|
58
|
+
### 3. Minimalism First
|
|
59
|
+
- Solve specific problems, not hypothetical future problems
|
|
60
|
+
- Consider abstraction only when there are three concrete cases, not before
|
|
61
|
+
- Features that might be needed → Skip. Features that are needed → Implement
|
|
62
|
+
|
|
63
|
+
### 4. Errors as First-Class Citizens
|
|
64
|
+
```
|
|
65
|
+
❌ catch (e) {}
|
|
66
|
+
❌ catch (e) { console.log(e) }
|
|
67
|
+
✅ catch (e) { logger.error('context', { error: e, input }); throw new DomainError(...) }
|
|
68
|
+
```
|
|
69
|
+
- Typed errors over generic strings
|
|
70
|
+
- Include context: what operation failed, with what input
|
|
71
|
+
- Distinguish recoverable vs fatal errors
|
|
72
|
+
|
|
73
|
+
### 5. Boundaries and Separation
|
|
74
|
+
|
|
75
|
+
| Layer | Contains | Never Contains |
|
|
76
|
+
|---|------|---------|
|
|
77
|
+
| Handler/Controller | HTTP/CLI parsing, validation | Business logic, SQL |
|
|
78
|
+
| Service/Domain | Business rules, orchestration | Infrastructure details |
|
|
79
|
+
| Repository/Adapter | Data access, external APIs | Business decisions |
|
|
80
|
+
|
|
81
|
+
### 6. Explicit Trade-offs
|
|
82
|
+
When making architectural choices, explain:
|
|
83
|
+
- What you chose, and why
|
|
84
|
+
- What you gave up
|
|
85
|
+
- When to revisit the decision
|
|
86
|
+
|
|
87
|
+
Example: "Using SQLite for simplicity. Trade-off: No concurrent writes. Reconsider if >1 write/sec needed."
|
|
88
|
+
|
|
89
|
+
### 7. PR-Ready Code
|
|
90
|
+
Before delivering any code:
|
|
91
|
+
- [ ] No dead code, commented blocks, or debug statements
|
|
92
|
+
- [ ] Functions under 30 lines
|
|
93
|
+
- [ ] No magic numbers — use named constants
|
|
94
|
+
- [ ] Early returns over nested conditions
|
|
95
|
+
- [ ] Handle edge cases: null, empty, error states
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Code Quality Signals
|
|
100
|
+
|
|
101
|
+
**High-level code reads like prose:**
|
|
102
|
+
- Names explain "what" and "why", not "how"
|
|
103
|
+
- Junior engineers can understand in 30 seconds
|
|
104
|
+
- No cleverness that needs comments to explain
|
|
105
|
+
|
|
106
|
+
**The best code is boring:**
|
|
107
|
+
- Predictable patterns
|
|
108
|
+
- Standard library over dependencies when reasonable
|
|
109
|
+
- Explicit over implicit
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Common Pitfalls
|
|
114
|
+
|
|
115
|
+
| Pitfall | Consequence | Prevention |
|
|
116
|
+
|------|------|------|
|
|
117
|
+
| Inventing APIs | Code doesn't compile | Verify methods exist in docs first |
|
|
118
|
+
| Over-engineering | 3 hours instead of 30 minutes | Ask: "Do I have 3 concrete cases?" |
|
|
119
|
+
| Ignoring context | Suggesting wrong tech stack | Read existing files before suggesting |
|
|
120
|
+
| Copy-paste without understanding | Hidden bugs surface later | Explain what code does |
|
|
121
|
+
| Empty error handling | Silent failures in production | Always log + type + rethrow |
|
|
122
|
+
| Premature abstraction | Complexity without benefit | Follow YAGNI until proven needed |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Pragmatic Delivery
|
|
127
|
+
|
|
128
|
+
**Critical Path (Do Right):**
|
|
129
|
+
- Authentication, authorization
|
|
130
|
+
- Payment processing
|
|
131
|
+
- Data integrity, migrations
|
|
132
|
+
- Secrets management
|
|
133
|
+
|
|
134
|
+
**Experimental Path (Ship Fast, Iterate):**
|
|
135
|
+
- UI/UX features
|
|
136
|
+
- Admin panels
|
|
137
|
+
- Analytics
|
|
138
|
+
- Anything unvalidated by users
|
|
139
|
+
|
|
140
|
+
Critical path test: "Could this wake me up at 3am or lose money?"
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Error Handling Best Practices
|
|
145
|
+
|
|
146
|
+
### Use Custom Exceptions
|
|
147
|
+
|
|
148
|
+
**Python Example:**
|
|
149
|
+
```python
|
|
150
|
+
class BusinessError(Exception):
|
|
151
|
+
"""Base exception for business logic errors"""
|
|
152
|
+
pass
|
|
153
|
+
|
|
154
|
+
class ValidationError(BusinessError):
|
|
155
|
+
"""Validation failed"""
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
class NotFoundError(BusinessError):
|
|
159
|
+
"""Resource not found"""
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
class DuplicateError(BusinessError):
|
|
163
|
+
"""Resource already exists"""
|
|
164
|
+
pass
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Java Example:**
|
|
168
|
+
```java
|
|
169
|
+
public class BusinessException extends RuntimeException {
|
|
170
|
+
private final String errorCode;
|
|
171
|
+
|
|
172
|
+
public BusinessException(String errorCode, String message) {
|
|
173
|
+
super(message);
|
|
174
|
+
this.errorCode = errorCode;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public BusinessException(String errorCode, String message, Throwable cause) {
|
|
178
|
+
super(message, cause);
|
|
179
|
+
this.errorCode = errorCode;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
public class ValidationException extends BusinessException {
|
|
184
|
+
public ValidationException(String message) {
|
|
185
|
+
super("VALIDATION_ERROR", message);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Handle at the Right Level
|
|
191
|
+
|
|
192
|
+
- **Handler/Controller**: Catch and convert to HTTP response
|
|
193
|
+
- **Service**: Throw business exceptions
|
|
194
|
+
- **Repository**: Let database exceptions bubble up
|
|
195
|
+
|
|
196
|
+
**Example (Python):**
|
|
197
|
+
```python
|
|
198
|
+
# Service layer - throw business exceptions
|
|
199
|
+
class UserService:
|
|
200
|
+
def create_user(self, user_data):
|
|
201
|
+
if self.user_repository.exists(user_data.email):
|
|
202
|
+
raise DuplicateError(f"User with email {user_data.email} already exists")
|
|
203
|
+
|
|
204
|
+
if not self._validate_email(user_data.email):
|
|
205
|
+
raise ValidationError(f"Invalid email format: {user_data.email}")
|
|
206
|
+
|
|
207
|
+
return self.user_repository.save(user_data)
|
|
208
|
+
|
|
209
|
+
# Handler layer - catch and convert to HTTP response
|
|
210
|
+
@app.post("/users")
|
|
211
|
+
def create_user(request: CreateUserRequest):
|
|
212
|
+
try:
|
|
213
|
+
user = user_service.create_user(request)
|
|
214
|
+
return JSONResponse(user.to_dict(), status_code=201)
|
|
215
|
+
except ValidationError as e:
|
|
216
|
+
return JSONResponse({"error": str(e)}, status_code=400)
|
|
217
|
+
except DuplicateError as e:
|
|
218
|
+
return JSONResponse({"error": str(e)}, status_code=409)
|
|
219
|
+
except Exception as e:
|
|
220
|
+
logger.error(f"Unexpected error creating user: {e}")
|
|
221
|
+
return JSONResponse({"error": "Internal server error"}, status_code=500)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Layered Architecture Example
|
|
227
|
+
|
|
228
|
+
### Project Structure
|
|
229
|
+
```
|
|
230
|
+
src/
|
|
231
|
+
├── handlers/ # HTTP/CLI handlers
|
|
232
|
+
│ └── user_handler.py
|
|
233
|
+
├── services/ # Business logic
|
|
234
|
+
│ └── user_service.py
|
|
235
|
+
├── repositories/ # Data access
|
|
236
|
+
│ └── user_repository.py
|
|
237
|
+
├── models/ # Domain models
|
|
238
|
+
│ └── user.py
|
|
239
|
+
└── exceptions/ # Custom exceptions
|
|
240
|
+
└── errors.py
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Handler Layer
|
|
244
|
+
```python
|
|
245
|
+
# handlers/user_handler.py
|
|
246
|
+
from flask import request, jsonify
|
|
247
|
+
from services.user_service import UserService
|
|
248
|
+
from exceptions.errors import ValidationError, DuplicateError
|
|
249
|
+
|
|
250
|
+
class UserHandler:
|
|
251
|
+
def __init__(self, user_service: UserService):
|
|
252
|
+
self.user_service = user_service
|
|
253
|
+
|
|
254
|
+
def create_user(self):
|
|
255
|
+
try:
|
|
256
|
+
data = request.get_json()
|
|
257
|
+
user = self.user_service.create_user(data)
|
|
258
|
+
return jsonify(user.to_dict()), 201
|
|
259
|
+
except ValidationError as e:
|
|
260
|
+
return jsonify({"error": str(e)}), 400
|
|
261
|
+
except DuplicateError as e:
|
|
262
|
+
return jsonify({"error": str(e)}), 409
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Service Layer
|
|
266
|
+
```python
|
|
267
|
+
# services/user_service.py
|
|
268
|
+
from repositories.user_repository import UserRepository
|
|
269
|
+
from models.user import User
|
|
270
|
+
from exceptions.errors import ValidationError, DuplicateError
|
|
271
|
+
|
|
272
|
+
class UserService:
|
|
273
|
+
def __init__(self, user_repository: UserRepository):
|
|
274
|
+
self.user_repository = user_repository
|
|
275
|
+
|
|
276
|
+
def create_user(self, data: dict) -> User:
|
|
277
|
+
# Business validation
|
|
278
|
+
if not data.get('email'):
|
|
279
|
+
raise ValidationError("Email is required")
|
|
280
|
+
|
|
281
|
+
if self.user_repository.exists_by_email(data['email']):
|
|
282
|
+
raise DuplicateError(f"User with email {data['email']} already exists")
|
|
283
|
+
|
|
284
|
+
# Create user
|
|
285
|
+
user = User(
|
|
286
|
+
email=data['email'],
|
|
287
|
+
name=data.get('name'),
|
|
288
|
+
created_at=datetime.utcnow()
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
return self.user_repository.save(user)
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Repository Layer
|
|
295
|
+
```python
|
|
296
|
+
# repositories/user_repository.py
|
|
297
|
+
from models.user import User
|
|
298
|
+
from sqlalchemy.orm import Session
|
|
299
|
+
|
|
300
|
+
class UserRepository:
|
|
301
|
+
def __init__(self, session: Session):
|
|
302
|
+
self.session = session
|
|
303
|
+
|
|
304
|
+
def save(self, user: User) -> User:
|
|
305
|
+
self.session.add(user)
|
|
306
|
+
self.session.commit()
|
|
307
|
+
return user
|
|
308
|
+
|
|
309
|
+
def exists_by_email(self, email: str) -> bool:
|
|
310
|
+
return self.session.query(User).filter(User.email == email).first() is not None
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Testing Best Practices
|
|
316
|
+
|
|
317
|
+
### Unit Test Structure (AAA Pattern)
|
|
318
|
+
```python
|
|
319
|
+
def test_create_user_success():
|
|
320
|
+
# Arrange
|
|
321
|
+
user_data = {"email": "test@example.com", "name": "Test User"}
|
|
322
|
+
mock_repo = Mock()
|
|
323
|
+
mock_repo.exists_by_email.return_value = False
|
|
324
|
+
mock_repo.save.return_value = User(**user_data)
|
|
325
|
+
service = UserService(mock_repo)
|
|
326
|
+
|
|
327
|
+
# Act
|
|
328
|
+
result = service.create_user(user_data)
|
|
329
|
+
|
|
330
|
+
# Assert
|
|
331
|
+
assert result.email == "test@example.com"
|
|
332
|
+
assert result.name == "Test User"
|
|
333
|
+
mock_repo.exists_by_email.assert_called_once_with("test@example.com")
|
|
334
|
+
mock_repo.save.assert_called_once()
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Test Edge Cases
|
|
338
|
+
```python
|
|
339
|
+
def test_create_user_duplicate_email():
|
|
340
|
+
# Arrange
|
|
341
|
+
user_data = {"email": "existing@example.com"}
|
|
342
|
+
mock_repo = Mock()
|
|
343
|
+
mock_repo.exists_by_email.return_value = True
|
|
344
|
+
service = UserService(mock_repo)
|
|
345
|
+
|
|
346
|
+
# Act & Assert
|
|
347
|
+
with pytest.raises(DuplicateError):
|
|
348
|
+
service.create_user(user_data)
|
|
349
|
+
|
|
350
|
+
def test_create_user_missing_email():
|
|
351
|
+
# Arrange
|
|
352
|
+
user_data = {"name": "Test User"}
|
|
353
|
+
service = UserService(Mock())
|
|
354
|
+
|
|
355
|
+
# Act & Assert
|
|
356
|
+
with pytest.raises(ValidationError, match="Email is required"):
|
|
357
|
+
service.create_user(user_data)
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## Collaboration Table
|
|
363
|
+
|
|
364
|
+
### Collaboration with Other Skills
|
|
365
|
+
|
|
366
|
+
| Collaborating Skill | Collaboration Mode | Description |
|
|
367
|
+
|---------|---------|------|
|
|
368
|
+
| **software-architect** | Consult | Get architecture decision context before implementation |
|
|
369
|
+
| **system-architect** | Consult | Consult when project structure issues arise |
|
|
370
|
+
| **expert-code-quality** | Reference | Perform quality check after code implementation |
|
|
371
|
+
| **pdd-implement-feature** | Sequential | PDD project feature implementation |
|
|
372
|
+
| **test-driven-development** | Sequential | Write tests first, then implement |
|
|
373
|
+
| **expert-ruoyi** | Consult | Consult when implementing RuoYi framework projects |
|
|
374
|
+
|
|
375
|
+
### Collaboration Workflow
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
Feature Implementation Request
|
|
379
|
+
↓
|
|
380
|
+
Invoke software-engineer
|
|
381
|
+
↓
|
|
382
|
+
(If architecture decisions needed) → Invoke software-architect
|
|
383
|
+
↓
|
|
384
|
+
(If tests needed first) → Invoke test-driven-development
|
|
385
|
+
↓
|
|
386
|
+
Code Implementation
|
|
387
|
+
↓
|
|
388
|
+
(If code quality check needed) → Invoke expert-code-quality
|
|
389
|
+
↓
|
|
390
|
+
Feature Implementation Complete
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Code Review Checklist
|
|
396
|
+
|
|
397
|
+
Verify before submitting code:
|
|
398
|
+
|
|
399
|
+
- [ ] **Functionality**: Does it solve the problem?
|
|
400
|
+
- [ ] **Testing**: Are there tests for happy path and edge cases?
|
|
401
|
+
- [ ] **Error Handling**: Are errors properly typed and logged?
|
|
402
|
+
- [ ] **Naming**: Are names clear and self-documenting?
|
|
403
|
+
- [ ] **Structure**: Is code in the right layer?
|
|
404
|
+
- [ ] **Dependencies**: Are imports correct for project versions?
|
|
405
|
+
- [ ] **Security**: Is input validated? Are secrets handled properly?
|
|
406
|
+
- [ ] **Performance**: Are there obvious performance issues?
|
|
407
|
+
- [ ] **Documentation**: Are complex decisions documented?
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Guardrails
|
|
412
|
+
|
|
413
|
+
- Code implementation must follow project's existing code style and patterns
|
|
414
|
+
- Must use correct imports and APIs (verify project versions)
|
|
415
|
+
- Error handling must include context, no swallowing exceptions
|
|
416
|
+
- Code must compile, no placeholders or TODOs
|
|
417
|
+
- Must verify functionality correctness before submission
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Version History
|
|
422
|
+
|
|
423
|
+
### v2.0 (2026-03-21)
|
|
424
|
+
- Unified to English descriptions
|
|
425
|
+
- Added collaboration table, clarifying collaboration with other skills
|
|
426
|
+
- Enhanced error handling best practices
|
|
427
|
+
- Added layered architecture examples
|
|
428
|
+
- Standardized output format
|
|
429
|
+
|
|
430
|
+
### v1.0 (Initial Version)
|
|
431
|
+
- Basic code implementation rules
|
|
432
|
+
- Error handling patterns
|
|
433
|
+
- Testing best practices
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
> **Remember**: Good code isn't about being clever — it's about being clear. Write simple, maintainable, testable code.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name": "software-engineer", "version": "1.0.0", "category": "expert", "description": "Production-ready software engineer writing clean code with proper architecture, error handling, and pragmatic trade-offs. Implement features, write business logic, create services, or build any code that needs to be production-ready. Focuses on code-level implementation with industry-standard patterns and security practices. 支持中文触发:软件开发、代码实现、功能实现、后端开发、API开发、工程实践。", "triggers": ["软件开发", "代码实现", "功能实现", "后端开发", "API开发"]}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Architecture Decisions — Software Engineer
|
|
2
|
+
|
|
3
|
+
## Layer Boundaries
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
┌─────────────────────────────────────┐
|
|
7
|
+
│ Handlers / Controllers / Routes │ ← HTTP parsing, validation
|
|
8
|
+
├─────────────────────────────────────┤
|
|
9
|
+
│ Services / Use Cases / Domain │ ← Business logic, orchestration
|
|
10
|
+
├─────────────────────────────────────┤
|
|
11
|
+
│ Repositories / Adapters / Gateways │ ← Data access, external APIs
|
|
12
|
+
├─────────────────────────────────────┤
|
|
13
|
+
│ Infrastructure / Config │ ← DB connections, env vars
|
|
14
|
+
└─────────────────────────────────────┘
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### What Lives Where
|
|
18
|
+
|
|
19
|
+
| Layer | Allowed | Forbidden |
|
|
20
|
+
|-------|---------|-----------|
|
|
21
|
+
| Handler | Parse request, validate schema, call service | SQL, business rules |
|
|
22
|
+
| Service | Business logic, coordinate repos | HTTP details, raw SQL |
|
|
23
|
+
| Repository | Data access, query building | Business decisions |
|
|
24
|
+
| Infrastructure | Connections, configs | Business logic |
|
|
25
|
+
|
|
26
|
+
## When to Abstract
|
|
27
|
+
|
|
28
|
+
**Create abstraction when:**
|
|
29
|
+
- You have 3+ concrete implementations
|
|
30
|
+
- You need to swap implementations (testing, different environments)
|
|
31
|
+
- The boundary naturally exists (external API, database)
|
|
32
|
+
|
|
33
|
+
**Do NOT abstract when:**
|
|
34
|
+
- You have 1 concrete case
|
|
35
|
+
- "Maybe we'll need this later"
|
|
36
|
+
- To follow a pattern for pattern's sake
|
|
37
|
+
|
|
38
|
+
## Dependency Direction
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Domain ← Application ← Infrastructure
|
|
42
|
+
↑
|
|
43
|
+
Never reversed
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Domain/core should have no dependencies on infrastructure. Use interfaces/ports.
|
|
47
|
+
|
|
48
|
+
## Configuration Strategy
|
|
49
|
+
|
|
50
|
+
**Environment-based:**
|
|
51
|
+
```
|
|
52
|
+
.env.development # Local defaults
|
|
53
|
+
.env.production # Production values (never committed)
|
|
54
|
+
.env.example # Template with dummy values (committed)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Access pattern:**
|
|
58
|
+
```typescript
|
|
59
|
+
const config = {
|
|
60
|
+
db: {
|
|
61
|
+
host: env.DB_HOST || 'localhost',
|
|
62
|
+
port: parseInt(env.DB_PORT || '5432'),
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Never access `process.env` directly throughout codebase — centralize in config.
|
|
68
|
+
|
|
69
|
+
## Database Decisions
|
|
70
|
+
|
|
71
|
+
| Scale | Recommendation |
|
|
72
|
+
|-------|----------------|
|
|
73
|
+
| <10K rows, single writer | SQLite |
|
|
74
|
+
| <1M rows, moderate concurrency | PostgreSQL |
|
|
75
|
+
| High read, eventual consistency OK | Add Redis cache |
|
|
76
|
+
| >1M rows, complex queries | PostgreSQL + read replicas |
|
|
77
|
+
|
|
78
|
+
**Migration rules:**
|
|
79
|
+
- Always reversible (up + down)
|
|
80
|
+
- Never destructive without backup verified
|
|
81
|
+
- Small, incremental changes
|
|
82
|
+
- Test on production copy first
|
|
83
|
+
|
|
84
|
+
## API Design
|
|
85
|
+
|
|
86
|
+
**RESTful conventions:**
|
|
87
|
+
```
|
|
88
|
+
GET /users # List
|
|
89
|
+
GET /users/:id # Get one
|
|
90
|
+
POST /users # Create
|
|
91
|
+
PUT /users/:id # Replace
|
|
92
|
+
PATCH /users/:id # Update
|
|
93
|
+
DELETE /users/:id # Remove
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Response structure:**
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"data": { ... },
|
|
100
|
+
"meta": { "page": 1, "total": 100 },
|
|
101
|
+
"error": null
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Or on error:
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"data": null,
|
|
109
|
+
"error": {
|
|
110
|
+
"code": "VALIDATION_ERROR",
|
|
111
|
+
"message": "Email is required",
|
|
112
|
+
"field": "email"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Scaling Checkpoints
|
|
118
|
+
|
|
119
|
+
| Symptom | First Action |
|
|
120
|
+
|---------|--------------|
|
|
121
|
+
| Slow reads | Add index, check query plans |
|
|
122
|
+
| High latency | Add caching layer |
|
|
123
|
+
| CPU bound | Profile, optimize hot paths |
|
|
124
|
+
| Memory pressure | Check for leaks, reduce in-memory data |
|
|
125
|
+
| Single point of failure | Add health checks, basic redundancy |
|
|
126
|
+
|
|
127
|
+
**Don't prematurely:**
|
|
128
|
+
- Add microservices (monolith is fine for a long time)
|
|
129
|
+
- Add Kubernetes (Docker Compose works to 100K users)
|
|
130
|
+
- Add message queues (sync is fine until proven otherwise)
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Code Patterns — Software Engineer
|
|
2
|
+
|
|
3
|
+
## Naming
|
|
4
|
+
|
|
5
|
+
| Type | Pattern | Example |
|
|
6
|
+
|------|---------|---------|
|
|
7
|
+
| Boolean | `is`, `has`, `should`, `can` | `isActive`, `hasPermission` |
|
|
8
|
+
| Function | verb + noun | `getUserById`, `validateEmail` |
|
|
9
|
+
| Handler | `handle` + event | `handleSubmit`, `handleError` |
|
|
10
|
+
| Transform | `to` + target | `toDTO`, `toJSON` |
|
|
11
|
+
|
|
12
|
+
**Avoid:** `data`, `info`, `temp`, `result`, `handle` without context.
|
|
13
|
+
|
|
14
|
+
## Function Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
function goodFunction(input) {
|
|
18
|
+
// 1. Validate early, return/throw fast
|
|
19
|
+
if (!input) throw new ValidationError('input required');
|
|
20
|
+
|
|
21
|
+
// 2. Main logic (single responsibility)
|
|
22
|
+
const processed = transform(input);
|
|
23
|
+
|
|
24
|
+
// 3. Return explicitly
|
|
25
|
+
return processed;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Max lines:** 20-30. If longer, extract.
|
|
30
|
+
|
|
31
|
+
## Error Handling Patterns
|
|
32
|
+
|
|
33
|
+
### Typed Errors
|
|
34
|
+
```typescript
|
|
35
|
+
class DomainError extends Error {
|
|
36
|
+
constructor(
|
|
37
|
+
message: string,
|
|
38
|
+
public code: string,
|
|
39
|
+
public context?: Record<string, unknown>
|
|
40
|
+
) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.name = 'DomainError';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Usage
|
|
47
|
+
throw new DomainError('User not found', 'USER_NOT_FOUND', { userId });
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Result Pattern (No Exceptions)
|
|
51
|
+
```typescript
|
|
52
|
+
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
|
|
53
|
+
|
|
54
|
+
function divide(a: number, b: number): Result<number, 'DIVISION_BY_ZERO'> {
|
|
55
|
+
if (b === 0) return { ok: false, error: 'DIVISION_BY_ZERO' };
|
|
56
|
+
return { ok: true, value: a / b };
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Conditional Patterns
|
|
61
|
+
|
|
62
|
+
### Early Returns
|
|
63
|
+
```
|
|
64
|
+
// ❌ Pyramid
|
|
65
|
+
function process(user) {
|
|
66
|
+
if (user) {
|
|
67
|
+
if (user.active) {
|
|
68
|
+
if (user.verified) {
|
|
69
|
+
return doWork(user);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ✅ Flat
|
|
77
|
+
function process(user) {
|
|
78
|
+
if (!user) return null;
|
|
79
|
+
if (!user.active) return null;
|
|
80
|
+
if (!user.verified) return null;
|
|
81
|
+
return doWork(user);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Guard Clauses
|
|
86
|
+
Put validation at the top, happy path at the bottom.
|
|
87
|
+
|
|
88
|
+
## Async Patterns
|
|
89
|
+
|
|
90
|
+
### Sequential (when order matters)
|
|
91
|
+
```javascript
|
|
92
|
+
const user = await getUser(id);
|
|
93
|
+
const orders = await getOrders(user.id);
|
|
94
|
+
const summary = await buildSummary(orders);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Parallel (when independent)
|
|
98
|
+
```javascript
|
|
99
|
+
const [user, config, permissions] = await Promise.all([
|
|
100
|
+
getUser(id),
|
|
101
|
+
getConfig(),
|
|
102
|
+
getPermissions(id)
|
|
103
|
+
]);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Error Boundaries
|
|
107
|
+
```javascript
|
|
108
|
+
try {
|
|
109
|
+
await riskyOperation();
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error instanceof NetworkError) {
|
|
112
|
+
// Retry logic
|
|
113
|
+
} else if (error instanceof ValidationError) {
|
|
114
|
+
// Return user-friendly message
|
|
115
|
+
} else {
|
|
116
|
+
// Log and rethrow unknown errors
|
|
117
|
+
logger.error('Unexpected error', { error });
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Immutability Patterns
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
// ❌ Mutation
|
|
127
|
+
user.name = newName;
|
|
128
|
+
users.push(newUser);
|
|
129
|
+
|
|
130
|
+
// ✅ New object
|
|
131
|
+
const updatedUser = { ...user, name: newName };
|
|
132
|
+
const updatedUsers = [...users, newUser];
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Dependency Injection (Simple)
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// ❌ Hard coupling
|
|
139
|
+
class UserService {
|
|
140
|
+
private db = new Database();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ✅ Injection
|
|
144
|
+
class UserService {
|
|
145
|
+
constructor(private db: Database) {}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Usage
|
|
149
|
+
const service = new UserService(new PostgresDatabase());
|
|
150
|
+
const testService = new UserService(new MockDatabase());
|
|
151
|
+
```
|