平常开发中的一些代码设计感悟
代码设计原则 SOLID ,迪米特原则(Law of Demeter)
其中迪米特原则又叫最少知识原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public方法,不对外泄露任何信息。还有一个更简单的定义:只与直接朋友通信。
在平时开发中,在类,方法的设计上也尽量保持这个原则。A依赖B对象,A不直接调用B对象中依赖的对象,但完全参考这个原则开发,会导致类内部方法的膨胀。因此在设计需要自己做出权衡,但是其中的平衡点并不好找。后面读了《代码简洁之道》第六章中也有提到迪米特原则,说明了某些场景并不需要遵守这个原则,或者说该原则不适用这种场景,例如:A类依赖B类,B类可能是个数据结构,无对象行为,那么直接调用B内部的数据是可以的。然而在 Java 中因为定义私有变量的原因(内聚、封装),提供了大量的访问方法(get)、该值方法(set)
其中还提到了 隐藏结构
,接着上面那个例子,假设 A 依赖 B,B就是具有行为的对象,我们在定义 B 对外的行为,应该更加符合我们系统的业务行为。比如:
1 | // A 拿到的B的某个值(可能在B内部经过大量计算) |
这样满足了 迪米特原则,也不会导致 B 对象暴露内部过多的数据结构。
好的代码
- 通常说到好的代码,指的都是:好的可读性,好的命名,干脆的抽象,应用设计模型,选择适合的架构,兼顾 可扩展、高可用、可监控等等。
- 我想说的是,要编写好的代码的前提一定是 开发者要
用心
,用心 便会思考命名、抽象、充分酌量架构的取舍,用心便会写出好的代码。
系统架构
- 系统架构,应该区分核心功能,附加功能,前期针对核心功能定义好架构、模型、流程。核心功能的定义决定了系统的稳定性,好的定义对于系统设计也就成功一半了,额外功能、边角功能也就水到渠成了。
- 避免过度设计,不要先做大的设计。
- 一个好的系统,一定离不开一套好的模型定义。梳理清楚系统中的核心模型,清楚的定义每个方法的类归属,无论对于代码的可读性、可交流性,还是和产品沟通,都有着莫大的好处。
整洁代码
- 不要重复代码,只做一件事,表达力,小规模抽象
怎么理解重构?
重构不是把整个系统推到重来,把一个功能代码重新设计也是重构,提取一个方法也是重构。
重构是研发最重要的能力,重构的目的就是让代码符合设计原则,例如:单一原则。所有的方法可以是单一职责,即使是复杂的业务方法也是单一职责,那就是分发与聚合,典型的便是策略模式。
抽象
我的理解:抽象的本质是找事务的共性,找到共性便能抽取、抽象。
之前做的导出报表的功能,Release 有 操作时间、操作人、操作类型,Confirm 也有操作时间、操作人、操作类型(approve同理),这里就能找到Release、Confirm、Approve针对报表导出这个功能的共性,进行抽象
不要盲目追求性能,所谓的流行架构 (KISS[保持简单])
之前有个项目需要导出很全面的报表、还存在汇总计算的需求。因为当时项目牵扯到多方的数据源,如果实时去查询多个数据库聚合会导致接口响应慢,同时存在数据量大的情况甚至会拉垮服务。
我们当时想了一套方案:建立一个新的数据源(MongoDB),通过 ETL 清洗一份新的数据结构存储在数据源。
这里存在数据同步实时的问题,我们使用 Job 去同步新的数据源数据则会存在不准确。正对这个问题我们又想到 Flink 分布式实时处理引擎。
仔细一想,我们需要实时吗?我们沟通了需求,报表的内容一般是只会查看上个月的项目信息。因此实时是个伪需求,不要为了用新技术,而新技术,技术是用来服务业务的。
Unix哲学
- 程序应该只关注一件事,并把做好。
引申出来的关于程序设计的格言:
- 过早的优化是一切罪恶的来源
- 尽量使用简单的算法和数据结构
- 数据决定一切,选择对的数据结构,算法就无关痛痒了