Ежедневная сборка - ваш союзник и друг
From The Joel on Software Translation Project
Автор: Джоэл Спольски
Переводчик: Александр Лебедев
В оригинале статья называлась Daily Builds Are Your Friend и была написана 27 января 2001
В 1982-м моя семья купила по заказу самый первый IBM-PC в Израиле. На самом деле мы пришли на склад и дожидались, пока наш компьютер будет доставлен из порта. Каким-то чудом мне удалось убедить отца купить "заряженную" версию, с двумя дисководами, 128 Кб памяти, а также одновременно матричным принтером (для черновиков) и барабанным принтером (для качественной печати), который при работе звучал в точности как пулемет, только громче. Думаю, мы взяли все возможные аксессуары: PC-DOS 1.0, 75-долларовое техническое руководство с полным исходным кодом BIOS, Macro Assembler, потрясающий дисплей IBM Monochrome с целыми 80 колонками и ... буквами в нижнем регистре! Все в сумме обошлось нам где-то в 10,000$. Какое расточительство!
Уже тогда, "все" знали, что Бейсик был языком программирования для детей, заставляющим писать "макаронный" код и превращающим ваши мозги в кашу. Так что мы отстегнули 600$ за IBM Pascal, который шел на трех дискетах. Первый проход компилятора располагался на первой дискете, второй проход - на второй, а компоновщик - на третьей. Я написал простую программу "Hello, world" и скомпилировал ее. В сумме потрачено времени: 8 минут.
Хмм. Это долго. Я написал скрип для автоматизации процесса, что позволило урезать время до 7 1/2 минут. Уже лучше. Но когда я пытался писать большие программы, наподобие своей сногсшибательной версии Отелло (прим. пер.: популярная игра также известная как "Реверси"), всегда побеждавшей меня, больше всего времени я тратил в ожидании завершения компиляции. "Да," - сказал мне профессиональный программист, "у нас был тренажер для пресса в офисе и мы упражнялись, пока код компилировался. Через несколько месяцев программирования у меня был потрясающий пресс."
В один прекрасный день в Дании появилась изящная программа Compas Pascal, которую Филлип Кан (Philippe Kahn) купил и переименовал в Borland Turbo Pascal. Turbo Pascal шокировал, поскольку он умел всё, что умел IBM Pascal, занимая при этом 33 Кб памяти, включая текстовый редактор. Это было невероятным потрясением. Еще более потрясало то, что маленькая программа компилировалась меньше секунды. Это было как если бы никому неизвестная компания выпустила клон модели Buick LeSabre, который мог разгоняться до 1,000,000 километров в час и объехать земной шар на таком малом количестве бензина, которое муравей мог бы выпить без вреда для здоровья.
Внезапно я стал намного продуктивнее.
Именно тогда я узнал о концепции REP-цикла. REP означает "Read, Eval, Print", и это описывает работу LISP-интерпретатора: он читает то, что вы ввели, исполняет это, затем печатает результат. Пример REP-цикла показан ниже: я пишу что-то, интерпретатор читает это, выполняет и печатает результат.
В несколько более глобальном масштабе, когда вы пишете код - вы находитесь в макро-версии REP-цикла, называемой Редактирование-Компиляция-Тестирование. Вы пишете код, компилируете его, тестирует его и проверяете, что все работает как надо.
Ключевой момент в том, что вам нужно снова и снова проходить через этот цикл, чтобы написать программу, следовательно чем быстрее ваш цикл Редактирование-Компиляция-Тестирование, тем продуктивнее вы можете быть, вплоть до естественного предела мгновенной компиляции. Это формальное, в духе Computer Science обоснование того, почему программисты хотят работать на самом быстром "железе", а разработчики компиляторов делают все возможное для получения сверхбыстрых циклов Редактирование-Компиляция-Тестирование. Visual Basic делает для этого разбор и лексический анализ каждой строки кода пока вы ее печатаете, поэтому финальная компиляция делается очень быстро. Visual C++ использует для этого инкрементную компиляцию, прекомпилированные заголовочные файлы и инкрементную компоновку.
Как только вы начинаете работать в команде с несколькими разработчиками и тестирощиками, вы видите тот же самый цикл в еще большем масштабе (ага, это фрактал!). Тестировщик находит ошибку и сообщает о ней. Разработчик исправляет эту ошибку. Сколько времени проходит, прежде чем тестировщик получает исправленную версию кода? В некоторых компаниях-разработчиках этот цикл Обнаружение-Исправление-Подтверждение может занимать несколько недель, делая работу компании непродуктивной. Чтобы поддерживать процесс разработки в хорошей форме, вам следует сфокусироваться на сокращении цикла Обнаружение-Исправление-Подтверждение.
Хорошим инструментом для этого является ежедневная сборка. Ежедневная сборка - это автоматическая, ежедневная, полная сборка всего исходного кода.
Автоматическая - потому что сборка должна запускаться в фиксированное время службой-планировщиком (CRON для UNIX, "Планировщик заданий" для Windows).
Ежедневная - или даже чаще. Соблазнительно делать постоянные сборки, но скорее всего это невозможно из-за проблем с контролем исходного кода, о которых я расскажу чуть позже.
Полная - возможно, у вашего кода есть несколько версий. Версии для разных языков, операционных систем, полная/упрощенная версии. Ежедневная сборка должна собирать их все. И она должна собирать каждый файл заново, не полагаясь на, быть может, несовершенный механизм инкрементной сборки.
Вот некоторые преимущества ежедневной сборки:
- Когда ошибка исправлена, тестировщики быстро получают новую версию и могут убедиться, что исправление корректно.
- Разработчики могут чувствовать себя безопаснее, зная, что внесенное ими изменение не сломает ни одну из 1024 версий системы, не имея, например, на своей машине OS/2 для тестирования работы кода на ней.
- Разработчики, выкладывающие свои изменения прямо перед происходящей по расписанию сборкой знают, что они не испортят всем жизнь, выложив что-то "ломающее сборку" -- то есть что-то, не позволяющее никому собрать продукт и работать. Это эквивалент "синего экрана смерти" в масштабе команды разработчиков. Такое часто происходит, когда разработчик забывает выложить в репозиторий только что созданный им файл. Сборка проходит нормально на их машине, но стоит кому-то другому взять свежую версию кода, как они получают ошибки компоновщика и не могут работать, пока проблема не будет исправлена.
- Внешние подразделения, например, отдела маркетинга, бета-тестеры и т.д, все те, кому нужно использовать "сырые" версии продукта могут взять конкретную сборку, считающуюся относительно стабильной, и использовать ее в течение относительно продолжительного времени.
- Поддерживая архив всех ежедневных сборок, вы, обнаружив новую, таинственную и непонятную ошибку, можете, используя двоичный поиск, легко обнаружить, когда именно ошибка была внесена в код. В сочетании с хорошей системой контроля версий исходного кода, вы, вероятно, можете отследить какое именно изменение вызвало проблему.
- Когда тестировщик сообщает об ошибке, которую разработчик считает уже исправленной, тестировщик может сказать в какой именно сборке он видел ошибку. Затем программист может посмотреть, когда он выложил исправление и выяснить, действительно ли ошибка уже исправлена.
И вот как всего этого добиться. Вам нужен сервер для ежедневной сборки, вероятно, самая быстрая машина на которую вы можете наложить руки. Напишите скрипт, который берет из репозитория полную копию последнего кода (вы же используете систему контроля версий исходного кода, правда?), затем собирает с нуля каждую версию кода, которую вы поставляете. Если вы поставляете инсталлятор, собирайте и его тоже. Все, что вы поставляете заказчикам должно быть включено в ежедневную сборку. Сохраняйте результаты каждой сборки в отдельную директорию, названную по дате сборки. Запускайте ваш скрипт в одно и то же время каждый день.
- Очень важно, чтобы все, что нужно для полной сборки, делалось упомянутым скриптом, включая выкладывание собранного продукта на веб-сервер для общего доступа (разумеется, в процессе разработки это будет тестовый сервер). Это единственный способ обеспечить, чтобы никакая информация о процессе сборки не была "задокументирована" только в чьей-то голове. Вы никогда не попадете в ситуацию, когда вы не можете выпустить продукт, потому что только Вася знает, как создать дистрибутив, а он попал под автобус. В команде Juno все, что нужно было знать для создания полной сборки системы с нуля - это где находится сервер сборки и как сделать двойной клик на ярлыке "Сделать сборку".
- Нет ничего хуже для вашей психики, чем когда вы пытаетесь сделать поставку, находите одну микроскопическую ошибку, исправляете эту микроскопическую ошибку прямо на сервере сборки и отгружаете продукт. Как золотое правило, вы должны поставлять только код, созданный в процессе полной обычной сборки, начатой с получения свежей полной копии кода из репозитория.
- Настройте ваши компиляторы на максимальный уровень предупреждений (/W4 в стране Microsoft; -Wall в мире gcc) и пусть они останавливаются при малейшем предупреждении (прим. пер.: /WX, а не /W4 в мире MS должно давать этот эффект).
- Если ежедневная сборка "сломана", вы рискуете остановить работу всей команды. Бросьте всё, исправляйте и пересобирайте, пока сборка не завершится успешно. Иногда у вас будет несколько сборок в один день.
- Ваш скрипт сборки должен сообщать об ошибках, по почте, всей команде разработчиков. Несложно также отфильтровать логи по наличию в строке слов "error" или "warning" и включить все найденные строки в письмо. Скрипт также может дописывать результаты на какую-нибудь HTML-страницу, которую видят все члены команды, так, чтобы разработчики и тестировщики могли быстро определить, какие сборки были успешны.
- Правило, которое мы с большим успехом использовали в команде Microsoft Excel, состояло в том, что человек, сломавший сборку становился ответственным за надзор за ежедневными сборками до тех пор, пока кто-нибудь другой не "отличится". Кроме предоставления четкой мотивации поддерживать корректную работу сборки это правило позволило практически каждому побыть "ответственным за сборки", так что все знали, как делается сборка.
- Если ваша команда работает в одном часовом поясе, сборку удобно проводить в обеденный перерыв. Таким образом, все выкладывают свой код сразу перед обедом, сборка происходит пока они едят, и когда все возвращаются к работе, то если сборка была сломана, все на месте, чтобы исправить проблему. Как только сборка прошла успешно, все могли тут же брать из репозитория последнюю версию, не боясь, что она не будет работать.
- Если ваша команда работает в двух часовых поясах, выбирайте время сборки так, чтобы люди в одном часовом поясе не могли, случайно испортив сборку, заблокировать работу людей в другом часовом поясе. В команде Juno, сотрудники в Нью-Йорке могли выложить свои изменения в 7 вечера по времени Нью-Йорка и пойти по домам. Если они испортили сборку, то команда в Хайдарабаде, Индия, придя на работу (где-то в 8 часов вечера по времени Нью-Йорка) была застопорена на целый день. Мы начали делать две сборки в день, за час до того, как каждая команда отправлялась домой, и полностью решили эту проблему.
Дополнительная Литература
- Обсуждение инструментов для ежедневной сборки.
- Ежедневные сборки достаточно важная вещь, чтобы входить в 12 шагов к лучшему коду.
- Много интересного о сборках (еженедельных), которые делала команда Windows NT в книге Грега Паскаля Захарии (G. Pascal Zachary) Showstopper.
- Стив МакКоннел (Steve McConnell) пишет о ежедневных сборках здесь.


