First rule: test coverage, no changes can be made if you're not secured
ideally with mutation testing showing us alive mutants
ideally with mutation testing showing us alive mutants
Repeat killing mutants until this specific part of code (the IF/ELSE monster) has 100% coverage
please note: I'm not advising the whole project to be 100% covered - only the place which you want to change
please note: I'm not advising the whole project to be 100% covered - only the place which you want to change
Detect the possible types in the IF/ELSE branches
In this case, those are different kinds of products with different behaviour.
In this case, those are different kinds of products with different behaviour.
Now the goal is to carefully refactor the conditions so that the top-level IF is all about the type. Let's look how we can do it safely and quickly to rearrange the conditions.
Flattening technique
We can merge conditions from subsequent IFs.
Thanks to this, the "type" condition travels one level above.
(remember our goal is to make them to top-level)
We can merge conditions from subsequent IFs.
Thanks to this, the "type" condition travels one level above.
(remember our goal is to make them to top-level)
Remember DeMorgan laws from Algebra classes?
They can be used to reduce the number of negations in the conditions.
They can be used to reduce the number of negations in the conditions.
another attempt to reduce the number of negative conditions
here we rely on knowing that there are only 4 types of products - we can replace the negation with checking for different types
we want to have positive flow instead of negative
here we rely on knowing that there are only 4 types of products - we can replace the negation with checking for different types
we want to have positive flow instead of negative
thanks to this duplication some logic is now clearly wrong
here it's all about spotting that it's an impossible condition - A and ! A - where A is sulfuras
here it's all about spotting that it's an impossible condition - A and ! A - where A is sulfuras
We move the behaviour to new objects, we use factory methods to create those objects - we use polymorphism to maintain the same API for the new objects. They have the same "update" method.
Those new objects are nice, but they seem to have the same problem - Primitive Obsession. Let's extract a Quality object, instead of treating it as a primitive integer
Now the main IF/ELSE method is reduced to this.
While the journey is not over (some IFs are to be refactored in those type objects) we can claim some improvement.
While the journey is not over (some IFs are to be refactored in those type objects) we can claim some improvement.
If you liked this refactoring session you will enjoy my new "Anti IF" online class
http://arkency.com/anti-ifs/
You can access the first edition by the end of Monday. The practical exercises are based on the Gilded Rose refactoring kata. This kata exists in all mainstream languages.
http://arkency.com/anti-ifs/
You can access the first edition by the end of Monday. The practical exercises are based on the Gilded Rose refactoring kata. This kata exists in all mainstream languages.
The class also contains the community part - you can post the IF/ELSE monsters that you fight against in your projects and we will help you prepare the refactoring steps.
See you there!
See you there!