refactoring of refactoring.guru
Overview
https://refactoring.guru/refactoring
把 dirty code 转变成 clean code 过程叫重构。
What is refactoring?
Clean code
clean code有如下特征:
- 可读性好
- 无重复逻辑
- 低代码 -- 包含最少数目的类
- 通过所有测试
- 容易维护
The main purpose of refactoring is to fight technical debt. It transforms a mess into clean code and simple design.
Nice! But what’s clean code, anyway? Here are some of its features:
Clean code is obvious for other programmers.
And I’m not talking about super sophisticated algorithms. Poor variable naming, bloated classes and methods, magic numbers -you name it- all of that makes code sloppy and difficult to grasp.
Clean code doesn’t contain duplication.
Each time you have to make a change in a duplicate code, you have to remember to make the same change to every instance. This increases the cognitive load and slows down the progress.
Clean code contains a minimal number of classes and other moving parts.
Less code is less stuff to keep in your head. Less code is less maintenance. Less code is fewer bugs. Code is liability, keep it short and simple.
Clean code passes all tests.
You know your code is dirty when only 95% of your tests passed. You know you’re screwed when you test coverage is 0%.
Clean code is easier and cheaper to maintain!
Technical debt
dirty code 产生的原因多种多样, 但总归产生了,我们成为技术债
产生的原因:
- 项目周期短
- 开发者不理解clean code的好处
- 紧耦合
- 缺测试
- 缺文档
- 组员缺沟通
- 长期在不同分支上并行开发,改进无法同步
- 延迟重构
- 缺少合规检查
- 开发者能力不足
Everyone does their best to write excellent code from scratch. There probably isn’t a programmer out there who intentionally writes unclean code to the detriment of the project. But at what point does clean code become unclean?
The metaphor of “technical debt” in regards to unclean code was originally suggested by Ward Cunningham.
If you get a loan from a bank, this allows you to make purchases faster. You pay extra for expediting the process - you don’t just pay off the principal, but also the additional interest on the loan. Needless to say, you can even rack up so much interest that the amount of interest exceeds your total income, making full repayment impossible.
The same thing can happen with code. You can temporarily speed up without writing tests for new features, but this will gradually slow your progress every day until you eventually pay off the debt by writing tests.
Causes of technical debt
Business pressure
Sometimes business circumstances might force you to roll out features before they’re completely finished. In this case, patches and kludges will appear in the code to hide the unfinished parts of the project.
Lack of understanding of the consequences of technical debt
Sometimes your employer might not understand that technical debt has “interest” insofar as it slows down the pace of development as debt accumulates. This can make it too difficult to dedicate the team’s time to refactoring because management doesn’t see the value of it.
Failing to combat the strict coherence of components
This is when the project resembles a monolith rather than the product of individual modules. In this case, any changes to one part of the project will affect others. Team development is made more difficult because it’s difficult to isolate the work of individual members.
Lack of tests
The lack of immediate feedback encourages quick, but risky workarounds or kludges. In worst cases, these changes are implemented and deployed right into the production without any prior testing. The consequences can be catastrophic. For example, an innocent-looking hotfix might send a weird test email to thousands of customers or even worse, flush or corrupt an entire database.
Lack of documentation
This slows down the introduction of new people to the project and can grind development to a halt if key people leave the project.
Lack of interaction between team members
If the knowledge base isn’t distributed throughout the company, people will end up working with an outdated understanding of processes and information about the project. This situation can be exacerbated when junior developers are incorrectly trained by their mentors.
Long-term simultaneous development in several branches
This can lead to the accumulation of technical debt, which is then increased when changes are merged. The more changes made in isolation, the greater the total technical debt.
Delayed refactoring
The project’s requirements are constantly changing and at some point it may become obvious that parts of the code are obsolete, have become cumbersome, and must be redesigned to meet new requirements.
On the other hand, the project’s programmers are writing new code every day that works with the obsolete parts. Therefore, the longer refactoring is delayed, the more dependent code will have to be reworked in the future.
Lack of compliance monitoring
This happens when everyone working on the project writes code as they see fit (i.e. the same way they wrote the last project).
Incompetence
This is when the developer just doesn’t know how to write decent code.
When to refactor
三个规则:
- 第一开发的时候,随意做
- 第二次做相似事情的时候,害怕重构,所以再做一遍重复的事情
- 第三次做相同的事情时候, 开始重构。
其它重构时机
- 添加一个新功能的时候
- 修复bug时候
- 代码审查
Rule of Three
When you’re doing something for the first time, just get it done.
When you’re doing something similar for the second time, cringe at having to repeat but do the same thing anyway.
When you’re doing something for the third time, start refactoring.
When adding a feature
Refactoring helps you understand other people’s code. If you have to deal with someone else’s dirty code, try to refactor it first. Clean code is much easier to grasp. You will improve it not only for yourself but also for those who use it after you.
Refactoring makes it easier to add new features. It’s much easier to make changes in clean code.
When fixing a bug
Bugs in code behave just like those in real life: they live in the darkest, dirtiest places in the code. Clean your code and the errors will practically discover themselves.
Managers appreciate proactive refactoring as it eliminates the need for special refactoring tasks later. Happy bosses make happy programmers!
During a code review
The code review may be the last chance to tidy up the code before it becomes available to the public.
It’s best to perform such reviews in a pair with an author. This way you could fix simple problems quickly and gauge the time for fixing the more difficult ones.
How to refactor
小步开走的方法。
重构使用正确方法:
- 代码更加整洁
- 不设计任何功能开发
- 所有测试都通过
Refactoring should be done as a series of small changes, each of which makes the existing code slightly better while still leaving the program in working order.
Checklist of refactoring done right way
The code should become cleaner.
If the code remains just as unclean after refactoring... well, I’m sorry, but you’ve just wasted an hour of your life. Try to figure out why this happened.
It frequently happens when you move away from refactoring with small changes and mix a whole bunch of refactorings into one big change. So it’s very easy to lose your mind, especially if you have a time limit.
But it can also happen when working with extremely sloppy code. Whatever you improve, the code as a whole remains a disaster.
In this case, it’s worthwhile to think about completely rewriting parts of the code. But before that, you should have written tests and set aside a good chunk of time. Otherwise, you’ll end up with the kinds of results we talked about in the first paragraph.
New functionality shouldn’t be created during refactoring.
Don’t mix refactoring and direct development of new features. Try to separate these processes at least within the confines of individual commits.
All existing tests must pass after refactoring.
There are two cases when tests can break down after refactoring:
You made an error during refactoring. This one is a no-brainer: go ahead and fix the error.
Your tests were too low-level. For example, you were testing private methods of classes.
In this case, the tests are to blame. You can either refactor the tests themselves or write an entirely new set of higher-level tests. A great way to avoid this kind of a situation is to write BDD-style tests.
Catalog of Refactoring
Code Smells
识别代码中的坏味道,是重构的第一步。
坏味道的代码有如下特征:
- 臃肿 -- 一个文件,一个类, 一个函数做了太多的事情。
- 面向对象的滥用 -- 不正确地使用OOP技术
- 变化阻拦 -- 代码无法应对可能的变化
- 可丢弃 -- 存在很多无用代码
- 耦合严重
Refactoring Techniques
重构的方法:
- 重新组织方法
- 在类之间移动功能
- 数据处理专门独立,从业务逻辑中分离
- 简化条件表达
- 简化方法调用
- 处理泛化