coding-effectively
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCoding Effectively
高效编码
Required Sub-Skills
必备子技能
ALWAYS REQUIRED:
- - Separate pure logic from side effects
howto-functional-vs-imperative - - Validate at every layer data passes through
defense-in-depth
CONDITIONAL: Use these sub-skills when applicable:
- - TypeScript code
howto-code-in-typescript - - PostgreSQL database code
howto-develop-with-postgres - - React frontend code
programming-in-react - - Writing or reviewing tests
writing-good-tests - - Tests for serialization, validation, normalization, pure functions
property-based-testing
必须掌握:
- - 将纯逻辑与副作用分离
howto-functional-vs-imperative - - 在数据流经的每一层都进行验证
defense-in-depth
按需使用: 在适用场景下使用以下子技能:
- - TypeScript 代码编写
howto-code-in-typescript - - PostgreSQL 数据库代码开发
howto-develop-with-postgres - - React 前端代码开发
programming-in-react - - 编写或评审测试用例
writing-good-tests - - 序列化、验证、归一化、纯函数相关测试
property-based-testing
Property-Driven Design
属性驱动设计
When designing features, think about properties upfront. This surfaces design gaps early.
Discovery questions:
| Question | Property Type | Example |
|---|---|---|
| Does it have an inverse operation? | Roundtrip | |
| Is applying it twice the same as once? | Idempotence | |
| What quantities are preserved? | Invariants | Length, sum, count unchanged |
| Is order of arguments irrelevant? | Commutativity | |
| Can operations be regrouped? | Associativity | |
| Is there a neutral element? | Identity | |
| Is there a reference implementation? | Oracle | |
| Can output be easily verified? | Easy to verify | |
Common design questions these reveal:
- "What about deleted/deactivated entities?"
- "Case-sensitive or not?"
- "Stable sort or not? Tie-breaking rules?"
- "Which algorithm? Configurable?"
Surface these during design, not during debugging.
在设计功能时,提前考虑属性特性。这能尽早暴露设计缺陷。
探索性问题:
| 问题 | 属性类型 | 示例 |
|---|---|---|
| 是否存在逆运算? | 往返一致性 | |
| 执行两次与执行一次结果是否相同? | 幂等性 | |
| 哪些量会被保留? | 不变量 | 长度、总和、计数保持不变 |
| 参数顺序是否不影响结果? | 交换律 | |
| 运算是否可重新组合? | 结合律 | |
| 是否存在单位元? | 单位元特性 | |
| 是否有参考实现? | 基准实现 | |
| 输出是否易于验证? | 易验证性 | |
这些问题能揭示的常见设计疑问:
- "已删除/停用的实体该如何处理?"
- "是否区分大小写?"
- "是否为稳定排序?排序规则是什么?"
- "使用哪种算法?是否可配置?"
在设计阶段就提出这些问题,而非等到调试时才发现。
Core Engineering Principles
核心工程原则
Correctness Over Convenience
正确性优先于便利性
Model the full error space. No shortcuts.
- Handle all edge cases: race conditions, timing issues, partial failures
- Use the type system to encode correctness constraints
- Prefer compile-time guarantees over runtime checks where possible
- When uncertain, explore and iterate rather than assume
Don't:
- Simplify error handling to save time
- Ignore edge cases because "they probably won't happen"
- Use or equivalent to bypass type checking
any
完整建模错误场景,绝不走捷径。
- 处理所有边缘情况:竞态条件、时序问题、部分失败场景
- 利用类型系统编码正确性约束
- 尽可能优先选择编译时保障而非运行时检查
- 不确定时,先探索迭代而非直接假设
禁止:
- 为节省时间简化错误处理
- 因“大概率不会发生”而忽略边缘情况
- 使用 或等效方式绕过类型检查
any
Error Handling Philosophy
错误处理理念
Two-tier model:
- User-facing errors: Semantic exit codes, rich diagnostics, actionable messages
- Internal errors: Programming errors that may panic or use internal types
Error message format: Lowercase sentence fragments for "failed to {message}".
Good: failed to connect to database: connection refused
Bad: Failed to Connect to Database: Connection Refused
Good: invalid configuration: missing required field 'apiKey'
Bad: Invalid Configuration: Missing Required Field 'apiKey'Lowercase fragments compose naturally: reads correctly.
"operation failed: " + error.message双层模型:
- 面向用户的错误:语义化退出码、丰富的诊断信息、可执行的提示消息
- 内部错误:可能触发 panic 或使用内部类型的编程错误
错误消息格式: 采用小写句子片段,格式为 "failed to {message}"。
正确示例: failed to connect to database: connection refused
错误示例: Failed to Connect to Database: Connection Refused
正确示例: invalid configuration: missing required field 'apiKey'
错误示例: Invalid Configuration: Missing Required Field 'apiKey'小写片段可自然组合: 读起来更通顺。
"operation failed: " + error.messagePragmatic Incrementalism
务实的增量式开发
- Prefer specific, composable logic over abstract frameworks
- Evolve design incrementally rather than perfect upfront architecture
- Don't build for hypothetical future requirements
- Document design decisions and trade-offs when making non-obvious choices
The rule of three applies to abstraction: Don't abstract until you've seen the pattern three times. Three similar lines of code is better than a premature abstraction.
- 优先选择具体、可组合的逻辑而非抽象框架
- 逐步演进设计,而非追求一蹴而就的完美架构
- 不为假设性的未来需求提前构建功能
- 做出非显而易见的选择时,记录设计决策和权衡点
抽象的三次原则: 不要过早抽象,直到你看到该模式出现三次。三段相似的代码比过早抽象更易维护。
File Organization
文件组织规范
Descriptive File Names Over Catch-All Files
使用描述性文件名,而非通用兜底文件
Name files by what they contain, not by generic categories.
Don't create:
- - Becomes a dumping ground for unrelated functions
utils.ts - - Same problem
helpers.ts - - What isn't common?
common.ts - - Actively unhelpful
misc.ts
Do create:
- - String manipulation utilities
string-formatting.ts - - Date calculations
date-arithmetic.ts - - API error utilities
api-error-handling.ts - - User input validation
user-validation.ts
Why this matters:
- Discoverability: Developers find code by scanning file names
- Cohesion: Related code stays together
- Prevents bloat: Hard to add unrelated code to
string-formatting.ts - Import clarity: is self-documenting
import { formatDate } from './date-arithmetic'
When you're tempted to create utils.ts: Stop. Ask what the functions have in common. Name the file after that commonality.
根据文件内容命名,而非使用通用类别名称。
禁止创建:
- - 会沦为无关函数的“垃圾桶”
utils.ts - - 存在同样问题
helpers.ts - - 什么内容不算“通用”?
common.ts - - 完全无帮助
misc.ts
建议创建:
- - 字符串处理工具
string-formatting.ts - - 日期计算工具
date-arithmetic.ts - - API 错误处理工具
api-error-handling.ts - - 用户输入验证工具
user-validation.ts
为何重要:
- 可发现性:开发者通过扫描文件名就能找到代码
- 内聚性:相关代码集中在一起
- 防止膨胀:很难将无关代码加入
string-formatting.ts - 导入清晰:自带文档属性
import { formatDate } from './date-arithmetic'
当你想创建utils.ts时: 停下来,思考这些函数的共性,根据共性命名文件。
Module Organization
模块组织
- Keep module boundaries strict with restricted visibility
- Platform-specific code in separate files: ,
unix.ts,windows.tsposix.ts - Use conditional compilation or runtime checks for platform branching
- Test helpers in dedicated modules/files, not mixed with production code
- 严格划分模块边界,限制可见性
- 平台特定代码放在单独文件中:、
unix.ts、windows.tsposix.ts - 使用条件编译或运行时检查处理平台分支逻辑
- 测试辅助代码放在专用模块/文件中,不要与生产代码混合
Cross-Platform Principles
跨平台开发原则
Use OS-Native Logic
使用操作系统原生逻辑
Don't emulate Unix on Windows or vice versa. Use each platform's native patterns.
Bad: Trying to make Windows paths behave like Unix paths everywhere.
Good: Accept platform differences, handle them explicitly.
typescript
// Platform-specific behavior
if (process.platform === 'win32') {
// Windows-native approach
} else {
// POSIX approach
}不要在 Windows 上模拟 Unix 行为,反之亦然。使用各平台的原生模式。
错误做法: 试图让 Windows 路径在所有场景下都表现得像 Unix 路径。
正确做法: 接受平台差异,显式处理这些差异。
typescript
// 平台特定行为
if (process.platform === 'win32') {
// Windows 原生实现
} else {
// POSIX 实现
}Platform-Specific Files
平台专属文件
When platform differences are significant, use separate files:
process-spawn.ts // Shared interface and logic
process-spawn-unix.ts // Unix-specific implementation
process-spawn-windows.ts // Windows-specific implementation当平台差异较大时,使用单独文件:
process-spawn.ts // 共享接口和逻辑
process-spawn-unix.ts // Unix 专属实现
process-spawn-windows.ts // Windows 专属实现Document Platform Differences
记录平台差异
When behavior differs by platform, document it in comments:
typescript
// On Windows, this returns CRLF line endings.
// On Unix, this returns LF line endings.
// Callers should normalize if consistent output is needed.
function readTextFile(path: string): string { ... }当行为因平台不同而变化时,在注释中记录:
typescript
// 在 Windows 系统中,此函数返回 CRLF 换行符。
// 在 Unix 系统中,此函数返回 LF 换行符。
// 如果需要一致的输出,调用方应自行归一化处理。
function readTextFile(path: string): string { ... }Test on All Target Platforms
在所有目标平台上测试
Don't assume Unix behavior works on Windows. Test explicitly:
- CI should run on all supported platforms
- Platform-specific code paths need platform-specific tests
- Document which platforms are supported
不要假设 Unix 行为能在 Windows 上正常工作。需显式测试:
- CI 应在所有支持的平台上运行
- 平台特定代码路径需要对应平台的测试用例
- 记录支持的平台列表
Common Mistakes
常见错误
| Mistake | Reality | Fix |
|---|---|---|
| "Just put it in utils for now" | utils.ts becomes 2000 lines of unrelated code | Name files by purpose from the start |
| "Edge cases are rare" | Edge cases cause production incidents | Handle them. Model the full error space. |
| "We might need this abstraction later" | Premature abstraction is harder to remove than add | Wait for the third use case |
| "It works on my Mac" | It may not work on Windows or Linux | Test on target platforms |
| "The type system is too strict" | Strictness catches bugs at compile time | Fix the type error, don't bypass it |
| 错误做法 | 实际问题 | 修复方案 |
|---|---|---|
| “先暂时放到utils里” | utils.ts 会膨胀到2000行无关代码 | 从一开始就根据用途命名文件 |
| “边缘情况很少见” | 边缘情况会引发生产事故 | 处理这些情况,完整建模错误场景 |
| “以后可能需要这个抽象” | 过早抽象比后期添加抽象更难移除 | 等第三次遇到相同模式时再抽象 |
| “在我的Mac上能正常运行” | 在 Windows 或 Linux 上可能无法运行 | 在目标平台上测试 |
| “类型系统太严格了” | 严格的类型检查能在编译时捕获bug | 修复类型错误,不要绕过类型系统 |
Red Flags
危险信号
Stop and refactor when you see:
- A or
utils.tsfile growing beyond 200 lineshelpers.ts - Error handling that swallows errors or uses generic messages
- Platform-specific code mixed with cross-platform code
- Abstractions created for single use cases
- Type assertions () to bypass the type system
as any - Code that "works on my machine" but isn't tested cross-platform
遇到以下情况时,请立即停止并重构:
- 或
utils.ts文件超过200行helpers.ts - 错误处理吞掉错误或使用通用提示消息
- 平台特定代码与跨平台代码混合在一起
- 为单一使用场景创建抽象
- 使用类型断言 () 绕过类型系统
as any - “在我机器上能运行”但未进行跨平台测试的代码