Как стать автором
Обновить

Makefile — умные шелл-скрипты для Джанго

Django
Make — одна из базовых утилит Юникса, есть на каждой юниксовой машине, и, к сожалению, неизвестная многим веб-разработчикам. В этой стате я покажу, как она может упростить работу, а сначала — постановка проблемы.


Чтобы проект на Джанге или Рельсах развернуть на новом сервере, нужно выполнить команд пять-десять. Если разработчик поправил схему БД, ему надо выполнить пару команд и перезапустить сервер. Если изменили список сторонних пакетов, нужно пересобрать и перезапустить, ещё 2 команды. Поменял перевод — ещё две. А если поменял сразу 2 вещи, БД и перевод? Или 3? Нужно помнить, проверять, возможны ошибки. Но ведь мы пользуемся компьютером! Он достаточно умён, чтобы понять, чтó обновить. Представьте себе фабрику дрелей, где не сумели сделать шуруповёрт и работают отвёртками. Глупо, правда?

То ли Джэфф Атвуд, то ли Пол Грэм как-то написал, что программисты должны тратить больше времени на разработку инструментов для самих себя. Раз мы пишем абстракции кода (функции, модули), чтобы уменьшить его повторения, то и инструментами тоже нужно заниматься, чтобы было меньше повторяющейся работы.

Давайте посмотрим так: что нам вообще нужно в описанных выше случаях? (Установка, обновления.) Мы устанавливаем сервер чтобы он что сделал? Заработал. Мы обновляем пакеты и хотим что? Чтобы что-то поменялось, и сервер снова заработал. Нам не важно как, главное — побыстрее, то есть чтобы лишнее не обновлялось.

Конечно, на все эти случаи можно написать скрипты, только опять же придётся помнить, какой для чего. Запустишь не тот — и время теряется.

На схеме в начале статьи — действия, которые нужно выполнять в моём проекте fastdev-django. До недавнего времени мне приходилось, по сути, приходилось держать аналог этой схемы в голове и каждый раз вспоминать, что делать. Однако конечные цели в схеме — только те, что выделены жёлтым цветом. Остальные действия — промежуточные остановки, и хорошая система должна сделать так, чтобы я про них не вспоминал.

Решение



Утилита Make вполне гибкая и может отследить точно, что нужно пересобрать, чтобы всё было обновлено, и при этом не пересобирать лишнее. Вот как выглядит правило в Makefile о том, что серверу Джанго нужно:

.PHONY: run
run: bin/django syncdb bin/sass compile_trans
	./bin/django runserver 0.0.0.0:8000

.PHONY: shell_plus
shell_plus: bin/django syncdb bin/sass
	./bin/django shell_plus

bin/django: bin/buildout buildout.cfg
	./bin/buildout

bin/buildout:
	python bootstrap.py --distribute

syncdb: bin/django
	./bin/django syncdb
	# touch a timestamp file to avoid re-syncing
	touch syncdb  

make_trans: bin/django
	./bin/django makemessages -a -e 'py,html,haml'

bin/sass:
	gem install sass --bindir bin

# watch buildout.cfg
buildout.cfg:

compile_trans:
	make locale/*/LC_MESSAGES/django.mo

locale/%/LC_MESSAGES/django.mo: locale/%/LC_MESSAGES/django.po
	./bin/django compilemessages -l $(word 2,$(subst /, ,$@))

locale/*/LC_MESSAGES/django.po:

(полный текст файла)

Когда есть такой файл, работа становится проще:

1. Поменял перевод — и если надо посмотреть его, идёшь в консоль и пишешь make run. А если не нужно сразу смотреть, просто правишь перевод. В другой раз обновится.
2. Добавил пакеты в зависимости — просто перезапускаешь сервер через make run или консоль в make shell_plus.

Здесь я не буду описывать, как пишутся Makefile, для этого достаточно материалов в Сети: книга от O'Reilly (на английском), руководство на русском, книга Эффективное использование GNU Make.

Удалось настроить файл так, чтобы компилировались любые переводы (не конкретные файлы), но только обновлённые.

Не удалось автоматизировать миграцию базы данных. Конечно, можно написать команду, которая будет удалять БД и пересоздавать её, но это опасно для рабочего сервера. Есть более тонкий инструмент, South, но пока что (версия 0.7.3) лучше не вызывать его автоматически. Если мы будем записывать каждое изменение БД в миграцию (в них записывается и дэльты, и полное состояние таблиц), то произойдёт вот что: я добавил поле, появилась миграция. Потом я поработал, ещё не коммитил ничего, но удалил это поле. Ещё одна миграция появилась на диске. Я сохранил файлы в СУВ, отправил другим разработчикам. Они должны будут запустить ненужные миграции, а репозиторий разбухáет от ненужных файлов.

Листинг: файлы в папке миграций. 0002 создаёт поле, 0003 удаляет его. Размер каждого — 17 килобайт!
29K 2011-10-13 12:33 0001_initial.py
17K 2011-11-13 02:07 0002_auto__add_field_address_test_field.py
17K 2011-11-13 02:07 0003_auto__del_field_address_test_field.py


Если же отключить автоматический запуск South, придётся помнить, какие изменения происходят в БД. И тут мы возвращаемся к началу статьи: мы должны помнить то, что может помнить компьютер.

Культура работы



Как-то раз я услышал такой аргумент: «Пусть разработчик помнит. Помнить и перепроверять всё — это вопрос культуры работы.» Пока я сам программировал на C и PHP, я тоже думал, что надо быть внимательным и, к примеру, прилежно ходить в Вики проекта, чтобы поддерживать там документацию своей библиотеки. В Питоне же есть docstring, и описание модуля, класса или метода лежат рядом с кодом. Тот же результат достигается меньшими усилиями, и ошибки случаются реже: глядя в код можно проверить, не устарела ли документация.



Даже в других отраслях, где технические решения сложнее и дороже, делают то же самое. Каким бы внимательным ни был пилот самолёта, он может ошибаться, поэтому, например, механизм поднятия шасси блокируется автоматически, чтобы случайно не выпустить колёса на большой скорости, и не убрать, стоя на земле.


Шасси Ан-124, Airliners.net

Поэтому я считаю, что культура работы — наоборот, уменьшать нагрузку на память и упрощать работу, экономить время людей (если экономия стоит того, конечно), а так же образовывать работников, чтобы они при необходимости могли починить свои инструменты.

Что дальше



1. Перезапускать сервер, когда обновляешь перевод — тоже трата времени, особенно если есть автоперезапуск. Хочу пропатчить django.utils.autoreload, чтобы он следил не только за загруженными модулями, но и за текстовыми и компилированными переводами.

2. В синтаксисе Make есть и переменные, и функции, и ленивые вычисления. Это ещё один язык разметки, который надо помнить. Неплохо было бы писать такое же, но на Питоне? Стоит попробовать SCons. Однако он есть не на всех системах, а Make есть и Линуксах, и на Маках.

Литература



  1. GNU Make, O'Reilly, 2003
  2. Руководство по GNU Make
  3. Эффективное использование GNU Make, Владимир Игнатов, 2000
  4. Python's Makefile, Ian Bicking
  5. Документация по setuptools


Добавление: в комментариях artifex подсказывает систему Fabric, скрипты похожие на Make на Питоне. По-моему, самая удобная из предложенных.
Теги:djangomakefile
Хабы: Django
Всего голосов 42: ↑39 и ↓3+36
Просмотры6.5K

Похожие публикации

Лучшие публикации за сутки