对代码库进行整理清理的指南

371 阅读9分钟

随着天气的转暖,我开始有动力对我的代码库进行春季清理。我曾经在一些项目中工作过,那里的混乱情况非常严重,以至于我们不敢碰任何东西;我也曾经在一些项目中工作过,我积极地试图达到代码中立(删除的代码行数比我增加的多)。但正确的平衡是在中间的某个地方。

多年来,我发现了一些我认为能提供最大收益的任务。你可以在一个小时内做一些简单的、低风险的事情,使你的代码库更适合居住。一周内每天做一件,或者在周五下午全力以赴,看看你能完成多少。

整理你的依赖关系

bundleryarn 这样的工具为你的项目生成了一堆文件和文件夹,但大部分的混乱是 "看不见,摸不着 "的,因为它们把东西放在了node_modules 的谚语地毯下。

我们甚至不谈未使用的依赖关系,只谈旧版本的库,因为你在一个分支中升级或尝试了新的工具。

捆绑器:运行bundle clean ,从你的bundler目录中删除未使用的宝石

➜ bundle clean --dry-run
Would have removed rails-html-sanitizer (1.2.0)
Would have removed jekyll-sitemap (1.3.1)
Would have removed que (0.14.3)
Would have removed aws-sdk-kms (1.28.0)
Would have removed actioncable (6.0.2.1)
Would have removed rake (12.3.2)
Would have removed administrate (0.12.0)
Would have removed factory_bot (5.1.0)
Would have removed sass (3.7.4)
Would have removed html-pipeline (2.12.3)
Would have removed minitest (5.11.3)
Would have removed uniform_notifier (1.12.1)
Would have removed parallel (1.19.1)
Would have removed colorator (1.1.0)

有一点需要注意的是,如果你使用系统级的宝石,并且有多个Ruby项目,运行bundle clean 会尝试删除你当前项目中没有使用的全局宝石。这可能不是你想要的。

为了避免这种情况,请切换到使用每个项目的包。你可以做bundle install --path vendor/bundle ,将宝石安装到一个项目特定的文件夹中,然后运行bundle clean ,删除项目中未使用的宝石,而不去干扰其他项目的宝石。

提示:你可以通过添加gem: -​-no-document 来禁止在本地下载宝石文档。~/.gemrc

Yarnnode_modules 有一个坏名声,就是体积膨胀。随着嵌套文件夹越来越大,当你试图删除这一大堆的JavaScript时,你甚至会开始遇到操作系统级别的限制

运行yarn autoclean --init ,生成一个模板文件,通过删除诸如测试文件、标记文件和其他潜入发布的包中的杂七杂八的垃圾来缩小你的node_modules 文件夹。

在添加一个.yarnclean 文件后,刷新过程将在你每次添加或安装软件包时运行(你也可以手动运行)。

➜ yarn autoclean --init
yarn autoclean v1.17.0
[1/1] Creating ".yarnclean"...
info Created ".yarnclean". Please review the contents of this file then run "yarn autoclean --force" to perform a clean.

➜ yarn autoclean --force
yarn autoclean v1.17.0
[1/1] Cleaning modules...
info Removed 4799 files
info Saved 17.75 MB.
✨  Done in 4.37s.

提示:当你运行安装命令时,Yarn会自动修剪不相干的软件包,所以不需要自己去做。

如果你真的觉得自己很有野心,可以审核你的依赖关系,看看是否有可以删除的。Mike Perham的《杀死你的依赖》(Kill Your Dependencies)一文中有一个检查表,可以在评估外部库时使用:

你的应用程序中的每一个依赖都有可能使你的应用程序变得臃肿,破坏你的应用程序的稳定性,通过Monkeypatching或错误的本地代码注入奇怪的行为。当你考虑在你的Rails应用中添加一个依赖项时,最好按照偏好的顺序做一个快速理智的检查。

  1. 我真的需要这个吗?杀了它。[卸载 gem]。
  2. 我可以自己实现所需的最小功能吗?拥有它。[复制/卖出代码] 如果你需要一个 gem。
  3. gem是否有本地扩展?寻找纯Ruby的替代品。[切换宝石]
  4. 创业板是否有大量的其他创业板?寻找更简单的替代品。[切换宝石]

带有本地扩展的宝石可能会破坏你的系统稳定;它们可能是神秘的错误和崩溃的来源。避免使用那些依赖性大于其价值的宝石。坏宝石的例子:fog宝石,它拉入了39个宝石,比rails本身的依赖性还多,而且其中大部分是不必要的。

修剪你的git分支

如果运行git branch -r ,你的终端就会充满过去功能的幽灵,那么你应该清理一下保持分支的整洁,可以让你很容易看到哪些分支是开放的,而不需要滚动浏览几十行(或几百行!)。

运行git remote prune origin 来删除在 origin 上不存在的本地跟踪分支。如果你担心的话,可以先用--dry-run

如果你再次运行git branch -r ,你应该会看到一个更细的列表,只显示存在于 GitHub 中的分支。

然后你就可以直接去 GitHub 或者用git ls-remote --heads origin 来列出当前的远程分支。如果有需要删除的,请运行git push origin -D BRANCH_TO_DELETE 删除它们。

Automatically delete head branches

提示:在GitHub中打开 "自动删除头部分支",这样你的分支就不会在你合并拉动请求后仍然存在。

删除未使用的路由和视图

虽然Rails生成器给我带来了快乐,但它们生成的路由和视图往往比你实际需要的多。运用你内心的Marie Kondo,删除你的应用程序中这些未使用的部分。

首先尝试在你的应用程序中搜索 "Find me in":这是Rails生成的一些视图的默认生成器文本。如果你有任何结果,恭喜你!你可以删除这些文件而不受惩罚。你可以肆无忌惮地删除这些文件。

接下来:通过寻找没有实现的控制器动作(或缺少视图),检查你的routes.rb 文件中是否有未使用的路线。

我从这个gist中找到了最好的结果。把这个脚本放到你的Rails应用的根目录下,然后运行它,就可以看到一个可能要清理的未使用的路由列表。

检查未使用的数据库表和列

最后要检查的领域是你的数据库,它可能积累了未使用的表或列。一个聪明的方法是寻找空表和每行都有相同值的列。这些都是需要调查的可疑之处。

把这个脚本(改编自这篇文章)粘贴到你的项目中,以扫描你的数据库(如果你的开发数据库没有代表性的数据,你可能想针对一个暂存数据库运行):

require_relative './config/environment.rb'

connection = ActiveRecord::Base.connection
connection.tables.collect do |t|
  count = connection.select_all("SELECT count(1) as count FROM #{t}", "Count").first['count']

  puts "TABLE UNUSED #{t}" if count.to_i == 0

  columns = connection.columns(t).collect(&:name).reject {|x| x == 'id' }
  columns.each do |column|
    values = connection.select_all("SELECT DISTINCT(#{column}) AS val FROM #{t} LIMIT 2", "Distinct Check")
    if values.count == 1
      if values.first['val'].nil?
        puts "COLUMN UNUSED #{t}:#{column}"
      else
        puts "COLUMN SINGLE VALUE #{t}:#{column} -- #{values.first['val']}"
      end
    end
  end
end
➜ ruby unused_db.rb
TABLE UNUSED active_storage_blobs
TABLE UNUSED friendly_id_slugs
TABLE UNUSED active_storage_attachments
COLUMN SINGLE VALUE investor_agreements:file_extension -- pdf
COLUMN UNUSED clients:comments
COLUMN SINGLE VALUE client_tasks:archived -- false
...

除了一些未使用的生成表之外,该脚本还发现有几十个列的值都是null ,或者都是单值(例如,一个archived 列总是 "假")。这些列需要更多的调查来删除,但也是一个很好的开始。

检查缺失的验证/约束

虽然ActiveRecord在你的数据库上面提供了一个验证层,但你仍然需要数据库约束的强大保护(不可归零的列,唯一的索引等),以确保没有坏数据潜入你的应用程序。

你的模型和底层数据库真的很容易失去同步性。使用database_consistencygem来运行一系列的检查,告诉你你的应用程序模型和数据库模式在哪里不同步:

 bundle exec database_consistency
fail ProjectType name column is required in the database but do not have presence validator
fail ProjectType slug column is required in the database but do not have presence validator
fail Project draft_documents associated model should have proper index in the database
fail Project attachments associated model should have proper index in the database
fail Project alerts associated model should have proper index in the database
fail Company name column should be required in the database
fail PurchaseApproval date column should be required in the database
...

你可能会被这个工具为一个项目吐出的大量错误所淹没,但不要着急,每一个变化都应该是直接的,你可以一点一点地处理它们。一旦你解决了所有问题,可以考虑把这个命令添加到你的Rails CI管道中,以便在将来提交错误代码的时候及时发现错误。

清理你的migrations文件夹

最后一个要检查的地方是你的迁移文件夹。随着时间的推移,你的db/migrate 文件夹中会有数百个迁移文件。如果你已经在生产环境中运行了这些迁移文件(如果你避免在迁移文件中直接创建种子数据),你可以安全地删除旧的迁移文件。

我喜欢Clutter所概述的方法

  • 删除超过3个月的迁移
  • 添加一个新的迁移,如果你的数据库非常过时,就会提出来(有关于如何加载模式的说明)

如果删除迁移让你感到不安,你也可以看看squasher:一个将你的旧迁移合并成一个巨型迁移的工具。

深度清理:更进一步

如果你已经准备好进行深度清理,可以考虑使用这些工具来帮助你进一步挖掘你的应用程序代码:

  • unused:一个用于查找死代码的通用工具,它的基础是ctags
  • debride:一个Ruby工具,用于查找潜在的未调用方法(有一些特定的Rails检查)。
  • coverband:一个 "在生产中运行 "的覆盖工具,收集方法使用情况的统计数据;它是最彻底的,但周转时间较长,因为你需要针对真实流量运行一段时间。
  • rcov:根据你的测试套件,你可以很好地了解到你的应用程序的哪些部分可能没有被使用。
  • attractor:指标可视化工具,用于绘制churn(代码变化的频率)与复杂性的对比。

我对这些工具没有那么多的成功经验,一般来说,我觉得它们的投资回报率并不高,但如果你想保持你的代码库闪闪发光,那就值得花一些时间去探索。就我个人而言,我对一点点的灰尘没有意见 :)

清洁愉快!如果你有任何其他在你的项目中使用过的技巧,请在Twitter上告诉我。