Makefile-driven development

💡 idea: good Makefile interface = important development tool

Today at the office my coworker asked why my UI tests ran so fast.

me: we can run them async now.
coworker: really?
me: yep. just use this command.
coworker: oh. didn't know we had that command.

lesson #1: without an interface, automation tools don’t get used

Here’s how I imagine the interaction between the and its neighbors:

            x   x
          x       x
        x  Makefile x
    x     x 
x        source code        x 

The README is typically used for day-1 items (how to I get this thing up and running?) and more meta concerns (why should I use this package in the first place?)

As a result, the README rots quickly unless you’re onboarding new devs very frequently.

If you want to keep track of how to use your project on a daily basis, the best option I’ve found is to use a Makefile.

lesson #2: have a Makefile!

Back to my coworker.

Why didn’t he just look at the Makefile?

Because the Makefile had a bad user interface.

Here’s an interaction with a typical Makefile.

    long cryptic cmd --mystery_arg='foo' --hmm_whats_this && do_this_too

Even if you understand each command perfectly, you may not understand the context of when/why you’d run it.

lesson #3: don’t let your Makefile user interface suck!

Now, the fun part: a solution!

Just add a short table of contents:

# Makefile
    @echo "📊 CODE QUALITY"
    @echo "lint:    lint using flake8"
    @echo "test:    run unit tests, view basic coverage report in terminal"
    @echo "cov:     view HTML coverage report in browser"
    @echo "📦 DEPENDENCIES"
    @echo "pipfr:   freeze dependencies into requirements.txt"
    @echo "pipin:   install dependencies from requirements.txt"
    @echo "piprs:   remove any installed pkg *not* in requirements.txt"

Then, next time you need to recall a workflow, just run make help:


lint:    lint using flake8
test:    run unit tests, view basic coverage report in terminal
cov:     view HTML coverage report in browser


pipfr:   freeze dependencies into requirements.txt
pipin:   install dependencies from requirements.txt
piprs:   remove any installed pkg *not* in requirements.txt

This is what I’ve done lately and it’s been working for me.