"Will my refactoring break my code ?" is the question the developer asks himself because he is not sure the tests cover all the cases. He should wonder, because tests that cover all the cases would be costly to write, run and maintain. Hence, most of the time, small decisions are made day after day to test this and not that. After some time, you could consider that in a sense, the implementation has become the specification and the rest of the code expects it not to change.

Enters Scientist, by GitHub, that inspired a Python port named Laboratory.

Let us assume you want to add a cache to a function that reads data from a database. The function would be named read_from_db, it would take an int as parameter item_id and return a dict with attributes of the items and their values.

You could experiment with the new version of this function like so:

import laboratory

def read_from_db_with_cache(item_id):
    data = {}
    # some implementation with a cache
    return data

def read_from_db(item_id):
     data = {}
     #  fetch data from db
     return data

When you run the above code, calling read_from_db returns its result as usual, but thanks to laboratory, a call to read_from_db_with_cache is made and its execution time and result are compared with the first one. These measurements are logged to a file or sent to your metrics solution for you to compare and study.

In other words, things continue to work as usual as you keep the original function, but at the same time you experiment with its candidate replacement to make sure switching will not break or slow things down.

I like the idea ! Thank you for Scientist and Laboratory that are both available under the MIT license.

blog entry of