Skip to content

四火的唠叨

一个纯正程序员的啰嗦

Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接
Menu

对几个软件开发传统观点的质疑和反驳

Posted on 11/02/201210/02/2024 by 四火

why 下面这些观点都是程序员在教科书上、在编码规范里、在正统的软件工程流程里流传开来的,帮助了许多人在程序员启蒙期间养成了良好的习惯、原则。对许多人(包括曾经的我)来说,似乎是理所当然的。但是随着阅历的增长,视角在变化、看法也在变化,曾经的好恶现在都可能大翻身了。

为代码写足够的注释,让代码易于理解

“ 所有程序员都会写自己看得懂的代码,但只有优秀的程序员才写大家看得懂的代码。” 这话没错,但是——

  1. 什么才是“ 大家看得懂” 的定义?我有必要让我的 C++代码对于一个月前才明白指针和引用区别的初学者简单易懂么?
  2. 更重要的是,要代码能够“ 看得懂”,主要是靠足够多的注释吗?

我觉得这两点都是扯淡。

关于第 1 点,造就了一些自我感觉过度良好的人,习惯性地把前人写的代码批得体无完肤。在他们眼中,这段代码巨烂,那段代码是屎,更有甚者,在评审别人代码的时候,一样说出这样的话来(请参见这篇文章里的“ 一坨屎型评审”)。

反对我的人会说,软件公司做产品赚钱,它们希望你的代码让不熟悉项目的新员工快速阅读、上手。这确实是个矛盾。说白了,你写的代码要和一个团队的能力匹配。在一个鱼龙混杂的团队,甚至一个糟糕的团队,你写出的代码也许很难和大伙儿产生共鸣,他们希望你写最普通最易懂的代码,没有精巧的设计(我指的是,“ 某一些精巧的设计,恰恰是以降低代码的可维护性为代价的”),没有语言高级特性,看着只有顺序、循环、分支判断的基本代码。如果大家都是 JavaEE 的初学者,那么就从 JSP+Servlet 开始吧,这样你们才在一个圈子里,要不然,没有人能真正和你一起讨论设计和代码的问题。

所以许多上进的程序员,会希望在一个牛人的团队里工作。这就像足球运动员一样,因为足球是集体运动,一个足球运动员能达到的高度,是和他所在的团队息息相关的。在一个优秀的团队里,大家个性各有千秋,擅长领域不甚相同,但是都学习迅速,能力不差太远,大家阅读代码都能够很快理解和领会,而且讨论问题可以用一些程序员才明白的隐喻(比如有人说“ 我觉得这里应该用一个 builder 来实现”,大家都明白 builder 指的是什么),氛围和效率显而易见。

如果你恰好对当前需要用到的业务和技术特别熟悉,领先团队里其他人一大截怎么办?那你就该在做设计编码的时候先行一步,你是那个最该去做架构设计、写骨架代码的人,完成一个架子以后再来给大家讲解,并和大家讨论,改进现有的设计。也就是说,你要多做一些更重要的事,而不是和大家一起分析、一起讨论,甚至一人负责一个模块,最后的结果就是大家根本和你讨论不到一块儿去。

关于第 2 点,要代码“ 看得懂”,是设计出来的,而不是注释加出来的。这和产品质量一样,产品质量是设计出来的,而不是测试测出来的。注释的意义在于对当前代码自解释做不到的地方进行补充。

所以,你的代码要易于理解,首先要保持简洁和清晰,这既包括良好的设计,也包括良好的编码习惯,也就是说,代码是自解释的,其次才通过注释的补充,让代码更易懂。注意,我不是说注释不重要和不必要,而是说,注释应该完成它自己的功用,它远不能代替代码本身自我解释的价值。

举一个简单的例子,你可以这样写代码:

/**
 * 图表模型
 */
class Chart{
    /**
     * 图表长度
     */
    private int length;
    
    /**
     * 获取图表长度
     * @return 图表长度
     */
    public int getLength(){
        return this.length;
    }

    /**
     * 设置图表长度
     * @param length 图表长度
     */
    public void setLength(int length){
        this.length = length;
    }
}

好,那么你告诉我,这段代码和下面这段代码相比,你获取了什么更多的有用信息?

class Chart{
    private int length;

    public int getLength(){
        return this.length;
    }
    public void setLength(int length){
        this.length = length;
    }
}

我想你懂我的意思,两段代码,代码本身意思已经够明确了,再加上这些无聊的注释,只是浪费资源、浪费生命。很多编程语言,利用语法糖,连简单 get、set 方法都可以省了(比如 Objective C),而加这种注释的做法却依然在反软件、反人类而行。也许你和我一样,曾经为了公司某些扯淡的规定,为了规避某些扯淡的代码静态检查工具(比如 CheckStyle 这样的,甚至自己开发这种无聊的检查工具)检查结果中的警告信息,加上了(包括 IDE 自动生成)这些毫无意义的注释,于是领导看了:“ 好,没有警告信息,代码质量好”。虽然至始都痛恨这样的做法,但我还是做了,至今后悔。最让人痛恨自己的事情就是不得不去做那些自己痛恨的事情。

设计文档要详细,细化到方法定义

持这个观点的大有人在。对于这个观点我并不是完全反对,如果你要说设计文档需要“ 详细到可以指导编码” 我还能同意,但是我确实非常不喜欢详详细细的设计文档。肯定设计文档的价值这没有错,但是过于详细的设计文档撰写,往往容易造成纸上谈兵的窘境。

有人说设计文档太过粗略了做不好设计,事实上,文档只是呈现设计的其中一种形式而已,做得好设计的人,可以一边编码一边思考,可能辅助草稿纸上写写划划,就可以完成优秀的软件;不会做设计的人,设计文档写多少页都没用。这让我想起了今天和同事关于 TDD 的讨论,会做设计的人,不让他用 TDD 也能写好代码;不会做设计的人,TDD 又有何用?所以让 TDD 成为设计的主要工具,那就是扯淡。

再一个,在设计文档中,不可能做完设计,不知你是否有这样的体会,设计文档思考得再缜密细致,等落到代码上的时候,还会和开始的思考有许多不同,至少有很多细小的不同。这是因为设计思考本身就是贯穿整个设计编码过程的,一人只做设计、另一人只写代码这样的理想模式是不可能达成的。

我了解一些对日外包公司,程序员拿到手的设计文档就是细化到方法定义了的,如果你有能力有志气,在中国最好就不要做外包,尤其是对日外包,这样的公司拒绝你的一切思考,就是在摧残人才。

另外一个原因,是针对一些阐明“ 设计文档可以传承业务和技术知识” 观点的人,详细的设计文档并不能够传承什么业务和技术,原因很简单,详细的文档初始撰写成本高,维护的成本更高。我不相信程序员在修改了代码逻辑以后,会去经常保持设计文档的同步性。这不合理,只有代码才是保持最新的,其它一切都会过时。而相对简要或粗略的文档,稳定性就要强得多。

让项目组各个角色去评审代码设计

下面我要驳斥的这个观点来源于我的一些经历,也许并不能算是主流观点。

对于设计文档的评审,如果是设计原理、实现原理,正到了程序员才关心的层面上,如果不写代码的测试跑来一起讨论,这就成了浪费时间、制造矛盾的做法。我经历过这样的事情,觉得很幽默。专职测试人员的定位各有千秋,许多人经验丰富、无可替代,但是至少,我接触的测试人员中,他们几乎是不阅读代码的,也就是说,对于代码设计(注意,是代码设计,不是产品设计)的讨论,他们不该参与进来。

另外,不要说“ 我几年前也是写代码的”,毛主席都讲了,“ 不了解情况,就没有发言权”,如果你对当前的代码实现不了解,就不要来碍手碍脚地评审代码层面的设计了。

我也经历过这样的场景,每一个产品都要组织一些有经验的程序员,去给别的产品的代码挑刺儿。我的看法是,这很难挑出特别有价值的毛病来,原因也是一样的,你对别的产品业务不了解,那么要花大量精力去阅读代码,更要去熟悉业务,否则只能从代码层面上抠抠细节。

所以,谁来把关实现层面的设计和代码的质量最卓有成效呢?正是熟悉项目的程序员们,尤其是项目组骨干,或者一起参与设计、编码和测试的架构师(其实架构师还是一名优秀的程序员,我从来不认为“ 只懂业务的架构师” 有什么资格去做软件架构)。

为代码设置量化的限制指标

统计指标是有价值的,但是如果设置这些量化指标给程序员套限,则是违背客观规律的行为。这一观点我有必要举例说明一下:

  • 测试代码覆盖率不得低于 95%(比如工具 EMMA);
  • 方法圈复杂度不能超过 15(你也许知道圈复杂度的检查工具 SourceMonitor);
  • 单个类的行数不能超过 500,单个方法的行数不能超过 200;
  • 任意两个类之间重复代码行数不能超过 10 行(你可能知道重复代码检测工具 Simian);
  • ……

这些硬生生限制,都是反软件、反人类的。你可以说圈复杂度高的方法也许过于复杂,你可以说重复比率高的代码往往可以优化,但是这些都只是一个辅助的指标。这些工具都是用来帮助程序员改善他们的设计和代码质量的,如今它们却被用来做反程序员的事。

对于测试代码覆盖率的要求,而且有许许多多公司拿来作为代码质量衡量的重要指标,我认为更是骇人听闻。我写代码也做单元测试,但是会有选择地写 UT 用例,不会去追求测试覆盖率,而且测试再全面也不可能保证结果的绝对正确,好钢要用在刀刃上,时间的投入要换取划算的回报,而不是不计代价地补充测试用例。而且,在这里我要说的是,保证软件质量的方式有很多,测试验证的方式也有很多。即便覆盖率达到 100%,也不能说明质量高到哪儿去,追求覆盖率始终太过功利。另外,有许多代码本身就没有多大被 UT 测试的价值,这也是不容忽视的。

优秀的程序员,应该难以容忍自己产出糟糕的代码,也许对代码有一点洁癖,对代码之美有不懈的追求。对这样的软件的使用动机,也应该来源于程序员,而相关数据的采集,最终一定要为程序员服务。

今天只是把上面这些观点做了个整理,在和别人谈起这些的时候,其实我觉得我只是说了实话而已,我的观点一点都不偏激。我知道很可能你会有不同看法,这太好不过了,但是善意地提醒你,请一定仔细思考一下,不要被公司的精神和文化洗了脑,我们都是程序员,我们最清楚,或许也都经历过那些针对程序员、软件开发荒唐可笑、乃至不可思议的做法。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

×Scan to share with WeChat

你可能也喜欢看:

  1. 泛型传递
  2. 泛型趣谈
  3. 一道随机数题目的求解
  4. 再谈大楼扔鸡蛋的问题
  5. 对象转换的问题

3 thoughts on “对几个软件开发传统观点的质疑和反驳”

  1. karry says:
    10/28/2021 at 8:01 PM

    1. 设计,代码本身 需要具有可读性,遵守规范和一些模式。 这其实是一个合格编码人员的基本功,这些东西构成了一门语言,只有都懂得这门语言的人沟通起来才畅通。否则及时他给你讲两小时也未必懂 更别说几行注释。
    2. 要求代码可读性,重要的是同一维度的人来读取。 这跟部门人员招聘就应该考虑的,把 CPU 和磁带放在一块,管理无限可击也是白搭
    3. TDD 我自己的赶脚是辅助工具,对于简单的可以一次设计完的就不需要什么 TDD,但对于很复杂,一次设计完全是不可行的,只能用 case 冲,直到解决所有 case 为主。
    4. 体温可以体现人的健康程度,但不可以要求每个人都不能超过 37 度,用指标考核最后只能得到指标,这些问题老祖先讨论过无限次了,可先做的很多管理者完全不懂,或者他们只需要一个管理的抓手,或者是对团队掌控的欠缺,只能用考核来拦截
    5. 给人家 review 代码,不看代码直接指点的只能是那些过了红线的部分,这部分需要开发人员特殊说明才可以过。谁都知道垃圾方案是对垃圾的现实的妥协,可需要特殊说清楚。大部分情况下,都是开发水平不到能力不行导致

    Reply
  2. star says:
    02/04/2013 at 6:41 PM

    我觉得规定是死的,人必须是活的,有些规定,如:
    单个类的行数不能超过 500,单个方法的行数不能超过 200;
    是可以提醒程序员拆分方法和类,降低维护难度,但是如果把这些规定作为一种束缚,那就大可不必了。

    Reply
  3. 甄码农 says:
    11/20/2012 at 5:22 PM

    作为码农太理解对那个 pojo 类加注释的无聊了。但是公司有统一的 checkstyle 模板,你不写都不行的,这很现实。

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

订阅·联系

四火,啰嗦的程序员一枚,现居西雅图

Amazon Google Groovy Hadoop Haskell Java JavaScript LeetCode Oracle Spark 互联网 亚马逊 前端 华为 历史 同步 团队 图解笔记 基础设施 工作 工作流 工具 工程师 应用系统 异步 微博 思考 技术 数据库 曼联 测试 生活 眼界 程序员 管理 系统设计 缓存 编程范型 美股 英语 西雅图 设计 问题 面向对象 面试

分类

  • Algorithm and Data Structure (30)
  • Concurrency and Asynchronization (6)
  • System Architecture and Design (43)
  • Distributed System (18)
  • Tools Frameworks and Libs (13)
  • Storage and Data Access (8)
  • Front-end Development (33)
  • Programming Languages and Paradigms (55)
  • Testing and Quality Assurance (4)
  • Network and Communication (6)
  • Authentication and Authorization (6)
  • Automation and Operation Excellence (13)
  • Machine Learning and Artificial Intelligence (6)
  • Product Design (7)
  • Hiring and Interviews (14)
  • Project and Team Management (14)
  • Engineering Culture (17)
  • Critical Thinking (25)
  • Career Growth (57)
  • Life Experience and Thoughts (45)

推荐文章

  • 聊一聊分布式系统中的时间
  • 谈谈分布式锁
  • 常见分布式系统设计图解(汇总)
  • 系统设计中的快速估算技巧
  • 从链表存在环的问题说起
  • 技术面试中,什么样的问题才是好问题?
  • 从物理时钟到逻辑时钟
  • 近期面试观摩的一些思考
  • RSA 背后的算法
  • 谈谈 Ops(汇总 + 最终篇):工具和实践
  • 不要让业务牵着鼻子走
  • 倔强的程序员
  • 谈谈微信的信息流
  • 评审的艺术——谈谈现实中的代码评审
  • Blog 安全问题小记
  • 求第 K 个数的问题
  • 一些前端框架的比较(下)——Ember.js 和 React
  • 一些前端框架的比较(上)——GWT、AngularJS 和 Backbone.js
  • 工作流系统的设计
  • Spark 的性能调优
  • “残酷” 的事实
  • 七年工作,几个故事
  • 从 Java 和 JavaScript 来学习 Haskell 和 Groovy(汇总)
  • 一道随机数题目的求解
  • 层次
  • Dynamo 的实现技术和去中心化
  • 也谈谈全栈工程师
  • 多重继承的演变
  • 编程范型:工具的选择
  • GWT 初体验
  • java.util.concurrent 并发包诸类概览
  • 从 DCL 的对象安全发布谈起
  • 不同团队的困惑
  • 不适合 Hadoop 解决的问题
  • 留心那些潜在的系统设计问题
  • 再谈大楼扔鸡蛋的问题
  • 几种华丽无比的开发方式
  • 我眼中的工程师文化
  • 观点的碰撞
  • 谈谈盗版软件问题
  • 对几个软件开发传统观点的质疑和反驳
  • MVC 框架的映射和解耦
  • 编程的未来
  • DAO 的演进
  • 致那些自嘲码农的苦逼程序员
  • Java 多线程发展简史
  • 珍爱生命,远离微博
  • 网站性能优化的三重境界
  • OSCache 框架源码解析
  • “ 你不适合做程序员”
  • 画圆画方的故事

近期评论

  • Ticket: TRANSACTION 1.922915 BTC. Go to withdrawal >> https://yandex.com/poll/enter/BXidu5Ewa8hnAFoFznqSi9?hs=20bd550f65c6e03103876b28cabc4da6& on 倔强的程序员
  • panshenlian.com on 初涉 ML Workflow 系统:Kubeflow Pipelines、Flyte 和 Metaflow
  • panzhixiang on 关于近期求职的近况和思考
  • Anonymous on 闲聊投资:亲自体验和护城河
  • 四火 on 关于近期求职的近况和思考
  • YC on 关于近期求职的近况和思考
  • mafulong on 常见分布式基础设施系统设计图解(四):分布式工作流系统
  • 四火 on 常见分布式基础设施系统设计图解(八):分布式键值存储系统
  • Anonymous on 我裸辞了
  • https://umlcn.com on 资源链接
© 2025 四火的唠叨 | Powered by Minimalist Blog WordPress Theme