REG.RU software process

В данном документе описаны особенности процесса разработки и регламенты разработки, используемые в проекте РЕГ.РУ.

Данный регламент устарел. У нас появилось много новых практик, которые тут не описаны.

Некоторые практики могут показаться банальными или само собой разумеющимися, однако эти практики не попали бы сюда, если бы автор не был свидетелем их многократного нарушения. А нарушение «техники безопасности» в таком деле, как внесение изменений в «живой» популярный проект может привести к обидным последствиям вроде утраты авторитета или даже потери клиентов.
В то же время, при кажущейся «сложности» предлагаемых практик к ним довольно легко привыкнуть — достаточно некоторое время «держать себя под контролем» и необходимая привычка будет доведена до автоматизма. В конце концов «накладные расходы», связанные с применением тех или иных процедур, будут сведены к минимуму, а выгода от их соблюдения будет налицо.

Наряду с данным документом рекомендуется ознакомиться с документом REG.RU coding standards (стандарты кодирования REG.RU).

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

Оглавление

  1. Внесение изменений в схему БД
  2. Перед тем, как сделать коммит...
  3. Выкатка изменений на сервер
  4. Работа над задачами, записанными в mantis
  5. Создание новых модулей ядра
  6. Стратегия работе с системой управления версиями
  7. Правка чужих CPAN-модулей
  8. Правка модулей в репозитории OSS
  9. Создание API-функций
  10. Практики XP

Процедура внесения изменений в схему БД

  1. Согласуйте изменения

    Все изменения в схеме БД (добавление / удаление / изменение любых полей / таблиц) обсуждаются с ведущим разработчиком проекта. Возможно, изменения, которые вы планируете внести, в чём-то не согласуются с логикой проекта или без них можно обойтись вовсе.

  2. Отразите изменения в файле с описанием таблицы

    В каталоге sql/ проекта regru для каждой таблицы должен быть предусмотрен SQL-файл со схемой таблицы. Данный файл должен содержать SQL-выражения для (пере)создания указанной таблицы (DROP TABLE IF EXISTS, CREATE TABLE). При любых изменениях в любой из таблиц должен редактироваться или создаваться (при создании новой таблицы) соответствующий SQL-файл. Информация об индексах таблицы также должна быть отражена в данном файле.

    Для всех вновь добавляемых полей в таблицы рекомендуется дописывать комментарий для каждого поля:

    DROP TABLE IF EXISTS user_prefs;
    CREATE TABLE user_prefs (
      user_id int(11) NOT NULL,		# ID пользователя в таблице users
      pref_code CHAR (32) NOT NULL,		# Название сохраняемого параметра
      pref_value varchar(64) NOT NULL,	# Значение сохраняемого параметра
      PRIMARY KEY  (user_id, pref_code)
    )
    

    Если для данной таблицы существует YAML-исходник, из которого автоматически генерироваться SQL-файл с описанием таблицы, то править, конечно же, нужно исходник, а SQL-файл перегенерировать:

    make <tablename>.sql
    

  3. Создайте migration-скрипт (кроме случая создания новых таблиц/процедур)

    В каталоге sql/migration/ создать SQL-скрипт для миграции на новую схему, т. е. набор SQL-инструкций для изменения метаданных. В случае создания НОВОЙ таблицы / хранимой процедуры необходимости в отдельном миграционном скрипте нет, т. к. для создания таблицы можно использовать соответствующих SQL-файл, описанный в предыдущем пункте.

    Также нет необходимости в создании миграционного файла, если изменяется таблица со «статичными» данными, то есть данными, которые не меняются автоматически в процессе эксплуатации системы, а изредка «перезаливаются» вручную. Примеры таких «статичных» таблиц: prices, servtypes, tlds, contfields. В подобных случаях, изменения вносятся только в SQL(YAML)-файл для соответствующей таблицы и структура таблицы вместе с данными «перезаливается» в базу из этого SQL-файла.

    Однако, при изменении большинства таблиц, миграционный файл всё-таки необходим. Примеры (из рекомендуемой практики) имён файлов с миграционными скриптами:
    <tablename>-add-<columnname>.sql
    <tablename>-add-key-<keyname>.sql
    <tablename>-drop-<columnname>.sql
    <tablename>-drop-key-<keyname>.sql
    <tablename>-modify-<columnname>.sql
    <tablename>-change-<columnname>.sql

    Примеры имён файлов с операциями, затрагивающими несколько полей в одной таблице:
    <tablename>-add-<featurename>.sql
    <tablename>-<featurename>.sql (несколько изменений, связанных с фичей <featurename>)
    <tablename>-add-keys.sql (добавление нескольких новых ключей)

    Пример имён файлов с операциями, затрагивающими несколько таблиц:
    <featurename>.sql (добавление фичи <featurename>)
    С другой стороны, создавать миграционные скрипты, затрагивающие несколько таблиц, НЕ РЕКОМЕНДУЕТСЯ (т. к. такие файлы трудно идентифицировать в последствии). Для таких «сложных» лучше создать несколько миграционных sql-файлов.

  4. Внесите изменения в БД на production-серверах

    Если у Вас имеется доступ на production-машины — самостоятельно внести изменения в БД на production и выделенные тестовые машины. Если такого доступа нет — попросите «старших товарищей», у которых соответствующий доступ есть, внести необходимые изменения.

  5. Напишите остальным разработчикам об изменениях

    Напишите в список рассылки devel [at] reg {dot} ru о произведённых изменениях, с тем чтобы остальные разработчики также могли поддерживать базу в актуальном состоянии. В противном случае рано или поздно у Ваших коллег начнут «отваливаться» тесты, либо возникать ошибки на локальной копии сайта; им придётся тратить время на то, чтобы понять в чём проблема и исправить её.

  6. Закоммитьте код, зависящий от изменения в базе

    Теперь, наконец, Вы можете «со спокойной совестью» коммитить код, который зависит от нововведений, сделанных Вами в базе.

    К чему такие предосторожности?
    Вы должны отдавать себе отчёт, что любой код, который Вы подтвердили, может быть выложен на боевые сервера «в любую секунду» другими разработчиками. Вы не можете надеяться на то, что внесёте изменения в базу «чуть позже». Идея в том, что любые атомарные изменения, которые вы делаете (любые коммиты) должны быть недеструктивными, т. е. их выкатка на боевые машины или машины других разработчиков не должна приводить к любым проблемам в работоспособности системы или тестов.

Перед тем, как сделать коммит...

  1. Проверьте синтаксис всех модулей, в которых Вы вносили изменения

    Даже если Вы поменяли всего лишь один символ. Выполнить команду

    perl -c <имяскрипта>
    

    не сложно, но сколько раз это уберегало от обидных опечаток и неоправданных «падений» сайта...

  2. Проверьте разметку POD всех модулей, в которых Вы вносили изменения

    Даже если Вы поменяли всего лишь один символ. Выполнить команду

    podchecker <имяскрипта>
    

    не сложно, но уберегает от проблем открытия файлов с некорректной документацией в некоторых редакторах, и делает perldoc чище...

  3. Проверьте все модули, в которые Вы вносили изменения, на соответствие нашему набору правил Perl Critic.
  4. Для простоты все вышеприведённые три пункта реализованы в скрипте /www/srs/script/plint.

    Он сейчас выглядит так:

    #!/bin/bash
    
    /usr/bin/env perl -I /www/srs/lib -c $@ && podchecker $@ && perlcritic --profile /www/srs/lib/perlcritic.profile $@
        

    Для удобства использования просто сделайте

    ln -s /www/srs/script/plint /usr/local/bin/plint
        
  5. Если вносили нетривиальные изменения, — прогоните тесты

    Прогоните тесты для тех модулей, в которые вносились изменения и для других модулей, на которых эти изменения могут отразиться.
    Однако, проще (и правильнее) всего — прогнать ВСЕ тесты:

    cd t/
    perl all.pl -n	# прогнать все тесты с параметром --no-internet

  6. Проверьте шаблоны TT-валидатором

    Если вносились масштабные изменения в шаблоны — прогоните автоматические тесты для шаблонов:

    t/templates/test_tmpl_mail.pl	# проверка шаблонов писем
    t/templates/test_tmpl_sites.pl	# проверка шаблонов сайта
    

    Дело в том, что не всегда имеется возможность посетить все страницы, в которые Вы вносили изменения (предположим, Вы участвовали в субботнике по переводу сайта на xhtml 1.0 strict и произвели массу автоматических замен тегов в разных файлах) и для «очистки совести» имеет смысл «провериться», дабы избежать досадных ошибок в конструкциях Template Toolkit.

  7. Проверьте новые шаблоны w3c-валидатором

    Конечно, было бы бесчеловечным предлагать проверять валидность HTML-кода после внесения ЛЮБЫХ изменений в шаблоны. Однако, в случае создания НОВЫХ шаблонов или СУЩЕСТВЕННОГО изменения существующих — провериться не помешает. Для чего рекомендуется установить локальную копию w3c-валидатора и использовать скрипт

    script/nakedsystem_server.pl

    для запуска облегчённой версии системы.

    Облегчённая версия системы (далее NakedSystem) предназначена специально для быстрого/лёгкого/необременительного запуска сайта БЕЗ бизнес-логики. При этом можно зайти на ЛЮБУЮ страницу сайта без аутентификации / авторизации, без «тормозов» и без риска создания каких-либо побочных эффектов. Если кратко: NakedSystem — это «безмозглая» версия сайта, «голый» движок для рендеринга страниц из шаблонов. Идеально подходит для применения совместно с валидатором.

  8. Если Вы начали использовать Новый CPAN-модуль, — убедитесь что он установлен на production-серверах

    Также обо всех новых сторонних модулях, которые раньше не использовались в системе и которые начинаете использовать Вы впервые сообщите в список рассылки остальным разработчикам, чтобы установили у себя этот новый модуль.

Выкатка изменений на сервер

Для выкатки изменений на сервер пользуйтесь скриптом remote-update.sh, который обеспечивает простой, быстрый и безопасный способ выкатки изменений. Сокращённый вариант вызова remote-update.sh, команда make sync. Существует несколько различных вариантов вызова remote-update.sh:

remote-update.sh (make sync)
обновить файлы на сервере из репозитория;
remote-update.sh --frontoffice (make sync-fo)
обновить файлы на сервере и перезапустить FrontOffice;
remote-update.sh --backoffice (make sync-bo)
обновить файлы на сервере и перезапустить BackOffice;
remote-update.sh --queueproc (make sync-qp)
обновить файлы на сервере и перезапустить queue_processor;
remote-update.sh --all (make sync-all)
обновить файлы на сервере и перезапустить FrontOffice, BackOffice, queue_processor.

При этом перед перезапуском FrontOffice автоматически производится проверка синтаксиса модулей сайта. Если проверка синтаксиса была неуспешной — web-сервер не будет перезапущен.

Различные варианты стратегии выкатки изменений

  1. В случае, если менялись только шаблоны или статика (картинки, JavaScript, CSS) и новые шаблоны совместимы со старым кодом — достаточно синхронизировать файлы на сервере. Нет нужды перезапускать web-сервер. Если изменения в шаблонах и статике некритичны / малозначительны — достаточно просто закоммитить их в репозиторий: кто-то выложит их вместе с очередным более важным обновлением.
    Резюме: при изменениях статики и совместимых изменениях шаблонов достаточно выполнить команду make sync либо вообще не делать деплоймент.
  2. В случае, если менялся код сайта, при этом изменения кода не завязаны на изменение шаблонов и схемы базы, а также изменения некритичны (их необязательно выкладывать как можно скорее) — достаточно просто обновить файлы на сервере: перезапускать скрипты сайта необязательно. Либо достаточно просто закоммитить изменения и вообще не выкатывать их самостоятельно. Тот, кто будет выкладывать другие, более важные изменения — заодно применит и Ваши.
    Резюме: при некритических и совместимых изменениях кода достаточно выполнить команду make sync либо вообще не делать деплоймент.
  3. Если выкладываются критические изменения (важные багфиксы) в коде, либо изменения кода завязаны на изменения шаблонов / схемы базы (т. е. новые версии шаблонов / кода несовместимы с предыдущими версиями кода / шаблонов / базы) — изменения выкладываются на сервер сразу же. При этом, если необходимо изменение схемы базы, синхронно с коммитом или выкладкой кода производятся изменения в схеме базы.
    Резюме: выкатка критических или несовместимых изменений производится как можно скорее (make sync-fo, make sync-qp и т. п.) и под контролем и ответственностью сотрудника, закоммитившего изменения.

Работа над задачами, записанными в mantis

  1. Если задача ещё не записана в Mantis — запишите её ;)

    Если задача, над которой Вы работаете / намереваетесь работать не тривиальна (критерий тривиальности — если Вы можете выполнить задачу ПРЯМО СЕЙЧАС, «не отходя от кассы») и задача отсутствует в Mantis — внесите её туда.

    Создав соответствующий тикет, Вы обеспечиваете следующие преимущества:

    1. гарантируете, что задача не будет забыта Вами;
    2. даёте понять сотруднику, поручившему Вам задание, что задача не забыта и держится Вами под контролем;
    3. другие сотрудники могут отписывать свои соображения относительно данной задачи ещё до того, как Вы за неё приметесь; возможно задача будет значительно видоизменена или даже отменена.
  2. Назначьте себя ответственным

    Если задача, за которую Вы берётесь, не назначена Вам — назначьте себя ответственным — статус задачи сменится на «назначен».

  3. По мере прогресса — отписывайте комментарии

    Если задача, над которой Вы работаете, достаточно объёмна и выполнение её состоит из нескольких этапов — отписывайте комментарии по мере прогресса. Например: «реализован пункт (1), прошу проверить» «сегодня боролся с функций X, пока безуспешно». Даже если Вы за весь день ничего не закоммитили по данной задаче, но работали над ней, можно написать чего удалось добиться / указать степень прогресса.

    Rationale:

  4. Расставляйте приоритеты

    Если у Вас накопилось много назначенных Вам задач, имеет смысл расставить им приоритеты. Если Вы затрудняетесь сделать это самостоятельно — попросите руководителя Вам подсказать: что более Важно, а что менее.

  5. Поставьте отметку о выполнении ;)

    После успешного выполнения задачи не забудьте сменить статус на «отработан». Если же Вы не уверены, что сделали всё правильно, попросите инициатора тикета поставить отметку о выполнении после проверки задачи.

    Про отличие статусов «ОТРАБОТАН» и «ЗАКРЫТ»

    Для успешно решённых тикетов (т. е. если Вы реально произвели действия и это решило проблему / задачу) устанавливается в статус «ОТРАБОТАН».
    Если багрепорт не подтвердился / задача отменена / уже решена в другом тикете и прочие ситуации, когда действия по решению проблемы не производились или не привели к результату — в этом случае устанавливается статус «ЗАКРЫТ».

    Т. е. ставим статус «ОТРАБОТАН» если вы решили проблему и статус «ЗАКРЫТ» — если действия не производились / задача неактуальна.

    Также при закрытии / отработке тикетов не забывайте корректно заполнить поле «Решение»: «решен» / «не удается воспроизвести» / «нерешаем» / «дубль» / «действия не нужны» / «решению не подлежит».

  6. При необходимости приложите к тикету патч

    Если код, связанный с решеним задачи требует согласования / если Вы не уверены в его корректности — приложите к тикету соответствующий патч и напишите комментарий с просьбой просмотреть патч.

    Требования к патчам:
  7. Как правильно создавать тикеты

    Тикет должен быть сформулирован максимально точно, конкрётно и детально. И идеале — так, чтобы человек, которому его назначают и который «не в теме» понял бы что ему надо делать без дополнительных пояснений.

    Не забывайте указывать адекватные значения для полей «Воспроизводимость» и «Серьезность». Для нововведений указывайте следующие значения: Серьезность: «нововведение», Воспроизводимость: «неприменима».

Создание новых модулей ядра

К коду ядра (модули SRS/*.pm) предъявляются повышенные требования, по сравнению с кодом других компонентов системы. В частности, модули ядра должны быть лучше документированы и быть обязательно покрыты тестами.

  1. Согласуйте создание нового модуля

    Создание нового модуля — серьёзный шаг. Который лучше всего обсудить с ведущим разработчиком проекта. Возможно создание данного модуля противоречит идеологии системы или данный функционал уже реализован где-то в другом месте.

  2. Убедитесь, что соблюдены требования к оформлению модуля

    Постарайтесь соблюсти требования к оформлению модулей. В частности, не забудьте установить комментарий в начале нового модуля, раскрывающий назначение оного. Также не забудьте на автомате включить use Modern::Perl;, который пришёл у нас на смену старым use strict; use warnings; ;)

  3. Добавьте тесты для модуля

    Создайте файл с тестами для нового модуля в каталоге t/. В соответствующем файле должен быть как минимум один тест:

    use Test::More;
    
    use_ok("<modulename>");
    

    Однако, желательно создать тесты для КАЖДОЙ функции / метода в модуле.

  4. use Perl::Critic

    Прогоните модуль через Perl::Critic:

    perlcritic --stern --profile /www/srs/lib/perlcritic.profile
    

    Это позволит отловить недочёты, которые Вы могли не заметить.

  5. А не вынести ли модуль в CPAN?

    Если модуль (группа модулей), который Вы разрабатываете, решает достаточно общую задачу, не привязанную жёстко к нашему проекту, возможно, имеет смысл задуматься о том, чтобы оформить это в виде дистрибутива CPAN. В этом случае код модулей размещается в репозитории «oss».

Стратегия работы с системой управления версиями

  1. Одна фича — один коммит

    Лучше не объединять несколько разных фич (или несколько разных багфиксов) в одном коммите. Сделал что-то одно — протестировал — закоммитил.

    Не нужно бояться, что изменений для одного коммита «слишком мало». Коммит может содержать исправление и 1-й буквы, в этом нет ничего страшного.

    Если патчи достаточно малы — проще будет делать откат или ревизию (анализ) произведённых Вами изменений.

    Если Вы «заработались» и у Вас накопилось несколько логически не связанных изменений, их можно закоммитить выборочно:

    git add <filenames>
    git commit -m "message"
        

  2. Все скрипты должны иметь установленный exec-флаг
  3. Чаще заливать свои изменения и получать апдейты

    Чем быстрее вы выкладываете изменения (git push), тем быстрее их можно проконтролировать / обкатать в работе, выявить ошибки. Ускоряется обратная связь и, как следствие, разработка в целом.

    Чем чаще вы получаете изменения (git pull), тем меньше вероятность нарваться на конфликт и тем согласованнее будут работа над кодом.

    Короткие частые итерации и «непрерывная интеграция» — одни из основополагающих принципов экстремального программирования, а экстремального программирования — это тот стиль работы, которому автор этих строк стремиться следовать в данном проекте.

  4. Комментарии — по-русски

    Старайтесь писать в меру подробные комментарии на русском языке. Если коммит связан с отработкой тикета, то, в принципе, достаточно указать номер соответствующего тикета в начале описания коммита в системе контроля версий.

Правка чужих CPAN-модулей

Если заметили в чужом CPAN-модуле ошибку — естественно, нужно о ней сообщить разработчикам. Напишите автору и/или создайте тикет в CPAN RT.

Что делать если ошибка ещё не исправлена, желаемое Вами нововведение ещё не реализовано либо разработчики принципиально отказываются его реализовывать? Ниже приведён набор вариантов освортированных по возрастанию их сложности и тяжеловесности.

  1. Локальная правка файла на отдельной машине.

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

  2. Перекрытие функций.

    Если разработчики забили на модуль и / или не хотят принципиально что-то править либо не откликаются — сделать локальный хак: перекрыть эту функцию в собственном коде:

    *MODULENAME::subname = sub { YOURCODE };
    
  3. Локальный форк модуля.

    Если изменения не вносятся разработчиками и изменений достаточно много, при этом модуль для нас очень важен — сделать форк. Форк можно сделать не меняя имя модуля, включив этот модуль в главный репозиторий проекта (в каталог lib/)

  4. Полный форк дистрибутива.

    Если изменений очень много и/или они вносятя более чем в один файл — можно сделать полноценный форк — создать дистрибутив с другим именем, поменяв при этом имя модуля. В этом случае дистрибутив форка включается в репозиторий OSS.

Правка модулей в репозитории OSS

Если правите модуль / дистрибутив, лежащий в репозитории OSS, пожалуйста, придерживайтесь следующих правил.

  1. При создании новых модулей — оформляйте их как стандартные CPAN-дистрибутивы.

    И не важно — собираетесь ли Вы выкладывать модуль на CPAN «прямо сейчас» или «когда-то в будущем». Следование CPAN-стандартам автоматически повышает качество на несколько пунктов ;)

  2. Перед коммитом вносите запись в change log.

    Ведите журнал произведённых изменений в файле Changes. Если этого файла нет — создайте его.

  3. Не забывайте инкрементировать номер версии модулей.

    Если Вы закончили правки — не забывайте поправить номер версии в .pm-файлах. Также перед нужно не забывать держать в актуальном состоянии файл META.yml. Самый простой способ сделать это — выполнить ./Build dist.

  4. Не набудьте выложить свежую версию модуля на CPAN

    Либо пините человека, имеющего соответствующие права.

Создание новых API-функций

Перед созданием любых новых API-функций обязательно посоветоваться с ведущим разработчиком системы. Представьте свои предложения по новой функции, описав концепцию и назначение, предполагаемое название, входные и выходные параметры функции.

Практики XP

Практика показывает, что мы в REG.RU, оказывается, УЖЕ применяем (интуитивно / полу-осознанно) большинство практик экстремального программирования.

Также согласно «классическим текстам», наш проект идеально попадает в «сферу комфортного применения» XP и обладает всеми свойствами, позволяющими применять эти практики наиболее эффективно.

В связи с этими отрадными фактами мне видится целесообразным глубже изучить принципы и практики экстремального программирования «как они есть» с тем чтобы начать их применение более осознанно и системно и, как следствие, добиваясь большего синергетического эффекта и большей «пользы делу».

В данном разделе описаны классические практики экстремального программирования и их преломление в свете проекта REG.RU. Основные 12 практик XP разделены на 4 группы.

  1. Короткий цикл обратной связи (Fine scale feedback)
  2. Непрерывный, а не пакетный процесс
  3. Понимание, разделяемое всеми
  4. Социальная защищенность программиста

Буду рад услышать любые замечания и дополнения по данному документу. Пишите на адрес: despair /at/ cpan {dot} org.

При перепечатке и цитировании документа на других сайтах — ссылка на оригинал обязательна.

Постоянный адрес этой страницы в интернете: http://www.reg.ru/software-process.

Автор документа: Walery Studennikov <despair [at] cpan {dot} org>
© ООО «Регистратор доменных имён РЕГ.РУ»