Good with a keyboard and fluent in gibberish

How I Just

Just is an incredibly power project task runner. I use it in everything now, and I’ve developed Opinions about its use.

Let’s talk about them.

Conceptual

First, I treat Just as a tool for people. I rarely invoke it in automation, instead copying the invocations into whatever script/YAML is applicable. (Especially since you often want to tweak some options between “ran locally directly for a person” and “ran in CI/CD”.) Because of this, the commands I want my colleagues to run are in the form of just test or just update. Which means I recommend installing Just as a system tool, not as a project dependency (even though it’s on both PyPI and NPM).

Secondly, a Justfile is documention for “how to do common things” and also “what are the things I expect you to need to do”. Reading a Justfile on an unfamiliar project gives quick and succinct insight on how the project is structured, while also providing useful entrypoints to get started quickly. For example, you’ll see poetry run ... in many of the samples below. This is both useful for simplifying invocation (don’t need to run poetry run just test) and making it clear this is a Poetry project.

Thirdly, I want the Justfile to be readable and the commands to be manually invocable. Generally, truly complicated things stay out of the Justfile (although there are exceptions).

(Also, always use docstrings)

System-level dependencies

While software engineering has gotten really good at project dependencies, you need some things installed at a system level. I try to keep these to a minimum, but the list tends to grow a bit.

At minimum, my projects will probably assume you have Just and pre-commit installed.

Additionally, I’ll probably expect you have whatever ecosystem package tools are used in the project. For Python I write, that’ll usually be Poetry.

I begin every Justfile with this block:

set windows-powershell := true

# Show this help
@help:
  just --list

This does two things:

  1. Sets up just and just help to be useful
  2. Tells Windows to use a useful shell

Install

Usually the first command I write is install, which is the first thing a developer should run after cloning the repo. It’ll set up the development environment but (probably) shouldn’t install system packages.

For my Python projects, it’ll probably be something like:

# Set up dev environments
install:
  poetry install
  pre-commit install

Although I do have a Caddy project where I do this:

# Set up dev environments
install $GOBIN=executable_directory():
  pre-commit install
  go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

Hooks

In projects with pre-commit (or similar), I’ll have a hooks:

# Run the pre-commit hooks
hooks:
  pre-commit run --all-files

This will clean up and formatting bombs and give a quick way to invoke the commit tooling.

build, test, types

Depending on the project, these will be my bread-and-butter commands.

just build just runs a build. Uncommon for Python, but I’ll use it with Go or Rust.

just test runs the test suite, in a configuration that’s probably useful to a developer. If I’m doing pytest, I’ll using add an option for flags:

# Run the test suite
test *ARGS:
  poetry run pytest --log-level=DEBUG 

This allows for easily doing just test -x --ff for incremental test work.

just types is largely specific to Python and out-of-band type checking. It invokes the static analysis tool of the project (generally mypy).

serve

For network services and websites, just serve starts a dev server.

For services, this is probably something Docker/Compose based.

For websites, this is a autobuild/autorefresh server.

If it’s easy and useful, I’ll have it randomize the port and open a browser (eg sphinx), to avoid port conflicts.

c

For services, I’ll generally do Docker and Composed-based development. Depending on the project, though, this might be docker-compose.yaml, compose.yaml, compose.dev.yaml, docker/compose.yaml or something else.

just c just wraps compose with the write options for local development:

# Manipulate docker compose (dev edition)
c *CMD:
  docker compose -f compose.dev.yaml 

So the developer can do just c up, just c down, just c run, etc.

Other Commands

Test data manipulation (load, reload, clear, etc) is a strong candidate for Just commands.

Common admin commands (or a wrapper to invoke commands) is a really good idea.

I largely don’t do dependency manipulation commands (eg, poetry add) because the invocations can vary a lot, and it’s generally not safe to do it untrained.

Exceptions

Pretty much this entire post is “usually” or “generally”. You should do what makes sense for your project and desired developer experience.

But there two things you should consider:

  • What does a new developer need to know?
  • What commands do you invoke every day?

These are things that a Justfile should be helping with.