《代码精进之路:从码农到工匠》读书笔记-技艺部分

1、命名

1.3 有意义的命名

1.3.1 变量名:如果一个变量名需要注释来补充说明,那么很可能说明命名就有问题;

魔术数用常量定义的好处是更易于搜索。

1.3.2 函数名:函数名要具体,空泛的命名没有意义;

函数的命名要体现做什么,而不是怎么做,合理的命名可以是你省掉记住“出栈”的脑力步骤。(例:getLastestEmployee优于popRecord)

1.3.3 类名:类可以分为实体类和辅助类;

实体类:承载了核心业务数据和核心业务逻辑,其命名要充分体现业务语义,并在团队内达成共识;

辅助类:辅佐实体类一起完成业务逻辑,其命名要能通过后缀来体现功能。(原文不建议使用Helper、Util之类的后缀,但是我认为应视情况而定)

1.3.4 包名:包代表了一组有关系的类的集合,起到分类组合和命名空间的作用;

1.3.5 模块名:在COLA架构规范中定义了xxx-controller、xxx-app、xxx-domain、xxx-Infrastructure(定义成小写可能更统一?) 4个标准模块。

 

1.4 保持一致性

1.4.1 每个概念一个词

方法名的约定

CRUD操作方法名约定
新增create
添加add
删除remove
修改update
查询(单个结果)get
查询(多个结果)list
分页查询page
统计count

 

1.4.3 后置限定词

避免使用Num,可以使用Total表示总数,Id表示编号。

 

1.5 自明的代码

1.5.1 中间变量

适当使用中间变量可以使语义更透明(此书中与《重构》一书中意见不同,但是我倾向于两种的折中,即适当使用能更好的帮助理解代码,而不是全部使用、也不是都不使用)

1.5.3 小心注释

1)不要复述功能;2)要解释背后的意图

 

2、规范

2.3 代码规范

2.3.2 空行规范

每个空白行都是一条线索,提示你下一组代码表示的是不同的概念或功能。

2.3.4 日志规范

1)ERROR级别:表示不能自己恢复的错误,需要立即被关注和解决。对于ERROR,我们不仅要打印线程和堆栈,最好打印出一定的上下文(例:链路TraceId、用户Id、订单Id、外部传来的关键数据);

2)WARN级别:对于可预知的业务问题,最好不要用ERROR输出日志,以免污染报警系统(例:参数校验不通过、没有访问权限等业务异常);在短时间内产生过多WARN日志,也是一种系统不健康的表现,如果是产品设计上有缺陷导致用户频繁出现操作卡点,可以考虑做一下流程或者产品上的优化;

3)INFO级别:用于记录系统的基本运行过程和运行状态(例:系统状态变化的日志、业务流程的核心处理、关键动作和业务流程化的状态变化);

4)DEBUG是输出调试信息,通常在开发和预发环境下,DEBUG日志会打开;只有当线上出现bug或者棘手的问题时,才可以动态地开启DEBUG。

2.3.5 异常规范

1)异常处理

在业务系统中设定两个异常,分别是BizException(业务异常-WARN级别)和SysException(系统异常-ERROR级别),而且这两个异常都应该是Unchecked Execption,因为Checked Exception破坏了开闭原则。千万不要在业务处理内部到处使用try/catch打印错误日志。

2)错误码

编号错误码:对于不同的错误波段,一定要预留足够的码号;

显性化错误码:显性化的错误码具有更强的灵活性,适合敏捷开发。(例:可以将错误码定义成3个部分:类型_场景_自定义标识符,并做一个约定,P代表参数异常、B代表业务异常、S代表系统异常。

 

2.6 防止破窗

 

3、函数

3.3 封装判断

如果没有上下文,if和while语句中的布尔逻辑就难以理解。如果把解释条件意图作为函数抽离出来,用函数名把判断条件的语句显性化地表达出来,就能立即提升代码的可读性和可理解性。

 

3.4 函数参数  3.5 短小的函数

作者的建议边界是:3个和20行

 

3.7 精简辅助代码

3.7.1 优化判空

Optional.ofNullable

3.7.2 优化缓存判断

此处我认为作者想表达的是利用注解替换铅板代码

实际案例:利用注解实现productId校验

 

3.8 组合函数模式 3.9 SLAP

组合函数要求将一个大函数拆成多个子函数的组合,而抽象层次一致性(Single Level of Abstraction Principle, SLAP)要求函数体中的内容必须在同一个抽象层次上,如果高层次抽象和底层细节杂糅在一起,就会显得凌乱,难以理解。

 

4、设计原则

4.1 SOLID概览

SRP、OCP、LSP、ISP、DIP

 

 4.2 SRP(单一职责原则)

衡量标准是模块是否只有一个被修改的原因。

 

4.3 OCP(开闭原则)

软件实体应该对扩展开放,对修改关闭。在面向对象设计中,我们通常通过继承和多态来实现OCP;还可以通过设计模式来实现,如:装饰者模式、策略模式、适配器模式、观察者模式。

 

4.4 LSP(里式替换原则)

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

 

4.5 ISP(接口隔离原则)

 

4.6 DIP(依赖倒置原则)

模块之间交互应该依赖抽象,而非实现。在COLA架构中,领域层不应该直接依赖基础设施层,它们之间的解耦就是通过DIP完成的。

 

4.9 Rule of Three

第一次,写一个特定方法;第二次,复制上一次的代码;第三次,抽象。

 

5、设计模式

(本章没有什么具体的内容)

 

6、模型

6.3 类图

类图不仅可以表示类之间的关系,其表示法还可以表达领域概念之间的关系,非常适合进行领域建模。

6.3.1 类的UML表示法

包括:类名、类的属性、类的操作

可见性:+(public)、-(private)、#(protected)

例:

6.3.2 类的关联关系

表示方法多重性说明
1——1..11对1的关系
1——0..*1对0或多的关系
1——1..*1对1或多的关系
1——0..11对0或1的关系
1——m..n1对m到n的关系

tips:

1)空心菱形代表聚合关系;

2)实心菱形代表组合关系,同生共死的关系,代码上的体现就是没有setter方法;

6.3.3 类的依赖关系

依赖关系用带箭头的虚线表示,由依赖一方指向被依赖的一方。

实施:作为方法中的参数、作为局部变量、调用另一个类中的静态方法。

6.3.4 类的泛化

泛化关系用带空心三角形的直线来表示。Java中即extends

6.3.5 接口与实现关系

接口与实现关系用带空心三角形虚线来表示。

 

7、DDD的精髓

7.5 DDD的核心概念

7.5.1 领域实体

判断领域实体一个简单的方法就是“找名词”。

7.5.2 聚合根

聚合根会把一组有相同生命周期、在业务上不可分割的实体和值对象放在一起,只有根实体可以对外暴露引用,这也是内聚性的一种表现。

7.5.3 领域服务

例:MoneyTransferDomainService

1)服务执行的操作代表了一个领域概念,这个概念无法自然地隶属于一个实体或者值对象;

2)被执行的操作涉及领域中的其他对象;

3)操作是无状态的。

7.5.4 领域事件

1)事件命名:推荐DomainName+动词的过去式+Event

2)事件内容:自恰,就是在事件payload中尽量多放数据,这样consumer不需要回查就能处理消息;回查,只在payload中放置id属性。

7.5.5 边界上下文

通过ACL(防腐层)实现

 

7.6 领域建模方法

7.6.1 用例分析法

1)获取用例描述;2)寻找概念类;3)添加关联;4)添加属性(区分概念和属性);5)模型精化(UML)。

7.6.2 四色建模法

 

7.8 为什么DDD饱受争议

7.8.1 照搬概念

7.8.2 抽象的灵活性

7.8.3 领域的边界

核心业务逻辑和技术细节相分离

消除Domain对Infrastructure的依赖性

1)使用依赖倒置

2)将Repository上移到Application层,也就是把组装Entity的责任转移给Application。

tip:COLA 2.0采用 2),但是我觉得 1)更合理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值