Программирование (управление исходным кодом, CI)

Весь код компании должен храниться в системе контроля версий. Лучше всего для этой цели подходит Git. Вам следует изучить эту систему, для чего можно воспользоваться книгой Pro Git.

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

Требования к исходному коду

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

Не пытайтесь заранее предусмотреть все варианты развития событий и написать универсальные требования к исходному коду. Вы можете дописывать их по мере возникновения непредвиденных ситуаций.

Мы использовали следующие правила написания кода:

  • наличие комментариев;
  • понятные имена объектов;
  • стандарт оформления имён объектов (зависит от языка программирования - camelCase, UpperCase и т.д.);
  • короткие функции, решающие одну задачу;
  • вынос констант из методов;
  • подход “один класс в одном файле”;
  • отсутствие дублирующего кода;
  • эффективность алгоритма (по времени и ресурсам);
  • визуальное удобство (наличие отступов, пробелов, пустых строк).

Можно также коллекционировать примеры неудачного кода (“как делать не надо”) и выставлять их на всеобщее обозрение.

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

Требования к именованию сборок

Сборки (если они у вас есть) должны иметь иерархические имена и начинаться с названии компании (по аналогии со сборками компании Microsoft - например, “Microsoft.Office.Interop.Excel”).

Структура папок должна отражать иерархию имени сборки.

Названия сборок должны ясно отражать их функционал.

Требования к пользовательскому интерфейсу

Некоторые базовые советы по проектированию интерфейсов:

  • не использовать модальные окна без надобности;
  • при выполнении долгой операции показывать пользователю прогрессбар, причём именно в той области, что ожидает выполнения операции;
  • стараться придерживаться интерфейса одного окна, без всплывающих дополнительных окон;
  • стараться спроектировать адаптивную вёрстку, единую для мобильный устройств и десктопов. Это сэкономит вам усилия на поддержку.

Билд-сервер

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

Разработчики не должны предоставлять куда-либо код со своих машин; весь код должен поставляться исключительно с билд-сервера, который и становится доверенным источником вашего ПО.

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

Модель ветвления

В основе модели лежит классическая модель, описанная здесь.

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

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

Предлагается использовать следующие ветви для разработки.

Ветвь

Порождается из

Обновляется из

Способ обновления

master

Создаётся изначально

release/develop

Merge

hotfix

Pull Request

develop

master

bugfix-, feature-

Pull Request

release

Merge

release

develop

bugfix-, feature-

Pull Request

hotfix

release/master

-

Commit

bugfix-, feature-

develop/release/bugfix-, feature-

-

Commit

Ветвь master - это ветвь ваших выпущенных релизов. Она содержит всегда стабильные версии вашего продукта. Все изменения “одобрены” автоматическим и ручным тестированием, Code Review и (возможно) вашим руководством. Если вам требуется срочно что-то исправить в выпущенном релизе, вы создаёте ветку hotfix из master-ветви, вносите и проверяете изменения и сливаете результат обратно в master (обычно при этом меняя третий номер в версии продукта). Таким образом, вы избегаете ситуации, когда у вас в команде находится разобранная версия продукта, а вам срочно нужно что-то исправить. Это значительно уменьшит вашу головную боль.

Ветвь develop - это ветвь текущей версии, находящейся в разработке. Она содержит изменения, проверенные автоматическим и ручным тестированием и Code Review. Изменения в эту ветвь попадают только через Pull Request, напрямую туда писать нельзя. Если функционал одобрен, но не планируется к включению в будущую версию, он остаётся висеть в Pending-состоянии до выпуска или до создания release-ветви.

Такой подход защищает вас от случайного попадания в релиз изменений, связанных с какими-то сторонними улучшениями (не слишком значимыми или незапланированными). Бывает, что кто-то из разработчиков внезапно хочет произвести рефакторинг прямо перед релизом, и это ломает продукт. Вы начинаете бегать, суетиться - вам надо выпускаться, в код находится в нерабочем состоянии. Закрытая на запись ветвь develop гарантирует вам стабильность и управляемость текущей разработки.

Ветвь release - необязательная ветвь готовящегося релиза. Как уже было сказано выше, вы можете выпускаться из develop-ветви, придерживая перспективные коммиты. Но можно и создать ветвь release из develop, впустив в последнюю ожидающие коммиты. Это удобно, если ваш коллектив может одновременно работать над двумя версиями продукта.

Если в develop коммитятся исправления ошибок, эти изменения можно слить в release (ведь мы гарантировали стабильность develop’а).

Перед выпуском релиза тестировщики проводят финальное тестирование выпускающей ветви (develop/release). Найденные ошибки исправляются в дополнительных ветвях (bugfix-).

После выпуска выпускающая ветвь сливается в master. Если используется release-ветвь, она сливается и в develop. Release-ветвь ещё существует некоторое время после релиза, а потом удаляется.

Ветвь hotfix служит для внеплановых доработок ветви release (если та используется и ещё не удалена) или master (в противном случае). Она порождается от указанной ветви, в неё вносятся коммиты срочных исправлений, затем прогоняются автоматические тесты. После чего через Pull Request и Code Review ветвь сливается с исходной, проходит ручное тестирование и производится новый релиз. Затем ветвь hotfix удаляется.

Ветви feature- и bugfix- создаются для работ над новым функционалом и ошибками соответственно. Таких ветвей будет много: в идеале на каждую задачу из системы багтрекинга порождается отдельная ветвь, в название которой включается идентификатор задачи (например, “bugfix-PROJ-666”). Ветви порождаются из develop (при обычном режиме разработки), из release (только ветви исправления ошибок для правки исключительно ошибок релиза) или из других подобных им ветвей (если нужно использовать функциональность, которая уже реализована, но не слита с develop-ветвью).

Содержимое этих ветвей проверено автоматическими тестами и (не полностью) ручными тестами.

Независимость ветвей-задач друг от друга позволяет проводить их чистое тестирование, без наведённых ошибок. Параллельно сразу видно, сколько новых ошибок привносит то или иное изменение. Разумеется, ошибки сочетания двух доработок никто не отменял, но они будут выявлены на тестировании релизной ветви.

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

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

  • master - для ветви master
  • develop - для ветви develop
  • feature - для ветвей feature-, bugfix- и hotfix (все ветви выбираются в один билд по шаблону имени). Запускается автоматически при коммите
  • release - для ветви release (при её использовании)

Тесты запускаются на билдах автоматически. Непрохождение тестов означает непрохождение билда.

Работа с указанной моделью ветвления проходит следующим образом.

  1. Руководитель разработки, начальник отдела тестирования и менеджер проекта определяют список фич, которые войдут в новую версию продукта. Если вы используете JIRA, то проставляете в ней номер версии для выбранных задач и багов.
  2. Программист при переходе к следующим задаче/багу создаёт из ветви develop новую ветвь разработки и называет её соответствующим образом (“feature-<ID>”/”bugfix-<ID>”).
  3. Программист выполняет требуемые изменения и коммитит свой результат на сервер.
  4. На сервере автоматически запускается билд, прогоняются тесты. При необходимости программист исправляет ошибки.
  5. По прохождении билда программист создаёт Pull Request из своей ветви в ветвь develop. Для Pull Request’а автоматически или вручную (им самим или руководителем - как зададите) назначаются ревьюеры.
  6. Ревьюеры верифицируют код (Code Review). В случае непрохождения Code Review программист возвращается к шагу 3.
  7. Руководитель разработки производит merge верифицированных Pull Request’ов, но лишь тех из них, что запланированы к включению в будущую версию продукта.
  8. Ветвь develop постепенно наполняется изменениями. Периодически запускается её билд, а также выполняется ручное тестирование. В случае нахождения ошибок в системе багтрекинга создаются новые баги, связанные с будущей версией.
  9. Когда ветвь develop наполнена до конца, возможны два варианта развития событий.

Вариант без использования ветви release:

  1. Ветвь develop считается выпускающей. Выполняется её тестирование и исправление ошибок.
  2. Когда все ошибки исправлены, никакие изменения в ветвь develop больше не вносятся.
  3. После выпуска ветвь develop сливается в master. Все Pull Request’ы, связанные со следующей версией продукта, сливаются в develop.
  4. При обнаружении внеплановых ошибок от ветви master порождается ветвь hotfix. Изменения тестируются, а затем через Pull Request попадают в master и  в develop. Из содержимого ветви master производится ещё один релиз.

Вариант с использованием ветви release:

  1. Из ветви develop порождается ветвь release, она считается выпускающей. Выполняется её тестирование и исправление ошибок. Pull Request’ы ошибок направляются в release. Все Pull Request’ы, связанные со следующей версией продукта, сливаются в develop.
  2. После выпуска release сливается в develop и master.
  3. При обнаружении внеплановых ошибок: если ветвь release ещё не удалили, то производится исправление ошибок в ней (опять же через дополнительную bugfix- ветвь), изменения сливаются в develop и master. Если ветви release уже нет, процедура аналогична предыдущему варианту.

Pull Request’ы и Code Review

Pull Request’ы - нечасто практикуемая в коммерческой разработке технология, но её использование крайне полезно. Программист, выполнив изменения в отдельной ветви (и осуществив там автоматическое и, при необходимости, ручное тестирование), создаёт Pull Request. Это запрос на слияние изменения из рабочей ветвь в основную ветвь.

Запрос должен быть одобрен одним или несколькими программистами, называемыми ревьюерами. Этот процесс называется Code Review. Ревьюером в команде может быть один человек. Ревьюер может быть закреплён за конкретным программистом (при этом получается циклическая цепочка программистов, контролирующих код друг друг; или пары взаиморевьюеров). Ревьюер может быть назначен на продукт. Наконец, автор изменений может самостоятельно выбирать ревьюера из списка свободных программистов, но эта практика ведёт к снижению контроля над разработкой.

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

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

Как только замечания у ревьюера заканчиваются, Pull Request переходит в статус approved. Через некоторое время руководитель разработки вливает одобренные изменения в основную ветвь.

За счёт использования такого подхода мы получаем изолированную работу над отдельными фичами приложения, стабильность основной ветви и дополнительный контроль за качеством исходного кода. Любые временнЫе и ресурсные затраты на Code Review окупятся на стадии сопровождения.

JIRA и Stash содержат встроенные средства для организации описанного механизма работы. В JIRA можно породить ветвь для отдельной задачи. В Stash можно создать Pull Request по завершению работы над задачами. Там же можно проводить ревью кода, общаться с помощью системы комментариев, привязывая комментарии к отдельным строкам кода. Также в Stash производится одобрение кода и его слияние в ветвь разработки.

Если при выполнении слияния возникнут конфликты, их придётся разрешать на локальной машине.

Переход к модели ветвления

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

  • текущую ветвь называем develop, создаём ветвь master. Master закрываем на запись;
  • создаём билды master, develop и feature. На билде feature настраиваем автозапуск по коммиту;
  • настраиваем производственный процесс (Workflow в JIRA) для поддержки Code Review;
  • отлаживаем процесс при помощи тестовых задач;
  • проводим демонстрацию программистам новой модели разработки;
  • вводим в строй новую модель и Code Review, закрываем develop на запись.
Далее