规则是写代码时的约束——变量命名方式、方法排序、第一行必须判空等等。它们管的是表面,是屏幕上文本的形态,靠惯例、审查者和 linter 来执行。结构则是代码真正的组织方式:职责落在哪些类里,边界划在哪里,数据如何流动。结构是文本底层的架构,决定了代码是否真的易于维护。规则与结构是表亲,相互影响,好的两者都能让代码库舒适,但它们不是一回事。
很多人混淆了它们,于是用规则去解决只有结构才能修复的问题,而规则是有代价的。每一条规则都是团队必须记住、应用并永远执行的约束。超过某个点后,它就不再让代码变好,反而让工作变差:开发变慢、PR变成风格争论、同事间积累摩擦。规则的成本是停滞和内耗。
一个常见的例子:某个类负责读取数据、转换后写入另一处。规则驱动的方法会不断加码:先加注释段,再要求XML文档,又要求变量名带read/write前缀。每步看似合理,合在一起却是用脚手架支撑一个本来就不好的形状——你在用规则补偿结构的缺失。
结构驱动的方法则问:为什么全塞在一个类?拆成 IReader、ITransformer、IWriter 后,读写各自有独立作用域,命名规则要解决的问题自然消失了。规则应该辅助已工作的结构,而不是替代它。
为什么团队倾向先加规则?因为“永远列出来”“加个文档”“重命名”在审查里只是一句话,听上去负责。而真正思考底层结构需要时间、精力,往往意味着更大的改动。于是我们在PR里贴创可贴,而不是根治。账单体现在一个很少被测量的地方:记忆力。一个人写代码时能同时记住的惯例有限(大约二十到三十条),每条自定规则都在消耗这个额度,超出后人们开始彼此责备,却忘了这个任务本身就不合理。
想象一条布满坑洞的路。坑洞是结构的真正问题,规则是引导车辆绕行。CI、测试、linter 是锥筒和护栏——并非坏事,但引导车辆绕开坑洞并不会填平坑洞。结构是把路重铺一遍。路平了,多数绕行规则就不再需要了。
我个人赞成语言惯例规则(如私有字段下划线)和团队协作规则(如公共函数需XML文档)。但反对那些伪装成结构的规则,比如“枚举必须用模式匹配”“函数第一行必须判空”“LINQ 超过三个语句必须加注释”——每条都在用一个风格要求去掩盖一个结构上的坏味道,并默认那个坏味道是不可避免的。
我不是让大家删掉 linter。我只建议一件事:对待每一条新规则,像对待一个结构变更那样严格评估。规则应该帮助你现有的结构,而不是替代你回避的结构。在添加新规则之前,像论证重构一样论证它:问题真实存在吗?规则是正确工具,还是更深层问题的临时包扎?
规则与结构可以协作得很好,但它们不是一回事。一旦拿一个去替代另一个的职责,你就等于选择了一条可以修好的路,却换来一辈子小心翼翼的绕行。
#开发者 #工具 #代码质量 #架构设计 #工程效率 #编程理念 #规则与结构
@DevToolboxHub