This is another post in the series lessons learned building machine learning systems.

Consider the following example. I used to always structure my code like this

import argparse
import sys

if __name__ == "__main__":
parser = argparse.ArgumentParser()
args, _ = parser.parse_known_args(sys.argv[1:])
foo = args.foo
result = foo + 1


Instead what we should do is this

def run(args: argparse.Namespace):
foo = args.foo
result = foo + 1

if __name__ == "__main__":
parser = argparse.ArgumentParser()
args, _ = parser.parse_known_args(sys.argv[1:])
run(args)


The difference is that the argparse becomes a specific implementation of the actual interface, which is the run function.

Before: No separation between interface (the argparse) and implementation (also the argparse).

After: Clear separation between interface (run function) and implementation (argparse).

This separation makes our code easier to test.

We now can write another testing implementation just using the run function instead of having to rely on the argparse to test the full flow of the application.

In this trivial example it almost seems obvious, but for some reason I did manage to completely forgot this in a larger and more complex codebase.

The solution is simple, just wrap whatever is happening in your __main__ into a single function called run :)

Tags:

Categories:

Updated: