“能稳定运行的普通写法,远比花哨但记不住的新特性重要。” —— 这不是保守,而是被无数工程验证过的智慧。本文不谈虚的,只记录真正让代码容易理解、容易维护、不易出错的务实原则。面向专业程序员,不解释基础语法,不写废话注释。
变量名多打几个字符不会让程序变慢,但少打几个字符会让维护者想打人。好的命名就是最好的注释。
// ❌ 不知所云
var a = GetData();
var b = a.Where(x => x.Status == 1).ToList();
// ✅ 自解释
var allOrders = GetOrders();
var activeOrders = allOrders.Where(order => order.Status == OrderStatus.Active).ToList();
例外:循环变量 i, j, k 和极短作用域的临时变量 tmp 可保留传统。
一个函数不应超过一屏 (40~50行)。超过就意味着它做了太多事,拆分是义务,不是重构。
// ❌ 巨型函数,注释分段也救不了
public void ProcessOrder(Order order) {
// 验证... 20行
// 价格计算... 25行
// 数据库保存... 20行
}
// ✅ 职责单一,函数名即文档
public void ProcessOrder(Order order) {
Validate(order);
CalculatePrice(order);
Save(order);
Notify(order);
}
嵌套超过3层,大脑开始烧毁。用卫语句提前返回异常路径,主干保持平坦。
// ❌ 箭头型代码
if (user != null) {
if (user.IsActive) {
if (user.HasPermission) {
// 核心逻辑
}
}
}
// ✅ 卫语句,清晰直接
if (user == null) return;
if (!user.IsActive) return;
if (!user.HasPermission) return;
// 核心逻辑
同一段代码出现3次,必须抽取函数。复制粘贴是技术债务的源头。
// 出现两次可能还能忍,第三次必须抽离
decimal CalculateTotal(Order order) => order.Items.Sum(i => i.Price * i.Quantity);
代码里出现原始数字必须给名字,即使你认为自己记得住。
// ❌ 幽灵数字
if (age >= 18) { }
Thread.Sleep(3000);
// ✅ 语义化常量
const int VotingAge = 18;
Thread.Sleep(TimeSpan.FromSeconds(3));
专业程序员的代码本身就是注释。注释的唯一价值是解释业务规则/陷阱/临时方案。
// ❌ 废话注释
// i加1
i++;
// ✅ 解释原因
// 等待3秒,确保主从同步完成
Thread.Sleep(3000);
// 使用 > 而不是 >= ,因为状态2表示“待审核”,不应该包含
if (status > OrderStatus.Pending) { }
不确定怎么处理的异常,就不要catch。吞掉异常会让程序在错误状态里狂奔,比崩溃更可怕。
// ❌ 沉默的灾难
try { DoSomething(); } catch { }
// ✅ 只处理明确可恢复的异常
try {
DoSomething();
} catch (SpecificException ex) {
LogAndRecover(ex);
}
// 其他异常向上抛出,由上层决策
日志必须包含上下文:谁、做了什么、影响什么对象、结果如何。不写只有你自己才懂的暗号。
// ❌ 无效日志
Log("开始处理");
// ✅ 可追溯
Log($"用户 {userId} 处理订单 {orderId},耗时 {elapsedMs}ms,状态 {status}");
在已有项目里,保持一致 优先于个人偏好。先看周围代码怎么写,然后跟随,不要搞特殊。
// 项目里大家都用 userList,你就别发明 userArr
var userList = GetUsers(); // 团队风格
var userList = GetUsers(); // 跟随,不要写 lstUser
一行行解释代码在做什么,是对同事的侮辱。注释只用于:
下面这张表是日常编码最实用的「决策速查」。
| 场景 | 务实原则 |
|---|---|
| 变量命名 | 名字长度和作用域成正比,全局/长作用域命名要详细 |
| 函数拆分 | 看到注释“步骤1/步骤2” → 立刻拆成小函数 |
| 条件复杂度 | if嵌套 > 2层 → 改用早返回或提取谓词函数 |
| 重复检测 | Copy-paste 两次就警惕,三次必须抽象 |
| 异常处理 | 只捕获你能处理的,否则让调用方决定 |
| 代码格式化 | 团队统一 .editorconfig / 格式化工具,不要手动对齐 |
| review重点 | 命名、嵌套、重复、异常吞噬、魔法数字 |
语言新特性是工具,不是勋章。记不住的就用旧写法,稳定优先。例如 C# 的 out var 内联声明,可用也可不用,对性能无影响,选团队最容易读的版本。
// 两种都可以,选你团队一看就懂的
int v;
if (dict.TryGetValue(key, out v)) { }
// 或者内联版本,但没必要刻意追求
if (dict.TryGetValue(key, out int v)) { }
原则:你写的代码三个月后大概率由另一个人维护,降低认知负担是最大的仁慈。
代码是写给人看的,只是恰好能被机器执行。
坚持务实,保持简单。不炫技,不设限。