代码之丑
郑晔
开源项目 Moco 作者
19833 人已学习
新⼈⾸单¥59
登录后,你可以任选2讲全文学习
课程目录
已完结/共 24 讲
代码之丑
15
15
1.0x
00:00/00:00
登录|注册

17 | 课前作业点评:发现“你”代码里的坏味道

你好,我是郑晔。
在这个专栏刚开始的时候,我给你留了一个课前作业,实现一个待办事项管理的软件。许多同学都利用自己的业余时间完成了这个作业,感谢大家的付出!
学习代码的坏味道,听别人讲是一种方式,但这种方式总会让人有一种隔岸观火的感觉,虽然知道有问题,但感觉并不深刻。最直接受益的方式就是自己写了代码,然后,让别人来点评。其实,这就是某种形式的代码评审。
所以,这一讲,我们就来做一次“代码评审”,直接来看看代码中存在的问题。题目背景我就不再做过多的介绍了,如果没有来得及完成作业的同学,可以先到“课前作业区”回顾一下题目。
既然是指出问题,得罪大家可能就在所难免了,希望你不要介意,毕竟能够发现自己的问题是精进的第一步。好,我们开始!

从已知的坏味道出发

极客双同学的代码仓库里,我在一段代码中看到了之前我们课程中讲过的坏味道:
Item itemNew = new Item(item.getName());
itemNew.setUserIndex(userIndex);
itemNew.setIndex(initUserIndex);
我们的业务需求是添加 TODO 项,这段代码就是在这个过程中创建一个新的 TODO 项对象。那这段代码有什么问题?一方面,这里有 setter,另一方面,这里的 setter 只在初始化的过程中用到。显然,我们可以用一个更完整的构造函数替换掉它。
其实,从这段代码出发,我们还能看到一些小问题,比如,这里创建 TODO 项设置了两个字段,一个是 userIndex,一个是 index。index 可以理解,表示这个 TODO 项的索引,但 userIndex 是什么呢?你需要仔细阅读代码才能发现,它其实是一个用户的标识,表示这个索引项是由某个用户创建的。既然是用户标识,按照通常的做法它可以叫 userId,这就降低了理解的难度。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文通过具体的代码示例,向读者展示了如何发现和改进代码中的坏味道,以及如何提高代码质量和规范性。作者首先指出了代码中存在的问题,如不合理的setter使用、类和接口命名不规范等,并强调了通过自己写代码并接受他人点评的方式来学习代码坏味道,以及如何改进代码质量。此外,文章还强调了代码命名的重要性,指出了一些常见的不规范命名方式。作者还通过重构的方式演示了如何一步一步地消除代码中的静态函数,以及如何进行代码重构,保证代码的安全。最后,作者提到了文档的重要性,强调了良好的README对于开源项目的重要性。整体而言,本文内容涵盖了代码质量、规范性和文档编写等方面的技术特点,对于读者快速了解如何改进代码质量和规范性具有一定的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《代码之丑》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(10)

  • 最新
  • 精选
  • 陈文昕
    “用 I 表示接口,用 Impl 表示实现”,这种问题需要怎么修改? 目前我的写法都是 用Impl表示实现,接口就正常写成XxxxService

    作者回复: 如果一个接口只有一个实现类,也许不需要这个层次关系,即便有,一个命名可以是 DefaultXXX。 如果一个接口有多个实现类,那就需要把不同实现类的特点描述出来,比如,FileXXX,DbXXX 等等。

    2021-02-07
    16
  • 斯盖丸
    请问老师,static转成final的那步里,如果不止是UserAccounts而是其他类也要用到这同一份userContext那应该怎么获取?能保证是同一份吗?

    作者回复: 你仔细看一下,调整的过程是,先把对象变成同一个对象,然后,才是消除 static,所以,它们用的肯定是同一个对象。

    2021-02-06
    5
    3
  • 邵俊达
    郑老师您好,「如果一个函数牵扯到 Singleton 类也不好测试」请问为什么一个函数牵扯到「Singleton类」会不好测试呢? 我一般会把一个包含工具函数的工具类做成 Singleton。 在测试调用了工具函数的某个方法的时候没发现不好测试。请问该如何理解这句话?

    作者回复: 我在几个专栏里都讨论过 Singleton 模式和 static 函数,关键点在于 static 函数如果参与到测试过程中,就不好模拟,所以,尽量不要写 static 函数。 但在这个讨论里,我也留了一个口子,就是程序库函数,用更具象的说法,就是不牵扯任何 static 字段的函数。你的场景其实是属于这种场景的。但是,在这种情况下,其实也没有必要使用 Singleton,简单的 static 函数就够了。

    2021-08-21
    2
  • 杨宇
    老师重构的过程让我眼前一亮——原来还能这样“小步”!

    作者回复: 抓住重点了

    2021-05-28
    2
  • norton/Dark
    老师,我觉得impl是过时的设计,说服力还不够,个人感觉挺直观的,有什么负面案例呢?如果在项目中消减这种设计,还是得有说服力的说法。麻烦再深入讲解下。

    作者回复: 严格地说 Impl 不直观,因为它看不出与接口之间的关系,这就好比,你说一个类名字应该叫 Class 一样,没错,但没有意义。我们应该用清晰的名字进行命名,比如,基于文件的实现就叫 FileXXX,基于数据库的实现就叫 DbXXX,基于 REST 的实现就叫 RestXXX。

    2021-04-24
    2
    1
  • fengkuok
    "如果一个接口只有一个实现类,也许不需要这个层次关系,即便有,一个命名可以是 DefaultXXX。" 有接口,单元测试时方便mock。如果没有接口,只能是集成测试?

    作者回复: 你可以站在类型的角度去理解,其实,mock 时模拟的是一个类型,这个类型可以是用一个接口实现的,也可以是用一个类去实现的。所以,没有接口,只有类是没有问题的。

    2021-02-18
  • 6点无痛早起学习的和尚
    绝了,读这章内容,昨晚刚碰到跟同事聊,static 方法如何 mock 测试,今天就看到这篇文章,解决方案就是:少用 static 方法!!! 对文中有个问题:如果你用完整的构造函数创建对象,那未来这个对象的参数数量变化了,那一旦涉及到初始化的地方,都得变动,并且每个参数并不是初始化都需要,这样怎么解呢?
    2023-11-14归属地:北京
  • ifelse
    尽量不使用 static--记下来
    2022-06-03
  • lamb
    第三方的工具类要使用它static方法:工具类有public构造方法通过new 工具类ide会提示 使用类名调用不要通过实例的方式;没有public方法如何处理
    2022-05-03
  • Geek_3b1096
    非常喜欢一步一步重构代码教学
    2021-02-08
收起评论
显示
设置
留言
10
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部