《代码精进之路:从码农到工匠》读书笔记

背景

实际开发一年了,自评开发习惯不好,没有形成很好的自己的代码风格,也很难写出优雅的代码。开始向别人学习,在此记录读书笔记。《代码精进之路:从码农到工匠》

书中有几句话,很有感触,共勉。

  • 留给公司一个方便维护、整洁优雅的代码库,是我们技术人员的最高技术使命,也是我们对公司做出的最大技术贡献。
  • 在程序设计中,一大忌讳就是教条。 
  • 我不是一个伟大的程序员,只是习惯比较好而已 。
  • 未经审视的人生不值得过。

第一部分 技艺

第1章 命名

命名的作用

提高代码可读性:使代码概念清晰,增强代码表达力。为什么代码可读性这么重要呢,书中有一句话,看了很感慨:。所以,代码即文档,可读性好的代码有一定的自明性。不借助注释和文档,代码本身就能显性化地表达开发者的意图。

命名规则

1. 常规命名

  • 变量
能够正确描述业务,有表达力的名词。
不需要用注释来补充说明。
避免魔术数,使用统一变量表达,提高代码的可搜索性。
  • 函数
命名要具体,空泛的命名没有意义。
要体现做什么,而不是如何做。
  • 类名
类是一组数据和操作的封装。可以将应用中的类分为两大类:实体类和辅助类。
实体类承载核心的业务数据和业务逻辑,命名要充分体现业务语义,并在团队内形成共识;
辅助类是辅助实体类一起完成业务逻辑的,命名可以通过后缀来体现功能。尽量不要使用Helper、Util做后缀,含义太过笼统,容易破坏单一职责原则。
  • 包名
package代表一组有关系类的集合,起到分类组合和命名空间的作用。
包名应该能够反映一组类在更高抽象层次上的联系,命名要适中,不能太抽象,也不能太具体。
  • 模块名
名称要反映模块在系统中的职责,代表着架构层次。

2. 命名要保持一致性:可以提高代码可读性,从而简化复杂度。命名规则一旦选中,就要持续遵循,保证名称始终一致。

3. 每个概念一个词:每个概念对应一个词,并且一以贯之。

4. 使用对仗词:有助于保持一致性,且易于理解。

5. 后置限定词:把限定词加到名字最后。

常见限定词:Total、Max、Min、Average等。

6. 统一业务语言:减少沟通成本。同一业务概念,不要用多个词汇描述,造成不必要的沟通成本。

7. 统一技术语言:使用通用的技术语言。例DAO、DTO、DO等等。

8. 自明的代码:好的代码是最好的文档。好的代码是指具备很好的可读性和自明性。

9. 中间变量:通过有意义的中间变量,从而把隐藏的计算过程以显性化的方式表达出来。

10. 设计模式语言:技术人员之间,提高沟通效率。

11. 注释

注释的作用是阐述代码背后的意图,而不是复述代码功能,复述功能意味着坏味道。

建议用显性化的方法名来表达意图,以减少不必要的注释。


第2章 规范

规范的作用

1. 事物的复杂程度在很大程度上取决于其有序程度,减少无序能在一定程度上降低复杂度,这正是规范的价值所在。

2. 发现共同和抽象机制可以在很大程度上帮助我们理解复杂系统。

代码规范

1. 代码格式:团队内保持一致

2. 空行规范:空行是“无”的价值,用于概念区隔。将概念相关的代码放在一起,不同逻辑块之间,用空行分隔。

3. 命名规范:

  • 包名:使用小写,“.”分隔符之间有且仅有一个自然语义单词,统一使用单数形式
  • 类名:“大驼峰”形式。如Object
  • 枚举类:以Enum或Type结尾,成员名称需要全部大写,单词间下划线连接
  • 抽象类名:以Abstract开头
  • 异常类名:以Exception结尾
  • 实现类名:以Impl结尾
  • 测试类名:以被测试类名为始,以Test结尾
  • 方法名:“小驼峰”形式,一般为动词,与参数组成动宾结构。如Thread.sleep(long millis)
  • 常量名:字母全部大写,单词间用下划线分隔

4. 日志规范

日志是线上故障分析、追溯的重要依靠,所以要保证日志输出格式统一,保证日志的质量。

常用以下4个级别的日志:ERROR、WARN、INFO、DEBUG。

  • ERROR级别:表示不能自己恢复的错误,需要被立即关注和解决。打印异常堆栈,最好要打印上下文信息(关键数据),便于排查问题。做好ERROR输出的场景定义和规范,再配合监控治理,双管齐下,确保线上系统的稳定。
  • WARN级别:可预知的业务问题,如参数校验不通过、无访问权限等业务异常。短时间内产生过多WARN日志也是需要被关注的,为WARN配置适当阀门报警是必要的。
  • INFO级别:INFO用于记录系统的基本运行过程和运行状态。主要包括系统状态变化日志、业务流程的核心处理、关键动作和业务流程的状态变化。切忌把INFO当成DEBUG使用。
  • DEBUG级别:输出调试信息,生产环境要关闭,有问题时动态的开启DEBUG,使用配置工具根据requestId进行判断,只打印需要的日志。

5. 异常规范

5.1 要进行统一的异常处理,否则非常容易出现以下场景:

  • 在业务处理内部到处使用try-catch打印错误日志,这样使得功能代码和业务代码缠绕在一起,代码凌乱,影响可读性

  • 异常处理不统一,有时候抛异常,有时候直接返回result

5.2 异常统一处理:

  • 定义两个Unchecked Exception: BizException(业务异常)、SysException(系统异常)

  • 对业务异常和系统异常做统一的异常处理,在应用处理请求的切面上进行异常处理收敛

        try {
            // 业务处理
        } catch (BizException e) {
            // 业务异常使用warn级别
            log.warn("BizException ", e);
        } catch (SysException e) {
            // 系统异常使用error级别
            log.error("SysException ", e);
        } catch (Exception e) {
            // 兜底
            log.error("SysException ", e);
        }

5.3  错误码:

显示化错误码相比编号错误码,更加灵活。将错误码定义为 类型_场景_自定义标识。示例:

埋点规范

业务数据化,数据业务化:业务要沉淀数据,数据要反哺业务 

架构规范

架构就是一组约束,遵从约束,才能符合架构,否则架构将失去意义

防止破窗

环境中的不良现象如果被放任存在,就会诱使人们效仿,甚至变本加厉。“第一扇破窗”常常是事情恶化的起点。所以我们要做两件事:

  • 不要做“打破第一扇窗”的人
  • 发现“破窗”要及时修复

第3章 函数

0. 程序逻辑都是写在函数中的,一个系统容易腐化的部分正是函数,不解决函数的复杂性,就hen n

1. 封装判断:好的函数应该是清晰易懂的。通过封装判断,将判断条件转化为显性的业务语义,代码可读性得到提升。

2. 函数参数:参数越少,函数越容易理解,也更容易使用和测试。如果函数需要3个以上参数,就说明其中一些参数应该封装为类

3. 短小的函数:“长方法”是典型的代码“坏味道”,将其结构化分解可以有效提升代码的可读性。建议一个方法不超过20行。

4. 职责单一(SRP):函数级别的单一原则,一个方法只做一件事。职责越单一,功能越内聚,可复用的可能性越大。

5. 精简辅助代码

5.1 辅助代码:非业务逻辑核心代码,如 判空、打印日志、鉴权、降级、缓存检查等。

5.2 优化判空:善用Optional类

5.3 优化缓存判断:自研缓存框架,通过注解来代替固定的铅板代码

5.4 优雅降级:Spring Cloud Hystrix

6. 组合函数模式:公有函数(入口函数)读起来像执行步骤的概要,步骤的真正实现细节在私有函数里。

7. 抽象层次一致性(SLAP):组合函数要求将一个大函数拆分成多个子函数组合,SLAP要求函数体中的内容必须在同一个抽象层次

8. 函数式编程:把函数作为参数传递给另一个函数

  • 减少冗余代码,让代码更简洁,可读性更好
  • 函数是“无副作用”的,即没有对共享的可变数据操作,可以利用多核并行处理,而不用担心线程安全问题

第4章 设计原则

遵从原则,可以事半功倍;反之,则可能带来麻烦。当然也不是要教条地遵守每一条原则,而是要根据具体情况进行权衡和取舍。SOLID原则之间并不是相互独立地,而是相互关联的。开闭原则 和 里氏代换原则 是 设计目标单一职责原则接口分离原则依赖倒置原则 设计方法

SRP(单一职责原则)

  • 任何一个软件模块中,应该有且只有一个被修改的原因。
  • 衡量职责单一的标准就是,“模块是否只有一个被修改的原因”。职责越单一,被修改的原因就越少,模块的内聚性就越高,被复用的可能性就越大,也更容易被理解。
  • 把重要的业务逻辑与数据放在一起,然后调用其他没那么重要的函数

OCP(开闭原则)

软件实体应该对扩展开放,对修改关闭。但是要想做到绝对的“不修改”是比较理想主义的,所以要在设计时做一定的权衡,不要提前做过多的“大设计”。

相关设计模式:装饰者模式策略模式适配器模式观察者模式

LSP(里氏替换原则)

程序中的父类型都应该可以正确地被子类型替换。

  • 警惕 instanceof :如果出现强制类型转换才能使用子类函数的情况,就要考虑“提升抽象层次”来解决这个问题。即 将子类中特有函数用一种更抽象、通用的方式在父类中进行声明。

  • 子类覆盖父类函数 :子类方法覆盖了父类方法,并改变了其含义。这样做里氏替换时,就会出现问题。比如“正方形-矩形”问题

ISP(接口隔离原则)

  • 多个特定客户端接口要好于一个宽泛用途的接口。
  • 在做接口拆分时,也要满足单一职责原则。 拆分之后,只需要依赖需要的东西,这样可以降低模块之间的耦合。

DIP(依赖倒置原则)

  • 模块之间交互应该依赖抽象,而非实现。
  • “面向接口编程”也是实现DIP的一个技法
  • 所谓依赖倒置,就是要反转依赖的方法,让原来紧耦合的依赖关系得以解耦。

DRY(避免重复代码)

  • 如果多次遇到相同的问题,就应该抽象出一个共同的解决方法,不要重复开发同样的功能
  • 避免“散弹式修改”,因为是典型的代码“坏味道”,因为一个小小的改动,会牵扯很多地方。

YAGNI(你不会需要它)

是指自以为有用的功能,实际上都是用不到的。因此,除了核心的功能之外,其他功能一概不要提前设计,这样可以加大开发进程。其实就是要避免过度设计。

Rule of Three(三次原则)

是指当某个功能第三次出现时,就有必要进行“抽象化”了。

  • 第一次,写一个特定的解决方法
  • 第二次,copy代码
  • 第三次,着手“抽象化”,写通用的解决方法

要衡量 代码冗余 和 开发成本 的 平衡点。软件设计本身就是一个平衡的艺术,我们既反对过度设计,也绝对不赞成无设计。

KISS原则

目标不是越复杂越好,反而是越简洁越好

POLA原则(最小惊奇原则)

代码要简单易懂,“惊奇度”越高,复杂性越大。


第5章 设计模式

利用模式,我们可以让一个解决方案重复使用,而不是重复造轮子。系统的设计,不是含有设计模式就好,也不是包含越多越好。但是我们要掌握常用设计模式的用法。做到“知道”,但不“滥用”。

设计模式的分类

1. 创建型模式:用于描述“怎样创建对象”,主要特点是“将对象的创建与使用分离”。

2. 结构型模式:用于描述如何将类或对象按某种布局组成更大的结。

3. 行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责

推荐图书

  • 《设计模式:可复用面向对象软件的基础》
  • 《设计模式解析》

其他设计模式

  • 拦截器模式
  • 插件模式
  • 管道模式:链式管道、流处理

第6章 模型

统一建模语言UML

UML分类


第7章 DDD的精髓

基本没看懂,over

推荐图书:《领域驱动设计:软件核心复杂性应对之道》 


第二部分 思想

第8章 抽象

1. 抽象就是简化事物,抓住事物本质的过程。抽象更接近问题的本质。

2. 面向对象的思想主要包括3个方面

  • 面向对象的分析
  • 面向对象的设计
  • 面向对象的编程

3. 如何进行抽象

  • 寻找共性
  • 提升抽象层次:内涵越小,外延越大;内涵越大,外延越小。不同层次的抽象,有不同的用途。当一个概念无法涵盖其外延的时候,我们就要考虑提升抽象层次来减少内涵,让其有更大外延。
  • 构筑金字塔:要自下而上地思考,总结概括;自上而下地表达,结论先行。(《金字塔原理》)
  • 多阅读
  • 多总结:不要摘录原文内容,要用自己的话总结归纳。这样可以加深理解,提升抽象能力。

第9章 分治

分治算法

  • 归并排序
  • 二分搜索
  • K选择问题

函数分解

长函数拆解

写代码的两次创造

  • 第一遍实现功能
  • 第二遍重构优化

分治模式

分层设计

  • 分层网络模型
  • 分层架构

横切和竖切

分布式数据库:

  • 横切:水平拆分,数据分片
  • 竖切:垂直拆分,按照领域进行拆分

第10章 技术人的素养

不教条

  • 瀑布还是敏捷:敏捷模型没有方法论
  • 贫血还是充血:关键点是控制复杂度

贫血模式:模型对象只包含数据,并提供简单的Getter、Setter

充血模式:数据和行为放在一起

  • 单体还是分布式:看业务规模

批判性思维

推荐书:《学会提问》、《思辨与立场:生活中无处不在的批判性思维工具》

成长型思维

把每一次失败都当作学习的机会

结构化思维:逻辑 + 套路

1. 如何落地新团队

2. 述职

工具化思维

磨刀不误砍柴工,不要蛮干,硬干、苦干

好奇心

学习的动力不应该来自于外界的强力,而应该来自于内在,来自于我们内心对知识的渴望,对世界的好奇心。做技术这一行,应该没有比持续学习更重要的了

记笔记

结构化表达:对于简短的内容要重点突出,粗体显示重点部分;对于篇幅较长的内容,最好要有目录,这样可以更加结构化地呈现笔记内容。

有目标

推荐书:《高效能人士的七个习惯》

选择的自由

积极主动的人有选择的自由,而消极被动的人往往是被动地接受影响,忘记了自己的主观能动性。

处乱世而不惊,临虚空而不惧,喜迎阴晴圆缺,笑傲雨雪风霜。

平和的心态

精进

慢就是快,每天必须进步一点点。

人生就像滚雪球,关键是要找到足够湿的雪,和足够长的坡。


第11章 技术Leader的素养

技术氛围

1. 代码好坏味道

2. 技术分享

3. CR周报

4. 读书会

目标管理

技术规划

1. 当前问题

2. 技术领域

3. 业务领域

4. 团队特色

推理阶梯

在日常生活中,个人的判断大部分基于自身的主观认识而非事实,这会产生许多误会。所以不要想当然,多沟通,多求证。

视人为人

  • 对待上级:有胆量
  • 对待平级:有肺腑
  • 对待下级:有心肝

第三部分 实践

第12章 COLA架构

https://github.com/alibaba/COLA

第13章 工匠平台

阿里对技术人进行测评的度量体系

猜你喜欢

转载自blog.csdn.net/yxz8102/article/details/106502726