Image Source: Software testing class (2015)
Whether you are a QA Engineer involved in automating test cases or planning to in the near future it is important that you learn about code refactoring. For all practical purposes, it is important that you learn to write good code first before jumping into refactoring. However, given the quick timelines in which you may have to deliver the code required to run your automation you might often overlook some of the best practices while writing code. Also, it may not be well structured and often come in the way of reusability, readability and quick execution. It may take more time to add more code especially when you continue to add new scripts. Imagine a multi-storey building with weak foundation, would it be possible to add more floors? Thankfully, software is unlike a building and can be tweaked, refactored to make the code work for you.
What is Refactoring?
Refactoring, simply put is the process of changing the source code of test scripts in such a way that it does not alter the functionality or external behaviour of the test code yet improves its internal structure.
Refactoring helps your code ready for changes or additions by reducing the complexity which is otherwise ignored while writing the initial code or test scripts. Refactoring also reduces redundancy in code, simplify logic or cut down on unnecessary loops, all this on a code which is already deployed and used in production.
Refactoring – HowTo:
Start by removing Code Smells
Not quite literally, but “Code Smells” according to Martin Fowler, “is a surface indication that usually corresponds to a deeper problem in the system”.
Steps to keep in mind while removing code smells:
- Make sure your tests pass
- Find some lines of test code that “smells” meaning repeated redundant code blocks or sections
- Determine and simplify this code
- Run tests to ensure things still work correctly
- Repeat the simplify/test cycle until the “smell” is gone
- What constitutes Code Smell and how to remove?
- Comments: Avoid using comments. Use descriptive method and variable names instead.
- Long Method: Shorter methods are always easier to read, understand, and troubleshoot. Refactor long methods into smaller chunks. Have a separate page (“class”) for your test activity.
- Long Parameter List: The more parameters a method has, the more complex it is. Simplify and rationalize the function to the least common denominator for the parameters being passed. Split and function calls if you have to, remove unused or rarely used parameters.
- Duplicate code: Stamp out duplication whenever possible.
- Conditional Complexity: Watch out for large conditional logic blocks. Consider alternative object-oriented approaches such as decorator, strategy, or state.(Object Oriented Design Patterns)
- Large Class: Restructure large class into smaller classes
- No Type in Name Rule: Avoid placing return types in method names; it’s not only redundant, but it forces you to change the name if the type changes.
For eg : choose subject.add(grade) over subject.addGrade(grade)
- Uncommunicative Name: Always use names that would clearly communicate the purpose, be it classname, method or a constant/variable.
- Inconsistent Name: Make sure that all your methods follow the same naming standard. This will make the code symmetric and understandable.
- Dead Code: Ruthlessly delete code that is not being used or leftover and redundant.
- Speculative Generality: Ensure to have no Predictions/Never keep code for the future hanging scenarios.
- Alternative Classes with Different Interfaces: If two classes are similar on the inside, but different on the outside, perhaps they can be modified to share a common interface.
- Data Class: Avoid classes that passively store data. Classes should contain data and methods to operate on that data, too.
- Refused Bequest: When the subclass never use any of the inherited functionality, remove inheritance.
- Indecent Exposure: Refactor classes to minimise their public states and behaviours. Used Object Oriented Programming.
- Feature Envy: Methods that make extensive use of another class may belong in another class.
- Lazy Class: If a class that is near-useless should be given the Inline Class treatment, can it be collapsed or combined into another class?
- Middle Man: If a class is delegating all its work, cut out the middleman(class).
- Shotgun Surgery: If a change in one class requires cascading changes in several related classes, consider refactoring so that the changes are limited to a single class.
Code refactoring is an important step in building reusable. Always add refactoring to your project estimation and spend time on some of the best practices as outlined above.
Do leave your thoughts and comments on code refactoring through the comment box below.
Also published on Medium.