Уроки, извлеченные за более чем 10 лет оказания помощи инженерным командам в создании высококачественного программного обеспечения.
Качество кода - одна из самых обсуждаемых тем в разработке ПО, но при этом обеспечение качества - остается одной из самых трудновыполнимых задач.
Интуитивно понятно, что качество кода влияет на способность команды разработки выполнять поставки быстро и часто, одновременно оказывая косвенное влияние на качество обслуживания клиентов. Но как?
Исследование среди разработчиков показало, что за прошедший год выделяются два показателя:
- 66% разработчиков не удовлетворены текущим качеством своего кода.
- В среднем 45% времени разработки тратится на техподдержку.
Как можно добиться большего успеха?
Поговорим о таких вещах как:
- 🚗 Что такое качество кода и почему это важно — рассмотрим на примере автомобильной метафоры.
- 🥇 Привычки высокоэффективных команд — как поддерживать высокое качество кода.
- 🔄 Качество как системный характер — создание системы, предназначенной для обеспечения качества.
- 🔨 Использование инструмента для обеспечения качества — как инструменты могут поддержать ваш процесс.
- 📚 Книги и ресурсы — от наших любимых авторов, для более глубокого погружения.
- 🔨Инструменты для улучшения качества кода
Поехали!
🚗 Что такое качество кода
Мы говорим о качестве кода, а не о качестве продукта, потому что первое вполне может быть невидимым для конечного пользователя.
Говоря о каком-либо продукте, часто упоминается фраза "под капотом" — это отсылка к автомобильной метафоре.
В нашем контексте автомобиль - это полноценный продукт. Как и у цифровых продуктов, у автомобиля есть пользовательский интерфейс, то есть то, как водитель (пользователь) взаимодействует с ним и какие ощущения вызывает у него автомобиль.
Тогда, если мы продолжим метафору, программное обеспечение, вероятно, должно быть автомобильным двигателем.
Что делает двигатель высококачественным?
Некоторые вещи являются универсальными и важными для всех автомобилей, например, надёжность и простота обслуживания.
В то же время, другие характеристики зависят от назначения автомобиля. Например, спортивные автомобили должны быть быстрыми и мощными, а городские автомобили - экономичными и комфортными.
Этот пример хорошо соотносится с программным обеспечением.
Невозможно сделать код качественным по всем показателям, это зависит от того, что вы вкладываете в понятие качество. Брендан Малхолланд, соучредитель Recital, написал отличный пост в блоге на эту тему:
Когда кто-то говорит о качественном коде, он неявно ранжирует набор факторов [...]
Хорошее качество для стартапа означает приоритетность скорости; для NASA это означает стабильность и отсутствие ошибок. Это возвращает нас к размытости понятия уровня качества; в то время как многие факторы качества могут быть измерены полуобъективно, их ранжирование основывается на факторах, более тесно связанных с качеством на уровне бизнеса.
Компромиссы и ранжирование, которые явно (и неявно) стимулируются в данном контексте, являются ценностями этого контекста.
Есть еще одна область, где метафора автомобиля дает сбой: эволиционирование программного обеспечения.
Эволюция придает ремонтопригодности совершенно другое измерение: речь идет не только об устранении дефектов, но и о возможности изменять код для поддержки новой функциональности в будущем.
Исследования показывают, что существует высокая корреляция между компаниями, которые быстро и часто осуществляют поставки и теми, которые в конечном счете добиваются успеха. В этом отношении высококачественный код должен быть таким, который можно легко изменить.
Джоэл Чиппиндейл, технический директор высказался по этому поводу:
Код, который легко постоянно изменять - это код, над которым приятно работать. Это помогает нам чувствовать себя умнее и позволяет выполнять более ценную работу для организаций, в которых мы работаем.
Что делает код легким для изменения и приятным для работы? Давайте рассмотрим популярные признаки, которые обнаруживаются в самых результативных командах 👇
👓 Удобочитаемость
Как говорит Мартин Фаулер:
Любой дурак может написать код, понятный компьютеру. Хорошие программисты пишут код, понятный людям.
Хорошо читаемый код может быть легко понят любым членом команды независимо от того кто его написал, это важно для удобства поддержки. В здоровых командах удобочитаемость является результатом многих практик, таких как:
- Хорошее разделение обязанностей — позволяет упростить код.
- Важное значение имеют структуры папок, благодаря которым код становится доступным для обнаружения.
- Соглашения об именовании – помогают сделать код более понятным и читабельным, что в свою очередь упрощает его сопровождение и поддержку.
Удобочитаемость настолько тесно связана с ремонтопригодностью, что границы часто размыты. Эти два понятия должны идти рука об руку. Удобство сопровождения также связано с документацией, файлами readme, схемами развертывания, механизмами аварийного восстановления, моделированием баз данных и стратегиями отката для новых функций.
Включение в текст комментариев, улучшает его удобочитаемость👇
✏️ Написание хороших комментариев
Комментирование кода стало несколько противоречивой практикой, так как многие разработчики считают, что хороший код документирует сам себя.
Высокопродуктивные команды, как правило, сосредотачиваются на нужном количестве комментариев и их качестве, чтобы достичь максимальной ценности своей кодовой базы вместо того, чтобы надеяться на самодокументирование кода.
Вот подробнее об распространенных типах комментариев:
✅ Комментарии вверху файла/класса — несколько строк, описывающих основную цель файла, могут значительно помочь разработчикам. Это также помогает избежать расширения области видимости с течением времени и сохранить соответствие файла его первоначальной цели.
✅ Комментарии к сложным функциям — большинство функций должны быть достаточно простыми, чтобы быть понятными как есть. Но есть алгоритмы и процессы, которые не могут быть простыми и понятными, независимо от того, насколько хорошо вы их пишете. В этих случаях полезно включить описание входных данных, логики и выходных данных функции.
❌ Построчные комментарии - хотя объяснение работы сложной функции имеет смысл, необходимость комментировать отдельные строки кода чаще всего является недостатком кода. Если понятно, что делает функция, но не понятно, что делают некоторые из ее строк, то лучше переписать функцию, а не вставлять построчные комментарии.
Комментарии к коду также легче поддерживать в актуальном состоянии, чем документы, которые находятся в другом месте, поскольку вы можете обновлять их на месте всякий раз, когда вносите изменения в сам код.
Также, в PR (Pull Request) можно обнаружить, что какой-то код изменился, а комментарии - нет и сообщить об этом.
Тестирование 🔍
Хорошее автоматизированное тестирование повышает скорость внесения изменения, что в свою очередь ускорят процесс поставки. А благодаря более раннему обнаружению дефектов это также сокращает время, которое вы тратите на поддержку.
Все это способствует поддержанию высокого качества вашей кодовой базы.
Хорошее покрытие кода не обязательно означает создание безумного количества тестов. Интеграционные тесты - это способ проверить, как ваш код работает с другими частями приложения, используя несколько важных вариантов использования.
Некоторые исследования показывают, что при 70%-ти процентном покрытии кода автотестами, на 60% сокращается время поддержки.
🤝 Проверка кода + статический анализ
Ни для кого не секрет, что проверка кода повышает качество кода и помогает обмениваться знаниями в команде.
Лучшие команды умеют сочетать ручную проверку с работой инструментов статического анализа, автоматически проверяя новый код на соответствие набору лучших практик, чтобы предложить области для улучшения.
Хорошие инструменты могут значительно улучшить ваш процесс проверки. Они облегчают работу рецензента, выполняя по-настоящему тяжелую работу, например, выявляя ошибки, “кода с запашком”, уязвимости и заботясь о правилах стиля и форматирования.
🦠 Малый объем технического долга
Для многих команд техническая задолженность является фактором №1 препятствующим темпам их разработки.
Продуктивные команды хорошо осведомлены о состоянии своего техдолга и целенаправленно работают над его устранением. Они постоянно отслеживают задолженности, расставляют по ним приоритеты в сравнении с инициативами по продуктам или выделяют отдельные потоки работ над ними.
Они также поддерживают тесные связи с заинтересованными сторонами и могут выступать за крупные инициативы по рефакторингу, когда рентабельность инвестиций окажется подходящей.
🔄 Качество как системный характер
Высокое качество программного обеспечения является результатом хороших систем и процессов, а не индивидуальной производительности.
Команда среднестатистических разработчиков, работающих в системе, предназначенной для обеспечения качества, в конечном итоге добьется лучших результатов, чем группа потрясающих разработчиков, работающих с процессами, которые для этого не предназначены.
Как пишет Джейкоб Каплан-Мосс, хорошие системы формируют “заколдованный” круг:
- Отличные тесты помогают выявить ошибки до их превращения в проблемы. Однако, эти тесты не появляются волшебным образом, а требуют обдуманного подхода и времени на их создание.
- Такой подход включает в себя то, что инженеры:
- высказывают свое мнение по поводу кода;
- тратят дополнительное время на проведение правильных тестов;
- понимают, что ошибки в производстве рассматриваются как системные проблемы и отдельных лиц не будут обвинять, наказывать или стыдить.
- Сбои в программном обеспечении рассматриваются как системные, потому что большинство из них таковыми и являются. Это является следствием того, что методы тестирования настолько хороши, что отдельные ошибки выявляются задолго до того, как они становятся серьезными сбоями.
Круг замкнулся.
📚 Книги о качестве кода
Если вы хотите глубже погрузиться в качество кода, вот наши любимые книги об этом 👇
- 📕 Чистая архитектура — автор Роберт Мартин.
- 📗 Чистый код — автор Роберт Мартин.
- 📙 Прагматичный программист — Дэвид Томас и Эндрю Хант.
- 📘 Рефакторинг — автор Мартин Фаулер.
🔨 Инструменты для улучшения качества кода
SonarQube – это современный инструмент автоматической проверки кода. Он является одним из ключевых элементов решения Sonar и может быть интегрирован в существующий рабочий процесс. SonarQube анализирует код на более чем 30 языках программирования и может помочь в непрерывной проверке кода проектов. Он также интегрируется в конвейер непрерывной интеграции и DevOps для обеспечения соответствия кода высоким стандартам качества.
AccessLint - мощный инструмент для автоматизированного тестирования доступности веб-сайтов, который ускоряет рабочий процесс разработки. AccessLint анализирует внесенные изменения, новые замечания и проблемы с доступностью, которые могут возникнуть при выполнении запроса и предоставляет своевременную и быструю обратную связь для быстрого исправления проблем до запуска кода.
DeepScan - это усовершенствованный инструмент для статического анализа JavaScript, TypeScript и React, который также поддерживает Vue.js и может автоматически обнаруживать ошибки во время исполнения. Он предоставляет полезные данные о производительности команды и следит за качеством кода, помогая менеджерам получать конструктивную обратную связь.