[Из песочницы] Управление конфигурацией в программном проекте

Сначала все было просто. Молодость, задор. Проект пилили несколько программистов. Все кодили, по мере готовности копировали код на общую виртуалку, изредка попинывали админа на предмет доставить какой-нибудь пакет или поправить конфиг. Как только понимали, что все, шли делать релиз. Сначала backup, потом старшой собирал всю свою крутизну в кулак, копировал проект на production сервер и, при содействии админа, добивался, чтобы оно там заработало. Команда выжидала два дня, убеждалась, что очереди из благодарных пользователей с топориками не образовалось, и, с чувством гордости за выполненную работу, шла пить пиво.

Потом все чуть-чуть повзрослели. Появились и начали как-то использоваться redmine/jira/etc, git/svn, jenkins, spinx-docs/rubydoc/doxygen/etc, wiki, unit тесты. Появились подпроекты, стенд подрос. Production сервачков стало несколько. Админ поднял salt/puppet/etc, мониторинг, сидит в своем логове как паук, правит конфиги на salt-master и дергает оттуда state.highstate.

Жизнь


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

Стадий жизненного цикла всего семь.

  1. Conceptual design. На этом этапе надо понять, что вообще надо делать.
  2. Architectural design. На этом этапе надо понять как это нужно делать.
  3. Implementation. Это непостредсвтенно кодинг и unit тестирование.
  4. Verification. Проверка того, что все задуманные функции программа выполняет.
  5. Validation. Проверка того, что программой таки можно пользоваться. Из предыдущего пункта это внезапно не следует.
  6. Ввод в эксплуатацию. В нее обычно входят выкатка релиза, миграция данных, обучение пользователей.
  7. Собственно сама эксплуатация.
  8. Вывод из эксплуатации


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

Это базовая схема, принятая в системной инжинерии. В зависимости от масштаба, специфики отрасли и религиозных убеждений ПМа, стадии могут переименовываться, склеиваться или наоборот дробиться, но соотнести вменяемый процесс с этой схемой можно всегда. Если в команде принят agile, то схема описывает жизненный цикл отдельной истории.

К чему это все. В таком разрезе, управление конфигурацией есть процесс поддержания изделия в целостном состоянии. Он начинается где-то в районе завершения первой стадии и заканчивается только со смертью проекта. Причем, если этим процессом пренебрегать, смерть может быть скоропостижной.

Что может сломаться?


Версии библиотек. Собрались, набросали диаграмку классов, договорились использовать libcrutch. Одна команда давно и долго сидела на libcrutch-1.0, вторая о ней только узнала и скачала из Интернета libcrutch-2.0. А выясниться это только на интеграционном тестировании. Словить bug можно даже на отличиях libcrutch-1.2.14 и libcrutch-1.2.15. А всякие LD_PRELOAD или docker только подливают масла в огонь. Даже если проект весь из себя на микросервисах, в интерфейсы может быть венесен обмен данными, полученными из libcrutch и имеющими в разных версиях разный формат.

Несоответствие версий компонент. Одни пилят libbase, другие libManagementFacade. В процессе выяснилось, что в libbase-1.14.3 есть мелкий, но коварный bug. Поговорили, поправили, забыли. Тестировались на libbase-1.14.4, а в релиз ушло libbase-1.14.3.

Изменение конфигурации окружения. Один POST запрос внезапно начал работать долго. Посмотрели, он не такой уж и важный, пусть себе поработает.Увеличили в nginx таймаут ожидания ответа backend’а. Админ на стенде поправил и забыл. Выкатились и опять старые баги ловить, но теперь уже в боевых условиях.

Изменение проектных решений. Начинали делать под Windows, потом прониклись идеями RMS’а, решили перейти на Ubuntu, но до всех решение не довели. Начали собирать, все принесли deb пакеты, а кто-то, кто был в танке, exe’шник.

Потеря значимого для пользователя функционала. Принесли новую версию, долго рассказывали про смену дизайна, про новые фреймворки, про передовые алгоритмы. Пользователи послушали, головой покивали, и сказали: «Это все хорошо, но вы для нас по нашей просьбе формочку делали. Раньше она была пятым подпунктом в третьем пункте меню, где она теперь?» Потеряли на каком-то merge request’е.

Что делать


Программистам очень повезло, что есть git. Основной удар он берет на себя и от них самих требуется совсем чуть-чуть.

  1. Индифицировать все компоненты, которые нужны для функционирования проекта, убедиться, что они корректно версионируются. Конфигурация в первом приближении это список компонент и их версий.
  2. Понять как обеспечивается перенос конфигурации со стенда в production.
  3. Начать управление требованиями. Вообще говоря, управление требованиями это отдельный процесс. В рамках управления конфигурацией нужно убедиться, что для каждого компонента, попавшего в релизный набор, прилагается документация, в которой точно описаны требования, предъявленные к этому компоненту, и их cтатуcы: выполнено, не выполнено, выполнено частично, с оговорками.
  4. Да и вообще у каждого компонента должна быть документация, которая описывает что как и зачем он делает.


На этапе завершения conceptual design’а, когда специалисты предметники говорят: «Такая система нам нужна!», — технари в один голос заявляют «Сделаем!», — менеджеры дают отмажку: «Ресурсы выделим — делайте!», — нужно убедиться, что согласованное описание системы из головы экспертов вынуто, на требования порезано и в документацию положено. В процессе разработки это описание будет меняться. Надо убедиться, что описание версионируется. Неплохой вариант, если это текст, забрать его в git

На этапе architectural design, когда архитектор сказал, как он это видит, нужно убедиться, что это видение из его головы вынуто, в документацию положено, бирка с версией наклеена. Если это тетрадный лист с диаграмкой, его нужно отсканить, положить в файломойку (или wiki) и сделать на него ссылку.

На этапе разработки нужно убедиться, что код документируется. Неплохо на модули заводить отдельные документы (в git), которые описывают требования к ним и их особенности поведения. Оставлять много информации в redmine/jira не стоит. После допила большой фичи, перед merge’ом в master, нужно убедиться, что ее описание из task tracker’а корректно перенесено в документацию. Просто потому, что через некоторое время в рамках другой задачи поведение может поменяться и собирать документацию по нескольким задачам будет сложно. Task tracker целостную картину не обеспечивает.

Пользовательскую документацию хорошо делать на этапе разработки. Держать (если можно) в git и править параллельно с кодом. Если на это нет специальных технических писателей, контекст уйдет, все забудут, документации точно не будет.

При верификации проверяется соответствие программы выдвинутым требованиям. В конце нужно убедиться, что всем требованиям присвоен статус выполнен/не выполнен.

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

На этапе ввода в эксплуатацию проверяется корректность подготовки и накатывания релиза. Надо убедиться, что в него подшиты все компоненты правильных версий. Основной удар здесь держит salt/puppet. Можно и без них, просто выпустив инструкцию по установке, но с ними проще. Готовить их надо правильно и загодя.

Про этап эксплуатации все понятно. Надо просто следовать инструкциям производителя.

На этапе вывода из эксплуатации надо убедиться, что все нужные данные вынуты.

Про сборку и salt/puppet. Это вторая линия обороны (сразу после git’а) Рабочая схема применения примерно такая:

  1. Нужно убедиться, что все сторонние пакеты индифицированны: откуда взято, какая версия, какие патчи накладывались. Если какая-то редиска (нехороший человек) приклеивает одинаковые версии на физически разные файлики, его надо убедить, что он не прав, или на всю его продукцию наклеивать дополнительную версию.
  2. Если все rpm’ки скидываются в один репозиторий, нужно убедиться, что понятно, какая именно версия будет накатана. Неплохой вариант — иметь скрипт пересборки всего репозитория и наклеивать версию на весь репозиторий целиком. Другой — версию указывать явно в манифесте/sls-файле. Кстати, у puppet’а есть bug, ресурс package не умеет версию понижать. Почему им не стыдно, я не знаю.
  3. Все манифесты/sls файлы храняться в git. В pillar для salt или параметры классов для puppet выносится только то, что отличает стенд от продакшена. Такими вещами, например, являются ulr’ы web сервисов, параметры наподобии shared_buffers для postgres, флаги, включающие debug режим. Все остальное безжаластно hard’кодится. Параметры задаются один раз при развертывании стенда и в дальнейшем меняются редко. sls файлы воспринимаются как код, он накатывается на стенд, тестируется и в неизменном виде переносится в production.


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

© Habrahabr.ru