The art of code(一)
一. 软件工程能力
为什么要重视工程能力
由于行业内竞争加剧,成本上涨和产业升级等形势的变化,工程能力收到越来越高的重视
工程能力首先会影响"打得准不准".如果从业者不能做好需求识别和分析,缺乏产品方面的意识,那么研发出的软件就没有市场和用户
工程能力还影响"是否能打赢".工程能力会影响软件研发的效率,质量和成本,一个低效,低质量和成本高的软件项目是没有市场竞争力的
什么是工程能力
提升工程能力不等于写好代码,工程能力反应的是团队的综合素质.在软件研发中,很多从业者的大量时间其实并没有用在琢磨技术上,而是用在了其他方面(沟通,项目协调,错误设计导致的返工),这些方面的时间消耗往往也没有得到大家的关注
工程能力的定义
在百度内部材料中,将工程能力定义为:使用系统化的方法,在保证质量的前提下,更高效率地为客户/用户持续交付有价值的软件或服务的能力
质量第一:无论如何定义质量,客户都不会容忍低质量的产品.质量必须被量化,并建立可落地实施的机制,以促进和激励质量目标的达成
实现价值持续交付:软件/服务的价值提供是长周期的,从业者做好长期维护,长期服务,持续改进优化的思想准备
怎样提升工程能力
工程能力的素质要求
- 公司能力素质
规范和指南,工具,平台,开源协作,知识管理,人力资源机制 - 团队能力素质
研发过程管理,研发效率,成本意识,教育培养 - 个人能力素质
需求把握,系统设计,编码能力,项目管理,运维能力,产品意识,客户服务意识,安全意识,质量意识,沟通能力
人是工程能力的根本
伟大的系统和产品一定来自优秀的人和团队.在人没有改变的情况下,团队规模的增加,劳动时间的延长,都无法从根本上改变软件的品质.无论是对于组织还是个人,都应该在培养人方面投入更多的资源
工程能力提升源自自我驱动
作者一直秉持的一个观点就是:如果一个人知道什么是高效而正确的方法,那么他一定不会继续使用低效且错误的方法相对于依赖指标考核,不如通过教育和培训让工程师了解什么才是正确的方法
个人能力的素质要求
写好代码(对应编码能力),写好文档(对应需求把握和系统设计),做好项目管理
- 没有好的管理,再好的技术也是没有用的
- 好的代码,首先来自好的设计
- 需求分析先于系统设计
二. 代码的艺术
背景和初衷
在尽量早的时候,形成正确的意识,对一名软件工程师的快速成长是非常关键的
代码和艺术
代码也能成为艺术品
软件工程师和码农
一个软件工程师要具备非常高的综合素质,具体包含一下几个方面:
- 专业知识
软件工程师需要掌握的专业知识包含数据结构,算法,编码方法,还包括系统结构,操作系统,计算机网络,分布式系统 - 产品
软件工程师还需要具有产品方面的思维,要对业务有深刻的理解,为了提供良好的用户体验,软件工程师需要学习交互设计,这是一个非常专业的学科方向;还需要学习产品数据,会基于这些数据来优化产品;更需要学习产品/业务运营,这对很多运营型的产品来说是非常重要的 - 项目管理
做软件项目不是一个人的工作,要做好软件项目需要懂得管理.有很大比例的软件工程师不懂项目管理,忽视项目管理对软件项目成功的巨大作用 - 研究和创新
有一些项目具有很强的研究和创新属性,这就要求软件工程师要具备研究的能力
来自艺术的启发
写代码并非易事
写代码并不是容易的事情,具体的原因如下:
- 写代码是从无序变为有序的过程,计算机中所运行的程序时按照严格的逻辑来执行的,而现实世界纷繁复杂,其中的秩序并不是一眼可以辨识的,需要我们把他整理为有序的结构
- 写代码将现实世界中的问题转化为数字世界中的模型.程序是数字世界的一种映射.其中涉及对现实世界的抽象和建模
- 写代码是一个认识的过程.在写代码的过程中,原来所未知的问题,在代码完成后变为已知.对于一项新业务,在开始时我们可能并不了解,但通过逐步分析,逐渐有了更深入的理解,在这个认识的基础上可能开发出对应的软件
好代码和坏代码
好代码的特性
- 鲁棒
- 高效
- 简洁
- 简短
- 可测试
- 共享
- 可移植
- 可观测/可监控
- 可运维
- 可扩展
坏代码的例子
- 不好的函数名称
- 不好的变量名称
- 没有注释
- 不好的排版
- 无法测试
好的代码从哪里来
好代码不止编码
- 在编码前,需要做好需求分析和系统设计.而这两项工作是经常被大量软件工程师忽略或轻视的环节
- 在编码时,需要编写代码和编写单元测试
- 在编码后,要做集成测试,上线,以及持续运营/迭代改进,这几件事情都是要花费不少精力,比如上线,不仅仅要做程序部署,而且要考虑程序是如何被监控的
需求分析和系统分析
- 几种常见的错误现象
- 研发前期多投入,收益更大
- 修改代码和修改文档,哪个成本更高
- 需求分析和系统设计之间的差别
需求分析:定义系统/软件的黑盒的行为,它是从外部看到的,在说明是什么
系统设计:设计系统/软件的白盒的机制,它是从内部看到的,要说明怎么做和为什么
如何做好需求分析
如何描述需求👍
在描述需求时,我们要考虑的是:如何用寥寥数语勾勒出一个系统的功能,以GFS(谷歌文件系统)为例:GFS的设计目的是:基于商用邮件组成的大型集群,为其提供有效和可靠的数据访问机制. 在获取需求信息后,我们需要更加详细的信息,而且在需求描述中,需要使用精确的数字来刻画需求.对于很多指标来说,量变会导致质变
对需求分析的误解
误解1. 需求分析和软件工程师没有关系(沟通)
误解2. 做需求分析时需要考虑实现细节(防止"实现决定需求")
需求分析的重要性
导航模块
如何做好系统设计
什么是系统设计
系统设计是定义系统的架构,模块,接口和数据以满足特定需求的过程
另外,这个定义没有提到下面两点,一个是系统中使用的关键算法,对于某些系统来说,算法是比较复杂的,需要花费不少精力来设计.另一个就是系统设计思路,当前的系统设计并不是终点,未来也会有优化或重构,对于未来从事这些工作的同事来说,系统设计中所留下的设计思路是非常有价值的
设计文档的分类👍
- 总体设计文档:描述系统的总体构成和运行机制
- 子系统设计文档:描述构成系统的某个子系统的组成和运行机制
- 接口定义文档:描述系统对外提供的接口
- 关键算法说明文档:描述系统中的关键算法
- 数据表设计文档:描述系统使用的数据表的设计,可能是数据库的设计,也可能是其他存储设备的设计
将不同类型的设计文档独立存放的原因在于:第一点是便于读者阅读,每个文档都有特定的读者,比较经典的是接口定义文档,这个文档是提供给系统的外部使用者的.第二点是便于编写文档的人进行修改和维护,进行切分文档后,在做修改维护时冲突的可能性会大大降低,同时也降低了设计文档成为"巨型文档"的可能性,对短小的文档进行阅读和维护的难度都更低
什么是系统架构
系统架构是概念模型,定义了系统的结构,行为和更多的视图
- 静:首先,从静止的角度,描述系统如何组成,以及系统的功能在这些组成部分之间是如何划分的,这就是系统的结构.一般要描述的是:系统包含哪些子系统,每个子系统有什么功能.在做这些描述时,应感觉自己是一名导游,带着游客在系统的各子系统间参观
- 动:然后,从动态的角度,描述各子系统之间是如何联动的,它们是如何相互配合完成系统预定的任务或流程的,这就是系统的行为,在做这个描述时,应感觉自己时一名电影导演,将系统的各种运行情况通过一个个短片展现出来
- 细:最后,在以上两种描述的基础上,从不同的角度,更详尽地刻画系统的细节和全貌,这就是更多视图
系统设计的原则和方法
- 单一目的
- 对外关系清晰
- 重视资源约束
- 根据需求做决策
- 基于模型思考
作者说,数据结构这门课可以用一下两句话来概括
- 如何用空间换时间,从链表到哈希表,再到二叉树,通过使用更多的存储空间,不断降低查找等操作的复杂度
- 如何在读复杂和写复杂间做权衡,对很多数据结构来说,读和写是一对矛盾的操作,在很多时候,我们会假设读的频率远高于写,于是在优化中更偏向于牺牲写的性能,从而提高读的性能
重视对外接口
- 对外接口比系统内部实现更重要
第一点.对外接口定义了系统对外所提供的功能.如果功能不正确,系统就不会产生价值,而我们编写软件的最终目的是提高价值.第二点,对外接口决定了系统的外部关系 - 对外接口的形态
- 设计和修改对外接口的注意事项
如何写好代码
代码的沟通价值
- 50%以上的时间是用于沟通的
- 写代码也是一种沟通方式
- 代码为人而写
- 表达能力很重要
模块的设计方法
- 程序的构成
程序由多个模块构成,每个模块内包含数据的定义,函数的实现和类的实现 - 模块的形态
- 模块划分的重要性
- 模块设计的方法
划分模块的方法
- 数据类的模块
- 过程类的模块
- 以BFE开源项目为例
函数的设计方法
- 类和函数
- 函数划分
- 函数描述三要素
第一个是功能,描述这个函数是做什么的,一个函数的功能尽量能用一句话表述清楚,最好在函数的开头就将函数的功能用注释的方式写下来
第二个是传入参数,各个参数的含义和限制条件,对于函数中的每个参数,其含义应该有明确的说明,对于参数的限制条件也应该给出说明
第三个是返回值:返回值的各种可能性.返回值并不是只靠一个数据类型就可以看懂,而是需要将返回值的各种可能性都写清楚 - 控制函数的规模
- 函数的返回值
- 单入口单出口
代码块的编写注意事项
- 案例对比
- 代码段落区分清楚
- Donnot make me think
- 注释不是补出来的
作者推荐写注释的方法是:先写注释,再写代码
软件开发中的命名
- 命名很重要
- 命名中出现的一些问题
- 命名不是一件容易的事情
如何支持系统运营
可检测性的重要性
成为优秀软件工程师的三条路径
学习 -- 思考 -- 实践
知识 -- 方法 -- 精神
基础乃是治学之根本
三. 代码评审
代码评审的常见误区
为什么要做好代码评审
代码评审的重要意义
- 代码评审的目的是改进代码质量.代码可以运行,但是并不意味着它一定正确.在软件开发中越早发现问题,修复的成本就越低
- 高质量的代码能够节省成本,虽然当前代码评审会花费时间,但是从长期来看这是值得的
- 仅从知识传递这一点考虑,代码评审也值得做.每个人不应该仅仅知道代码是怎么修改的,更应该知道设计决策背后的原因.代码评审给了开发者一个解释它们设计的机会.在代码评审中,开发者之间可以相互学习
- 在辅导他人编码方面,代码评审是最好的方法
- 代码评审使团队对顶级开发者更有吸引力
没有做好代码评审的后果
为什么要提升代码质量
为什么要提升编码能力
作者说:很多工作多年的软件工程师在编码方面任然处于业余水平,写出来的代码,既不符合基本的编码规范,也缺乏设计思想,这样的人很容易在35岁左右出现职业危机
如何做好代码评审
代码评审的常见问题
- 各种拼写错误
- 未优化的代码实现
- 不必要的复杂代码
- 重复实现已经存在的代码逻辑
- 缺少必要的注释
- 缺少必要的单元测试
.....