В Scrum не говорится об инженерных практиках разработки ПО. Но Scrum подразумевает, что, когда команда начнет работать гибко, вскоре она поймет, что хорошие инженерные практики необходимы для того, чтобы стать высокопроизводительной и эффективной Scrum-командой. Инженерные практики — это магия, сила. Я не пытаюсь определить все технические приемы, которые вам необходимо внедрить в свои проекты Scrum. Для этого есть другие книги, например, Кент Бек: Экстремальное программирование: разработка через тестирование. Я пытаюсь донести, почему вам нужны инженерные практики и как они могут помочь командам разработчиков преодолеть некоторые типичные препятствия.

Инженерные практики разработки ПО

5 инженерных практик для Scrum

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

  • Разработка через тестирование (Test-driven development)
  • Рефакторинг (Design improvement, Refactoring)
  • Непрерывная интеграция (Continuous integration)
  • Парное программирование (Pair programming)
  • Автоматизация интеграционного и приемочного тестирования (Automated integration and acceptance tests)

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

Разработка через тестирование (TDD)

Вопреки тому, что подразумевает название, разработка через тестирование не является процессом тестирования. Это метод проектирования программного обеспечения, когда код разрабатывается в короткие циклы. Вы можете представить процесс TDD как светофор (красный, зеленый, рефакторинг). Первым шагом является написание нового модульного теста без написания кода, необходимого для его прохождения. Очевидно, что при запуске этого теста он не пройдёт. Это красное состояние. Следующим шагом является написание кода, достаточного для прохождения модульного теста или зеленое состояние. Если тест проходит успешно, то написанный код работает правильно. Последний шаг, который необходимо делать несколько раз — это рефакторинг. Вовремя рефакторинга код изменяется, но модульные тесты всегда должны проходить успешно. Затем процесс разработки через тестирование начинается снова с самого начала. Написание новых тестов и нового кода, пока пользовательская история не будет завершена.

Процесс TDD – лучший выбор для достижения целей спринта при высокой скорости.

Реализуя TDD, вы будете менее сопротивляться внедрению изменений, которые требуются ключевым заинтересованным сторонам или клиентам, даже в конце проекта. Без TDD такие изменения считаются слишком рискованными, потому что команда не может предсказать последствия изменения, и нет времени для тестирования всех возможных побочных эффектов. При наличии защиты в виде разработки через тестирование риск существенно уменьшается, поэтому команды будут уверены, что они смогут внести необходимые изменения, независимо от стадии проекта. Хорошая практика контроля версий также помогает повысить уверенность. Если рефакторинг проходит неудачно или ломает слишком много тестов, вы можете легко откатиться к исходной точке.

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

Рефакторинг

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

Симптомы

Проблема

Комментарии Существует разница между комментариями, которые разъясняют и запутывают. Подумайте, необходимо ли здесь комментировать код? Вы объясняете почему, а не что? Можно ли сделать рефакторинг, чтобы можно было убрать комментарий? Помните, вы пишите комментарии для людей, а не для машины.
Длинный метод Чем короче метод, тем его легче прочитать, понять и отладить. Сделайте рефакторинг длинного метода в короткие, если это возможно.
Противоречивое название Установите стандарты в терминологии в ваших методах.

Помните, что рефакторинг кода не означает переписывание. Вместо этого, рефакторинг — это оптимизация кода без изменения намерения кода. У Роберта Мартина есть набор принципов с аббревиатурой SOLID, в котором он рассказывает о первых пяти принципах проектирования классов.

  • S: Single Responsibility Principle (Принцип единственной ответственности).
  • O: Open-Closed Principle (Принцип открытости-закрытости).
  • L: Liskov Substitution Principle (Принцип подстановки Барбары Лисков).
  • I: Interface Segregation Principle (Принцип разделения интерфейса).
  • D: Dependency Inversion Principle (Принцип инверсии зависимостей).

Зачем вам делать рефакторинг? Проще говоря, это инвестиции в ваш код. Аналогия может быть уборкой по 5 мнут каждый день, чтобы сохранить ваш дом в чистоте. Рефакторинг подобен уборке после себя немного каждый день – иногда вы будете убираться больше, иногда меньше, но важно то, что вы убираетесь регулярно и не ждете, пока мусор и грязь накопиться.

Непрерывная интеграция

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

Непрерывная интеграция позволяет нам иметь более быстрые циклы обратной связи по коду. Вместо того, чтобы проверять тысячу или более строк одновременно, каждый человек или пара могут проверять около ста строк кода одновременно. Они также создают локальную сборку перед внесением изменений в более крупную ветку. Как локальные сборки, так и основная сборка должны быть полностью автоматизированы, что означает, что лицо, отправляющее код, может «щелкнуть и забыть», в то время как машина выполняет набор автоматических приемочных и модульных тестов. Эти сборки также могут запускать проверки статического анализа, проверять желаемое покрытие модульных тестов и т. д. Как только код запущен и в ветви, сервер непрерывной интеграции вытягивает все в ветку и запускает больший набор тестов. Поскольку регистрация небольшая, обратная связь короткая. Поэтому гораздо проще увидеть, что сломало сборку и почему.

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

Замечательная книга по теме непрерывной интеграции – «Непрерывная интеграция. Улучшение качества программного обеспечения и снижение риска”, Гловер Эндрю, Матиас Стивен , Дюваль Поль М.

Парное программирование

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

Парное программирование стимулирует коллективное владение кодом и увеличивает обмен знаниями между членами команды.

Пары укрепляют стандарты кодирования команды о том, как построить систему.

Важно понимать, что практика парного программирования не обязательно означает, что работа занимает вдвое больше времени. В университете Юты Лори Уильямс обнаружил, что парное программирование было на 15 процентов медленнее, чем у двух независимых разработчиков, но привело к появлению на 15 процентов меньше ошибок. Этот вывод еще раз подчеркивает, что команды, делающие инвестиции в более дисциплинированные инженерные методы, поначалу идут немного медленнее, но имеют более высокую окупаемость в будущем благодаря уменьшенному риску, лучшей видимости и более низкому уровню дефектов.

Еще одним преимуществом парного программирования является снижение шума. Слово шум означает телефонные звонки, электронная почта, мгновенные сообщения, ненужные встреч и другие отвлекающие факторы. Было бы грубо работать с кем-то над проектом и проверять свою электронную почту или звонить по телефону, верно? Когда вы работаете совместно, вы сосредотачиваетесь на том, над чем работаете с другим человеком, просто потому, что это хорошие манеры.

Есть несколько замечательных статей и книг по парному программированию. Начните со старой книги Лори Уильямс и Роберта Кесслера «Pair Programming Illuminated». Другой хороший пример – «Искусство гибкой разработки» Джеймса Шора.

Автоматизация интеграционного и приемочного тестирования

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

Пирамида автоматизированного тестирования

Приемочные тесты предназначены для эмуляции поведения пользователя. Если вы строите систему с пользовательским интерфейсом, эти тесты будут записаны в сценарии, чтобы прокликать и имитировать поведение пользователя.

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

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

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

Сравнение затраченного времени на ручное и автоматизированное тестирование