Refactoring Trees: An exercise in Research Software Engineering

In this exercise, you will convert badly written code, provided here, into better-written code.

You will do this not through simply writing better code, but by taking a refactoring approach, as discussed in the lectures.

As such, your use of git version control, to make a commit after each step of the refactoring, with a commit message which indicates the refactoring you took, will be critical to success.

You will also be asked to look at the performance of your code, and to make changes which improve the speed of the code.

The script as supplied has its parameters hand-coded within the code. You will be expected, in your refactoring, to make these available as command line parameters to be supplied when the code is invoked.

Some terrible code

Here’s our terrible code:

%matplotlib inline
from math import sin, cos
from matplotlib import pyplot as plt

s = 1
d = [[0, 1, 0]]
plt.plot([0, 0], [0, 1])
for i in range(5):
    n = []
    for j in range(len(d)):
                d[j][0] + s * sin(d[j][2] - 0.2),
                d[j][1] + s * cos(d[j][2] - 0.2),
                d[j][2] - 0.2,
                d[j][0] + s * sin(d[j][2] + 0.2),
                d[j][1] + s * cos(d[j][2] + 0.2),
                d[j][2] + 0.2,
        plt.plot([d[j][0], n[-2][0]], [d[j][1], n[-2][1]])
        plt.plot([d[j][0], n[-1][0]], [d[j][1], n[-1][1]])
    d = n
    s *= 0.6

Suggested Marking Scheme

If you want to self-assess your solution you can consider using the marking scheme below.

Part one: Refactoring (15 marks)

  • Copy the code above into a file, invoke it with python, and verify it creates an image tree.png which looks like that above.

  • Initialise your git repository with the raw state of the code. (1 mark)

  • Identify a number of simple refactorings which can be used to improve the code, reducing repetition and improving readability. Implement these one by one, with a git commit each time.

    • 1 mark for each refactoring, 1 mark for each git commit, at least five such: 10 marks total.

  • Do NOT introduce NumPy or other performance improvements yet (see below.)

  • Identify which variables in the code would, more sensibly, be able to be input parameters, and use Argparse to manage these.

    • 4 marks: 1 for each of four arguments identified.

## Part two: performance programming (10 marks)

  • For the code as refactored, prepare a figure which plots the time to produce the tree, versus number of iteration steps completed. Your code to produce this figure should run as a script, which you should call, invoking a function imported from The script should produce a figure called perf_plot.png. Comment on your findings in a text file, called For your performance measurements you should turn off the actual plotting, and run only the mathematical calculation using an appropriate flag. 5 marks:

    • Time to run code identified. (1 mark)

    • Figure created. (1 mark)

    • Figure correctly formatted. (1 mark)

    • Figure auto-generated from script. (1 mark)

    • Performance law identified. (1 mark)

  • The code above makes use of append() which is not appropriate for NumPy. Create a new solution (in a file called which makes use of NumPy. Compare the performance (again, excluding the plotting from your measurements), and discuss in 5 marks:

    • Array-operations used to subtract the change angle from all angles in a single minus sign. (1 mark)

    • Array-operations used to take the sine of all angles using np.sin. (1 mark)

    • Array-operations used to move on all the positions with a single vector displacement addition. (1 mark)

    • Numpy solution uses hstack or similar to create new arrays with twice the length, by composing the left-turned array with the right-turned array. (1 mark)

    • Performance comparison recorded. (1 mark)