代码质量在「内卷时代」的重要性

这里是Z哥的个人公众号

每周五11:45 按时送达

当然了,也会时不时加个餐~

我的第「173」篇原创敬上

大家好,我是Z哥。

提到代码质量,不知道你的脑海中浮现出的第一个词是什么?规范?可读性?优雅?

在我的心中,好的代码质量 = 舒服。看着舒服,接手这样的项目感觉舒服,在其中找问题和改代码舒服。

软件开发这个行业是一个年轻的行业,如果在十几年前谈代码质量,可能还算是个比较高级的问题。但是在大家都认为越来越内卷的当下,注重和提升代码质量我认为是每个程序员的必修课。说的严重一些,它影响了你在团队中的价值,说的表面一些,它是你在团队中的“面子”。

假象一下,你接手了两个项目,一个项目代码干干净净、非常整洁,另一个随处可见的相似代码以及杂乱无章的分类摆放。你对这两个项目的前负责人是什么想法?未来你更愿意和谁合作?我想答案是显而易见的。

在我看来要写出舒服的代码并不需要对那些代码规范背的滚瓜烂熟,其实只要掌握一个六字核心原则:高内聚低耦合。如此写出的代码至少能在60分以上。

可以回想一下,当你在做一个简单项目的时候,使用那些成熟的框架和工具可以轻松地完成大部分工作。甚至会感觉有点无聊,因为感觉都是在CRUD。这就是应用了经过精心设计的高内聚低耦合的框架和工具所具有的效果,让事情变简单。

讲句题外话,「高内聚低耦合」在软件开发领域真是一个黄金原则,在哪都适用,大到一个分布式系统的设计,小到一个class的设计。如果我的脑子只能记住一条原则的话,毫不犹豫会选择它。

那么如何让自己也能写出高内聚低耦合的代码呢?我们要对「高内聚低耦合」有更深入地理解,而不是仅仅停留在这6个字上。

葡萄牙马德拉大学精确科学与工程中心的教授,被认为是计算机领域先驱者之一的赖瑞·康斯坦丁带队对内聚性和耦合性做了深入的研究和分析,对内聚性和耦合性的强弱关系进行了梳理,得到了以下结论。(摘自于维基百科)

内聚性的分类如下,强度由低到高排列:

偶然内聚性:是指模块中的机能只是刚好放在一起,模块中各机能之间唯一的关系是其位在同一个模块中(例如:“工具”模块)。

逻辑内聚性:是只要机能只要在逻辑上分为同一类,不论各机能的本质是否有很大差异,就将这些机能放在同一模块中(例如将所有的鼠标和键盘都放在输入处理副程序中)。模块内执行几个逻辑上相似的功能,通过参数确定该模块完成哪一个功能。

时间性内聚性:是指将相近时间点运行的程序,放在同一个模块中(例如在捕捉到一个异常后调用一函数,在函数中关闭已开启的文件、产生错误日志、并告知用户)。

程序内聚性:是指依一组会依照固定顺序运行的程序放在同一个模块中(例如一个函数检查文件的权限,之后开启文件)。

联系内聚性/信息内聚/通信内聚:是指模块中的机能因为处理相同的资料或者指各处理使用相同的输入数据或者产生相同的输出数据,因此放在同一个模块中(例如一个模块中的许多机能都访问同一个记录)。

依序内聚性/顺序内聚:是指模块中的各机能彼此的输入及输出资料相关,一模块的输出资料是另一个模块的输入,类似工厂的生产线(例如一个模块先读取文件中的资料,之后再处理资料)。

功能内聚性:是指模块中的各机能是因为它们都对模块中单一明确定义的任务有贡献(例如XML字符串的词法分析)。

耦合性的分类如下,强度由高到低排列:

内容耦合:也称为病态耦合当一个模块直接使用另一个模块的内部数据,或通过非正常入口而转入另一个模块内部。

共享耦合/公共耦合:也称为全局耦合指通过一个公共数据环境相互作用的那些模块间的耦合。公共耦合的复杂程度随耦合模块的个数增加而增加。

外部耦合:发生在二个模块共享一个外加的资料格式、通信协议或是设备界面,基本上和模块和外部工具及设备的沟通有关。

控制耦合:指一个模块调用另一个模块时,传递的是控制变量(如开关、标志等),被调模块通过该控制变量的值有选择地执行块内某一功能;

特征耦合/标记耦合:也称为数据结构耦合,是指几个模块共享一个复杂的数据结构,如高级语言中的数组名、记录名、文件名等这些名字即标记,其实传递的是这个数据结构的地址;

资料耦合/数据耦合:是指模块借由传入值共享资料,每一个资料都是最基本的资料,而且只分享这些资料(例如传递一个整数给计算平方根的函数)。

消息耦合:可以借由以下二个方式达成:状态的去中心化(例如在对象中),组件间利用传入值或消息传递 (计算机科学)来通信。

无耦合:模块完全不和其他模块交换信息。

如果你代码写的还不够多,上面有些差异还无法很好的感知。但是你不需要把这些概念一字一句背下来,只要平时在写代码的时候多思考一下:“当前的代码设计是属于哪种类型?”。如果不能确定的话回头来看这篇文章:D。慢慢地,通过写更多的代码,你会对耦合和内聚的强弱,有更敏感的感知力。

根据上面的这些概念,写出高质量代码的思路就很清晰了。method的归类、class的归类能根据功能内聚性归类的绝不用顺序内聚,能根据顺序内聚性归类的绝不用更弱的。耦合也是同样的,能不耦合的就不耦合,能用消息耦合的绝不用数据耦合。

但是想要保证代码按照这个设想去发展,还是需要通过做一些具体的事情作为抓手。这些事不需要全部做,但每一项都有助于提高代码质量。

/01  执行代码规范+Code Review/

在Z哥看来,执行代码规范,最重要的价值并不是非得让100%的代码符合这个规范,而是让所有人一起养成一种意识,意识到我的代码会被别人看到,被评价。这样才能在写代码的时候,不仅仅是为了实现功能。

所以具体代码规范是什么样,并没那么重要,可以是自己定义的,也可以是参考大厂的。当然我更推荐前者,大厂的规范虽好,但是你要全部照搬,这个执行成本可不小。

如果你想提高代码质量,但又不想做很多事。那么执行代码规范+Code Review可以是你的唯一选择。如果你是一位个人开发者,那么可以让身边你认为代码写的最好的人帮你做CodeReview,以他的规范作为代码规范即可。

很多人觉得代码规范是一种约束,会降低开发效率。其实不会,最多在初期因为自己并不习惯一些规范,所以花了很多时间在修正代码。一旦走上正轨后,代码规范反而会提高开发效率,因为节省了很多阅读代码的时间以及同事之间沟通的时间。

就算它真的降低了开发效率,但你要提升效率也不应该降低代码质量,而是通过其它方式去提效。

/02  写单元测试/

写单元测试之所以能提高代码质量,是因为如果不是高内聚低耦合的代码,你会发现单元测试非常难写。

比如,你只想测一下方法A,但是发现里面的依赖错综复杂,好吧,都stub掉。最后发现测一个方法写了几十个stub,这种操作我亲眼看到过……。这就是前面提到的「内容耦合」过多了。

所以,能轻松地写出单元测试,并且将其养成一种习惯,你的代码质量必然不会差。

/03  设计先行/

虽然设计不出完美的代码,但是优先考虑设计可以让你多思考“我应该怎么写这段代码”,而不是直接抄起家伙就写,写到哪算到哪。

毕竟大多数功能都不可能一步到位,需要多次迭代。这种情况下最初的设计就显得尤为重要,毕竟大部分人遇到不舒服的代码不会推翻重写,最多就是修修补补,甚至是直接在这之上叠加新的代码。

/04  项目与团队”微服务化”/

保证一个几万行代码的项目质量和几百万行代码的项目必然难度不同。所以,如果合适的话可以将项目拆小,并且由专门的团队负责。这样可以提高团队把控代码质量意愿,并降低其难度。

/05  利用相关的工具/

主流的编程语言或多或少都有一些静态代码分析工具、单元测试覆盖率统计工具,这些要充分利用起来。它们可以快速的帮助避免一些低级的代码坏味道,节约大量时间。

/06  几个代码层面的小建议/  

01  勿过度使用链式编程

很多人会追求极致少的代码行数,恰好链式编程能投其所好。的确在很多时候链式编程可以提高代码的可读性,但是它带来的弊端也是显而易见的,

  1. 调试的时候观察变量变得很不方便。

  2. 容易在当前方法里处理不应该在这里处理的业务逻辑。毕竟很多class的方法和属性是public的,相比单独做一层封装再调用,“点”出来直接用多香啊~所以在使用链式编程的时候也得遵守「得墨忒耳定律」。

得墨忒耳定律:

每个单元对于其他的单元只能拥有有限的知识:只是与当前单元紧密联系的单元;

每个单元只能和它的朋友交谈:不能和陌生单元交谈;

只和自己直接的朋友交谈。

维基百科

02  避免随处可见的try-catch

Try-catch虽好,切勿贪杯。很多人喜欢写try-catch然后通过一个单独封装的通用返回模型告知调用方出现了什么异常。

这种方法的目的最初是为了避免上层调用者没有做异常捕获导致程序崩溃,但是弊端也是显而易见的,如果调用方没有正确的判断返回模型里的异常相关属性,会导致程序在错误的状态下继续执行,这个后果就不可预知了。

所以我认为通过try-catch封装异常应该出现在更上层的代码里,越底层的代码越不应该封装异常。

03  认真编写访问修饰符

很多编程语言都有多个访问修饰符,我们在编写的代码的时候应该尽可能的选择最严格的修饰符,而不是什么都是public。

因为public会导致很多变量在不知道什么情况下就被外部修改了,导致bug层出不穷、排查困难,项目质量堪忧。

访问修饰符的过于宽松也是前面提到的链式编程被过度使用的推手之一。

访问修饰符的目的是为了防止程序员在无意间误用不应该使用的方法和属性,毕竟代码往往不只有一个人写。

04  慎用继承

继承的确挺香的,可以少写很多代码。但是使用不当会破坏封装的效果,造成访问修饰符的失效。

继承的正确使用姿势应该传达的是“子父”的关系,而不是“相似”的关系。比如“汽车”可以继承于“交通工具”,但是不应该继承于“自行车”,虽然它们都有轮子。

像汽车和自行车的这种情况要复用的话,可以抽象提炼出相同的部分,然后通过「组合」的方式进行。

最后,如果你对代码质量有更高的追求,想修炼和强化“内功”,那必须不能错过这本经典书籍。(之前的黄皮版本更新成这本灰皮了)

好了,总结一下。

这篇呢,Z哥和你分享了我对代码质量这件事的看法。在行业越来越内卷的趋势下,注重“质”总是没错的。

Z哥认为想要提高代码质量最核心的原则就是:高内聚低耦合。文中给你罗列了赖瑞·康斯坦丁教授提炼了不同的内聚性和耦合性原则来表达关系的强弱。

基于对内聚性和耦合性原则的理解,再通过以下抓手进行代码质量的提升工作:

  1. 执行代码规范+Code Review

  2. 写单元测试

  3. 设计先行

  4. 项目与团队”微服务化”

  5. 利用相关的工具

最后还分享了几个代码层面的建议:

  1. 勿过度使用链式编程

  2. 避免随处可见的try-catch

  3. 认真编写访问修饰符

  4. 慎用继承

希望对你有所启发。

推荐阅读:

  • 及时享乐,延迟痛苦

原创不易,如果你觉得这篇文章还不错,就「在看」或者「分享」一下吧。鼓励我的创作 :)

如果你有关于软件架构、分布式系统、产品、运营的困惑

可以试试点击「阅读原文

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

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

相关文章

.NET Core AWS S3云存储

【导读】最近有需要用到AWS S3云存储上传附件,这里对利用.NET或.NET Core在调用SDK APi需要注意的一点小问题做个记录,或许能对后续有用到的童鞋提供一点帮助Amazon Simple Storage Service (Amazon S3) 是一种对象存储服务,提供行业领先的可…

MiniProfiler,一个.NET简单但有效的微型分析器

背景MVC MiniProfiler是Stack Overflow团队设计的一款对ASP.NET MVC的性能分析的小程序。可以对一个页面本身,及该页面通过直接引用、Ajax、Iframe形式访问的其它页面进行监控,监控内容包括数据库内容,并可以显示数据库访问的SQL(支持EF、EF …

龙芯.NET正式发布 稳步推进生态建设

2020年12月19日,2020中国. NET开发者大会于苏州开幕。此次大会上,龙芯发布了龙芯.NET 3。龙芯.NET 3基于.NET Core 3.1,支持该版本具备的所有主要功能,包括GC、AOT等。CoreCLR、CoreFX、ASP.NET Core等库的测试通过情况与x64/arm6…

有温度的技术,改善上亿人的生活

06有温度的技术,改善上亿人的生活鱼小皮哥,现在的 APP 真是越来越难用了,功能多、操作复杂、广告更多。唉,可不是么,而且人们的生活已经离不开 APP 了!老百鱼小皮我爷爷最近的视力下降的很快,用…

Linux链接文件包括,Linux操作系统——系统各目录有什么作用、以及文件链接过程...

三、 Linux 系统目录结构/bin — 用来贮存用户命令。目录 /usr/bin 也被用来贮存用户命令。/sbin — 许多系统命令(例如 shutdown)的贮存位置。目录 /usr/sbin 中也包括了许多系统命令。/root — 根用户(超级用户)的主目录。/mnt — 该目录中通常包括系统引导后被挂载的文件系统…

刚转Java?那准备转回.NET5吧!

再过几天就2021年了,回首今年最大的变化就是.NET5的发布,终结了.NET Framework和.NET Core两个分支。虽然因为新冠疫情原因,原定于.NET5的部分功能被推迟到.NET6了,但.NET5是一个非常非常重要的版本,会载入史册的一个版…

在 xunit 测试项目中使用依赖注入

在 xunit 测试项目中使用依赖注入Intro之前写过几篇 xunit 依赖注入的文章,今天这篇文章将结合我在 .NET Conf 上的分享,更加系统的分享一下在测试中的应用案例。之所以想分享这个话题是因为我觉得在我们开发过程中测试是非常重要的一部分,高…

利用 C# 中的 FileSystemWatcher 制作一个文件夹监控小工具

利用 C# 中的 FileSystemWatcher 制作一个文件夹监控小工具独立观察员 2020 年 12 月 26 日前一段看到微信公众号 “码农读书” 上发了一篇文章《如何使用 C# 中的 FileSystemWatcher》(翻译自:https://www.infoworld.com/article/3185447/how-to-work-w…

u盘安全删除 linux,为什么要安全删除U盘

原标题:为什么要安全删除U盘移除闪存设备时会对电脑造成危害吗?我们为什么要安全的移除它们?历史上,操作系统将磁盘作为信任对象不需要突然改变状态。当读写文件时,操作系统不希望文件在读写的过程中突然消失。如果文件…

如何在 C# 中使用 投影(Projection)

投影(Projection) 是一种可以将查询结果进行 塑性 的一种操作,你可以使用 投影 将一个 object 转成仅包含你需要属性的新对象,这篇文章中,我们就一起看看如何使用 投影 功能。C# 中的投影 LINQ 集成查询中有两个支持投影的扩展方法&#xff0…

Linux语言写的高通滤波,高通滤波器c语言实现

描述高通滤波器,又称低截止滤波器、低阻滤波器,允许高于某一截频的频率通过,而大大衰减较低频率的一种滤波器。它去掉了信号中不必要的低频成分或者说去掉了低频干扰。高通滤波器是一种让某一频率以上的信号分量通过,而对该频率以…

在 WSL Ubuntu 上使用 .NET 进行跨平台开发新手入门

翻译自 haydenb 2020年6月3日的文章《Getting started with cross-platform development using .NET on Ubuntu on WSL》 [1].NET 是一个开源软件框架,用于在 Linux、Windows 和 macOS 上构建跨平台应用程序。WSL 上的 Ubuntu [2]允许您同时为 Ubuntu 和 Windows 构…

明源云·天际,地产⾏业的Salesforce Lightning Platform

源宝导读:2020年11月6日,明源云在CIO峰会上正式对外发布了“天际开放平台”,这是明源云凝聚其20多年行业经验打造的一款企业级PaaS平台。本文将介绍我们对企业级PaaS平台的行业思考,以及为加速泛地产生态链数字化转型而做的技术创…

c程序设计语言选修难吗,欢迎大家选修C语言程序设计这门课,本帖解释一下一些常见的问题...

置顶欢迎大家选修C语言程序设计这门课,本帖解释一下一些常见的问题叶卡林娜发表于2017年01月05日首先欢迎大家选修浙大翁恺老师的C语言程序设计课程。开课2天就看到讨论区已经有这么多帖子,说明同学们的学习热情很高。结合前几次开课的经验以及目前在讨论…

IdentityServer4系列 | 支持数据持久化

一、前言在前面的篇章介绍中,一些基础配置如API资源、客户端资源等数据以及使用过程中发放的令牌等操作数据,我们都是通过将操作数据和配置数据存储在内存中进行实现的,而在实际开发生产中,我们需要考虑如何处理数据持久化呢&…

c语言修仙受控可看吗,强推三本神奇到爆的小说,c语言修仙,程序员与修真会擦出什么火花...

大家好,我是小龙。今天我给大家推荐三本神奇到爆的小说,c语言修仙,程序员与修真会擦出什么火花!一《c语言修仙》【一十四洲】【简介】: 林浔是一个程序员,通宵编代码后发现自己身体内多了一个程序输入窗口。他尝试编了一个循环程序…

【Vue】Vue与ASP.NET Core WebAPI的集成

SPA单页面应用已经遍地开花,熟知的三大框架,Angular、Vue和React,其中Angular与React均可集成至ASP.NET Core,且提供了相关了中间件。但是Vue没有:“As far as I’m aware, we don’t have plans to introduce Vue-specific featu…

引入Jaeger——封装

随着微服务的普及,微服务间的调用全链路跟踪也火了起来,Jaeger(https://www.jaegertracing.io/)是CNCF孵化的全链路跟踪型项目,在.net core中,提供了一个Jaeger的Nuget(https://github.com/jaegertracing/jaeger-client-csharp)包…

临近年关,发生两起磁盘占满引发的服务下线故障

一口气说两个因为磁盘空间不足引发的应用故障。作为拿起键盘一把梭的Coder, 开发--->部署-->收工--->心旷神怡,滋一口82年的可乐.过了几个月,服务突然下线了!CTO又有杀程序员祭天的理由了!事故1:Azure App Se…

c语言幼儿园积木游戏,幼儿园《积木游戏》课件【三篇】

【导语】课件制作本身就是作者综合素养的一种体现,它显现出制作者对教育、教学、教材改革方向的把握,对课堂教学的理解,对现代教育技术的领悟。因此教师在设计课件时一定要吃透教学内容,设计出符合教学的方案用于课件。下面是无忧…