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

Парное программирование – одна из самых недопонятых практик экстремального программирования. Думаю, название сыграло в этом не последнюю роль. Парное программирование, ну что тут непонятного? Сели вместе и давай писать код. Но почему тогда вокруг этой практики столько мифов и легенд? Почему не у всех и не всегда работает, если все так просто? А вдруг парное программирование – это не просто программирование в паре? Чтобы разобраться в вопросе мы обратимся к первоисточнику, научным исследованиям, личному опыту и опыту коллег.

Если код-ревью — это хорошо, значит, мы будем ревьюить код постоянно (парная разработка)

Кент Бек, Экстремальное программирование, 1999

Оглавление

Что такое парное программирование?

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

Парное программирование (pair programming) — методика, при которой весь разрабатываемый код пишется двумя программистами на одном компьютере.

В паре две роли, назовем их «Штурман» и «Водитель». В руках «Водителя» клавиатура, он пишет код и его мышление сфокусировано на том, как здесь и сейчас написать некоторый код лучшим способом. Мышление «Штурмана», – стратегическое. Он думает о том, является ли оптимальным код «Водителя» для решения в целом, размышляет об альтернативах и способах упростить систему.

On Pair Programming

Основной контраргумент

«Как это, два человека выполняют одну задачу?, – простонал эффективный менеджер, – по-отдельности они же могут сделать за то же самое время в два раза больше!». Только есть один нюанс – задачи не похожи друг на друга, мы не знаем наперед, как продукт будет развиваться, а вариантов решения одной и той же задачи у нас примерно сколько угодно. Одних только алгоритмов сортировки чисел более тридцати, а мы не просто числа сортируем, а, например, сортируем продукты по цене с учетом скидок, пейджингов, рейтингов и еще десятка параметров.

Вообще, этот аргумент мне приходилось слышать сотни раз. Самое интересное, что с этим аргументов не поспорить, он железобетонный, если… вы продаете или покупаете «ресурсы» и «часы» на проект, а не прирост бизнес-возможностей (тот самый инкремент) в продукте. Именно поэтому в компаниях, в которых оплата/контроль работы разработчиков идет по отработанным по конкретным фичам часам, контракты с вендорами заключены с учетом количества доступных часов разработчиков, работать в паре – это как выстрелить себе в ногу, урезать прибыль, причем если все всё время работают в парах (как и описано в книге у Кента Бека), то ровно в два раза.

Первая страница статьи не закончена, а мы уже видим, что ограничением для парного программирования может быть такая штука, как контрактные отношения с вендором или индивидуальные KPI менеджмента, направленные на утилизацию «ресурсов»(разработчиков) или система учета/контроля за временем работы каждого разработчика в отдельности с соответствующими методами планирования, когда емкость команды == (количество разработчиков)x(длина спринта)x(8 часов).

Если закопаться, то и ежегодный пересмотр зарплаты может стать препятствием к парному программированию, если «заслуги» людей рассматриваются сугубо по результатам индивидуальной работы. Здесь есть свои лайфхаки, но для этой статьи это оффтопик.

Выгоды от парного программирования

Какие выгоды обычно перечисляются, когда упоминается парное программирование? Например, касающиеся кода:

  • Повышение качества кода
  • Соблюдение/передача стиля кодирования
  • Передача знаний о коде и коллективное владение кодом

Не реже встречаются преимущества, касающиеся передачи знаний:

  • Обучение менее опытных коллег
  • Повышение скорости погружения в новый проект (нет тупнякам и бездумному скроллингу исходников)
  • Эффективное решение интеграционных задач на стыке систем или библиотек

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

Обратимся для начала к работе «The Costs and Benefits of Pair Programming» за авторством Alistair Cockburn и Laurie Williams. Рекомендую ознакомиться с работой, здесь же приведу лишь краткие выводы:

  • При парном программировании стоимость разработки, выраженная в часах, увеличивается на 15%, а не в два раза;
  • Код, разработанные в парах содержит в среднем на 15% меньше дефектов;
  • При парном программировании объем кода в среднем на 20% меньше.

Каждый баг – это оформление дефекта в багтрекинге, передача дефекта на исправление, переключение контекста разработчика, воспроизведение дефекта разработчиком, поиск дефекта в коде, исправление, мерж в нужную ветку и повторное тестирование. Но это только если дефект не пролез в прод. Иначе прибавим работу call-центров с недовольными клиентами, развертывание исправленной версии на проде, возможно – извинения перед клиентами, не исключено, что с подарками и скидками, коммуникация со СМИ. Ну и конечно, все перечисленное выше – это чистой воды потери (согласно Бережливому Производству), – могли сделать фичу, но потратили время на исправление бага.

А по поводу объема кода достаточно процитировать Роберта Мартина:

Соотношение времени чтения и написания кода превышает 10:1. Мы постоянно читаем свой старый код, поскольку это необходимо для написания нового кода.

Robert C. Martin (Uncle Bob), «Clean Code»

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

Остальные выгоды от парного программирования, перечисленные в статье, это:

  • Рост удовлетворенности от работы
  • Упрощение дизайна (Simple Design) (простой не равно примитивный)
  • Быстрее решаются «не решаемые» проблемы
  • Непрерывный код-ревью (меньше пропущенных дефектов)
  • Выстраивание коммуникаций в команде,  «дешевый» способ тимбилдинга
  • Кросс-обучение
  • Повышение bus factor

Из собственного опыта добавлю, что с помощью грамотно организованного парного программирования удавалось в разное время и в разных компаниях:

  • Сократить время на онбординг разработчиков в проект со сложной предметной областью в среднем с 2-3 месяцев до 1-3 недель. В этом проекте я выступал в роли архитектора и полностью выстраивал процесс разработки. Согласно процессу, один из старожил брал менторство над новичком и помогал ему адаптироваться и в коде и в архитектуре и в компании. Адаптация в компании тоже улучшилась. Когда этим занимались HR, они рассказывали как должно быть «по процессу» (что в целом, наверное, правильно). Ментор же делился житейской мудростью и полезными лайфхаками, например, как оформить овертаймы или записаться на корпоративный английский.
  • Сократить время разработки отменив обязательные Code Review. Code Review в этом проекте был такой штукой, на которую вечно не хватало времени и вместо того, чтобы насильно заставлять его проводить было предложено попробовать пару спринтов поработать в парах. Через полтора месяца в команде появилась общая договоренность: «разработчики сами решают, отправлять код на ревью или нет». Качество кода выросло (сильно упала цикломатическая сложность, например), время на ревью сократилось почти до нуля и теперь все понимали, что если кто-то отправил код на ревью, «значит это кому-нибудь нужно», а не просто по процессу и для галочки.
  • Повысить bus factor. В этом случае в пары объединялись разработчики разных компонентов, которым нужно было провести интеграцию между собой в рамках реализации общей фичи. Обычно такой способ парного программирования описывается как «запилить интеграцию в паре», но мы предложили в паре не только над интеграцией поработать, но разработать всё от начала и до конца. Интеграция заняла на порядок меньше времени, а знание особенностей тех с кем интегрируешься улучшило отношения и качество принимаемых решений. Как приятный бонус, оказалось, что «ТЗ на интеграцию» не так уж и нужны…
  • Сократить WIP. Это эффект второго порядка и происходит органически, так как в моменте в работе оказывается меньшее количество задач. И если само парное программирование сокращает время работы над отдельно взятой задачей, уменьшение WIP сокращает время прохождения задач через всю производственную систему (иными словами – позволяет снизить средний Lead Time и улучшить пропускную способность системы).

Еще пара свежих исследований на тему выгод от парного программирования:

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

Долгое время исследования касались парного программирования как такового. Берем задачу и даем ее выполнить разным программистам в парах и в одиночку (solo в англоязычной литературе). Повторяем много-много раз и смотрим на результат. Это упрощенное описание, но в целом оно верно. Такие исследования позволяли определить, есть ли польза (да, польза есть) от парного программирования прежде чем начать копать глубже. И вот пришло время более глубоких исследований, показывающих чем отличаются хорошие сессии парного программирования от плохих. Раз есть понятия «лучше» и «хуже», значит есть и навык парного программирования, который можно развить. Косвенно об этом упоминается в вышеупомянутой статье от Alistair Cockburn:

But about four months into the merge, I began to notice that things were changing. One pair in particular spent their whole day together, doing honest-to-goodness pair programming, and the other two pairs were getting much closer to that ideal. In discussions it was clear that they knew why the change was happening. It simply worked better!

The Costs and Benefits of Pair Programming

А вот явно об этом говорится в исследовании 2021-го года «Two Elements of Pair Programming Skill». Согласно этой статье, парное программирование – это навык, который складывается из:

  • Togetherness (единство, единение). Хорошим парам удается устанавливать и поддерживать общую ментальную модель на протяжении всего сеанса. Они выявляют и устраняют отличия в понимании задач, систем и разработки в целом.
  • Expediency (целесообразность). Хорошие пары уравновешивают краткосрочные цели, такие как выявление дефектов или реализация новой фичи и долгосрочные, например – устранение пробелов в знаниях партнеров, онбординг.

Исходя из этих характеристик, авторы статьи выделили три анти-паттернна парного программирования:

  • Lost in the Weeds (блуждание в трех соснах). Проявляется, когда участники начинают тратить время на исследование не относящихся к делу деталей и упускают из виду то, что является важным. Снижает expediency.
  • Losing the Partner (потеря партнера) происходит, когда один из участников сосредоточился на задаче и не обращает внимание на то, что второй участник выпал из контекста. Снижает togetherness.
  • Drowning the Partner. Один из участников крайне избыточно объясняет свои мысли и действия. Может снизить и expediency и togetherness.

Результаты исследований соответствуют и моим наблюдениям. Например, togetherness, единая ментальная модель. Без нее работа в паре может превратиться в спор, бесконечный и беспощадный. Именно поэтому само по себе парное программирование не позволит «соблюдать и передавать стиль кодирования», если вы в команде, вместе, заранее об этом стиле не договорились. Именно поэтому код не станет понятнее, если команда и бизнес вместе, заранее не определили Единый Язык (Ubiquitous Language) на основе модели предметной области, например, с помощью Event Storming и Domain Driven Design.

Event Storming Example
Исследование предметной области с помощью Event Storming

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

Были и другие исследования парного программирования, например в работе «The effectiveness of pair programming: A meta-analysis» приведены выводы об эффективности парного программирования в зависимости от сложности задач и уровня разработчиков.

pair programming
Влияние опыта программистов (a) — (d) и сложности системы (e) — (h) на продолжительность, усилия и корректность

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

Стили парного программирования

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

«Штурман» и «Водитель»

Самый «старый» стиль.

  • Партнеры совместно прорабатывают решение на бумаге, доске, в miro; формируют общую ментальную модель. Еще не код, но уже не воздух.
  • «Водитель» пишет код и проговаривает свои действия, «Штурман» поверяет решение на прочность и смотрит на картину в целом
  • Через некоторое время, обычно 30 минут, партнеры меняются ролями

Водитель мыслит тактически – пишет код и проговаривает свои действия. «Штурман» мыслит стратегически – проверяет решения «Водителя» на прочность, смотрит на картину в целом (первичные исследования работы мозга во время парного программирования показали, что уровень концентрации у «Штурмана» значительно выше, чем у «Водителя», что само по себе – контринтуитивно).

Строгое парное программироваие

Строгое парное программирование – более строгая версия стиля Штурман/Водитель, в которой «Штурман» говорит «Водителю» что делать, а «Водитель» только пишет то, что ему говорят. Если у «Водителя» появляется идея, он занимает место «Штурмана». Идея в том, что для «Штурмана» «Водитель» является своего рода «интеллектуальным интерфейсом ввода».

Ping Pong

Этот стиль идеально сочетается с TDD. Для старта парного программирования в удаленном режиме рекомендуется использовать именно этот стиль.

Ping pong pair programming

Алгоритм:

  • Боб пишет тест
  • Алиса пишет код так, чтобы тест успешно выполнился
  • Алиса пишет следующий тест
  • Боб пишет код под этот тест
  • И так далее

Смешанное парное программирование

Подходит для опытных, хорошо сработавшихся команд. Все работают по кругу со всеми, пока задача не будет выполнена.

Алгоритм:

  • A работает в паре с Б
  • Б работает в паре с В
  • В работает в паре с Г
  • Над одной и той же задачей, возможно в течение одного дня

Командное программирование (Mob Programming)

Вся команда работает над одной задачей в один момент времени, в одном месте за одним большим экраном. Устраняет любые очереди в разработке, так как по сути команда работает в режиме one-peace-flow Подробнее в выступлении Ивана Зимина «Командное программирование».

Mob Programming

Варианты структур при организации пар

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

Обычно рассматриваются три варианта структур:

  • Junior — Senior
  • Junior — Junior
  • Senior — Senior

Иногда еще добавляют middle. Не вижу в этом большой ценности, так что остановимся на Junior/Senior.

Для начала попробуем пойти от особенностей и потребностей Junior- и Senior-разработчиков, составим портреты.

JuniorSenior
Мыло опытаЭксперт
Чаще неуверенныйУверен в себе и своих силах
Стесняется предлагать решенияАктивно предлагает решения
Минимальные знания кодаОтлично знает код
Фокус обучения: код, терминология, архитектура, работа с IDEФокус обучения: лучшие практики, тренды, производительность, безопасность
Портреты (особенности) Junior и Senior

Отличия достаточно серьезные и если у Senior еще и ментальность супергероя, он легко станет Keyboard Dominator 🙂 и у Junior не останется шансов на развитие, продуктивную работу и закрытие своих потребностей, а именно:

  • Возможности пробовать новые для себя вещи,
  • Допускать собственные ошибки,
  • Экспериментировать,
  • Получать конструктивную обратную связь и поддержку от партнера.
Senior Developer

Многие Senior забывают со временем, что именно благодаря закрытию этих потребностей они и стали Senior’ами.

Иногда в паре Junior-Senior Senior воспринимает Junior как человека, который только замедляет разработку. К слову – это правда, но для успеха команды важно не это (еще Фредерик Брукс об этом писал), важно другое – сделали ли партнеры всё возможное, чтобы стать немного эффективнее, чем было к началу сессии. Постепенно, навык к навыку, Junior нарастит скорость. Небольшие улучшения капитализируются и из них складываются большие достижения.

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

Динамика работы в паре

Движемся дальше. Парное программирование – это социальный навык, который можно развить и оно дает серьезные выгоды при правильном применении. Существует несколько проверенных временем стилей парного программирования. Структурно в парах могут работать люди с различным уровнем знаний: Senior-Junior, Senior-Senior и Junior-Junior. Интуиция подсказывает, что в зависимости от структуры по-разному может проявляться и динамика. Так ли это?

В исследовании «Explaining pair programming session dynamics from knowledge gaps» (Freie Universität Berlin) авторы изучали поведение пар c позиции недостаточности знаний. Знания они разделили на специфичные для разрабатываемой системы и общие (как вообще разрабатывать, паттерны, знание языка программирования и так далее). Рассмотрим оптимальные модели поведения в зависимости от типа недостающих знаний и конфигурации пары.

Отсутствие пробелов в знаниях

Оба партнера обладают всеми необходимыми для разработки знаниями. Чаще всего это либо комбинация «Senior-Senior», либо greenfield-проект. К слову, пара Senior-Senior хорошо подходит и для срочного багфикса. Дефект будет закрыт быстрее, а код будет качественнее (см. конец раздела «Парное программирование – это навык»)

Недостаток специфичных знаний у одного из партнеров

Может произойти, если один из партнеров раньше начал работать над задачей. В статье на эту тему два примера:

  • Багфикс, при котором один из разработчиков знает код, в котором обнаружен дефект. Тогда все просто – он рассказывает второму разработчику как устроен код, после чего они вместе фиксят дефект.
  • Один из разработчиков начал разработку новой фичи раньше, чем к нему присоединился второй. Продуктивная работа началась только после того, как второй разработчик смог построить в голове всю логику уже реализованной части решения от начала и по текущий момент.

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

Недостаток специфичных знаний у обоих партнеров

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

Авторы статьи приводят стратегии:

  • Совместное создание знания. Формулируется гипотеза о системе, изучается код и само приложение, после чего инсайты интегрируются друг с другом.
  • Изучение в одиночку. Один из разработчиков изучает систему и затем рассказывает второму.

Недостаток общих знаний у одного из партнеров

Согласно результатам исследования, конструктивной стратегией в такой ситуации является pull-стратегия, при которой разработчик с недостатком общих знаний наблюдает и «вытягивает» (например — спрашивает, уточняет) знания о том, что ему не понятно в то время, как более опытный пишет код. Код становится примером, а вопросы раскрывают суть действий.

Недостаток общих знаний у обоих партнеров

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

К слову, наблюдал это на практике несколько раз. Есть различные крылатые выражения о том, что «Senior может выполнить задачу в 10 и 100 раз быстрее, чем Junior». Правда в том, что иногда Junior вообще не может выполнить задачу. И два таких Junior все равно не выполнят задачу. Они могут просто-напросто не знать какого-то алгоритма, библиотеки, особенности языка и не знать о том, что они пока еще этого не знают (те самые unknown unknowns).

Управление временем

Мы на финишной прямой. Парное программирование – это социальный навык, который можно развить и оно дает серьезные выгоды при правильном применении. Существует несколько проверенных временем стилей парного программирования. Структурно в парах могут работать люди с различным уровнем знаний: Senior-Junior, Senior-Senior и Junior-Junior. В зависимости от структуры по-разному может проявляться и динамика работы в паре. Так сколько же нам вот так в паре работать времени, как часто?

Работать паре весь день и всю неделю – контрпродуктивно. Есть немало задач, которые лучше делать в одиночку, например – исследования, рутина. Планируйте заранее сколько времени вы будете работать в паре. Четверть дня три дня в неделю и пол дня два дня в неделю.

Pair programming – a start guide for newbies - DEV Community

Для самих сессий отлично подходит техника Pomodoro. Сам сейчас использую приложение Flow, но подойдет любой таймер. Так как меняться ролями лучше не реже, чем каждые 30 минут, то подойдут 25 минутные рабочие интервалы с 5-минутным перерывом.

Шесть простых шагов для старта

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

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

  1. Договоритесь о высокоуровневой цели
  2. Разбейте работу на таски и проставьте им приоритеты
  3. Выберите подходящий стиль парного программирования
  4. Устраните отвлекающие факторы
  5. Работайте в выбранном стиле с перерывами
  6. Закончите с небольшой ретроспективой

Если у вас возникли вопросы, пишите на sb@agilemindset.ru

Приятного парного программирования!

Share

Добавить комментарий