当您遇到哪些类型的编码反模式时,您总是会重构它们?
我只是重构了我正在处理的类的不同部分中的一些代码,因为它是一系列嵌套的条件运算符 (?:),通过相当简单的 switch 语句 (C#) 使其变得更加清晰。
你什么时候会接触那些不是你正在直接处理的代码以使其更清晰?
I just refactored some code that was in a different section of the class I was working on because it was a series of nested conditional operators (?:) that was made a ton clearer by a fairly simple switch statement (C#).
When will you touch code that isn't directly what you are working on to make it more clear?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
删除/更新明显错误或明显毫无意义的评论。
删除它们是:
这是我所知道的唯一 100% 无风险的重构。
请注意,在诸如 javadoc 注释之类的结构化注释中执行此操作是另一回事。 更改这些并不是没有风险的,因此它们很可能被修复/删除,但不能像标准的错误代码注释那样保证修复。
Deletion/updating of comments which are clearly wrong or clearly pointless.
Removing them is:
It is about the only 100% risk free refactoring I know.
Note that doing this in structured comments like javadoc comments is a different matter. Changing these is not risk free, as such they are very likely to be fixed/removed but not dead certain guaranteed fixes as standard incorrect code comments would be.
我曾经在重构时遇到过这样的代码:
Resharper 指出 .ToString() 是多余的,所以我把它去掉了。 不幸的是,这最终破坏了代码。 每当 MySessionVar 为 null 时,它就不会导致 NullReferenceException,而代码正是依靠 NullReferenceException 将其降至 catch 块。 我知道,这是一些悲伤的代码。 但我确实从中吸取了很好的教训。 不要依赖工具来快速浏览旧代码来帮助您进行重构 - 自己思考一下。
我最终将其重构如下:
更新:由于这篇文章正在被投票,并且从技术上讲不包含问题的答案,我认为我实际上应该回答这个问题。 (好吧,这让我很困扰,以至于我真的在做梦。)
就我个人而言,在重构之前我会问自己几个问题。
1) 系统是否受到源代码控制? 如果是这样,请继续进行重构,因为如果出现问题,您随时可以回滚。
2)我正在改变的功能是否存在单元测试? 如果是这样,那就太好了! 重构。 这里的危险在于单元测试的存在并不表明所述单元测试的准确性和范围。 好的单元测试应该能够发现任何重大变化。
3)我是否彻底理解了我正在重构的代码? 如果没有源代码控制和测试,并且我并不真正理解我正在更改的代码,那么这是一个危险信号。 在重构之前我需要更熟悉代码。
在情况 #3 中,我可能会花时间实际跟踪当前正在使用我正在重构的方法的所有代码。 根据代码的范围,这可能很容易,也可能不可能(即,如果它是公共 API)。 如果归结为公共 API,那么您确实需要从业务角度理解代码的初衷。
I once was refactoring and came across something like this code:
Resharper pointed out that the .ToString() was redundant, so I took it out. Unfortunately, that ended up breaking the code. Whenever MySessionVar was null, it wasn't causing the NullReferenceException that the code relied on to bump it down to the catch block. I know, this was some sad code. But I did learn a good lesson from it. Don't rapidly go through old code relying on a tool to help you do the refactoring - think it through yourself.
I did end up refactoring it as follows:
Update: Since this post is being upvoted and technically doesn't contain an answer to the question, I figured I should actually answer the question. (Ok, it was bothering me to the point that I was actually dreaming about it.)
Personally I ask myself a few questions before refactoring.
1) Is the system under source control? If so, go ahead and refactor because you can always roll back if something breaks.
2) Do unit tests exist for the functionality I am altering? If so, great! Refactor. The danger here is that the existence of unit tests don't indicate the accuracy and scope of said unit tests. Good unit tests should pick up any breaking changes.
3) Do I thoroughly understand the code I am refactoring? If there's no source control and no tests and I don't really understand the code I am changing, that's a red flag. I'd need to get more comfortable with the code before refactoring.
In case #3 I would probably spend the time to actually track all of the code that is currently using the method I am refactoring. Depending on the scope of the code this could be easy or impossible (ie. if it's a public API). If it comes down to being a public API then you really need to understand the original intent of the code from a business perspective.
我只会在测试已经到位的情况下重构它。 如果不是,通常不值得我花时间为可能有效的代码编写测试和重构。
I only refactor it if tests are already in place. If not, it's usually not worth my time to write tests for and refactor presumably working code.
这是一个很小的反模式,但它让我非常恼火,每当我发现它时,我都会立即删除它。 在 C(或 C++ 或 Java)中
,
在 Scheme 中
,
在 ML 中
,
我几乎完全在本科生编写的代码中看到这种反模式。 我绝对不是编造的!
This is a small, minor antipattern but it so irritates me that whenever I find it, I expunge it immediately. In C (or C++ or Java)
becomes
In Scheme,
becomes
and in ML
becomes
I see this antipattern almost exclusively in code written by undergraduate students. I am definitely not making this up!!
每当我遇到它并且我不认为改变它会引起问题(例如,我可以足够理解它,我知道它的作用。例如,巫毒的水平很低)。
Whenever I come across it and I don't think changing it will cause problems (e.g. I can understand it enough that I know what it does. e.g. the level of voodoo is low).
只有当我修改代码有其他原因时,我才懒得去更改它。
我愿意走多远取决于我对不会破坏任何东西的信心以及我自己对代码的更改将有多大。
I only bother to change it if there is some other reason I'm modifying the code.
How far I'm willing to take it depends on how confident I am that I won't break anything and how extensive my own changes to the code are going to be.
这是展示单元测试好处的绝佳情况。
如果单元测试到位,开发人员可以勇敢而积极地重构他们可能遇到的奇怪编写的代码。 如果它通过了单元测试并且您提高了可读性,那么您已经完成了当天的善行并且可以继续前进。
如果没有单元测试,简化充满巫术的复杂代码会带来破坏代码的巨大风险,甚至不知道您引入了新的错误! 因此,大多数开发商都会采取谨慎的路线并继续前进。
This is a great situation to show off the benefits of unit tests.
If unit tests are in place, developers can bravely and aggressively refactor oddly written code they might come across. If it passes the unit tests and you've increased readability, then you've done your good deed for the day and can move on.
Without unit tests, simplifying complex code that's filled with voodoo presents a great risk of breaking the code and not even knowing you've introduced a new bug! So most developers will take the cautious route and move on.
为了进行简单的重构,我尝试清理深层嵌套的控制结构和非常长的函数(超过一屏的文本)。 然而,在没有充分理由的情况下重构代码并不是一个好主意(尤其是在一个大的开发团队中)。 一般来说,除非重构会对代码产生很大的改进或修复一个严重的错误,否则我会尽量不去管它。
不是按说重构,而是作为一般内务处理的问题,当我开始处理模块时,我通常会做这些事情:
For simple refactoring I try to clean up deeply nested control structures and really long functions (more than one screen worth of text). However its not a great idea to refactor code without a good reason (especially in a big team of developers). In general, unless the refactoring will make a big improvement in the code or fix an egregious sin I try to leave well enough alone.
Not refactoring per-say but just as a matter of general housekeeping I generally do this stuff when I start work on a module:
超过(可以说)三行或四行重复代码总是让我考虑重构。 另外,我倾向于经常移动代码,将我预计会更频繁使用的代码提取到一个单独的位置 - 一个具有自己明确定义的目的和职责的类,或者静态类的静态方法(通常放置在我的 Utils.* 命名空间)。
但是,要回答你的问题,是的,在很多情况下,缩短代码并不一定意味着使其结构良好且可读。 在 C# 中使用 ?? 运算符是另一个示例。 您还必须考虑的是您选择的语言中的新功能 - 例如 LINQ 可以用来以非常优雅的方式做一些事情,但也可以使非常简单的事情变得非常难以阅读并且过度复杂的。 您需要非常仔细地权衡这两件事,最终一切都归结为您的个人品味,尤其是经验。
好吧,这是另一个“视情况而定”的答案,但恐怕必须如此。
More than (arguably) three or four lines of duplicate code always makes me think about refactoring. Also, I tend to move code around a lot, extracting the code I predict to be used more frequently into a separate place - a class with its own well-defined purpose and responsibilites, or a static method of a static class (usually placed in my Utils.* namespace).
But, to answer your question, yes, there are lot of cases when making the code shorter does not necessarily mean making it well structued and readable. Using the ?? operator in C# is another example. What you also have to think about are the new features in your language of choice - e.g. LINQ can be used to do some stuff in a very elegant manner but also can make a very simple thing very unreadable and overly complex. You need to weigh these two thing very carefully, in the end it all boils down to your personal taste and, mostly, experience.
Well, this is another "it depends" answer, but I am afraid it has to be.
如果重构使代码更容易阅读,那么对我来说最常见的是重复代码,例如仅第一个/最后一个命令不同的 if/else。
If the refactor makes the code much easier to read, the most common for me would be duplicate code, e.g. an if/else that only differs by the first/last commands.
我几乎总是将 >2 个相似的条件句分解为一个开关……最常见的是关于枚举。 我将简短地返回而不是冗长的声明。
ex:
变成:
提前突破减少了额外的缩进,并减少了长代码...另外作为一般规则,我不喜欢具有超过 10-15 行代码的方法。 我喜欢具有单一目的的方法,即使在内部创建更多私有方法也是如此。
I almost always break >2 similar conditionals into a switch... most often with regards to enums. I will short a return instead of a long statement.
ex:
becomes:
breaking out early reduces extra indents, and reduces long bits of code... also as a general rule I don't like methods with more than 10-15 lines of code. I like methods to have a singular purpose, even if creating more private methods internally.
通常,如果我只是浏览代码而不是积极处理代码,我就不会重构代码。
但有时 ReSharper 会指出一些我无法抗拒 Alt+Enter 的东西。 :)
Usually I don't refactor the code if I'm just browsing it, not actively working on it.
But sometimes ReSharper points out some stuff I just can't resist to Alt+Enter. :)
如果我了解块的输入和输出集,我倾向于重构很长的函数和方法。
这对可读性有无止境的帮助。
I tend to refactor very long functions and methods if I understand the set of inputs and outputs to a block.
This helps readability no end.
在完成以下步骤后,我只会重构我遇到的并且没有积极处理的代码:
I would only refactor the code that I come across and am not actively working on after going through the following steps:
为了重构而重构是万恶之源之一。 请永远不要这样做。 (单元测试确实在一定程度上缓解了这个问题)。
Refactoring for the sake of it is one of the roots of all evil. Please don't ever do it. (Unit tests do somewhat mitigate this).
大量注释掉的代码是反模式吗? 虽然不是具体的代码,(它是注释)我看到很多这样的行为,这些人不了解如何使用源代码控制,并且希望保留旧代码以供以后使用,以便他们可以更轻松地返回,如果引入了一个错误。 每当我看到大量被注释掉的代码时,我几乎总是将它们全部删除。
Is vast swaths of commented out code an antipattern? While not code specifically, (it's comments) I see a lot of this kind of behaviour with people who don't understand how to use source control, and who want to keep the old code around for later so they can more easily go back if a bug was introduced. Whenever I see vast swaths of code that are commented out, I almost always remove them in their entirety.
我尝试根据以下因素进行重构:
有时,如果我有足够的时间,我会重构来学习。 例如,我知道我的更改可能会破坏代码,但我不知道在哪里以及如何破坏。 所以我无论如何都会改变它,以找出它的问题所在以及原因。 这样我就可以更多地了解代码。
我的领域是移动软件(手机),其中大部分代码驻留在我的电脑上,不会影响其他人。 由于我还为公司维护 CI 构建系统,因此我可以在重构的代码上运行完整的产品构建(适用于所有手机),以确保它不会破坏任何其他内容。 但这是我个人的奢侈,你可能没有。
I try to refactor based on following factors:
And sometimes, if I have enough time, I refactor to learn. As in, I know my change may break the code, but I dont know where and how. So I change it anyways to find out where its breaking and why. That way I learn more about the code.
My domain has been mobile software (cell phones) where most of the code resides on my PC and wont impact others. Since I also maintain the CI build system for my company I can run a complete product build (for all phones) on the refactored code to ensure it doesnt break anything else. But thats my personal luxury which you may not have.
如果全局常量和枚举被认为重构风险较低,我倾向于对其进行大量重构。 也许只是这样,但像 ClientAccountStatus 枚举这样的东西应该位于或接近 ClientAccount 类,而不是位于 GlobalConstAndEnum 类中。
I tend to refactor global constants and enumerations quite a bit if they can be deemed a low refactor risk. Maybe it's just be, but something like a ClientAccountStatus enum should be in or close to the ClientAccount class rather than being in a GlobalConstAndEnum class.