rails git_用Ruby删除Rails和git上未使用的代码

rails git

One of my recent projects was to try to identify unused pieces of code and remove them safely. This can be quite a difficult task in Ruby, as there is little way to be certain what calls what.

我最近的项目之一是尝试识别未使用的代码段并将其安全删除。 在Ruby中,这可能是一项艰巨的任务,因为几乎没有办法确定什么叫什么。

A solution to this problem of identifying such code is to record all calls for a relatively long period on your production server, and then see what hasn’t been called. For this purpose, we developed a custom solution on top of the oneshot_coverage gem; but after taking a step back, I think I would recommend the coverband gem for this purpose (it has a polished UI, is maintained, based on standard tools such as Redis, etc.).

解决此类代码问题的一种解决方案是在生产服务器上记录较长时间的所有调用,然后查看未调用的内容。 为此,我们在oneshot_coverage gem之上开发了一个自定义解决方案; 但退后一步,我想我会为此目的推荐Coverband gem(它具有优美的UI,并根据Redis等标准工具进行维护)。

Assuming you now have a list of suspiciously unused methods, you can either be satisfied with that (you should probably not), delete them at once, and move on; or try to dig a bit more. This is the topic I would like to cover in this post, and by reading it, I hope you will learn more about this process and the tools I used to follow said process.

假设您现在有了可疑未使用方法的列表,则可以对此感到满意(您可能不应该),立即删除它们,然后继续进行; 或尝试多挖一点。 这是我想在这篇文章中讨论的主题,并且希望通过阅读它,您可以了解有关此过程以及我遵循该过程所使用的工具的更多信息。

If you have numerous tests and excellent test coverage, this whole process might seem excessive to you, as you would simply say that if the tests continue passing after deleting the code, then everything is good. You would be right, but things are not always as simple!

如果您有大量测试,并且测试覆盖面广,那么整个过程对您来说似乎是多余的,因为您只是说如果删除代码后测试继续通过,那么一切都很好。 您将是对的,但事情并不总是那么简单!

I will try to use a real example from our application to illustrate my point. Here, I found a method called related_posts in our PostArticle model that seemed to be unused for a while on our production platform.

我将尝试使用应用程序中的真实示例来说明我的观点。 在这里,我找到了一个方法叫做related_posts我们PostArticle模式,似乎是未使用的为我们的生产平台上一段时间。

Image for post
The method is loaded by the code loader (green), but the code inside the method is never executed, which means no call for this method was recorded.
该方法由代码加载器加载(绿色),但是该方法内部的代码从未执行,这意味着未记录此方法的调用。

当前参考 (Current references)

The very first action you should do, before deleting the method blindly, is checking if the method name appears anywhere else in your code or potential dependents of your code. For a simple project, you can just search the method’s name in your favourite IDE, you can also use ripgrep in a folder containing your project and its dependents. This first check is fundamental because your method could simply be called by some other code but is not for some understandable reasons (very rarely used feature, randomness, code specific to some platform, code not actively used yet, problem in the coverage tool, etc.).

在盲目删除方法之前,您应该做的第一步就是检查方法名称是否出现在代码中的其他位置或代码的潜在依存关系中。 对于一个简单的项目,您可以只在自己喜欢的IDE中搜索方法的名称,也可以在包含项目及其依赖项的文件夹中使用ripgrep 。 第一次检查是很基本的,因为您的方法可以被其他代码简单地调用,但是由于某些可以理解的原因而不能被调用(很少使用的功能,随机性,特定于平台的代码,尚未被积极使用的代码,覆盖工具中的问题,等等)。 )。

One thing you want to be aware of at this point is because there could be some meta-programming calling your method, you might want to check for some sub-string of your method name. Usually in these cases, your method would have some kind of resemblance pattern with other methods declared close by, so you would want to search for the discriminatory part of the method name. For example, if you have two methods process_carrots and process_potatoes , you might have somewhere a code calling .send("process_#{food_item}") inside some sort of iteration over the food items. In that case, you would like to know whether a particular food item is still called or not, and thus you would search for that name (i.e: carrots or potatoes respectively).

您现在需要注意的一件事是,因为可能会有一些元编程调用您的方法,所以您可能需要检查方法名称的某些子字符串。 通常,在这些情况下,您的方法将与附近声明的其他方法具有某种相似的模式,因此您需要搜索方法名称中的歧视性部分。 例如,如果您有两个方法process_carrotsprocess_potatoes ,则可能在某个食品迭代中的某处有一个代码调用.send("process_#{food_item}") 。 在这种情况下,您想知道某个食品是否仍被调用,因此您将搜索该名称(即分别是carrotspotatoes )。

In my case, there are many matches, so I need to check manually for each of them if they are related, and while most of them are not, I noticed another model (that inherit from the same base model) that has a method with the same name. I checked with our coverage tool, and as suspected it is also apparently unused.

就我而言,有很多匹配项,因此我需要手动检查每个匹配项是否相关,尽管大多数都不相关,但我注意到另一个模型(该模型继承自相同的基本模型)具有同名。 我检查了我们的覆盖率工具,并怀疑它显然也未被使用。

Image for post
Checking references with VSCode
使用VSCode检查引用

Note that in this case, checking for dependent projects is not necessary as our models are not used outside of our project. For the sake of completeness, here is the command assuming you are in a folder containing all your relevant projects.

请注意,在这种情况下,无需检查相关项目,因为我们的模型不在项目外部使用。 为了完整起见,以下命令假定您位于包含所有相关项目的文件夹中。

rg "related_posts"

方法的起源 (The method’s origin)

The second thing you should ask yourself is when was the method implemented, and were there any hints towards how it was used then. It will give you other hints of code you might want to delete (that is linked to the feature, but that the production-code-coverage tools cannot detect because it is outside of its scope, for example: views, styles, JS, scripts, configurations, etc.). It might also give you more information on how the code is called and ultimately make yourself confident that you are deleting something that is indeed unused.

您应该问自己的第二件事是什么时候实现了该方法,以及关于如何使用该方法的任何提示。 它会为您提供其他可能要删除的代码提示(与功能链接,但是生产代码覆盖工具无法检测到,因为它超出了它的范围,例如:视图,样式,JS,脚本,配置等)。 它还可能为您提供有关如何调用代码的更多信息,并最终使您确信自己正在删除确实未使用的内容。

To do this, I like using the GitLense extension for VSCode, which gives me a link to the commit on GitHub, but you can also do a normal git blame on your file. If the methods you are looking at have been modified since they have been introduced you might need to chain git blames for finding their original commit (You could also use git log at this point).

为此,我喜欢使用GitLense扩展名,该扩展名使我可以链接到GitHub上的提交,但是您也可以对文件进行常规的git blame 。 如果自介绍方法以来,您正在查看的方法已被修改,则可能需要链接git blames以查找其原始提交(此时您也可以使用git log )。

Image for post
Using GitLense, hover the grayed text at the right of the code to trigger a toolbox with more options, then click on the top-right pointing arrow to open the commit on your git service (here GitHub)
使用GitLense将鼠标悬停在代码右侧的灰色文本上,以触发带有更多选项的工具箱,然后单击右上角的箭头打开git服务的提交(此处为GitHub)
git blame app/models/post_article.rb -L 54,54
Image for post
Using git blame
使用git怪

If I have a "commit hash" from running command-line git commande, I usually just copy it, insert it in a GitHub URL to show commits, and from there retrieve the PR, but there might be better approaches depending on the tools you use.

如果我在运行命令行git commande时有一个“提交哈希”,我通常只复制它,将其插入GitHub URL中以显示提交,然后从那里检索PR,但是根据您使用的工具,可能会有更好的方法用。

Image for post
Using GitHub to display a commit and retrieve the related Pull Request
使用GitHub显示提交并检索相关的Pull Request

In this case, the method was not originally introduced by this commit but was transferred from the parent model to the child models with a slightly different implementation. At this point there are two things I need to do:

在这种情况下,该方法最初不是由此提交引入的,而是通过稍微不同的实现从父模型转移到子模型的。 此时,我需要做两件事:

  • Check the original branch where the code was introduced, and see how it was called.

    检查引入代码的原始分支,并查看其调用方式。
  • Check the branch where the method was split between models and see if the calling code was also changed.

    检查在模型之间拆分方法的分支,并查看调用代码是否也已更改。

In this case, the code was only originally used in one place, and this calling code was changed in the “split branch” at the same time as the related_posts method itself.*

在这种情况下,该代码最初仅在一个地方使用,并且此调用代码与related_posts方法本身同时在“拆分分支”中进行了更改。*

One additional thing that should be checked is whether there could be some additional resources (JS, CSS, etc.) to delete: resources that were introduced at the same time than these prior modifications that might also not be used anymore. In the present case, there were none I could think of while reading the original code.

还应检查的另一件事是,是否可能要删除一些其他资源(JS,CSS等):与这些先前的修改同时引入的资源也可能不再使用。 在当前情况下,在阅读原始代码时我没有想到。

跟踪调用代码 (Tracking the calling code)

Now that we know how the code was introduced, I would like to know more about how the calling code was changed for the related_posts method which seems not to be called anymore. Was it changed to meta-programming at some point? Was the code just removed and the underlying method forgotten? Is this code still called, but somehow I missed it with my checks so far?

现在我们知道了代码的引入方式,我想更多地了解为related_posts方法更改了调用代码的方法,该方法似乎不再被调用。 在某个时候它变成了元编程吗? 只是删除了代码,而忘记了底层方法吗? 仍然会调用此代码,但是到目前为止我还是以某种方式错过了检查代码吗?

By checking the “splitting branch” code changes, I know that the method I want to delete was called in a file called _post_footer.haml.html . But unfortunately, this file does not exist any more. To know when the code was removed from that file I use the following command (note that this also works if the files still exists)

通过检查“ splitting branch”代码的更改,我知道要删除的方法已在名为_post_footer.haml.html的文件中调用。 但不幸的是,该文件不再存在。 要知道何时从该文件中删除了代码,我使用以下命令(请注意,如果文件仍然存在,这也适用)

git log -S "related_posts" -- app/views/post_articles/_post_footer.html.haml
Image for post
Use of “git log -S”
使用“ git log -S”

I have seen this command fail a few times for deleted files. In that case, I fallback to a broader command that will give all commits to the file from the most recent commit. Usually, it is then quite fast to find the commit that removed the call to the code you want to delete.

对于删除的文件,我已经看到此命令多次失败。 在那种情况下,我回退到一个更广泛的命令,该命令将从最近一次提交中为该文件提供所有提交。 通常,找到要删除对要删除的代码的调用的提交会很快。

git log -p -- app/views/post_articles/_post_footer.html.haml

By looking at the branch where the commit 995ed4d7 happened (same process as when we got the commit hash before), I can see that the related feature was in fact refactored: the implementation was changed and the original method was simply not deleted.

通过查看发生995ed4d7提交的分支(与之前获得提交哈希的过程相同),我可以看到实际上重构了相关功能:实现已更改,并且原始方法根本没有删除。

In this particular case, I found out that another call to the original method was deleted at the same time in that last “refactoring branch”, so I get a bit suspicious (but not too much!), check quickly when it was introduced again and ensure there were no other calls that were left unchecked. And finally, I am quite confident deleting this code is now safe*.

在这种特殊情况下,我发现在最后一个“重构分支”中同时删除了对原始方法的另一个调用,因此我有点可疑(但不要太多!),请再次检查它是否再次引入并确保没有其他未取消的呼叫。 最后,我很有信心删除此代码现在是安全的*。

To sum up, in this archaeological journey we understood:

综上所述,在这次考古之旅中,我们了解到:

  • That the code appears not to be used.

    该代码似乎未被使用。
  • For what reasons it was introduced and modified at some point.

    由于什么原因在某些时候引入和修改了它。
  • When it was not called any more and by what it was replaced.

    什么时候不再被调用以及被什么代替。

So we can create a “delete commit” for this code, create a PR where we sum-up our findings, and have/display the confidence* that it is a safe/legitimate change.

因此,我们可以为此代码创建“删除提交”,创建PR,在其中汇总我们的发现,并具有/显示出它是安全/合法更改的信心*。

*NB: This is by no mean a way to be absolutely certain that your code is not called somewhere by some weird meta-programming. It is always possible that such a meta-programming code to be introduced in between the creation/use of the method and it’s apparent “un-call”; I do not believe there is a way to be absolutely sure about this. Even if you would git log the whole repository with a discriminatory part of the method name, it could still be possible not to find something that you are about to break. In the end, this is a compromise: with the help of automated testing, reviews, production code coverage, etc, to be fairly confident the deletion is safe.

* NB:这绝不是一种绝对确定某些奇怪的元编程未在某处调用您的代码的方法。 这种元编程代码总是有可能在方法的创建/使用与明显的“取消调用”之间引入; 我不相信对此有绝对的把握。 即使您使用方法名称的区分部分git log了整个存储库,仍然有可能找不到您要破坏的内容。 最后,这是一个折衷方案:在自动测试,审查,生产代码覆盖率等的帮助下,要完全确信删除是安全的。

I hope you have learned a bit more about ruby and git tools you can use to try deleting your old code in a confident manner. Some might argue that this is too complex and time-consuming to just delete some old unused code, and they might be right, but establishing this process can save your company some time: during the review process for example, if you show that you did investigate the matter thoughtfully and thus the reviewer can check it easily without spending too much of their own time. Also, being able to detect additional potential code/resources that can be deleted can save you time in the long run.

希望您了解了更多有关ruby和git工具的信息,可用于尝试以自信的方式删除旧代码。 有人可能会争辩说,仅删除一些旧的未使用的代码太复杂且耗时,这也许是正确的,但是建立此流程可以为您的公司节省一些时间:例如,在审核过程中,如果您证明自己做了考虑周到地进行调查,因此审阅者可以轻松地进行检查,而不会花费太多时间。 此外,能够检测到其他可能被删除的潜在代码/资源,从长远来看可以节省您的时间。

As for me, during the course of my code-deletion project, I have successfully deleted thousands of lines of ruby (and other thousands of JS, CSS, translations, configuration) by following this method without breaking anything (so far!), so I wanted to share this method as I haven’t seen much literature on the subject. 🤗

对于我来说,在执行代码删除项目的过程中,我已经遵循这种方法成功删除了数千行Ruby(以及其他数千个JS,CSS,翻译,配置),而没有破坏任何内容(到目前为止!),因此我想分享这种方法,因为我没有看到太多有关该主题的文献。 🤗

翻译自: https://medium.com/wantedly-engineering/deleting-unused-code-with-ruby-on-rails-and-git-d5268bb83647

rails git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值