Managing Sqitch with Make

If you, like me, have worked on any project in rapid development, you've had the joy of dealing with changes to your database. Tables get added. Tables get removed. Columns get renamed. Constraints get added. Stored procedures change their parameters. Refactoring code is easy (if you have discipline, source code control, and an effective testing strategy), but refactoring your database seems more difficult.

In the good old days, you may have had a directory full of little .sql files with DDL for schema changes and insert, add, delete, and update statements to mangle data.

Sqitch is a database change management system designed and developed by the inestimable David Wheeler. David is also responsible for pgTAP, which provides usable automated testing of PostgreSQL databases.

Sqitch gives you a command-line tool to manage database changes. You can add new changesets, apply them, and even verify them. (In practice, verification happens automatically; Sqitch encourages you to write pgTAP-style tests to verify that your changes do the right thing. If your tests fail, Sqitch rolls back the change. Obviously this works best on mature database systems such as PostgreSQL.)

I've used DBIx::Class::DeploymentHandler on other projects successfully, but there was always a little mismatch between how I prefer to work (maintaining DDL by hand) and how DBIC tends to want you to work (manage your schema as a set of DBIC classes and let it generate the DDL for you). That's mostly personal preference, but I do believe the Sqitch documentation is easier to understand at the moment as well.

The only substantive complaint of any sort I have with Sqitch at all is that its idea of an ideal directory structure in which to store migration files is different from my idea. (This may not be true of the most recent versions.) You can override its notions with environment variables, but I use it on multiple projects.

A while back, on a previous project, Allison said something like "What if we had a Makefile just to automate away the common commands that we're all typing all the time?" These commands did things like "Run a development version of the web server" or "Recreate the testing database" or "Update all of the dependencies we're using with Carton." While I hate the use of Make as a requirement to build CPAN modules, Make solved a real problem for us.

The problem is: how do you create a consistent set of commands, scoped to the project, which collect common operations and configure external tools to work as the project desires? We had a little directory, tools/, because the kind of people who work on Unix-like systems and have no problem writing Perl code are the kind of people who have directories full of useful, single-purpose tools. Yet we wanted something a little different.

Makefiles are unholy unions of dependency-based procedural programming and shell commands. They're not really either one, but at least they let you extend them so that you can type make command and have something reasonable happen. You're not cluttering up your shell alias list with aliases for every project you have in development and you don't have to remember paths or invocations special to every project. You get a little bit of consistency so your brain can spend its power on more important differences.

Here's what I have for the current project:

PSQL=psql -h localhost -U mpuser
PG_LATEST_DDL=db/current/myproj_ddl.sql
PG_TEST_DATA=tools/test_db_build/test_db_fixtures.sql
SQITCH_CONFIG=config/sqitch/sqitch.conf
HAS_TEST_ENVIRONMENT:=$(shell perl -Ilib -MMyProj::Config -e 'print MyProj::Config->new->allow_testing_db')

sqitch_cttester:
    @echo sqitch deploy cttester
# Makefiles are tricky about indentation
ifeq ("$(HAS_TEST_ENVIRONMENT)", "1")
    @SQITCH_CONFIG=${SQITCH_CONFIG} sqitch -d cttester -u cttester deploy; true
    @SQITCH_CONFIG=${SQITCH_CONFIG} sqitch -d cttester -u cttester status  >/dev/null 2>&1
else
    @echo not in test environment, skipping
endif

sqitch_myproj:
    @echo sqitch deploy myproj
    @SQITCH_CONFIG=${SQITCH_CONFIG} sqitch deploy; true
    @SQITCH_CONFIG=${SQITCH_CONFIG} sqitch status  >/dev/null 2>&1

sqitch_deploy: sqitch_myproj

sqitch_add:
    SQITCH_CONFIG=${SQITCH_CONFIG} sqitch add $(name)
    vim "config/sqitch/deploy/$(name).sql" "config/sqitch/revert/$(name).sql" "config/sqitch/verify/$(name).sql"
    git add "config/sqitch/deploy/$(name).sql" "config/sqitch/revert/$(name).sql" "config/sqitch/verify/$(name).sql"

First, the Makefile defines a couple of environment variables used throughout the file. The most important are SQITCH_CONFIG, which controls the location of the project-specific Sqitch configuration file and HAS_TEST_ENVIRONMENT which returns a boolean representing whether the current environment allows the use of a separate testing database. (The production server has no testing database. Development servers do.)

I only ever use the sqitch_deploy and sqitch_add commands. The deployment command tells Sqitch to deploy the most recent migrations it knows about in its plan. Sqitch's status command returns a boolean representing the success or failure (so that the exit code of make sqitch_deploy is useful and that make command doesn't think that the target failed).

The sqitch_add command helps add a new database migration. It takes one argument, so invoke it with make sqitch_add name=new_migration_name. Not only does it add the migration, it opens the new files Sqitch has created in vim (it should use the $EDITOR environment variable, but I haven't needed to care about anyone other than Vim users yet) and then adds all of the saved files to git's index.

This saves me a few dozen keystrokes and a few seconds every time I make a database change. If that sounds trivial to you, good. A few keystrokes and a few seconds are trivial. My brainpower isn't trivial. Those keystrokes and seconds mean the difference between staying in the zone and fumbling around trying to remember commands I don't use all day every day. They save me minutes every time I use them, if you count the friction of switching between "How do I do this in Sqitch again? What's the directory layout here?" and "What was I really working on?"

Automating silly tasks which take up a few seconds here and there is valuable if you can get rid of that friction. Sqitch has helped remove that friction from database migrations. Automating Sqitch with a simple Makefile has gone even further.

Modern Perl: The Book

cover image for Modern Perl: the book

The best Perl Programmers read Modern Perl: The Book.

sponsored by the How to Make a Smoothie guide

Categories

Pages

About this Entry

This page contains a single entry by chromatic published on February 9, 2014 6:00 AM.

Fatal Warnings are a Ticking Time Bomb was the previous entry in this blog.

The Mid-Career Crisis of the Perl Programmer is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.


Powered by the Perl programming language

what is programming?