本文同步發自於個人blog - [Refactoring] Chapter 2 Principles in Refactoring - Book Summary
1. Defining Refactoring
- Noun's definition: A change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.
- Verb's definition: To restructure software by applying a series of refactorings without changing its observable behavior.
Both definitions have the same objective: don't change the software's behavior.
Like electrical wiring for our life, we plug electrical appliances and the electric current moves through the wiring. The plug-in is like an API. Electrical appliances get the electric current with this API and don't understand what plug-in electrical panel works. If API's internal code structure is like:
Electrical Panel before re-wiring (Source: https://theintegrityexperience.com/rewiring-a-house-and-electrical-panel-upgrade/)
It's ugly but it still works to supply electric current. Someday, the power failure occurs and we should check the electrical panel then open it, OS: "What the hell" and very hard to find the broken wires.....
After refactorings(re-wiring), the new electrical panel is like:
Electrical Panel after re-wiring (Source: https://theintegrityexperience.com/rewiring-a-house-and-electrical-panel-upgrade/)
What a beautiful wiring! It supplies electric current like the last ugly wiring but next time we will find correct wires quickly. This analogy to our coding refactorings is very similar.
The tip at book's page 46 describes:
**_
If someone says their code was broken for a couple of days while they are refactoring, you can be pretty sure they were not refactoring.
_**
This tip is very funny XD. According to chapter 1's tip, refactoring is driven by testings. Every refactoring step is done, then run the testings to validate the observable behavior is not changed.
2. The Two Hats
When we are developing the software, we have 2 hats: one hat for adding functionality and the other one for refactoring. Only wear one of these 2 hats in a period of developing. Do not add functionality and refactor concurrently.
3. Why Should We Refactor?
3.1 Refactoring Improves the Design of Software
- If we don't refactor, the code becomes more messy
- Messy code means maintenance is more difficult.
- DRY (Don't Repeat Yourself) is a fundamental design principle and reduces the code size
3.2 Refactoring Makes Software Easier to Understand
- Programmer is the reader of the code and it's the major time cost
- If the reader spends 1 week understanding the code and modifying it ---- What a terrible code
- If the reader spends 1 hour understanding the code and modifying it ---- What a great code
- We spend a little time refactoring our code and make the code more readable. Next time the reader will spend less time working.
- If the code function is easily looked up by documentation, programmers don't deliberately remember them.
3.3 Refactoring Helps Me Find Bugs
- When we are refactoring the code, code structure maybe shows some bugs we have never noticed
3.4 Refactoring Helps Me Program Faster
- The previous points result in this point
- Does not the time of refactoring slow the development? No! If the system with poor design, it would add features like putting many "patches" on it.... It's hard to understand what a module works.
- Design Stamina Hypothesis: Good designs increase the stamina of the software effort
- Refactoring makes the design better than the last
The development time with good and poor design (Redraw at book's page 49)
4. When Should We Refactor?
The Rule of Three
The first time you do something, you just do it. The second time you do something similar, you wince at the duplication, but you do the duplicate thing anyway. The third time you do something similar, you refactor.
Or for those who like baseball: Three strikes, then you refactor.
4.1 Preparatory Refactoring - Making It Easier to Add a feature
-
Parameterize Function skill reduces the duplicated code. Similar codes are centered.
- Like before I move to a place, I check the map and find a short route to arrive at the place.
4.2 Comprehension Refactoring: Making Code Easier to Understand
- Read codes to understand "What is the section of the code doing?". Spending much time reading code is a refactoring chance.
- Refactoring makes the code logics clearer
4.3 Litter-Pickup Refactoring
- If there is a small trash code (duplicated codes, terrible variable naming...), immediately refactor it
- If the trash code is not easy to be refactored with current task, note the trash code, put it aside and continue current task. After finish the task, then refactor the noted trash code.
4.4 Planned and Opportunistic Refactoring
- Previous 3 refactoring examples are opportunistic. Planned refactoring is not a natural thing. Adding features or fixing bugs are normal with refactoring.
The tip at book's page 52 describes:
You have to refactor when you run into ugly code - bug excellent code needs plenty of refactoring too.
Kent Beck also described:
For each desired change, make the change easy (warning: this may be hard), then make the easy change.
The two sections are excellent points.
- Author thinks that creating a new branch to refactor codes in control version system is not good because refactoring is closed with adding new features.
4.5 Long-Term Refactoring
- Like previous Planned Refactoring, it's not recommend by author.
- Example: If the system wants to replace a existing library, use Branch By Abstraction to make the replacement easy
4.6 Refactoring in a Code Review
- Better practice: Pair-programming and refactoring/reviewing the code
4.7 What Do I Tell My Manager?
- If the manager doesn't know what the refactoring is, don't tell him/her why you do refactoring. Manger just wants the task to be finished before the deadline. We just use refactoring this professional skill to smoothly complete the job.
4.8 When Should I Not Refactor?
- If there is a messy code and it's not required to be modified, don't refactor with it.
- If some ugly code is hidden under an API, don't refactor.
- Sometimes rewriting is easier than refactoring but it's hard to decide which method should be executed.
5. Problems with Refactoring
5.1 Slowing Down New Features
The tip at book's page 56 describes:
The whole purpose of refactoring is to make us program faster, producing more value with less effort.
- If there are a large-scale refactoring situation and small-scale urgent new feature, finish the urgent new feature and then back to the refactoring.
- Refactoring's target doesn't equal to the one of "Clean Code" and "Good Engineering Practice". Refactoring focuses on adding features quickly, fixing bugs quickly.
5.2 Code Ownership
- Example: A naming is not good and we use Change Function Declaration skill to rename it. But the renamed function is used by other teams / product API caller, it will result in blocked situation.
- Use Rename Function skill and the old function is pass-through to the new one. Mark the old function as [deprecated].
- Team ownership of code is recommended by author, not only restricted to one person.
5.3 Branches
- Every branch is responsible for specific features, after a period, those branches will be merged into master/trunk. But if the feature branch is isolated for a long time, the integration with master will be hard.
- Refactoring like renaming for merging branch sometimes is a difficult integration
- Continuous Integration (CI) / Trunk-Based Development: Use this practice to require every member to merge branch into master and integrate. This action avoid the large difference between branches.
- Refactoring very fits CI practice. Small changes are easily integrated when using CI.
- Kent Beck's Extreme programming uses CI and refactoring
5.4 Testing
- If we want refactoring, self-testing code is required
- If no testing can support, we can use automated refactoring. But it only executes safe refactoring methods.
- Special style of refactoring: only use proved and absolutely safe refactoring methods. Like an example that shows how to safely execute Extract Method skill in C++ provided by Jay Bazuzi.
- I very recommend that every programmer should read this book to learn unit testing: The Art of Unit Testing: with examples in C# written by Roy Osherove
5.5 Legacy Code
- Legacy code without testings is very terrible...
- Adding new testings in current legacy code is not easy
-
Working Effectively with Legacy Code by Michael Feathers is recommended by author. It teaches how to perform refactoring and testings in legacy code
- Step-by-step refactor legacy code instead of changing it widely
5.6 Databases
-
Refactoring Databases: Evolutionary Database Design by Scott Ambler & Pramod Sadalage is recommended by author.
- Add migration scripts into version control system with code. This makes the database development efficient
- Example with .NET, Entity Framework has a migration tool to upgrade/downgrade database's structure.
- The book provides a refactoring skill: parallel change. I think I should buy this book to deeply learn it!
6. Refactoring, Architecture, and Yagni
- In early period, architecture was first designed. So the later development was restricted with the architecture and the system continued to become decayed.
- Refactoring is the iterative method to improve current design
- you aren't going to need it : Yagni mixes architecture, design and development and depends on refactoring
-
Building Evolutionary Architectures: Support Constant Change by Neal Ford, Rebecca Parsons, Patrick Kua is a continuously developing subject and discover what pattern and practice are useful for iterative developement.
7. Refactoring and the Wider Software Development Process
- Self-testing is the first foundation of refactoring
- Self-testing, CI and refactoring are the 3 major practices for a refactoring team
- Based on these 3 practices, some products can be published in one day
- These practices are not easy to build up
8. Refactoring and Performance
- 3 methods to write fast software
1. Time budgeting: It's a serious method for real time system like heart pacemakers. Every module is restricted with limited resources.
2. Constant attention: Every programmer keeps the system with high performance anytime.
3. Use the optimization statistic analysis to improve the system
9. Where Did Refactoring Come From?
- In 1980, Smalltalk project with refactoring skills influenced the development community
- First one wrote the refactoring book is Martin Fowler
10. Automated Refactorings
- IntelliJ IDEA provides many automated refactoring tools for popular programming language.
- IDE analyzes the syntax tree of the code and provides safer refactoring results
11. Going Further
12. References
Refactoring: Improving the Design of Existing Code (2nd Edition)