这一团糟的代码,真的是我写的?!

阿里妹导读:你有没有遇到过这种情况:过几周或者几个月之后,再看到自己写的代码,感觉一团糟,不禁怀疑人生?我们每天都与代码打交道,但当被问道什么是好的代码时,很多人可能会先愣一下,然后给出的回答要么比较空泛,要么比较散,没办法简单明了地概括出来。今天,我们就来说什么是好的代码?

一句话概括
衡量代码质量的唯一有效标准:WTF/min —— Robert C. Martin

Bob大叔对于好代码的理解非常有趣,对我也有很大的启发。我们编写的代码,除了用于机器执行产生我们预期的效果以外,更多的时候是给人读的,这个读代码的可能是后来的维护人员,更多时候是一段时间后的作者本人。

我敢打赌每个人都遇到过这样的情况:过几周或者几个月之后,再看到自己写的代码,感觉一团糟,不禁怀疑人生。

我们自己写的代码,一段时间后自己看尚且如此,更别提拿给别人看了。

任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员。 —— Martin Fowler

所以,谈到好代码,首先跳入自己脑子里的一个词就是:整洁。好的代码一定是整洁的,给阅读的人一种如沐春风,赏心悦目的感觉。

整洁的代码如同优美的散文。 —— Grady Booch

好代码的特性

很难给好的代码下一个定义,相信很多人跟我一样不会认为整洁的代码就一定是好代码,但好代码一定是整洁的,整洁是好代码的必要条件。整洁的代码一定是高内聚低耦合的,也一定是可读性强、易维护的。

高内聚低耦合

高内聚低耦合几乎是每个程序员员都会挂在嘴边的,但这个词太过于宽泛,太过于正确,所以聪明的编程人员们提出了若干面向对象设计原则来衡量代码的优劣:

  • 开闭原则OCP (The Open-Close Principle)
  • 单一职责原则SRP (Single Responsibility Principle)
  • 依赖倒置原则DIP (Dependence Inversion Principle)
  • 最少知识原则LKP (Least Knowledge Principle)) / 迪米特法则 (Law Of Demeter)
  • 里氏替换原则LSP (Liskov Substitution Principle)
  • 接口隔离原则ISP (Interface Segregation Principle)
  • 组合/聚合复用原则CARP (Composite/Aggregate Reuse Principle)

这些原则想必大家都很熟悉了,是我们编写代码时的指导方针,按照这些原则开发的代码具有高内聚低耦合的特性。换句话说,我们可以用这些原则来衡量代码的优劣。

但这些原则并不是死板的教条,我们也经常会因为其他的权衡(例如可读性、复杂度等)违背或者放弃一些原则。比如子类拥有特性的方法时,我们很可能打破里氏替换原则。再比如,单一职责原则跟接口隔离原则有时候是冲突的,我们通常会舍弃接口隔离原则,保持单一职责。只要打破原则的理由足够充分,也并不见得是坏的代码。

可读性

代码只要具有了高内聚和低耦合就足够好了吗?并不见得,我认为代码还必须是易读的。好的代码无论是风格、结构还是设计上都应该是可读性很强的。可以从以下几个方面考虑整洁代码,提高可读性。

| 命名

大到项目名、包名、类名,小到方法名、变量名、参数名,甚至是一个临时变量的名称,其命名都是很严肃的事,好的名字需要斟酌。
名副其实:好的名称一定是名副其实的,不需要注释解释即可明白其含义的。

/**
* 创建后的天数
**/
int d;
int daysSinceCreation;

后者比前者的命名要好很多,阅读者一下子就明白了变量的意思。

容易区分:我们很容易就会写下非常相近的方法名,仅从名称无法区分两者到底有啥区别(eg. getAccount()与getAccountInfo()),这样在调用时也很难抉择要用哪个,需要去看实现的代码才能确定。

可读的:名称一定是可读的,易读的,最好不要用自创的缩写,或者中英文混写。
足够短:名称当然不是越长越好,应该在足够表达其含义的情况下越短越好。

| 格式

良好的代码格式也是提高可读性非常重要的一环,分为垂直格式和水平格式。

垂直格式:通常一行只写一个表达式或者子句。一组代码代表一个完整的思路,不同组的代码中间用空行间隔。


public class Demo {
@Resource
private List<Handler> handlerList;
private Map<TypeEnum, Handler> handlerMap = new ConcurrentHashMap<>();@PostConstruct
private void init() {
if (!CollectionUtils.isEmpty(handlerList)) {
for (Handler handler : handlerList) {handlerMap.put(handler.getType(), handler);}}}public Result<Map<String, Object>> query(Long id, TypeEnum typeEnum) {Handler handler = handlerMap.get(typeEnum);
if (null == handler) {
return Result.returnFailed(ErrorCode.CAN_NOT_HANDLE);}
return handler.query(id);}
}

如果去掉了空行,可读性大大降低:


public class Demo {
@Resource
private List<Handler> handlerList;
private Map<TypeEnum, Handler> handlerMap = new ConcurrentHashMap<>();
@PostConstruct
private void init() {
if (!CollectionUtils.isEmpty(handlerList)) {
for (Handler handler : handlerList) {handlerMap.put(handler.getType(), handler); } } }
public Result<Map<String, Object>> query(Long id, TypeEnum typeEnum) {Handler handler = handlerMap.get(typeEnum);
if (null == handler) {
return Result.returnFailed(ErrorCode.CAN_NOT_HANDLE);}
return handler.query(id); }
}

类静态变量、实体变量应定义在类的顶部。类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter方法。

水平格式:要有适当的缩进和空格。

团队统一:通常,同一个团队的风格尽量保持一致。集团对于Java开发进行了非常详细的规范。

| 类与函数

类和函数应短小,更短小:类和函数都不应该过长(集团要求函数长度最多不能超过80行),过长的函数可读性一定差,往往也包含了大量重复的代码。

函数只做一件事(同一层次的事):同一个函数的每条执行语句应该是统一层次的抽象。例如,我们经常会写一个函数需要给某个DTO赋值,然后再调用接口,接着返回结果。那么这个函数应该包含三步:DTO赋值,调用接口,处理结果。如果函数中还包含了DTO赋值的具体操作,那么说明此函数的执行语句并不是在同一层次的抽象。

参数越少越好:参数越多的函数,调用时越麻烦。尽量保持参数数量足够少,最好是没有。

| 注释

别给糟糕的代码加注释,重构他:注释不能美化糟糕的代码。当企图使用注释前,先考虑是否可以通过调整结构,命名等操作,消除写注释的必要,往往这样做之后注释就多余了。

好的注释提供信息、表达意图、阐释、警告:我们经常遇到这样的情况:注释写的代码执行逻辑与实际代码的逻辑并不符合。大多数时候都是因为代码变化了,而注释并没有跟进变化。所以,注释最好提供一些代码没有的额外信息,展示自己的设计意图,而不是写具体如何实现。

删除掉注释的代码:git等版本控制已经帮我们记录了代码的变更历史,没必要继续留着过时的代码,注释的代码也会对阅读等造成干扰。

| 错误处理

错误处理很重要,但他不能搞乱代码逻辑:错误处理应该集中在同一层处理,并且错误处理的函数最好不包含其他的业务逻辑代码,只需要处理错误信息即可。

抛出异常时提供足够多的环境和说明,方便排查问题:异常抛出时最好将执行的类名,关键数据,环境信息等均抛出,此时自定义的异常类就派上用场了,通过统一的一层处理异常,可以方便快速地定位到问题。

特例模型可消除异常控制或者null判断:大多数的异常都是来源于NPE,有时候这个可以通过Null Object来消除掉。

尽量不要返回null,不要传null参数:不返回null和不传null也是为了尽量降低NPE的可能性。

如何判断不是好的代码?

讨论了好代码的必要条件,我们再来看看好代码的否定条件:什么不是好的代码。
Kent Beck使用味道来形容重构的时机,我认为当代码有坏味道的时候,也代表了其并不是好的代码。

代码的坏味道

重复可能是软件中一`切邪恶的根源。 —— Robert C.Martin

重复:Martin Fowler也认为坏味道中首当其冲的就是重复代码。很多时候,当我们消除了重复代码之后,发现代码就已经比原来整洁多了。

函数过长、类过大、参数过长:过长的函数解释能力、共享能力、选择能力都较差,也不易维护。

过大的类代表了类做了很多事情,也常常有过多的重复代码。

参数过长,不易理解,调用时也容易出错。

发散式变化、霰弹式修改、依恋情结:如果一个类不是单一职责的,则不同的变化可能都需要修改这个类,说明存在发散式变化,应考虑将不同的变化分离开。

如果某个变化需要修改多个类的方法,则说明存在霰弹式修改,应考虑将这些需要修改的方法放入同一个类。

如果函数对于某个类的兴趣高于了自己所处的类,说明存在依恋情结,应考虑将函数转移到他应有的类中。

数据泥团:有时候会发现三四个相同的字段,在多个类和函数中均出现,这时候说明有必要给这一组字段建立一个类,将其封装起来。

过多的if...else 或者使用switch:过多的if...else或者switch,都应该考虑用多态来替换掉。甚至有些人认为除个别情况外,代码中就不应该存在if...else。

总结

本文首先一句话概括了我认为的好代码的必要条件:整洁,接着具体分析了整洁代码的特点,又分析了好代码的否定条件:什么样的代码不是好的代码。仅是本人的一些见解,希望对各位以后的编程有些许的帮助。

我认为仅仅编写出可运行的代码是远远不够的,还要时刻注意代码的整洁度,留下一些漂亮的代码。


原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/517911.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

迅雷下载Linux Oracle11gR2和Oracle12c

很多朋友分享的都是百度云盘链接&#xff0c;那个下载速度对于贫民来说&#xff0c;真的是等到花都谢了 而Oracle官网现在只能下载Oracle19C了&#xff0c;特此分享11和12版本的迅雷下载链接 11g下载链接&#xff1a; https://download.oracle.com/otn/linux/oracle11g/R2/lin…

除了吃月饼,中秋节还能干啥?

明天 八月十五&#xff0c;团圆夜 花好月圆之际 除了吃月饼&#xff0c;还能干啥&#xff1f; 阿里妹带来双重好礼&#xff0c;陪你过中秋~ &#xff08;往下看&#xff0c;送云栖大会三日通票哦&#xff09; 1重礼 — 阿里技术热门精选 — 《Java 开发手册》发布&#…

恭喜了!5 月逼自己学下这项技能,年薪 35 万起

你觉得 15 年内自己所在的 IT 行业很安全吗&#xff1f;No&#xff01;据麦肯锡全球研究院发布的一份就业报告中显示&#xff0c;到 2030 年&#xff0c;中国预计将有 1200 万&#xff5e; 1.02 亿人面临重新就业的局面。越来越多的人学习编程不再只是为了当程序员&#xff0c;…

Linux7/Redhat7/Centos7 安装Oracle 12C_系统安装_01

文章目录一、安装虚拟机1. 新建虚拟机2. 稍后安装3. 选择linux版本4. 安装位置5. 处理器配置6. 内存配置7. 网络配置8. 创建新磁盘9. 设置磁盘大小10. 选择镜像&#xff0c;完成二、虚拟机配置2.1. 重新启动2.2. 选择语言2.3. 设置时区2.4. 选择安装模式2.5. 自定义分区2.6. 接…

源码分析RocketMQ ACL实现机制

有关RocketMQ ACL的使用请查看上一篇《RocketMQ ACL使用指南》&#xff0c;本文从源码的角度&#xff0c;分析一下RocketMQ ACL的实现原理。 备注&#xff1a;RocketMQ在4.4.0时引入了ACL机制&#xff0c;本文代码基于RocketMQ4.5.0版本。 根据RocketMQ ACL使用手册&#xff0c…

Linux7/Redhat7/Centos7 安装Oracle 12C_配置IP、系统参数_02

文章目录一、基础配置1. 重新启动2. 安装VMware Tools3. 修改主机名4. 网络配置5. 重新加载网络二、配置系统参数2.1. 检查硬件环境2.2. 查看共享内存大小2.3. 创建用户和组2.4. 配置内核参数2.5. 配置资源限制2.6. 创建目录赋予权限2.7. 设置环境变量2.8. 映射配置三、基础关闭…

华为:跨过时艰,向未来

[中国&#xff0c;深圳&#xff0c;2020年5月18日] 华为公司第十七届全球分析师大会18日在深圳开幕。华为与来自全球的2000多名行业分析师&#xff0c;金融分析师&#xff0c;通讯、互联网、金融等行业意见领袖和媒体一起&#xff0c;以现场在线的方式&#xff0c;共同探讨在当…

阿里巴巴飞天大数据架构体系与Hadoop生态系统

很多人问阿里的飞天大数据平台、云梯2、MaxCompute、实时计算到底是什么&#xff0c;和自建Hadoop平台有什么区别。 先说Hadoop 什么是Hadoop&#xff1f; Hadoop是一个开源、高可靠、可扩展的分布式大数据计算框架系统&#xff0c;主要用来解决海量数据的存储、分析、分布式…

Linux7/Redhat7/Centos7 安装Oracle 12C_配置VNC远程安装数据库_03

文章目录1. yum安装VNC2. 在线安装时钟3. VNC配置4. 重新加载5. 加入开机自启动6. 启动vncserver7. vnc测试1. yum安装VNC # 在线安装vnc yum install tigervnc-server2. 在线安装时钟 # 在线安装时钟为了测试远程连接oracle主服务器图形化 yum install xclock3. VNC配置 # …

对不起,我把APP也给爬了

来源 | 凹凸数据责编 | Carol封图 | CSDN 付费下载于视觉中国最近群里很多小伙伴对爬取手机App和小程序感兴趣&#xff0c;今天本厨师将给大家呈现这道菜&#xff0c;供小伙伴们品尝。相信大家都对爬虫有一定的了解&#xff0c;我们爬PC端时候可以打开F12去观察url的变化&#…

从踩坑到填坑|淘宝Web 3D应用与游戏开发实战

导读&#xff1a;本文是淘宝前端技术专家——徐乾伟&#xff08;烧鹅&#xff09;分享的淘宝 Web 3D 应用与游戏开发实战&#xff0c;这个话题在业界被谈及得比较少。今天将会从移动、3D、游戏三种交叉的话题来和大家探讨。接下来和小编一起从初试 Web 3D、使用 WebGL、工作流相…

Warning: Missing charsets in String to FontSet conversion

当出现Warning: Missing charsets in String to FontSet conversion时 输入export LANGC即可解决

sstableloader工具使用及原理解析

sstableloader是cassandra提供的bulkload工具&#xff0c;可以将sstable文件导入到集群中。本文详细介绍其用法和实现原理。 用法 sstableloader工具在cassandra的bin目录下面&#xff0c;用法如下&#xff1a; bin/sstableloader <options> <dir_path> 具体的…

什么是工程师文化?

作者 | 王尊&#xff0c;帷幄 Whale CTO责编 | 唐小引头图 | CSDN 下载自东方 IC出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;什么是工程师文化&#xff1f;这篇文章的契机&#xff0c;是在 Whale All Hands 上团队成员提出的问题基础上展开的。All Hands 后我在…

Linux7/Redhat7/Centos7 安装Oracle 12C_安装Oracle软件_04

文章目录一、安装准备1. 下载oracle12c2. 上传oracle12c3. 赋予权限4. vnc远程连接主机5. 解压5. 安装二、安装流程2.1. 邮箱设置2.2. 只安装数据库软件2.2. 单实例数据库安装2.3. 企业级数据库2.4. 校验依赖2.5. 依赖安装2.6. root执行脚本2.7. OK2.8. 完成安装一、安装准备 …

从校招生到核心架构师,支付宝研究员李俊奎谈如何成为一名优秀的程序员

校招进入支付宝&#xff0c;11年时间&#xff0c;从一线工程师成长为支付宝安全核心架构师&#xff0c;这个技术牛人就是李俊奎。 李俊奎一直聚焦风控平台的技术和架构发展&#xff0c;并着手搭建了中国第一家云上的商业银行——网商银行。 在2016年双11和新春红包等活动中&a…

在 Apache Spark 中利用 HyperLogLog 函数实现高级分析

在 Apache Spark 中利用 HyperLogLog 函数实现高级分析 预聚合是高性能分析中的常用技术&#xff0c;例如&#xff0c;每小时100亿条的网站访问数据可以通过对常用的查询纬度进行聚合&#xff0c;被降低到1000万条访问统计&#xff0c;这样就能降低1000倍的数据处理量&#xf…

华为智能IP网络,加速联接智能化转型

[中国&#xff0c;深圳&#xff0c;2020年5月19日]在华为第17届全球分析师大会期间&#xff0c;华为“引领智能网络&#xff0c;加速联接智能化转型”峰会隆重召开&#xff0c;会上首次阐述了智能IP网络的三大特征——“智能超宽、智能联接、智能运维”&#xff0c;并分享智能I…

Linux7/Redhat7/Centos7 安装Oracle 12C_监听配置及DBCA安装数据库_05

文章目录一、监听配置二、创建数据库一、监听配置 # 切换到oracle用户 su - oracle# 启动监听图形化页面 netca二、创建数据库 dbca

Kubernetes-native 弹性分布式深度学习系统

9月11日&#xff0c;蚂蚁金服在 Google Developer Day Shanghai 2019 上宣布开源了基于 TensorFlow 2.0 eager execution 的分布式深度学习系统 ElasticDL。基于 TensorFlow 的支持弹性调度的深度学习系统&#xff0c;据我们所知&#xff0c;ElasticDL 是第一 个。项目负责人王…