Чек-лист хороших инженерных практик в компаниях
Разработка программного обеспечения — нетривиальный процесс, который имеет тенденцию значительно усложняться с ростом количества участников. Больше людей в команде — больше коммуникаций и необходимости синхронизироваться (обмениваться знаниями о частях системы и происходящих процессах, следить за бизнесом и его требованиями). Растет цена ошибки, система перестает умещаться в голове одного разработчика, изменения в одном месте влияют на изменения в других местах.
В этих условиях разные команды проявляют себя по-разному. Некоторые продолжают поддерживать высокий темп разработки и регулярно выпускают новые версии. В других командах происходит сильное замедление процессов: переговоры отнимают больше времени, чем разработка, качество падает, выпуск новой версии становится стрессом и приключением. Общая скорость внедрения новых фич в таких командах может различаться во много раз и даже на порядок.
Причин такой катастрофической разницы довольно много. Вот некоторые из них:
- Ошибки топ-менеджмента в бизнесе. Если бизнес делает не то, что надо, то не важно насколько эффективно он делает это — в конце концов бизнес закроется. Эта тема выходит за рамки текущего гайда.
- Ошибки топ-менеджмента в области процессов. Если на этом уровне все плохо, то все остальное вторично. Даже неверная система бонусов может привести к разладу в команде и полной блокировке разработки в конечном счете.
- Человеческий фактор. Личные качества и человеческие пороки могут создать проблемы как остальным членам команды, так и всему проекту в целом. Главная проблема в том, что эту часть невозможно выправить никакими процессами. Только изменение поведения. Либо расставание.
- Плохой процесс разработки. Эта тема касается всех инженеров без исключения. Сюда входит все, начиная от взаимодействия и работы с задачами, заканчивая тестированием и проведением ревью кода.
На некоторые проблемы повлиять либо сложно, либо невозможно (с уровня разработчика). Но другие, особенно относящиеся к инженерным практикам, нужно постоянно улучшать и менять. Программисты должны принимать в этом самое активное участие.
- Книги
- Человеческий фактор. Успешные проекты и команды
- Мифический человеко-месяц, или Как создаются программные системы
- Идеальный программист. Как стать профессионалом разработки ПО
- Цель. Процесс непрерывного совершенствования
- Manifesto for Agile Software Development
- Bus Factor
- Карго культ
И хотя практик довольно много, в конечном итоге все сводится к тому, как быстро клиенты получают результат вашей работы и насколько они им удовлетворены. Ниже приводится чек-лист, который позволяет понять, используются ли в команде те инженерные практики, которые считаются наиболее удачными.
Соответствие этим практикам не гарантирует того, что в компании нет проблем. Возможно это культ-карго, либо процессы формализованы настолько, что больше мешают, чем помогают. С другой стороны из каждого правила есть исключения и всегда найдется проект, где что-то из списка ниже не применимо. Ну и наконец, некоторые из указанных подходов могут идти вразрез с чьими-то ценностями.
Код
Хорошо
- VCS. Код находится под контролем версий (как правило гит).
- Общий код. Любой член команды в любой момент времени может изменить любую часть системы.
- Единый стиль кода. В команде все придерживаются стандартов кодирования, принятых для данного стека (языка, платформы).
Плохо
- Отсутствие единого стиля. Каждый пишет код в том стиле, к которому он привык. Нет общих стандартов либо есть, но свой, совершенно отдельный от общепринятого.
- Не используется контроль версий. Вместо этого используются бекапы кода, а разработчикам приходится договариваться, чтобы не перетереть изменения друг друга.
- Код имеет "владельца". Программисты защищают свой участок кода от посягательства других участников.
Ссылки
Среда разработки
Хорошо
- Девелопмент среда. Разработка ведется в специальной development (dev) среде. Как правило, это локальная машина (возможно, с использованием Vagrant или Docker Compose). Эта среда у каждого разработчика полностью своя, и изменения в одной среде не могут влиять на другие среды разработки.
- Разворачивание среды автоматизировано и происходит "одной кнопкой". Это позволяет легко вводить в проект новичков, быстро и в автоматическом режиме распространять инфраструктурные изменения, работать без страха что-либо поломать, так как легко восстановить.
- Инфраструктура как код. Распространение изменений конфигурации происходит через код проекта. Достаточно еще раз выполнить развертывание дев среды (с новым кодом проекта), как подхватятся все обновления.
- Среда разработки максимально приближена к условиям продакшена. Если сервис работает на Linux, то и разработка ведется на Linux. То же самое касается и других аспектов.
Плохо
- Разворачивание среды и настройка происходит по мануалам, либо методом "попробовал запустить — прочитал сообщение об ошибке — погуглил — исправил". Дорого и неэффективно. Мануалы устаревают практически сразу после того, как их пишут. Новый человек может тратить дни на разворачивание среды с нуля.
- Ручное обновление конфигурации. Всем разработчикам рассылается директива произвести локальные изменения настройки среды (например, доставить что-нибудь новое) для работы нового кода.
- Общая база данных для всех разработчиков. Нагрузка от одного человека влияет на всех. Случайная поломка также тормозит всех остальных.
Качество
Хорошо
- Кодовая база покрыта тестами. Тесты повышают уверенность в работоспособности кода. Хорошие тесты положительно влияют на дизайн самого кода. Как правило, код, покрытый тестами, сам по себе лучше кода без тестов. Хотя есть корреляция.
- Частично протестированная фича или вовсе — фича без тестов — не считается выполненной. Наличие тестов значительно снижает нагрузку на всех остальных членов команды и положительно влияет на качество решения задачи. К тому же часто происходит, что если тесты не написать сразу, то потом на них времени не останется.
- Программист отвечает за фичу до самого конца. Фича считается выполненной, только когда она работает на продакшене. Каждый человек в команде должен понимать, что наиважнейшая цель — это доставка ценности клиенту. Пока фичей никто не пользуется, то не важно, написана она или нет, потому что бизнес в этот момент остается в пролете.
- Команда ревьювит код друг друга (без фанатизма). Ревью — не только способ найти ошибки, но и способ учиться друг у друга.
- Парное программирование. Техника эффективна не только между программистами. Она очень полезна в парах "программист и тестировщик", "новичок и опытный".
- Continuous integration (CI). Репозитории проекта подключены к серверу непрерывной интеграции, на котором после каждого коммита проверяется стиль кодирования (через запуск линтеров), прогоняются тесты, осуществляется сборка проекта (например, компиляция).
- В случае инцидентов проводятся пост мортемы.
- Ретроспектива. Процесс непрерывно улучшается и на изменения влияет каждый член команды.
Плохо
- Нет тестов. Работа нового кода проверяется только ручным способом, через прокликивание. Последствия катастрофические — скорость доставки низкая, а качество кода, скорее всего, неудовлетворительное.
- Отсутствует код ревью. Разный стиль кодирования, изоляция программистов друг от друга, слабый обмен опытом, плохие решения в продакшене.
- Программист считает, что фича закрыта, когда код попал в основную ветку. Новый код лежит мертвым грузом и не приносит пользы. Может устареть до попадания клиенту.
- KPI. Активно используются количественные метрики: строки кода, выпущенные фичи, закрытые баги. Вместо ориентации на результат, разработчики стремятся выполнить KPI. Даже в случае, если это идет вразрез с задачами бизнеса.
- Высокий уровень формализации процессов. Замедляется скорость, падает мотивация.
Ссылки
- Экстремальное программирование
- Парное программирование (доклад Николая Рыжикова)
- Как распространять инженерную культуру в своей компании
Процесс разработки
Хорошо
-
Разработчики руководствуются принципами 12factors. Приложения проще разворачивать, масштабировать и мониторить.
-
Запуск одного теста выполняется за доли секунды. Разработка через тесты подразумевает очень частый запуск тестов в процессе отладки. В такой ситуации крайне важна скорость старта конкретного теста — она должна быть настолько быстрой, чтобы разработчик оставался в контексте.
-
Тесты писать легко и приятно. Лакмусовая бумажка для определения того, насколько хорошо с тестами в проекте. Если приходится себя заставлять, то есть вероятность, что тесты написаны плохо (например, много моков) и их будет недостаточно.
-
Test-driven development (TDD). По возможности тесты пишутся до кода. Есть несколько причин, по которым это важно:
Тесты заставляют думать не о реализации, а о том, как тестируемый код будет использоваться. Благодаря такому подходу, программисты видят изъяны в интерфейсах на самых ранних стадиях.
Код в любом случае надо проверять. Если теста не будет, то это придется делать руками.
-
Перед починкой бага сначала пишется тест, который его воспроизводит, затем происходит исправление. Только в этом случае тесты действительно помогают.
Плохо
- Тесты есть, но приходится заставлять себя писать тесты, потому что их сложно писать, они долго выполняются, часто ломаются или постоянно приходится их переписывать.
- Запуск одного теста занимает секунды. Такой тест тяжело запускать при разработке через тесты и общее время выполнения тестов становится слишком большим.
- Код правится прямо на продакшене (то место где он работает). Без комментариев.
Ссылки
Выкатка новых версий (более актуально для веб-проектов)
Продакшен-среда — инфраструктура (например, сервера), в которой развернут проект. Она обеспечивает доступ к проекту конечным пользователям.
Деплой (выкатка) — процесс, в рамках которого происходит обновление проекта в продакшен среде.
Хорошо
- Автоматизация. Развертывание автоматизировано и выполняется одной кнопкой.
- Частые небольшие релизы. Развертывание — рядовое событие, которое может выполняться в любой момент по готовности фич, без необходимости отвлекать команду.
- Zero Downtime Deploy. Обновление версии происходит прозрачно для пользователей.
- Развертывание, технически (то есть все хорошо автоматизировано), может выполнить любой член команды.
Плохо
- Выкладка происходит в ручном режиме. Например, через прямое управление с сервера. Самый ненадежный и не масштабируемый подход, подвержен ошибкам и может занимать значительное время. При наличии нескольких серверов просто не работает.
- Выкладка кода сопровождается эмоциональным напряжением и вовлечением большого числа участников. В такой атмосфере все стремятся выкатываться реже, что приводит к еще большим проблемам и напрямую вредит бизнесу.
- Процесс развертывания длится десятки минут или часы. Скорее всего, это означает, что процесс сборки проекта интегрирован с самим деплоем. Эти задачи нужно выполнять независимо.
- Разворачивание происходит раз в неделю и реже. Чем больше изменений выкатывается сразу, тем выше шанс поломки. И тем сложнее отследить влияние каждой фичи на бизнес-показатели. Кроме того, происходит забывание тех изменений, которые были сделаны ранее и ждали своего часа до выхода в продакшен.
- Во время разворачивания наблюдаются длительные даунтаймы. Пользователи вынуждены ожидать завершения деплоя. Такая ситуация мешает деплоить часто.
- Развертывание выполняет один специальный человек. Знания хранятся в одной голове. Уход в отпуск или болезнь ломает весь процесс. Остальные программисты не понимают "как оно работает там".
- Деплой конфигурации. Обновление конфигурации, не относящейся непосредственно к логике кода, требует повторного деплоя. Например, изменение пароля к базе данных или адреса базы. Эти параметры являются чисто инфраструктурными и должны попадать в код так, как описано в 12factors.
Ссылки