Refactor identical code. Merge functions with duplicating functionality into one generic function.
If such a functions appear in classes inherited from a same ancestor, create the generic function in the ancestor and call it from the descendants. If the classes are not inherited from one ancestor then create the generic function in a third class (even if you have to create that class only for one function!). If you find yourself thinking whether to duplicate code using copy-paste (10 minutes of work) or take it to a third place (2 hours including testing) - stop thinking immediately! NEVER THINK ABOUT THAT, even in last days of your contract - SIMPLY TAKE THE CODE TO A THIRD PLACE and call it from where needed. If you are still in doubt about spending your time (which really belongs to the company) - ask your manager, but it's better to do the work well and after that to explain the manager why it has taken longer time: if the manager understands what the quality programming is then your effort will be appreciated!
Refactor similar code. Merge functions with similar functionality into one generic function.
If the functions, being taken by you into a third place to prevent duplication, are very similar but not exactly identical, then you need to exploit your brain a little bit more. Do the following:
Merge the original scripts as described in "Refactor identical code" removing code duplication in the maximum way you can.
Supply the different stuff (unique for each original function) from the application areas the original functions appeared in before.
For example, we have two original functions in different classes that are like these (fragments 1 and 2 of the second object are exactly as fragments 1 and 2 accordingly of the first class, but the DataObjects are different):
*** BAD code: ***
SomeFunction() of the first class:
- Code: Select all
_entityDescription = "Car";
SomeFunction() of the second class:
- Code: Select all
[fragment 1] // exactly like [fragment 1] in the first class
_entityDescription = "Bike"; // oops, this line is different...
[fragment 2] // exactly like [fragment 2] in the first class
*** GOOD code: ***
SomeFunction() taken into the ancestor class:
- Code: Select all
_entityDescription = this.GetEntityDescription();
So, we use the function GetEntityDescription to overcome the problem of difference between two the discussed functions. GetEntityDescription() is created in the ancestor class. Create it as an abstract function if your programming language supports them. If doesn't support (so you are forced to implement the function in the ancestor level) then display an error message or throw an exception letting know that this code must not be ever called. The function must be implemented in the descendant classes to supply circumstances-specific information, i.e. entities descriptions in our example: in the first descendant the function should be coded as return "Car";, in the second one - as return "Bike";.
If the function is taken into a third class (which doesn't belong to the inheritance hierarchy) then the SPECIFIC (different) data can be supplied as argument(s) of the new merged function, so the fragment _entityDescription = this.GetEntityDescription(); will become _entityDescription = aEntityDescription; where aEntityDescription is the function's argument.
Finally, there is one more method to achieve the goal - we can populate the _entityDescription instance variable while initializing the instance (for example, in its constructor), but this approach is not always applicable.
So, that is the rule to obey:
DIFFERENT PARTS OF THE APPLICATION MUST SUPPLY SPECIFIC (UNCOMMON) DATA TO A GENERIC (UNIVERSAL) ALGORITHM IMPLEMENTED ONLY ONCE.
In one of my projects the old problem of duplicated "almost same" code was so serious that I suggested to perform refactoring of entire application sub-system, and my suggestion was accepted - I spent a week doing that, and it was one of the most interesting tasks in my career! As a result, my resume was decorated with the following beautiful fragment:
Proposed and performed code refactoring of existing corporative reporting system, moving duplicating functionality from descendant to ancestor classes. Facilitated maintenance and troubleshooting and made adding of new reports much easier and quicker.
But, of course, it's better to spend some time before development and think how to organize classes instead of thoughtless straightforward coding which forces the keys Ctrl+C and Ctrl+V to work hard.
- Site Admin
- Posts: 111
- Joined: 19 Feb 2013, 20:33
Return to Managing Functions
Who is online
Users browsing this forum: No registered users and 1 guest