代码 | 一天一点代码坏味道(1)

【代码精进总结/Edison Zhou


作为一个后端工程师,想必在职业生涯中都写过一些不好维护的代码。本文是我学习《代码之丑》的学习总结,今天第一天发车,先来看看在命名上的一些常犯的坏味道。

0为何要品代码坏味道

Martin Flower在《重构》一书中给不好维护的这一类代码取了一个艺名:代码的坏味道,而这些坏味道一旦堆积多了,整个系统虽然还是可以平稳运行,但是就是让程序员不敢动,更别提重构了。

因为......

哎,都是打工人,谁容易啊?

1不精准的命名

直接来看一段坏味道代码:

public void ProcessChapter(long chapterId)
{Chapter chapter = _repository.GetChapterById(chapterId);if (chapter == null){throw new ArgumentException($"Unknown chapter [{chapterId}]");}chatper.TransactionState == TransactionState.TRANSLATING;_repository.UpdateChapter(chapter);
}

此段代码存在的问题:方法名ProcessChapter命名过于宽泛,不能精准描述意图,是代码难以理解的根源所在

同类型的词汇请各位看官自查,例如:data,info,flag,process,handle,build,maintain,manage,modify等等等,它们应该都出现在你我的项目代码中过。

重构方法:命名需要能够描述出这段代码在做的事情,根据代码的逻辑含义,调整其命名为 ChangeChapterToTranslating,是不是无论谁来接手这个方法的代码就都好理解了?

public void ChangeChapterToTranslating(long chapterId)
{......
}

一个好的名字应该是描述意图,而非细节的。那么,我们再重构一下,结合具体的业务,将其命名改为 StartTranslation,即开始翻译,是不是就更能体现业务含义了?

public void StartTranslation(long chapterId)
{......
}

2用技术术语命名

这是一个我也经常犯的坏味道:

List<Book> bookList = service.GetBooks();

这个bookList的原因是因为它的类型是List,还有xxxDict,xxxMap等,它不费脑子,但它却只是一种基于实现细节的命名方式。

重构方法:使用面向意图的名字

List<Book> books = service.GetBooks();

又如,如果在业务代码中出现了Redis这类的中间件:

public Book GetByIsbn(string isbn)
{Book cachedBook = redisBookStore.Get(isbn);if (cachedBook != null){return cachedBook;}Book book = service.GetByIsbn(isbn);redisBookStore.Put(isbn, book);return book;
}

通常来说,这里只是需要一个缓存,那么Redis也就只是这个缓存的一个具体实现,如果换为其他的NoSQL存储如Memcached呢?

因此,我们其实缺少了一个模型,在这里其实就是一个接口,假设这个接口如下:

public interface ICacheClient
{object Get(string key);void Put(string key, object value);
}

使用接口替代之后,我们就是面向接口编程了:

public Book GetByIsbn(string isbn)
{Book cachedBook = ICacheClient.Get(isbn);if (cachedBook != null){return cachedBook;}Book book = service.GetByIsbn(isbn);ICacheClient.Put(isbn, book);return book;
}

技术人喜欢用技术名词命名,因为这是大家习惯的语言。但是,对于业务项目而言,需要尽可能将技术术语隔离开,因为业务语言才是最好的命名方式

DDD领域驱动设计方法就号召我们建立统一语言,这个统一语言是可以和业务部门的人员无障碍交流的语言,换句话说,也就是业务语言。另一方面来看,这就倒逼技术团队需要建立团队的业务词汇表,让团队成员达成统一共识,这也是要统一共识需要付出的额外成本,但是这个成本是有价值的。

编写可维护的代码之路

比如,我们经常会写下面的参数命名:

public void ApproveChapter(long chapterId, long userId) 
{...
}

假设通过业务分析,这里的user其实是审核人,而我们为了方便就命名为userId了。那么,将其改为reviewerUserId是不是更加贴近业务?

public void ApproveChapter(long chapterId, long reviewerUserId) 
{...
}

在实际开发中,这样子的例子还有很多。

3乱用英语来命名

作为一个受了多年义务教育与高等教育的我们来说,English一点也不陌生,但是就是始终感觉用不到位。

如果能用中文来命名,我们是不会到处查单词用英文来命名的,但是,用中文,没有B格啊,我放弃!

违反语法规则的命名

类是一个名字,表示一个对象。而方法名一般是一个动词或动宾短语,表示一个动作。但是,有时候,我们喜欢忽视这个规则。

public void CompletedTranslate(List<string> chapterIds)
{List<Chapter> chapters = _repository.GetByChapterIds(chapterIds);chapters.ForEach(chapter => chapter.TranslationState = TranslationState.TRANSLATED);_repository.SaveChapters(chapters);
}

CompletedTranslate 是个啥(四不像结构)?改为 CompleteTranslation 是不是好一点(动宾结构)?

public void CompleteTranslation(List<string> chapterIds)
{......
}

又比如,一个方法名叫 ReTranslation(额,Translation好像是个名词吧),意为重新翻译,但作为方法名,应该选择动词,改为 ReTranslate 会更好(Translate是个动词,棒!)。

不准确的英语词汇

由于英文单词可以有多个含义,且在不同场景下含义也可以不同,这就难为我们中国人了。

比如,下面的一个枚举,想表达的是审核状态:

public enum ChapterAuditStatus
{PENDING,APPROVED,REJECTED
}

但是,Audit这个词虽然也有审核的含义,但是它更偏重于财务审计这块,而这里的业务是文稿的审核。


因此,改为Review可能会更加贴近一些:

public enum ChapterReviewStatus
{......
}

从上也可以看出,技术团队建立一个统一的业务词汇表,很有必要!这是集体的智慧,而非个体的。一个人的英语可能不太好,但是一群人在一起,总有那么一个会找出合适的说法。

英语单词拼写错误

这个,我相信大家各自项目中都有不少拼错的案例,很多人查了单词之后,都还是拼错... 

但是,往往很多时候就是差了或者多了那么一个字母,就会让人懵逼了。

4小结

本文总结了命名相关的两类坏味道,一是命名是否具有业务含义,二是命名是否符合英语语法。

最后,感谢郑晔老师的这门《代码之丑》课程,让我受益匪浅!我也诚心把它推荐给关注EdisonTalk公众号的各位童鞋!

参考资料

郑晔,《代码之丑》(推荐订阅学习)

Martin Flower著,熊杰译,《重构:改善既有代码的设计》(推荐至少学习第三章)

????扫码订阅《代码之丑》

????点击购买《重构:改善既有代码的设计》

年终总结:Edison的2020年终总结

数字化转型:我在传统企业做数字化转型

C#刷题:C#刷剑指Offer算法题系列文章目录

技术管理:IT技术人的技术管理学习进阶

商业知识:IT技术人的底层商业知识兵器库

.NET大会:2020年中国.NET开发者大会PDF资料


????扫码关注EdisonTalk

不变的依旧是分享

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

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

相关文章

python base64编码_JS和Python实现AES算法

1. AES原理AES算法是典型的对称加密算法&#xff0c;AES原理可以学习这两篇文档&#xff1a;漫画&#xff1a;什么是AES算法&#xff1a;https://www.toutiao.com/i6783550080784794124/AES加密算法的详细介绍与实现&#xff1a;https://blog.csdn.net/qq_28205153/article/det…

当你老了,一生最后悔什么?大数据告诉你!

‍ 当你老了&#xff0c;一生最后悔什么&#xff1f;

@scheduled注解配置时间_SpringBoot2.0实战(32)配置定时任务

定时任务的几种实现方式&#xff1a;Timer&#xff1a;Java自带的java.util.Timer类&#xff0c;这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行&#xff0c;但不能在指定时间运行。一般用的较少。Quartz&#xff1a;使用Quartz&…

小心 Enum Parse 中的坑

小心 Enum Parse 中的坑Intro最近使用枚举的时候&#xff0c;踩了一个小坑&#xff0c;分享一下&#xff0c;主要是枚举从 int 值转成枚举时可能会遇到Sample来看下面的示例&#xff1a;首先定义一个枚举&#xff1a;public enum Color : byte {Red 0,Green 1,Blue 2, }来看…

python判断列表是否为空_Jinja2: 判断返回的列表是否为空

我们在使用 Python 或者 Ansible 来进行自动化任务的时候常常会进行一些数据的组合和提取来生成文件。但是我们需要为不同的情况来做分析和进行判断。如果我们需要对返回的 list 来进行提取的时候我们常常只是运行一个 for loop 就解决了问题。如果输出如下所示&#xff1a;{&q…

在php中使用kind,KindEditor 4.x在PHP中的应用实例!

1.解压放入php项目静态资源文件夹&#xff0c;如下图&#xff1a;Paste_Image.png2.如果只是php使用&#xff0c;可以删除其它类型语言的文件夹&#xff0c;文件结构如下图&#xff1a;Paste_Image.png3.打开php文件夹&#xff0c;更改upload_json.php里文件上传目录文件夹至Up…

你的朋友国庆假期都去了哪里玩?微信大数据告诉你!最远的朋友圈签到竟然来自……

国庆中秋八天假 你是出门四处浪浪浪了 还是躺在家里看朋友圈里的世界名景 10月8日&#xff0c;微信发布《国庆假期微信大数据报告》 从出境人数、热门地区、境外消费等角度 全方位展示国庆期间微信用户的出游情况 哪些城市的人最爱出境游&#xff1f; 哪个国家是最热门的出境目…

mysql安装版和解压版哪个好_红米k30pro变焦版和荣耀30pro哪个好-哪个更值得入手...

红米k30pro变焦版和荣耀30pro&#xff0c;两款手机都有着很强的性能配置&#xff0c;也在同等的价位上&#xff0c;今天我们就来对比一下&#xff0c;看看红米k30pro变焦版和荣耀30pro哪个性价比更高&#xff0c;有哪些配置区别&#xff01;一、主要参数对比荣耀30 Pro红米K30 …

记一次CPU持续100%及分析方法

背景 某天晚上八点多&#xff0c;突然收到一个 CPU 爆表的告警。过了一会&#xff0c;几个业务线就开始反馈系统变慢了。后面紧急处理了这台机器后&#xff0c;让业务先恢复正常。后续看了一下监控&#xff0c;拔凉拔凉的。这个服务是比较重要的一个老业务&#xff0c;.NET Fra…

php中请写出定义变量的两种方法,php定义变量几种

1、定义常量define("CONSTANT", "Hello world.")&#xff1b;常量只能包含标量数据(boolean&#xff0c;integer&#xff0c;float 和 string)&#xff0c;调用常量时&#xff0c;只需要简单的用名称取得常量的值&#xff0c;而不能加“$”符号。注: 常量和…

c语言三目运算符_C语言中的三目运算符是啥?有何用处?

一般来说&#xff0c;C语言中的三目运算符为a?b:c即有三个参与运算的量。由条件运算符组成条件表达式的一般形式为&#xff1a;表达式1? 表达式2&#xff1a;表达式3求值规则为&#xff1a;如果表达式1的值为真&#xff0c;则以表达式2 的值作为条件表达式的值&#xff0c;否…

Dotnet的局部函数和委托的对比

上一篇说了一下委托&#xff0c;这篇来说说局部函数和委托的对比。把委托和局部函数放成前后篇&#xff0c;是因为这两个内容很像&#xff0c;用起来容易混。需要了解委托相关内容&#xff0c;可以看这一篇 【传送门】使用委托表达式(Lambda)假设一个场景&#xff1a;我们有一个…

经纬度 c代码中定义_如何将TXT文本格式的批量经纬度值导入到奥维成为标签

文本编辑&#xff1a;示例1&#xff1a;最基本的&#xff0c;只批量导入WGS-84经纬度值成为标签&#xff0c;不需要导入标签名称。 文本编辑格式&#xff1a;经度值空格纬度值换行&#xff0c;如下图&#xff1a;示例2&#xff1a;除WGS-84经纬度外&#xff0c;还要导入标签名称…

中国式创新技术“步态识别”终于来临,你大胆地走两步,我就知道你是谁

放完假的数据君&#xff0c;回到办公室&#xff0c;苦恼该码一篇什么文章&#xff0c;来给各位送上“节后的祝福”。 这么想着&#xff0c;数据君便开始浏览最新的科技报道&#xff1a; 什么鬼&#xff01;这难道是什么新兴的黑科技吗&#xff1f;&#xff01; 数据君赶紧查了…

帆软获取上月的第一天与最后一天_《原神》岩港打工第一天怎么玩 岩港打工第一天玩法攻略...

《原神》在11月2日开启了岩港奇珍行记&#xff0c;玩家可以在璃月港进行打工了&#xff0c;可能有的小伙伴还不清楚第一天的打工要怎么做&#xff0c;所以小编这次就为大家带来了《原神》岩港打工第一天玩法攻略&#xff0c;感兴趣的小伙伴可以来看一下。岩港打工第一天玩法攻略…

mysql卸载时弹框,win10卸载mysql5安装mysql8

使用mysql5的过程中使用 datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP 无法执行&#xff0c;原因是版本问题&#xff0c;因此我需要安装更高级的版本。一、卸载原有的mysql1、在控制面板中卸载mysql2、运行“regedit”文件&#xff0c;删除HKEY_LOCAL_MACHINE\SYSTEM\Co…

感谢Adobe,用上了Silverlight RC0版本

Adobe 23号发布CS4系列&#xff0c;24号网络上出现下载&#xff0c; MicorSoft 25号发布Silverlight RC0&#xff0c;26号网络上出现下载。 用上了Silverlight RC0&#xff0c; 真的要感谢Adobe&#xff0c;推出全新体验的Adobe Flash CS4正式版&#xff0c;也是Flash 10&#…

css中的单位换算_金蝶ERP入门教程:动态换算率及辅助计量单位的应用

金蝶ERP入门教程&#xff1a;动态换算率及辅助计量单位的应用关注我&#xff0c;我将定期分享更多的ERP解决方案如果您喜欢且觉得内容有用&#xff0c;请点击分享转发如果你有什么关于ERP系统的问题和疑问&#xff0c;可私信联系我大家好&#xff0c;我是Eric顾问哥&#xff1a…

因为加班,谈了7年的女友跟我分手了……

记得有一句很流行的话&#xff1a; 世界那么大&#xff0c;我想去看看 此时的你&#xff0c;走到了哪里&#xff1f; 还是停留在这里吗&#xff1f; 世界很小&#xff0c;小到仅有这几尺办公桌 工作很多&#xff0c;多到生活只余下工作 最近&#xff0c;腾讯上线了一支视频广告…