2

I was assigned a refactoring.

We have several modules having similar functions with some differences. My task is to extract common portions of code for DRY principle.

I am a little lost how to do it.

I could just cut&paste similar fragments of code, extracting them into separate functions, but if I do it this way mechanically, then the declarations and usage of local variables of the fragmented functions may happen to fall into different functions, what could lead to invalid code.

Could you do some practical advice how to handle this issue. I'd wish a step-by-step guide on refactoring such code with local variables.

And also: In some reason my boss wants the resulting code not to be object oriented. I think this can be solved by passing fragments of code as function pointers.

I can't show a code example for my question, because the real code is closed-source and I can't write a minimal example, because the entire issue is dealing with long functions.

One more note: We write in Perl.

asked Mar 5, 2017 at 18:19
2
  • Some idea: I may move the declarations of variables lower in the source more near to the usage, before splitting the functions into fragments. Is it a good idea? Commented Mar 5, 2017 at 18:36
  • I started this work. It now looks like that a right strategy is first extract small fragments of code Commented Mar 6, 2017 at 15:16

3 Answers 3

3

You should look for what they have in common, e.g. they all open an SQL connection, they all need to handle errors and close resources at the end, they all call some API in the middle, etc. Then focus on separating what is constant from what is variable.

There are a few patterns that help deal with this. Consider the

Strategy Pattern

Template Pattern

answered Mar 5, 2017 at 19:28
1
  • Egad! Please, no more template pattern! Don't forget decorator pattern and good old functional composition. Commented Mar 5, 2017 at 19:59
1

Find out what parts are common, and separate the uncommon parts into separate functions. Then combine them.

Suppose that you have two functions:

def foo_y(x):
 <fragment A dealing with x>
 <fragment X>
def foo_z(x):
 <fragment A dealing with x>
 <fragment Y>

Now it's easy to create functions fragment_a, fragment_x, fragment_y and combine them into foo_x and foo_y.

You may have a layered structure:

def foo_y(x):
 <fragment A dealing with x>
 b = <fragment X>
 <fragment B dealing with b>
def foo_z(x):
 <fragment A dealing with x>
 b = <fragment Y>
 <fragment B dealing with b>

Extract fragment_x and fragment_y s functions.

You can now write:

def parametric_foo(x, handler_of_b):
 <fragment A>
 b = handler_of_b(...)
 <fragment B>

Combining these two approaches should help you with the majority of the task.

answered Mar 5, 2017 at 19:58
6
  • Good, but you haven't answered my question: How to ensure that variable declarations will be extracted into the same function which uses them? I yet not quite understand how to do it in practice, because if I do fragments cut&paste it may split variable usages from its declaration. What is particular a better thing than cut&paste? Commented Mar 5, 2017 at 21:07
  • 1
    @porton: In a compiled language, the compiler will tell you. In an interpreted language, your test suite will (likely) tell you. IDEs often allow to factor out a block of code as a function, adding proper parameters to pass the needed variables and eliminating now-disused variables. In any case, human oversight is desirable. If the resulting functions are still complicated, continue the process until the data flow is obvious. Commented Mar 5, 2017 at 23:03
  • I don't ask how to check whether a given refactoring is correct, but how to make the refactored program text Commented Mar 6, 2017 at 12:37
  • @porton: I'm afraid there's no universal tool. A language-specific IDE often helps. Otherwise, I use text search and my judgment when facing a task like this. It's like solving a puzzle (as much of programming is in general). Commented Mar 6, 2017 at 13:03
  • I am not about a special tool, but how to do it with a regular text editor. What the programmer should do? (not what a tool should do) Commented Mar 6, 2017 at 16:12
0

It can be done replacing all (or most of) local variables with a structure/record (hash in Perl) having these variables as members.

Then it is enough to pass to the extracted fragment function a pointer to the structure, without the need to pass (reference to) every local variable.

This strategy makes easy to extract fragments of code into separate functions.

This approach also resembles object oriented programming: the structure I tell about is like an object (whose purpose is to keep intermediate data for calculating the refactored function).

answered Mar 9, 2017 at 14:50

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.