Чистый Agile. Основы гибкости Мартин Роберт

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

Несогласованность зашкаливала. Качество оставляло желать лучшего. Нужно было много переделывать[41]. В последующие годы технологии в какой-то мере стали совершеннее. В наши дни скорость передачи данных позволяет регулярно связываться по видео и передавать изображение на экране. Два разработчика в разных концах света теперь могут работать в паре над тем же кодом почти так же, как если бы сидели за одним столом. Конечно, такой прогресс не решает проблему разных часовых поясов, культурных и языковых различий, но электронное написание кода лицом к лицу несомненно предпочтительнее, чем пересылка исходного кода туда-обратно по электронной почте.

Можно ли так работать по методам Agile? Я слышал, что можно. Но сам никогда не видел, чтобы это хорошо удавалось. Может быть, вы видели.

Удаленная работа из дома

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

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

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

Не поймите превратно. В начале 1990-х мы с моим партнером Джимом Ньюкирком благополучно управляли командой, все члены которой находились на удаленке. Почти все работали только из дома. Некоторые жили в других часовых поясах. Мы лично встречались от силы пару раз в год. С другой стороны, мы все говорили на одном языке, у нас был один менталитет, а разница во времени не превышала двух часов. У нас получалось работать. И мы работали. Весьма хорошо. Но мы бы работали лучше, если бы находись в одной комнате.

Заключение

На встрече в Сноуберде в 2000 году Кент Бек выразил мысль, что одна из наших задач — построить мост над пропастью, существующей между клиентами и разработчиками. Методы взаимодействия с клиентами играют важную роль при выполнении этой задачи. Если применять этот метод, то у разработчиков и клиентов будет простой и однозначный способ общения. Такое общение порождает доверие.

Глава 4. Методы взаимодействия внутри команды

Средняя полоса модели жизненного цикла Рона Джеффриса состоит из методов взаимодействия внутри команды. Эти методы регулируют отношения членов команды и их отношение к создаваемому продукту. Методы, которые мы обсудим, — это метафора, 40-часовая рабочая неделя, коллективное владение и непрерывная интеграция.

А потом кратко обсудим стендап-митинги.

Метафора

В годы накануне и после подписания Манифеста Agile метафора была методом расплывчатым, нам было стыдно, что не могли дать ему нормального описания. Мы знали, что это важно, поэтому могли привести удачные примеры. Но четко выразить то, что имели в виду, у нас не получалось. В некоторых наших беседах, на курсах и лекциях мы просто вскакивали и, выпучив глаза, восклицали: «Да вы сами все поймете, когда увидите!»

Для плодотворного общения команде требуется ясный и упорядоченный словарный запас из понятий и концепций. Кент Бек предложил понятие «метафора», так как это связывало его проекты с чем-то, о чем у всех команд было общее представление.

Первым примером Бека была метафора, которая использовалась в проекте расчета заработной платы «Крайслер»[42]. Он сравнил оформление зарплатных чеков с конвейером. Чеки движутся от одной точки к другой, где к ним присоединяют разные «запчасти».

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

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

Но метафоры часто заводят не туда.

Например, в конце 1980-х я работал над проектом, в котором измерялось качество передачи данных в сетях T1. Мы загрузили данные счетчиков ошибок с конечных точек каждой линии связи. Эти данные были объединены в слои по полчаса. Мы рассматривали эти слои как ломтики чего-то сырого, из чего можно приготовить еду. Когда мы нарезаем хлеб ломтями, где мы жарим ломтики? В тостере! И тут мы метафорически стали описывать хлеб.

У нас были ломтики, батоны, сухари и так далее.

У программистов такой словарный запас работал неплохо. Мы отлично понимали друг друга, когда разговаривали о сырых и приготовленных ломтиках, батонах и так далее. С другой стороны, менеджеры и клиенты, которые слышали наши разговоры, крутили пальцем у виска и выходили из комнаты. Им казалось, что мы несем чушь.

А есть пример еще хуже. В начале 1970-х я работал над системой разделения времени. Она перемещала приложения в память, которая была ограничена, и выгружала их из нее. За время, за которое приложение находилось в памяти, она загружала в буфер текст и отправляла его на медленный телетайп. Когда буфер заполнялся, приложение уходило в спящий режим и выгружалось из памяти на диск, в то время как буфер постепенно очищался. Мы называли такие буферы мусоровозами, которые ездили между мусорными баками и свалкой.

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

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

Предметно-ориентированное проектирование

В своей прогрессивной книге Domain-Driven Design[43] Эрик Эванс решил нашу проблему с метафорами, и наконец мы избавились от чувства стыда. В этой книге он ввел понятие повсеместного языка — как раз так стоило назвать метод, который получил название «метафора». Команде была нужна именно модель предметной области, которую описывают теми словами, с которыми согласны все.

Под «всеми» я имею в виду всех: программистов, QA-специалистов, менеджеров, клиентов, пользователей и так далее.

В 1970-х Том Демарко назвал такие модели «словарями данных»[44]. Они были простыми представлениями данных, которыми манипулирует приложение, и процессов, которые манипулировали этими данными. Эванс значительно развил этот простой замысел в дисциплину моделирования предметной области. И Демарко, и Эванс использовали эти модели как транспортные средства для общения с партнерами.

Как простой пример: я недавно написал видеоигру Space War. Элементы данных носили названия «корабль», «клингон», «ромуланин», «выстрел», «удар», «взрыв», «база», «транспорт» и прочее. Я внимательно относился к тому, чтобы изолировать эти понятия в их собственных модулях и использовать эти названия исключительно в приложении. Это был мой «повсеместный язык».

Такой язык используется во всех частях проекта. На нем говорят клиенты. Разработчики говорят на нем. И QA-специалисты. Специалисты по DevOps тоже на нем говорят. Даже клиенты берут на вооружение те части, которые будут им полезны. Повсеместный язык применяется в бизнес-моделях, требованиях, архитектуре и приемочном тестировании. Он прочной нитью последовательно объединяет составляющие проекта на каждом этапе его жизненного цикла[45].

40-часовая рабочая неделя

Не быстрый побеждает в беге…

Екклесиаст 9: 11

Претерпевший же до конца спасется.

От Матфея 24: 13

На седьмой день Бог решил взять отдых. А позже Бог велел в этот день отдыхать всем. Видимо, даже Богу нужен метод «40-часовая рабочая неделя», или равномерная работа.

В начале 1970-х, когда я был восемнадцатилетним, меня и моих школьных приятелей взяли работать джуниор-программистами для работы над крайне важным проектом. Менеджеры установили сроки. Сроки были жесткими. Требовалось выкладываться по полной. Мы были незаменимыми винтиками в сложном механизме компании. Мы были важны!

Хорошо, когда тебе восемнадцать, не правда ли?

Мы, молодые и горячие, только окончившие школу, работали как волы. Мы работали долгими часами месяц за месяцем. В среднем мы работали по 60 часов в неделю. Были недели, когда мы работали даже по 80 часов. Десятки раз мы работали по ночам.

И мы гордились тем, что работали сверхурочно. Вот мы-то были настоящими программистами. Мы посвятили себя проекту. Нас ценили. Потому что мы были единственной силой, которая могла спасти такой важный проект. Мы. Были. Программистами.

А потом мы сгорели, причем жестко. Так жестко, что ушли всем скопом. Мы вылетели оттуда, оставив компании еле работающую систему разделения времени, при этом в компании не было толковых программистов, которые могли бы ее сопровождать. Вот так им!

Хорошо, когда тебе восемнадцать и ты в ярости, да?

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

Работа сверхурочно

Как думаете, я усвоил урок из того, что вам только что рассказал? Нет, конечно. В течение последующих 20 лет я точно так же горел на работе ради своих работодателей. Я продолжал прельщаться байками о том, что проект чрезвычайно важен. Я, конечно, не сходил с ума, работая сутками, как в 18 лет. В среднем я работал уже где-то по 50 часов в неделю. Ночные посиделки стали происходить реже, но никуда не исчезли.

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

Затем случилось кое-что, что заставило меня задуматься. Я и мой будущий деловой партнер Джим Ньюкирк занимались ночным бдением. Где-то около двух часов ночи мы пытались выяснить, как переместить единицу данных из низкоуровневой части нашей программы в другую часть, которая находилась намного выше в цепочке выполнения. Решение возвращать эти данные в стек не подходило.

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

Даже сейчас, спустя более трех десятилетий, каждый раз, когда мы с Джимом хотим описать чье-то неудачное решение, мы говорим: «Да уж. Они просто отослали это самим себе».

Я не буду грузить вас скучными подробностями, почему это решение было дурацким. Достаточно сказать, что на него ушло намного больше усилий, чем мы, как казалось, сберегли. И, конечно же, это решение привело к слишком глубоким и труднообратимым изменениям, поэтому мы потеряли много времени[46].

Марафон

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

Таким образом, вы должны работать в темпе, который можно поддерживать в течение длительного времени. Должна быть 40-часовая рабочая неделя. Если пытаться бежать в более быстром темпе, чем вы можете поддерживать, все равно придется замедляться и отдыхать до пересечения финишной черты. Средняя скорость будет ниже, чем при умеренном темпе. Когда финишная черта близко, еще остается немного сил на то, чтобы совершить рывок. Но нет необходимости делать его раньше времени.

Менеджеры могут просить вас поторопиться. Ни в коем случае не поддавайтесь. Ваша работа — грамотно распоряжаться своими ресурсами, чтобы выстоять до конца.

Самоотдача

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

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

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

Шел 1995 год. На следующий день была запланирована к выходу из печати моя первая книга, и мне кровь из носу нужно было представить корректуру. Было 6 утра, у меня уже все было на руках. Надо было просто залить файл на FTP-сервер издателя.

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

Мы посмотрели друг на друга и тяжело вздохнули. Джим сказал: «Нужно все переделывать». Это был не вопрос. Это была констатация факта. Все трое посмотрели друг на друга, потом на часы. Потом снова друг на друга. А потом пошли горбатиться.

Но когда мы все сделали, посиделки закончились. Мы отправили книгу. И пошли спать.

Сон

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

Коллективное владение

В проекте, где применяется Agile, у кода нет владельца. Код — это коллективное владение команды как единого целого. Любой член команды в любое время имеет право проверить и усовершенствовать любой модуль проекта. Команда коллективно располагает всем кодом.

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

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

У центрального компьютера и периферийных были совершенно разные архитектуры. Один был такой же, как PDP-8, только его слово составляло 18 бит. У него было 256 килобайт оперативной памяти, а данные загружались с кассеты с магнитной лентой. Другой имел 8-битный микропроцессор 8085 с 32 килобайтами оперативной памяти и 32 килобайтами постоянной памяти.

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

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

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

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

За свой достаточно долгий карьерный путь я видел, как некоторые компании делали наоборот. У каждого программиста были свои модули, и никто больше не имел права к ним прикасаться. Такие команды были чрезвычайно разлажены, в них царило непонимание, и все сваливали вину друг на друга. Работа над модулем прекращалась, когда автор был не в офисе. Никто даже и не думал браться за чужой участок работы.

Секретные материалы

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

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

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

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

Проблем от этого было море. Во взаимодействии возникают очевидные трудности, если невозможно проверить используемый код. В таком случае неизбежно перекладывание ответственности и подставы.

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

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

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

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

В первые дни существования Agile метод «непрерывная интеграция» означал, что разработчики отмечали изменения в своем исходном коде и объединяли их с основной веткой каждые «пару часов»[47]. Все модульные и приемочные тесты проходили успешно. Не оставалось веток, которые бы не были объединены. Все ненужные при развертывании изменения отключались с помощью тумблера.

В 2000 году на одном из уроков на курсах XP Immersion один студент угодил в классическую ловушку. Эти уроки были очень насыщенны. Мы сократили циклы так, что итерации составляли всего один день. Цикл непрерывной интеграции составлял лишь от четверти до получаса.

Один студент работал в команде из шести разработчиков, пятеро из которых отмечали изменения чаще, чем он. Непонятно почему, он был без пары. И вышло так, что он не выполнял слияние кода более часа.

Когда он наконец решил отметить изменения и выполнить слияние кода, он увидел, что накопилось столько изменений, внесенных другими студентами, что ему пришлось хорошенько повозиться, чтобы объединить код. Пока он копался и выполнял слияние, остальные программисты продолжали отмечать изменения каждые 15 минут. И когда он наконец разобрался и попробовал отметить изменения в своем коде, то увидел, что снова попал впросак.

Он так расстроился, что встал посреди кабинета и громко провозгласил: «Ваше экстремальное программирование — полная ерунда!» После этого он вылетел из класса и направился в бар гостиницы.

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

Мораль: метод «непрерывная интеграция» работает только тогда, когда интеграция действительно непрерывна.

А вот и непрерывная сборка

В 2001-м Thought Works значительно изменили положение дел. Они создали CruiseControl[48], первое средство непрерывной сборки. Я помню, как в 2001-м на XP Immersion Майк Ту[49] читал ночную лекцию об этом. Не сохранилось записи этой лекции, но история была примерно таковой:

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

«Боб сломал сборку».

Мы ввели простое правило в отношении тех, кто ломал сборку. В тот несчастный день, когда вас угораздило сломать сборку, вы должны надеть футболку с надписью «Я сломал сборку». Которую никто никогда не стирал.

С тех пор было создано много других средств непрерывной сборки. К ним относятся инструменты наподобие Jenkins (или Hudson?), Bamboo и TeamCity. С помощью этих инструментов можно в наибольшей степени сократить время между слияниями. «Пара часов», о которой изначально говорил Кент Бек, превратилась в «несколько минут». «Непрерывная интеграция» стала «непрерывной отметкой».

Дисциплина при непрерывной сборке

При непрерывной сборке ничего не должно ломаться. Потому что программист, который не хочет надевать грязную футболку, как в случае с Майком Ту, проводит приемочное и модульное тестирование до того, как отметить изменения в коде. Если сборка сломалась (как так можно?), значит, случилось что-то очень странное.

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

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

Внимание!

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

Стоимость обмана

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

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

Стендап-митинг

На протяжении многих лет было много путаницы в понятиях ежедневный скрам и стендап-митинг. Позвольте мне разъяснить.

Вот вам правда о стендап-митингах:

• Такие встречи не обязательны. Многие команды прекрасно обходятся без них.

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

• Они должны занимать примерно 10 минут даже у больших команд.

• Встреча проводится по простому сценарию.

Смысл этого мероприятия в том, что каждый член команды встает[50] в круг и отвечает на три вопроса:

1. Что я делал после прошлой встречи?

2. Что я буду делать до следующей встречи?

3. Что мне нужно сделать?

И все. Никаких обсуждений. Никакого позерства. Никаких пространных объяснений. Никаких грустей и печалей. Никаких жалоб и обвинений кого угодно на свете.

У каждого есть полминуты на то, чтобы ответить на три вопроса. Потом встреча заканчивается, и все идут работать дальше. Все, аллес. Финита. Ферштейн?

Наверное, еще лучше стендап-митинги описаны на «вики» Уорда: http://wiki.c2.com/?StandUpMeeting.

Курицы и свиньи?

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

Как по мне, без разницы, кто говорит, главное, чтобы встреча проводилась в формате трех вопросов, а собрание длилось около 10 минут.

Красавчик

Мне понравилось одно изменение — это добавить дополнительный четвертый вопрос.

• Кто у нас сегодня красавчик?

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

Заключение

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

Глава 5. Технические методы

Методы этой главы предлагают полный отход от тех, что господствовали среди большинства программистов на протяжении 1970-х годов. Раньше предлагался набор осмысленных ритуалов, проводимых периодично — ежеминутно и ежесекундно, которые большинство программистов изначально считают чушью. Поэтому многие программисты пробовали применять Agile, исключив эти методы. Однако у них ничего не получилось, потому что эти методы как раз лежат в основе Agile. Без разработки через тестирование, рефакторинга, простой структуры проекта и, да-да, даже парного программирования Agile становится бесполезным жалким подобием того, чем должен быть.

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

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

Профессия программиста уникальна. Мы создаем огромные документы, написанные загадочными техническими символами. Каждый символ такого документа должен быть правильным, иначе может произойти что-то действительно страшное. Один неверный символ повлечет за собой потери больших средств или жизни. Разве есть другие такие профессии?

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

Двойная запись

У бухгалтеров есть инструмент, который появился еще тысячу лет назад. Это двойная запись[51]. Каждая операция, которую они проводят, заносится в книгу дважды: один раз как кредит в активном счете и еще раз, в дополнение, как дебет в пассивном счете. Затем эти счета сводят в единый документ, балансовый отчет, где из суммы финансовых активов вычитается сумма долговых обязательств и долей собственников. Бухгалтер должен выйти в ноль. Если в итоге получается не ноль, значит, где-то допущена ошибка[52].

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

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

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

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

И то и другое служит одной цели — предотвращать ошибки в критически важных документах, где каждый символ должен быть правильным. Хотя программирование и стало неотъемлемой частью нашего общества, мы до сих пор не обязали проводить разработку через тестирование на законодательном уровне. Но учитывая то, скольких жизней и средств стоило плохо написанное ПО, может, такой закон не за горами?

Три правила разработки через тестирование

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

• Не пишите готовый код до того, как напишете тест, который не получится пройти из-за нехватки этого кода.

• Не пишите тестов больше, чем это необходимо для неудачи, — сбой при компиляции также считается неудачей.

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

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

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

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

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

Отладка

Что было бы, если бы минуту назад все всегда работало? Как долго пришлось бы выполнять отладку? Если минуту назад все работало, то почти каждый сбой, с которым вы столкнетесь, произошел не больше минуты назад. Отладка сбоя, который появился только что, зачастую пустяк. И в самом деле использовать отладчик для поиска проблемы, наверное, чересчур.

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

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

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

Документация

Вам хоть раз доводилось интегрировать сторонний пакет? Скорее всего, он пришел в zip-архиве, в котором были исходники, библиотеки, Java-архивы и тому подобное. Скорее всего, в архиве был и документ PDF, в котором содержались инструкции по интеграции. А в конце PDF, наверное, было уродливое приложение с примерами всего кода.

Что вы прочли первым делом, как открыли этот документ? Если вы программист, то промотали в самый низ и прочитали примеры кода, потому что в этом коде вся правда.

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

Тесты — это один из видов документации, которая описывает тестируемую программу.

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

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

Радость

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

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

Полнота

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

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

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

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

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

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

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

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

Но в 100 %-ной полноте тестов нет необходимости для принятия решения о развертывании. Значения в 95 % вполне достаточно — и такая полнота тестов поистине достижима.

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

Внимание

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

Еще раз внимание

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

Проектирование

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

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

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

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

Смелость

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

Я уже рассказывал историю в самом начале книги, но стоит ее повторить.

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

В вас говорит страх. Вы боитесь кода. Боитесь что-либо делать с ним. Боитесь что-то сломать, потому что будут последствия. Так вы отказываетесь от того единственного, что может улучшить код, — от его чистки.

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

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

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

Представьте себе другой сценарий. Вернемся к монитору, на котором мы видим запутанный код. Первая мысль, которая вас посещает, — надо почистить код. Что, если бы у вас был настолько полный тестовый набор, что ему можно полностью доверять? А если этот тестовый набор работал бы быстро? Что бы вы подумали следующим делом? Наверное, что-то вроде этого:

Боже, думаю, просто надо поменять имя этой переменной. О, код все еще проходит тесты. Ладно, а теперь я разделю ту большую функцию на две поменьше… Здорово, все еще удается пройти… Хорошо, теперь, думаю, можно перенести одну из этих новых функций в другой класс. Опа! Тест не пройден. Так, ну-ка, вернем все… А, я понял, надо было переместить и саму переменную. Да, тест снова пройден…

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

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

Рефакторинг

Рефакторинг — еще одна тема, достойная целой книги. К счастью, ее уже написал Мартин Фаулер[53]. В этой главе мы просто обсудим это тему, не углубляясь в отдельные методы. И как и прежде, в этой главе нет кода.

Страницы: «« 12345678 »»

Читать бесплатно другие книги:

Современные англичане забыли о многих своих гнусных «изобретениях», например об институте «сервентов...
У вас в руках третье издание «Кода публичности». Бестселлер Аны Мавричевой дополнен бонусной главой ...
Предлагаю вашему вниманию два первых тома из цикла "Мир Танария". В книгу вошли части 1. Месть Сашки...
Пустота - мир бессмысленности, мир бесконечных иллюзий, сковавший собой множество разумных существ. ...
Старопименовский переулок, бар "Перебрал", смешная зарисовка про столичные нравы в эпоху пандемии.Со...
Стройно объяснить происхождение разума не удавалось еще никому. В этой концептуальной книге эволюцио...