Внедрение инженерных практик для повышения качества разработки продукта
15.09.21, Ср, 10:00, Мск,
Низкое качество разработки бьет по репутации IT-компании, но последствий гораздо больше. Например, моральное состояние коллектива ухудшается. Из-за допущенных на этапе первоначального production ошибок ситуация с патчами и обновлениями становится неконтролируемой. Технический долг (подробнее об этом ниже) отнимает все больше времени. Как повысить качество? Прежде всего, надо понимать, что это проблема инженеров лишь отчасти.
Инженерные практики и системы менеджмента качества в IT
Качество разработки IT-решений для заказчика является комплексной проблемой менеджмента в бизнесе. Международные организации давно выработали при участии инженеров, разработчиков и руководителей крупных компаний ряд стандартов, обобщающих опыт тех, кто уже добился стабильного и постоянно повышающегося (continual improvement) качества разработки:
- ISO/IEC 9126 (ГОСТ Р ИСО 9126-93). Стандарт предназначен для внедрения бизнес-процесса «управления качеством программного обеспечения» (software quality management – SQM);
- ISO 9001 (ГОСТ Р ИСО 9001). Это норматив с требованиями к созданию системы менеджмента качества (СМК), позиционирующийся, как фундаментальное решение для любой отрасли и любого типа компании;
- PMBOK и PRINCE2. Стандарты, которые подходят к проблеме качества разработки под углом проекта компании, а не процессов компании в целом;
- Agile. Эта философия организации совместной разработки, которая не нацелена на качество выпускаемого ПО напрямую, однако многие ее элементы способны положительно сказаться на этом KPI. Например, согласование работ на каждом этапе реализации проекта;
- COBIT. Еще один нормативный документ, в котором можно узнать, как другие успешно решали проблемы управление качеством в IT;
- Waterfall. Модель управления качеством в процессе разработки, основанная на циклах постоянно повторяющихся действий: анализ требований, проектирование, реализация, тестирование, интеграция, поддержка;
- Scrum. Свод правил и принципов, выполняя которые можно повысить качество, скорость разработки. Ключевыми понятиями Scrum являются принципы прозрачности, инспекции и адаптации;
- Nexus. Развитие идей Scrum, существующие в форме отдельных спецификаций. Позволяет масштабировать применение уже известных по Scrum best practices. Здесь можно ответить на вопрос как и в каком объеме эти правила надо применять, если отдел разработки насчитывает сотни человек.
В отличие от книг по вопросу качества в IT, эти стандарты, по сути, становятся «нотариально заверенным» консенсусом отраслей и групп экспертов о том, что такое качество программного обеспечения. Мало кто знает, что есть процедуры международных организаций, таких, как ISO (Международная организация по стандартизации), которые позволяют актуализировать документы и через временные промежутки удостоверять: являются ли те или иные практики по-прежнему общепринятыми и дающими результат.
Таким образом, любая методология из перечисленных, – больше, чем просто учебник или программный документ. По многим из спецификаций даже можно сертифицировать свою IT-компанию или ее бизнес-процессы. Так можно сообщить клиентам, что вы работаете по Scrum или ISO 9126. Независимая, третья сторона проводит у вас аудит и подтверждает официальным документам, что вы действительно соответствуете указанным практикам. Вам выдается сертификат, который вы используете в рекламе услуг разработки. Благодаря тому, что некоторые из документов по тем или иным методологиям переводятся и принимаются в России в качестве ГОСТов, с их содержанием совершенно бесплатно можно познакомиться на сайте ФАТРиМ (Федеральное агентство по техническому регулированию и метрологии).
Что касается инженерных практик как таковых, то их множество. Все они были выработаны для двух основных целей:
- Скорость получения продукта и результата клиентами, пресловутый time-to-market.
- удовлетворенность клиента качеством продукта.
Инженерные практики и качество разработки
Раздел 8.5 стандарта ISO 9001 называется «Производство продукции и оказание услуг». В любом стандарте повышения качества IT-продукции наступает время инженерных практик, которые позволяют сделать результат «менее подверженным вариациям».
Так менеджеры и директора по качеству называют предсказуемый, стабильный результат работы. Перечислим наиболее востребованные практики, позволяющие «встроить» качество в свои процессы и процедуры.
1. Код. Версионирование, читаемость и «чистота»
Читаемость считается основным и наиболее популярным критерием качества разработки. Нужно добиться, чтобы разработчики могли легко и быстро понимать код друг-друга и заливать в рабочую версию проекта только качественно написанный код. От этого зависит многое.
Плохо отформатированный, с плохим неймингом и запутанной логикой код ведет к багам, нестабильной работе приложений. Наконец, вам приходится то и дело переписывать сегменты кода, которые тормозят всю команду при реализации новых проектов.
Некоторые примеры хороших практик в этой области:
- использование контроля версий кода (git);
- доступ к коду для всех членов команды, чтобы любой сотрудник в рамках своей компетенции мог в любой момент внести изменения в информационную систему (GitHub, GitLab, Bitbucket);
- единый code style. Члены команды придерживаются стандартов и рекомендаций, принятых для используемого в проекте стека, языка программирования. Для контроля соблюдения данной практики другие члены команды проводят code review вносимых изменений.
Примеры плохих практик:
- нет единого стиля кода. Каждый член команды пишет код в том стиле, к которому он привык, что усложняет и увеличивает срок проведения code review;
- отдельные куски кода и реализации правятся только одним членом команды, что создает потенциальную точку отказа в случае увольнения или болезни сотрудника, который является «башней знаний» на данном участке;
- отсутствие контроля версий. Каждый член команды разработки использует локальный backup кода и вынужден договариваться, чтобы не перезаписать изменения других разработчиков.
2. Часто проводите рефакторинг
Процессом рефакторинга в IT называется модификация и перестройка уже написанной программы. Обычно тем же разработчиком, который ее писал. Цель – сделать код еще более читаемым, эргономичным и эффективным. Например, можно поменять название метода или то, каким способом он вызывается.
В этом случае, возможно, удастся добиться, чтобы без больших изменений другой специалист мог быстро понять, что происходит в коде, если ему это необходимо для написания своего собственного. Рефакторинг позволяет преобразовывать legacy-код под меняющиеся требования к разработке, обеспечивает всей системе гибкость. Совершенствует навыки разработчика (является ответом на экзистенциальный вопрос «Как стать мидлом?», с которым носится большинство джунов). Новые модули будет гораздо проще создавать, и вся система в целом сохранит свою устойчивость.
Лучше, чтобы рефакторинг был запланирован и имел конкретные цели.
Например, вы можете заложить ресурс на его проведение раз в квартал, полгода или через n количество спринтов (скажем, каждые 8 спринтов). Также необходимо сформулировать цель преобразований, иначе можно увлечься изменениями, которые приведут к необратимым последствиям и деградации приложения.
Главное проводить refactoring постепенно, небольшими итерациями: легкие правки -> тест, небольшое изменение -> тест и так далее. При таком подходе рефакторинг пройдет быстро и без неблагоприятных последствий для проекта.
3. Сократите «технический долг»
Технический долг используется в разработке ПО для того, чтобы охарактеризовать время, которое команда постоянно затрачивает из-за накопленных в кодовой базе ошибок (багов), неэффективного кода, а также нехватки документации по написанным программам. Техдолг обычно становится результатом погони за скоростью создания программ или доработок в ущерб качеству кода.
Если проблема стала хронической, то становится бичом команд разработки. Пример: состоявшаяся не так давно публичная перепалка нового владельца Twitter (X) Илона Маска с разработчиком мобильного приложения Эриком Фронхофером. Илон Маск спрашивал о причинах того, что оно работает медленно, а разработчик ссылался на технический долг и ряд других проблем. В результате полемики в соцсети Фронхофер был уволен.
Накопленные в приложении неверные или неэффективные решения полезно рассматривать в качестве растущего долга. Это формирует менталитет качества, когда менеджмент не торопит разработчиков, а программисты избегают «костыльных» решений. Накопление технического долга приводит к тому, что в итоге все ваше время может уходить на «тушение пожаров», а новые заказы будут выполняться с черепашьей скоростью.
Важно! Выделяйте квоту на работу с техдолгом в рамках каждого спринта/месяца/квартала/недели, в зависимости от циклов вашей разработки. Хорошим соотношением будет закладывать 20% времени от общего количества ресурсов.
4. Реализация на практике существующих паттернов качественной разработки
В этом пункте можно вспомнить KISS, YAGNI, DRY и SOLID. Хотя паттернов качества кода гораздо больше, остановимся подробно хотя бы на этих:
- KISS (Keep It Simple, Stupid): обычно разработчики поначалу выбирают более сложные способы решить ту или иную задачу, чем это необходимо. Если можно придумать, как выполнить работу с меньшим количеством кода, то нужно это сделать. Если есть выбор между простым и эффективным решением и интересным, то сделайте просто;
- YAGNI (You Aren’t Gonna Need It): разработчики тяготеют писать обобщенный код, не учитывающий потенциальных будущих требований, которые к нему могут возникнуть. Часто – это не лучший вариант;
- DRY (Don't repeat yourself): при написании неумелого кода неизбежно возникает дублирование. Избегайте повторов и нескольких операций, которые на самом деле можно выполнить одной. Это буквально стоит денег, так как увеличивает время и затраты на поддержку кода;
- SOLID: под одной аббревиатурой скрывается ряд положений, применяя которые в работе инженер может избежать плохой архитектуры программы. Особенно активно SOLID используется в объектно-ориентированном коде. Одним из принципов, которые объединяются в SOLID является принцип единственной ответственности: один класс – одна какая-либо работа в приложении.
5. Покрывайте Unit-тестами свой код
Это инженерная практика номер один, когда речь заходит о качестве создаваемого программного обеспечения. Существуют специальные фреймворки, например, PHP Unit в языке PHP, Cypress в JS, Postman (для тестирования запросами API, сервисов хуков на основе REST API). Будучи установлены в среду разработки, они позволяет запускать в тестовом окружении методы и классы вашего основного кода, проверяя, как они сработают на различные варианты обращений.
Можно проверить ту или иную функцию миллионом значений и выявить проблемы, которые не были очевидны при написании кода. При ручном, функциональном тестирования подобное не всегда возможно из-за сложности программы и регулярного цикла обновлений. Чтобы защитить себя от потери времени и фатальных проблем, нужно выйти на полное покрытие своего кода Unit-тестами. Небольшие группы разработчиков часто мирятся с внезапными багами и проблемами, так как Unit-тестирование требует написания отдельной, небольшой программы под каждый сегмент кода в «боевом» проекте.
6. Автоматизированный приемочный тест
Как минимум, приемочный тест является спецификацией о том, каким должен быть получившийся код на выходе. Ясность в этом вопросе вносится исходя из ожидаемого способа эксплуатации ПО. Применение спецификации можно «встроить» в продукт, избежав обычного пренебрежения правилами или проблем, связанных с забывчивостью сотрудников.
Устоявшейся практикой среди хороших команд является сотрудничество разработчиков и заказчика/аналитика в написании automated acceptance tests. Особенно в подготовке автотестов, которые описывают ожидаемый результат заказчиком. Получите пригодные для автоматизации формулировки теста. При использовании приемочных автотестов команда получает объективное понимание того, как должна вести себя информационная система или программа (реализуемая отдельная функциональность).
При использовании современных библиотек тестирования (в виде пакетов для Linux, например), настройка регулярных автотестов, которые запускаются автоматически и через нужные промежутки времени, оказывается банальной и простой задачей. Единственная проблема заключается в написании тестов и в решении вопроса о том, что именно и как проверять.
7. Тестирование производительности
Перед сдачей готового программного обеспечения клиентам лучше проводить также тестирование производительности. Оно нацелено уже не на соответствие требованиям клиента или требованиям к качеству кода, а на то, что будут выполняться некоторые требования к регулярной эксплуатации ПО. Например, в течение некоторого времени проверяется скорость загрузки в тех или иных заданных условиях. Нагрузочное тестирование позволяет выявить слабые места при увеличении нагрузки на информационную систему.
Суть в том, чтобы смоделировать ситуацию, которая может произойти с вашим продуктом при его эксплуатации, например:
- резкий и непредсказуемый рост пользователей;
- большое количество однотипных запросов на одну услугу;
- наплыв новых пользователей для регистрации после, например дорогой и эффективной рекламы от команды маркетинга.
Конечно, если на стадии MVP вы искусственно ограничиваете нагрузку на продукт (тестовая группа пользователей, запуск одной услуги, отсутствие рекламы), можно пренебречь нагрузочным тестированием, так как потребуется потратить ресурс на его создание, а также на инфраструктуру, которая будет соответствовать вашему ПРОД контуру, чтобы тестирование оказалось релевантно.
Однако если стадия MVP была успешно пройдена, и вы начинаете привлекать массового пользователя, то лучше потратить время на нагрузочное тестирование, например в рамках упоминаемого в статье технического долга. Также стоит периодически повторять такой вид тестирования (2 раза в год или пропорционально ожиданиям пользовательского роста).
8. TDD – производство ПО с постоянным тестированием
Это общая концепция, которая вбирает в себя многое из того, о чем уже сказано выше. Она состоит в том, что нужно покрыть тестами весь свой код, основываясь на обратной связи от заказчиков и пользователей. В идеале, согласно этому методу разработчик сначала пишет тест с ожидаемым результатом, а уже затем, соответствующий сегмент «боевого кода». Во многих организациях предпочитают не писать тесты, так как это отнимает очень много времени. С другой стороны, время, которое уйдет на исправление ошибок – их могло бы не быть – без тестов окажется еще большим. Вывод: команды разработчиков, которые применяют весь потенциал тестирования, выигрывают в конкурентной борьбе.
9. Непрерывная интеграция, непрерывный деплой (CI/CD)
Практика первоначально возникла в Agile, концепция которого предполагает согласовывать маленькие изменения в создаваемом программном продукте с клиентом, чтобы отправляемые на переделку заказчиком улучшения не были чересчур объемными и не приводили к существенному замедлению проекта. CI/CD предполагает, что изменения «на бой» (в проект, а не в тестовую среду) заливает каждый разработчик и делает это часто, минимум, 2-3 раза в день. Это подход, противоположный традиционному, когда деплой (заливку нового кода на рабочий сервер) производит один, специальный программист. Подобная практика делает изменения средой и стихией, в которой постоянно работает команда. Особое внимание в методологии уделяется тому, чтобы каждый умел в случае возникновения проблем быстро с ними справится (банальный пример: использовать git commit –amend), если «боевой» сервер развернут в Gitlab.
10. Архитектура программного обеспечения. Микросервисы
Микросервис представляет собой отдельный маленький блок-проект, который можно при определенных условиях соединять с остальными в единое целое. Проекты, основанные на микросервисах, мобильны, их можно быстро переписывать, а ошибки легко локализуются и не распространяются на стальное приложение, так как происходящее в одном микросервисе влияет только на него и не создает последствий для других. Микросервисы связаны друг с другом только в одной точке, а размещены иногда на разных портах или даже серверах.
При использовании микросервисной архитектуры вы получите несомненное преимущество в виде доступности, отказоустойчивости, производительности и масштабируемости.
Если один из компонентов выходит из строя, то в большинстве случаев для клиента будет недоступна какая-то из услуг, а не полная деградация сервиса при использовании в монолитной архитектуре.
Модульность микросервисов позволит быстро и легко добавлять новые функции в эксплуатируемую информационную систему.
Производительность же достигается за счет разделения выполнения различных операций между несколькими сервисами/адаптерами/инструментами.
11. Монолитная архитектура
Микросервисы – лучший вариант не для любого проекта. Иногда выстраивать архитектуру на микросервисах сразу будет слишком сложно, поэтому специалисты рекомендуют сначала создать монолитный проект, разделив логические элементы приложения просто на отдельные модули, а затем выделить эти модули в микросервисы.
На старте проекта подобная архитектура позволяет быстрее и дешевле запустить рабочее решение, например для проверки гипотезы или сбора первой обратной связи от пользователей по продукту.
12. Логирование и мониторинг
Стоит обязательно подумать и позаботиться о полноте информации о работе кода, которая собирается в вашем окружении. Внедрение инструментов мониторинга и логирования позволяет определить узкие места в работе программ. Существует системный и бизнес-мониторинг. Бизнес-мониторинг настроен на поведение ваших клиентов и помогает улучшить взаимодействие с пользователем. В то время как системный мониторинг позволяет увидеть полноту работы вашей информационной системы в различные периоды времени и, возможно, предотвратить аварийные ситуации.
Наличие же доступных логов для всей команды, а также их историчность, сильно упростит и ускорит диагностику возникающих дефектов.
14. Документирование
Никогда не забывайте про документирование вашей информационной системы. Сотрудники приходят и уходят, а в современной среде это случается довольно часто. Best practices для того, чтобы организация не теряла свои знания, объединены в одну из технологий научного менеджмента – «управление знаниями».
Здесь лишь скажем, что если вы не хотите тратить время при найме новых сотрудников на долгое обучение или при попытке вспомнить причины той или иной реализации – всегда ведите документацию своих проектов. Дизайн-макеты, бизнес-функциональности и требования, системные требования, описание инфраструктуры серверов и сервисов, руководства пользователей и администраторов системы. Проще всегда постепенно создавать и актуализировать документацию, чем впоследствии попытаться всё описать за один раз. Хорошей практикой является создание и актуализация документации перед каждым релизом.
Автор: Артур Шеремет, software разработчик с опытом создания и запуска FinTech-проектов с нуля