December 13, 2020

パターンルールと黒魔術

パターンルールは便利な反面、Makefile を複雑化しやすいです。

例えば、docker-compose のインターフェースとして、よく使うサブコマンドを、黒魔術の誘惑によってこのように書きたくなることもあります。 <サービス名>/<操作> といった規則の糖衣構文的なルールです。

database/%:
  make docker-compose/$(@F) SERVICE=$(@D)

docker-compose/%:
  docker-compose $(@F) $(SERVICE)
version: "3.8"
services:
  database:
    build:
      context: .
      target: ${TARGET:-production-pseudo}
    environment:
      MYSQL_ROOT_PASSWORD: password
    volumes:
      - mysqldata:/var/lib/mysql

volumes:
  mysqldata:
FROM mysql:8.0.22 AS production-pseudo

# --

FROM production-pseudo AS development

# https://forums.mysql.com/read.php?12,426247,432315#msg-432315
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
      man \
      man-db \
      manpages \
      && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

しかしこういった黒魔術はメンテナンス性を下げますし、統一的に書けるという幻想は大抵すぐに瓦解します。

本当に自動化したいルールを重視し、糖衣構文的なルールを用意するにしても使用頻度が高いものに絞り、できるだけ素朴に書くのが、Makefile をメンテナンスして育てる秘訣ではないかと思います。

.PHONY: help setup setup-dev build up logs down migrate clean

TARGET := production-pseudo

help:
	@cat $(firstword $(MAKEFILE_LIST))

setup: \
	.env

setup-dev: \
	$(eval TARGET := development) \
	setup

build: docker-compose.yml
	docker-compose build

up:
	docker-compose up -d

logs:
	docker-compose logs -f

down:
	docker-compose down

migrate:
	# ...

.env:
	echo "TARGET=$(TARGET)" > $@

clean:
	docker-compose down -v
	rm -rf .env

README などで補足するのもよいと思います。使用頻度が高いものを Makefile に昇格させるようにすれば、それがメンテナンス性を考慮する機会になるはずです。

## How to use
~~~sh
make -f docker.mk setup-dev
make -f docker.mk build up
make -f docker.mk down
~~~

## Basic usages of docker-compose
~~~sh
docker-compose ps [service]
docker-compose exec <service> <command>
docker-compose run --rm <service> <command>
~~~

リンク