关于写代码这件事

关于写代码这件事,我提出三个问题,并先答为敬:


其一,什么样的代码是好代码?

很炫的代码。
每个函数都使用了STL。
每个类都散发着设计模式的味道。
每个处理流程都曲径通幽,需要读者焚香沐浴,静心细品,才能发现作者的匠心独运。
这就是好代码吗?

Oh no,也许不是这样的。
首先代码能跑起来,实现用户的功能需求。然后再谈写得好不好。
怎么算好呢?

简洁明了
代码(函数,类)功能单一

一个函数只干一件事情,一个类只抽象一个明确的主题。不要只盯着面向对象里面有一个SRP(单一职责原则),实际上,不管是面向过程,也不管是面向对象还是函数式编程,内聚是永远不会错的。

又想上班,又想炒股又想做生意,结果可能是什么也做不好。
又接收报文,又解析报文,又校验报文,又存库,又组装报文,又发送报文,全铺开在一个函数里面,结果这个函数就变成了脏乱差。

想想我们的项目代码里面,有多少用鼠标滚轮、总也滚不到结尾的函数?这是病,得治啊。

实际上,大部分的函数,按功能封装封装,接收和解析报文提取一个函数,校验报文一个函数,组装报文一个函数,发送报文一个函数,就能弄得汤清水净,各个函数都功能单一了。

只有很少的机会,才会碰到需要我们拆分接口,或者按聚合、组合还是继承关系划分出几个类,才能实现功能单一的情况。

简单就是美。

代码干净利落,不拖泥带水

如果功能单一,那么干净利落已经做到大半。
这个标题下是想专门说说头文件的包含。

生成目标文件越来越大。宏的重复定义、编译告警越来越多。
头文件包含另外的一堆头文件。源文件包含所有能想到的头文件。
有时候编译不过去,要把源文件里面#include的a.h放到b.h后面,才能编过去。

你确定,你真的需要这么多头文件吗?
你知道,编译器会把你#include的所有头文件的每行代码,都铺开并占领到你的源文件中,一起参与编译,因此你编译的代码行数,并不仅仅是你的源文件代码行数这么少吗?
拜托,不需要的头文件,别#include进来吧。
尤其是,尽量别在头文件中包含头文件好吗,亲?

变量、函数、类命名清晰、准确

这个本来是不消说的。

生个娃,取个好名字能让娃今后万事如意,这是所有家长都懂的了。

定义个变量,写个函数,创建一个类,写个宏,如果从名字根本看不出来是用作啥的,那读者看着多闹心。

同一个文件中的函数名:有的全小写,用下划线连起来各个单词,这是linux风格的命名;有的大小写相间,用大写字母分开各个单词,这是骆驼命名法;有的又有下划线,又有大小写,好像雨天披着雨衣还同时打着伞,这是混搭命名法。总体看这是不好的命名。

按编码规范,整齐统一,像给娃取名那样,谨慎的命名自己的变量、函数、类、宏的,这才是极好的。

表达到位
代码的意图清楚

意图清楚,就是读者一看代码,就知道是干什么的。
代码首先是给人看懂,其次才是给机器看。

简洁明了,是意图清楚的前提。

注释恰当,不多不少。
不要故弄玄虚。不要使用不必要的STL。不用使用不必要的复杂算法。
可以用简单数组搞定的,就不用指针、堆内存。

命名多用set、get、check这些标准单词。
更主要的,如果你非要大段注释才能说明白一段代码,这个代码多半需要重构。
你可以把一组、甚至一条语句提取为一个小函数,只为让函数名称说明这是要干啥。

提取函数.PNG
代码的处理逻辑层次分明

写代码和写文章是一样一样的。
谋篇布局,主次分明,逻辑清楚,才好看。

如果你实在没啥逻辑,就给代码标上1、2、3、4吧。
写文章可以有章节编号,1,2,3,4,写代码为什么不能有?
真的可以有:

代码标号.PNG
代码的处理逻辑,与问题领域的概念、规则吻合

这个是比较高的境界。可意会。言传就落了俗套。
与问题领域吻合,意思是代码的样子,符合我们对代码所描述的事物的直观认识。
非高手不能。非多次重构不能。

举个例子。

保龄球记分,领域规则就是,全中得分为本轮加后两次,补中得分为本轮加后一次,普通得分为本轮。
好的代码,主函数就展现了它的领域规则。

保龄球记分.PNG
安全可靠
代码运行状态、时序管理得当

尽量保证函数是可重入的。尽量不用全局变量。
独占资源(锁定数据库、占用信号量)的时间尽量短。

不滥用assert。传入数据不合要求你就挂起,真的合适吗?
避免时序引起的偶发故障。别人的进程起来得比平时慢了,你就可以出错吗?

代码具有必要的测试安全网络

TDD、ATDD都是不错的选择。
对于嵌入式软件,上设备调试太慢。找设备太难。
还是PC仿真最方便。

用例跑完一遍要快。秒级最好,分钟也行,不超过10分钟可以接受。为啥?用例跑得太慢,就没人爱用,没人爱用,修改代码就不安全了呢。

改完代码,跑一遍用例。喝口茶,等着VC打印最后的OK。享受。

易于扩展
扩展新功能时,只需新增代码,无需改动老代码

不要只盯着面向对象里面有一个OCP(开放-封闭原则),实际上,不管是面向过程,也不管是面向对象还是函数式编程,不动老代码、也能扩展新功能,都是一种追求。
老代码都测试过了,能不动当然好啊。

容易做到吗?不容易。
但至少,你不能加一个小功能,都要翻天覆地改一遍吧?那只能说明你原来的设计太逊了。

C语言里面,函数功能单一化,在易变的地方采用注册回调机制、表驱动机制,都可以把改动限制在局部,保持老代码的稳定。
C++里面,工厂模式,让你创建新子类的对象时,不用改动使用这个对象的客户类代码;策略模式,让你面对不同产品的处理差异,不用改动基类和客户类代码,这都是一些具体办法。


其二,代码是资产还是债务?

黄蓉每天写500行代码。郭靖每天写100行代码。
黄蓉比郭靖厉害?
都是完成相同的功能,慕容复拥有2000行代码。乔峰只拥有200行代码。
慕容复比乔峰厉害?

用户要的是代码还是功能?

代码能按行收钱吗?
古龙写武侠小说,经常是一句话一行,一行一段。据说那时候台湾小说界是按行付稿费的。
问题是代码不是小说。

代码的目的是实现用户需求。
在满足用户需求的前提下,我们的代码应该——
尽可能少。
看看下面的代码。这样的代码,大量出没在超过10000000行的软件项目中。

复杂代码.PNG

维护这些代码,得花多少人力?
维护者是否会觉得上辈子欠了原作者的债呢。
公司和项目是否都在背着这些代码的债务,负重前行呢?
有些严谨又有趣的老外,好像已经把这个债务算清了:
Technical Debt Is Now Costing Us $3.61 Per Line Of Code(“CAST估计,现在公司要解决技术负债的花费,是每行代码3.61美元。”). -- Jonathan Bloom From CAST.


其三,代码只是设计的实现吗?

据说程序员都是码农。
真正的大牛只画UML图,偶尔提出一些软件思想和理论,供码农们崇拜。
码农们像蚂蚁那样coding,给别人的设计来作嫁衣裳。
真的是这样吗?

软件工程的理论基础,是和传统工程学做对比,尤其是和建筑业做对比。
设计主要是画图,好比画建筑图纸;实现就是coding,好比砌砖。
真的是这样吗?

建筑师画图纸,民工砌砖。没听说哪个民工砌砖砌得好变成了建筑师,没听说建筑师以前都是砌砖的。
但软件SE都是从coding过来的,而且必须是coding很好的程序员。
为什么呢?

从程序员到架构师.PNG

所以,软件工程,无法解释软件系统工程师的来源问题。
如果说——代码也是设计,程序员编程的过程,也属于设计的过程。那就好解释了——
作为程序员,你一直在设计,设计能力提高了,你就成了软件SE。

工程活动分成设计和生产。
在软件开发中,编程完全属于设计活动。我们通常说的软件SE“设计”的过程,也是软件设计的一部分。
软件里的生产工人,就是编译器。
软件的测试和调试,也是设计的一部分,是设计的验证。

如果认可这一点,除了自豪感油然而生,是否你也应该把代码写得更好点?


上述观点,纯属作者自言自语。
作为有思想的程序员,你不必同意作者的观点。

你只需想想,对这三个问题,你从前是怎么看的、现在又怎么看,这么多年过去,自己的看法是否有变化、是否有进步,就OK了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,544评论 25 707
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,003评论 11 349
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,292评论 18 399
  • 一首诗用看长篇小说的眼光看,觉得它太简陋; 一部长篇小说用看诗的眼光看,觉得它太冗长。
    九尾喵丿阅读 312评论 0 1
  • 文/三枚 任何成就都是从决定尝试开始 笔耕不辍的弘丹老师说,你可以尝试写下2017年的100项梦想清单,然后不断实...
    三枚阅读 329评论 0 1