我在阿里写代码学会的六件事

简介: 从团队的角度来看,写好代码是一件非常有必要的事情。如何写出干净优雅的代码是个很困难的课题,我没有找到万能的 solution,更多的是一些 trade off,可以稍微讨论一下。

8.14头图.png

写了多年的代码,始终觉得如何写出干净优雅的代码并不是一件容易的事情。按 10000 小时刻意训练的定理,假设每天 8 小时,一个月 20 天,一年 12 个月,大概也需要 5 年左右的时间成为大师。其实我们每天的工作中真正用于写代码的时间不可能有 8 个小时,并且很多时候是在完成任务,在业务压力很大的时候,可能想要达到的目标是如何尽快的使得功能 work 起来,代码是否干净优雅非常可能没有能放在第一优先级上,而是怎么快怎么来。

在这样的情况下是非常容易欠下技术债的,时间长了,这样的代码基本上无法维护,只能推倒重来,这个成本是非常高的。欠债要还,只是迟早的问题,并且等到要还的时候还要赔上额外的不菲的利息。还债的有可能是自己,也有可能是后来的继任者,但都是团队在还债。所以从团队的角度来看,写好代码是一件非常有必要的事情。如何写出干净优雅的代码是个很困难的课题,我没有找到万能的 solution,更多的是一些 trade off,可以稍微讨论一下。

代码是写给人看的还是写给机器看的?

在大部分的情况下我会认为代码是写给人看的。虽然代码最后的执行者是机器,但是实际上代码更多的时候是给人看的。我们来看看一段代码的生命周期:开发 --> 单元测试 --> Code Review --> 功能测试 --> 性能测试 --> 上线 --> 运维、Bug 修复 --> 测试上线 --> 退休下线。开发到上线的时间也许是几周或者几个月,但是线上运维、bug 修复的周期可以是几年。

在这几年的时间里面,几乎不可能还是原来的作者在维护了。继任者如何能理解之前的代码逻辑是极其关键的,如果不能维护,只能自己重新做一套。所以在项目中我们经常能见到的情况就是,看到了前任的代码,都觉得这是什么垃圾,写的乱七八糟,还是我自己重写一遍吧。就算是在开发的过程中,需要别人来 Code  Review,如果他们都看不懂这个代码,怎么来做 Review 呢。还有你也不希望在休假的时候,因为其他人看不懂你的代码,只好打电话求助你。这个我印象极其深刻,记得我在工作不久的时候,一次回到了老家休假中,突然同事打电话来了,出现了一个问题,问我该如何解决,当时电话还要收漫游费的,非常贵,但是我还不得不支持直到耗光我的电话费。

所以代码主要还是写给人看的,是我们的交流的途径。那些非常好的开源的项目虽然有文档,但是更多的我们其实还是看他的源码,如果开源项目里面的代码写的很难读,这个项目也基本上不会火。因为代码是我们开发人员交流的基本途径,甚至可能口头讨论不清楚的事情,我们可以通过代码来说清楚。代码的可读性我觉得是第一位的。各个公司估计都有自己的代码规范,遵循相关的规范保持代码风格的统一是第一步(推荐谷歌代码规范和微软代码规范)。规范里一般都包括了如何进行变量、类、函数的命名,函数要尽量短并且保持原子性,不要做多件事情,类的基本设计的原则等等。另外一个建议是可以多参考学习一下开源项目中的代码。

KISS (Keep it simple and stupid)

一般大脑工作记忆的容量就是 5-9 个,如果事情过多或者过于复杂,对于大部分人来说是无法直接理解和处理的。通常我们需要一些辅助手段来处理复杂的问题,比如做笔记、画图,有点类似于在内存不够用的情况下我们借用了外存。

学 CS 的同学都知道,外存的访问速度肯定不如内存访问速度。另外一般来说在逻辑复杂的情况下出错的可能要远大于在简单的情况下,在复杂的情况下,代码的分支可能有很多,我们是否能够对每种情况都考虑到位,这些都有困难。为了使得代码更加可靠,并且容易理解,最好的办法还是保持代码的简单,在处理一个问题的时候尽量使用简单的逻辑,不要有过多的变量。

但是现实的问题并不会总是那么简单,那么如何来处理复杂的问题呢?与其借用外存,我更加倾向于对复杂的问题进行分层抽象。网络的通信是一个非常复杂的事情,中间使用的设备可以有无数种(手机,各种 IOT 设备,台式机,laptop,路由器,交换机...), OSI 协议对各层做了抽象,每一层需要处理的情况就都大大地简化了。通过对复杂问题的分解、抽象,那么我们在每个层次上要解决处理的问题就简化了。其实也类似于算法中的 divide-and-conquer, 复杂的问题,要先拆解掉变成小的问题,从而来简化解决的方法。

KISS 还有另外一层含义,“如无必要,勿增实体” (奥卡姆剃刀原理)。CS 中有一句 "All problems in computer science can be solved by another level of indirection", 为了系统的扩展性,支持将来的一些可能存在的变化,我们经常会引入一层间接层,或者增加中间的 interface。在做这些决定的时候,我们要多考虑一下是否真的有必要。增加额外的一层给我们的好处就是易于扩展,但是同时也增加了复杂度,使得系统变得更加不可理解。对于代码来说,很可能是我这里调用了一个 API,不知道实际的触发在哪里,对于理解和调试都可能增加困难。

KISS 本身就是一个 trade off,要把复杂的问题通过抽象和分拆来简单化,但是是否需要为了保留变化做更多的 indirection 的抽象,这些都是需要仔细考虑的。

DRY (Don't repeat yourself)

为了快速地实现一个功能,知道之前有类似的,把代码 copy 过来修改一下就用,可能是最快的方法。但是 copy 代码经常是很多问题和 bug 的根源。有一类问题就是 copy 过来的代码包含了一些其他的逻辑,可能并不是这部分需要的,所以可能有冗余甚至一些额外的风险。

另外一类问题就是在维护的时候,我们其实不知道修复了一个地方之后,还有多少其他的地方还需要修复。在我过去的项目中就出现过这样的问题,有个问题明明之前做了修复,过几天另外一个客户又提了类似的问题出现的另外的路径上。相同的逻辑要尽量只出现在一个地方,这样有问题的时候也就可以一次性地修复。这也是一种抽象,对于相同的逻辑,抽象到一个类或者一个函数中去,这样也有利于代码的可读性。

是否要写注释

个人的观点是大部分的代码尽量不要注释。代码本身就是一种交流语言,并且一般来说编程语言比我们日常使用的口语更加的精确。在保持代码逻辑简单的情况下,使用良好的命名规范,代码本身就很清晰并且可能读起来就已经是一篇良好的文章。特别是 OO 的语言的话,本身 object(名词)加 operation(一般用动词)就已经可以说明是在做什么了。重复一下把这个操作的名词放入注释并不会增加代码的可读性。并且在后续的维护中,会出现修改了代码,却并不修改注释的情况出现。在我做的很多 Code Review 中我都看到过这样的情况。尽量把代码写的可以理解,而不是通过注释来理解。

当然我并不是反对所有的注释,在公开的 API 上是需要注释的,应该列出 API 的前置和后置条件,解释该如何使用这个 API,这样也可以用于自动产品 API 的文档。在一些特殊优化逻辑和负责算法的地方加上这些逻辑和算法的解释还是非常有必要的。

一次做对,不要相信以后会 Refactoring

通常来说在代码中写上 TODO,等着以后再来 refactoring 或者改进,基本上就不会再有以后了。我们可以去我们的代码库里面搜索一下 TODO,看看有多少,并且有多少是多少年前的,我相信这个结果会让你很惊讶(欢迎大家留言分享你查找之后的结果)。

尽量一次就做对,不要相信以后还会回来把代码 refactoring 好。人都是有惰性的,一旦完成了当前的事情,move on 之后再回来处理这些概率就非常小了,除非下次真的需要修改这些代码。如果说不会再回来,那么这个 TODO 也没有什么意义。如果真的需要,就不要留下这个问题。我见过有的人留下了一个 TODO,throw 了一个 not implemented 的 exception,然后几天之后其他同学把这个代码带上线了,直接挂掉的情况。尽量不要 TODO, 一次做好。

是否要写单元测试?

个人的观点是必须,除非你只是做 prototype 或者快速迭代扔掉的代码。

Unit tests are typically automated tests written and run by software developers to ensure that a section of an application (known as the "unit") meets its design and behaves as intended. In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure. In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method. 

 From Wikipedia

单元测试是为了保证我们写出的代码确实是我们想要表达的逻辑。当我们的代码被集成到大项目中的时候,之后的集成测试、功能测试甚至 e2e 的测试,都不可能覆盖到每一行的代码了。如果单元测试做的不够,其实就是在代码里面留下一些自己都不知道的黑洞,哪天调用方改了一些东西,走到了一个不常用的分支可能就挂掉了。我之前带的项目中就出现过类似的情况,代码已经上线几年了,有一次稍微改了一下调用方的参数,觉得是个小改动,但是上线就挂了,就是因为遇到了之前根本没有人测试过的分支。单元测试就是要保证我们自己写的代码是按照我们希望的逻辑实现的,需要尽量的做到比较高的覆盖,确保我们自己的代码里面没有留下什么黑洞。关于测试,我想单独开一篇讨论,所以就先简单聊到这里。

要写好代码确实是已经非常不容易的事情,需要考虑正确性、可读性、鲁棒性、可测试性、可以扩展性、可以移植性、性能。前面讨论的只是个人觉得比较重要的入门的一些点,想要写好代码需要经过刻意地考虑和练习才能真正达到目标!

 

 

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

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

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

相关文章

FLOWABLE 流程中的自动跳过

文章目录1. 背景2. 流程3. 实施方案1. 背景 在实际场景中,我们往往会有这样的需求,当流程到达某一个节点的时候,当某角色或岗位不存在时直接跳过当前节点,到下一个节点(我们让其自动的跳过去,不做任何操作…

减少运维工作量,如何通过 ROS 轻松实现资源编排新方式

简介: 以“基础设施即代码”的理念代替“重复劳动”。 在日常工作中,我们一定遇到过需要快速构建系统的工作情形: 作为资源管理人员,需要接收一定数量以及配置的资源申请,这些申请要求网络、存储设备按需到位&#xf…

开放下载!《无需从0开发 平头哥教你1天上手蓝牙Mesh应用解决方案》

当你疲惫了一天,回到家里,点点手机灯就亮了,再唤醒天猫精灵放首歌,这样智能的家,恐怕这是很多人梦寐以求的吧。而蓝牙 MESH 智能灯,是智能家居系统中最基础的设施。蓝牙 MESH 智能灯是如何实现轻松、高效地…

2020 年微服务项目活跃度报告

简介: 2020 年 8 月 18 日,首届云原生微服务大会于线上召开,会议首日,阿里云资深技术专家、CNCF TOC 李响 Keynote 演讲中正式发布了《 2020 年微服务领域开源数字化报告》。 导读:2020 年 8 月 18 日,首届…

又一低代码平台火了!15 分钟小白轻松开发在线课堂,人人都是开发者时代来了?

据艾瑞咨询统计,2020 年中国在线教育行业市场规模 2573 亿元,过去 4 年的复合增长率达 34.5%。如今在线教育行业如火如荼,亟待一款好的在线教育平台。 此时,不少开发者和教育机构遇到新的难题:如果使用标准化 SaaS 平…

阿里巴巴大数据实践—实时技术

来源:数智化转型俱乐部 数据价值是具有时效性的,在一条数据产生的时候,如果不能及时处理并在业务系统中使用,就不能让数据保持最高的“新鲜度”和价值最大化。 相对于离线批处理技术,流式实时处理技术作为一个非常重…

全民加速节:全站加速在互联网媒体应用上的最佳实践

8月19日,全民加速节第三场直播中,阿里云CDN解决方案架构师拓州进行了《全站加速在媒体服务行业的实践》主题分享,针对互联网媒体服务行业中的特征和痛点,介绍阿里云全站加速产品的应用实践。 互联网媒体服务的特征 互联网媒体服…

云原生全景图之六 | 托管 Kubernetes 和 PaaS 解决什么问题

作者 | Catherine Paganini、Jason Morgan来源 | K8sMeetup头图 | 下载于视觉中国在本系列之前的文章中,我们讨论了 CNCF 云原生全景图的各层:供应层、运行时层、编排管理层以及应用定义和开发层。本文我们将聚焦在平台层。正如我们在本系列文章中看到的…

报告:5G 网络切片可能会给不法分子留下漏洞!

责编 | 寇雪芹头图 | 下载于视觉中国据爱尔兰安全公司 AdaptiveMobile Security 的一份报告显示,由于缺乏传输层与应用层之间的映射关系,因此结合了传统技术的 5G 网络可能更容易受到威胁。网络切片对于实现5G的许多功能至关重要。网络切片(N…

独家下载!小程序Serverless云上开发一站到底

阿里云小程序Serverless 提供包括云函数、数据存储、文件存储等一整套后端服务。开发者通过API 方式即可获取云函数、数据存储、文件存储、音视频、图像处理等服务,不需要关心服务器或底层运维设施,可以更专注于代码和业务本身。 《小程序Serverless 云…

Gartner发布云产品评估报告:阿里云计算能力全球第一

简介: 92.3% 得分率,阿里拿下计算类厂商全球第一。 8月17日消息,国际知名咨询机构Gartner发布了最新云厂商产品评估报告,作为国内唯一入选的云厂商,阿里云在计算大类中,以92.3%的高得分率拿下全球第一&…

携程赴港二次上市在即 “旅游营销枢纽”战略助价值重估

携程董事局主席梁建章发布“旅游营销枢纽战略”4月7日,携程集团有限公司正式启动香港公开发售计划。在赴港二次上市前夕,包括国盛证券、广发证券在内的多家券商公司维持对携程股票“买入”的评级,最新发布的“旅游营销枢纽”战略也将为携程的…

RuoYi-Vue Spring Security 配置介绍

文章目录核心配置类方法注解开关自定义认证规则自定义获取用户详情自定义注解实现匿名访问自定义验证异常处理类自定义登出逻辑流程自定义JWT拦截器核心配置类 核心配置文件 com.ruoyi.framework.config.SecurityConfig.java 方法注解开关 开启全局方法权限配置&#xff0c…

一个易用、易部署的Python遗传算法库

简介: # [scikit-opt](https://github.com/guofei9987/scikit-opt) [![PyPI](https://img.shields.io/pypi/v/scikit-opt)](https://pypi.org/project/scikit-opt/) [![release](https://img.shields.io/github/v/relea scikit-opt 一个封装了7种启发式算法的 Pyth…

如何部署一个Kubernetes集群

来源 | 无敌码农责编 | 寇雪芹头图 | 下载于视觉中国在上一篇文章《Kubernetes和Docker的关系是什么?》中,和大家分享了关于Kubernetes的基本系统架构以及关于容器编排相关的概念,并总体阐述Kubernetes与Docker之间的基本关系。而要学习Kuber…

KubeCon 2020 演讲集锦|《阿里巴巴云原生技术与实践 13 讲》开放下载

2020 年 7 月 30 日至 8 月 1 日,由 Cloud Native Computing Foundation (CNCF) 主办的云原生技术大会 Cloud Native Open Source Virtual Summit China 2020 首次于线上召开。 阿里巴巴在大会上为全球企业和开发者分享了 27 场实践经验、行业趋势和技术演讲&…

RuoYi-Vue Spring Security 密码加密

文章目录一、密码加密配置二、密码匹配~具体使用三、密码加密~具体使用一、密码加密配置 默认密码加密 encode密码加密和matches密码校验 二、密码匹配~具体使用 在登录接口进行用户名密码的验证 抽象方法 进入抽象方法 密码验证(明文密码和数据库一打包密已加…

限免下载!揭秘你不知道的计算机“进化论”

计算机的发展,除了ENIAC,你还知道什么? 是不是有点卡顿! 没关系,你只会更卡顿,因为下面的这些你可能从未听说: 你知道程序员的“开山鼻祖”是女性吗?你知道“ENIAC”专利曾经被盗吗…

吴文俊人工智能科学技术奖十周年颁奖盛典揭晓,100个项目成果摘得中国智能科学技术奖励最高殊荣

2021年4月10日上午,北京春意盎然,荣耀绽放。我国智能科学技术最高奖“吴文俊人工智能科学技术奖”十周年颁奖盛典在此揭晓。军事科学院系统工程研究院研究员、中国工程院院士李德毅在计算机工程、自动控制、认知科学和无人驾驶等人工智能领域取得多项国际…

RuoYi-Vue Spring Security 登录配置

文章目录自定义用户信息登录接口入口调用loadUserByUsername方法重写实现逻辑自定义配置实现UserDetails接口自定义用户信息 登录接口入口 调用loadUserByUsername方法 重写实现逻辑 咱们自己实现了org.springframework.security.core.userdetails.UserDetailsService类重写lo…