Эффективная совместная работа backend и frontend команд

teamwork

В WB-Tech мы любим разрабатывать проекты полного цикла, начиная от прототипов на салфетке и заканчивая деплоем на продакшн сервер и дальнейшей поддержкой. Часть этапов разработки проекта идет последовательно, например, до тех пор пока не будут собраны все требования и готово ТЗ, мы не начинаем писать код. Основная же часть процесса работы над проектом (непосредственно разработка) ведется параллельно backend и frontend командами. Такое распараллеливание значительно уменьшает календарный срок разработки проекта и увеличивает качество конечного результата. Но также как в программировании, в управления проектами распараллеливание создает определенные трудности. Тому как мы решаем эти трудности и посвящен этот пост.

Пост можно разделить на 2 части: список инструментов и как мы их используем, подходы к разработке.

Инструменты

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

Vagrant

Поддерживать рабочее окружение крайне важная задача. Чем больше различий между рабочим окружением и продакшеном тем больше потенциальных багов из-за несовместимостей. Также, наверняка каждый опытный разработчик сталкивался с раздражающим типом багов «а на моей машине работает». Если backend разработчики обычно могут поддерживать рабочее окружение в актуальном состоянии, то для фронтендеров это более сложная задача, что естественно, т. к. это далеко от их профиля. Чтобы решить эту задачу раз и навсегда и предоставить всем разработчикам идентичное рабочее окружение и к тому же ускорить переключение между проектами и добавление к проекту новых разработчиков, мы используем Vagrant.

При правильной настройке Vagrant позволяет — получить рабочее окружение в одну команду `vagrant up`, а используемый для настройки (provision) скрипт можно и нужно использовать для настройки production/staging/testing серверов. Vagrant поддерживает большое количество, т.н. provisioners, мы для себя выбрали Ansible, полученные скрипты для настройки сервера (playbook) используем при настройке всех окружений проекта с минимальными изменениями.

GitHub

Рассказывать зачем нужно использовать VCS (система управления версиями) я не буду — про это уже много писали. Расскажу как мы используем Git и GitHub для решения проблем возникающих при распараллеливании разработки. Мы используем технику GitHub Flow, каждая фича разрабатывается в отдельной ветке, затем создается Pull Request, который проходит code-review, автоматическое тестирование, ручное тестирование и после этого сливается в master, откуда уже попадает на сервер.

На самом деле все немного сложнее, рассмотрим разработку сферической фичи в вакууме (назовем ее фича1). Сначала мы разрабатываем backend код фичи1 по ТЗ в отдельном бранче `feature1`. После того, как разработчик решил что все готово и код можно проверять он пишет документацию по интеграции с фронтендом (API методы, формат входящих исходящих данных и обработка ошибок) и открывает Pull Request. После устранения недочетов и ошибок (без этого никак) бекенд версия считается стабильной и передается фронтенд команде (путем перевешивания задачи в BaseCamp), которая в этом же бранче дорабатывает фичу1 согласно спецификации полученной от бекенд команды. После этого PR проходит повторную проверку и после этого сливается в master и соответственно на продакшн.

Внимательный читатель может спросить, «а где же обещанное распараллеливание?». Чтобы ответить на этот вопрос я нарисовал небольшую картинку:

project flow

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

Подходы к разработке web-проектов

Hard way (REST Api, SPA)

В сложных проектах, с большим количеством серверной логики и объемной предметной областью мы применяем подход основанный на разработке SPA и REST Api. Суть подхода в том, чтобы клиентская часть приложения (frontend) и серверная часть (backend) взаимодействовали через строго определенное Api. Такое разделение позволяет максимально распараллелить разработку и уменьшить зависимости между клиентским и серверным слоями.

На серверной стороне разрабатывается REST Api, бегло рассмотрим этот вопрос. API состоит из набора URI обслуживающих, т.н. ресурсы (они же сущности предметной области). Для каждого ресурса реализовывается определенный набор операций, в зависимости от того какие операции нужны клиенту. Кроме обычных CRUD (create/read/update/delete), могут быть реализованы также другие специфические операции, если того требует предметная область или если это существенно упрощает/ускоряет работу клиентского слоя. Данные при в запросах на сервер передаются или в GET параметрах или в теле запроса. Сервер же возвращает результат обработки запроса в http статус коде и подробный ответ в виде JSON документа в теле ответа. В итоге для работы с полученным API фронтенд разработчику нужно знать следующую информацию про каждое действие над ресурсом:

Описание Пример
URI /users
HTTP метод POST
Что делает создает нового пользователя
Входящие данные email и password в теле запроса
Пример ответа статус 200 и тело ответа {«status»: ok}
Обработка ошибок статус 400 и тело ответа {«email»: «Указанный email уже зарегистрирован в системе»}

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

Используя известные характеристики Api, frontend команда может достаточно просто эмулировать работу бекенда (например, fake backend для Angular.js) и работать не дожидаясь готового Api, а для подключения настоящего Api потребуется совсем не много времени.

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

Simple way (static site)

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

При таком подходе совместная работа происходит очень просто. Выделяются части страниц, которые должны заполняться данными из админки, в отдельные подключаемые шаблоны, эти шаблоны затем рендерятся при изменении данных в админке и результат сохраняется в определенном месте, где его ищет и подключает сборщик статического сайта. Таким сборщиком, например, может быть gulpjs, используя плагины которого можно также оптимизировать изображения, компилировать coffee/sass и т. д. В итоге для обновления верстки нужно только поменять шаблон и запустить сборщик статического сайта.

Заключение

Спасибо всем, кто дочитал до конца. Если у вас возникли какие-то вопросы или вы хотите обсудить способ применяемый в вашей компании — пишите здесь в комментариях или твиттер @dizballanze.