Делай как в Google. Разработка программного обеспечения
Қосымшада ыңғайлырақҚосымшаны жүктеуге арналған QRRuStore · Samsung Galaxy Store
Huawei AppGallery · Xiaomi GetApps

автордың кітабын онлайн тегін оқу  Делай как в Google. Разработка программного обеспечения

 

Титус Винтерс, Том Маншрек, Хайрам Райт
Делай как в Google. Разработка программного обеспечения
2021

Научный редактор М. Коробко

Переводчик А.Киселев

Литературные редакторы А. Попова, А. Руденко

Художник В. Мостипан

Корректоры М. Одинокова, Н. Сидорова, Г. Шкатова


 

Титус Винтерс, Том Маншрек, Хайрам Райт

Делай как в Google. Разработка программного обеспечения. — СПб.: Питер, 2021.

 

ISBN 978-5-4461-1774-1

© ООО Издательство "Питер", 2021

 

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

 

Предисловие

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

Сотрудничество с «экс-гуглерами» только усилило мое любопытство. Если в одной команде с вами работает бывший инженер Google, вы будете часто слышать: «А вот мы в Google...» Переход из Google в другие компании кажется шокирующим опытом, по крайней мере для инженера. Человек со стороны считает системы и процессы разработки кода в Google одними из лучших в мире, учитывая масштаб компании и то, как часто люди хвалят ее.

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

Самое замечательное в программной инженерии — это возможность добиться желаемого результата несколькими способами. В каждом проекте инженер должен учитывать множество компромиссов. Что можно заимствовать из открытого исходного кода? Что может спроектировать команда? Что имеет смысл поддерживать для масштаба? У своих друзей-гуглеров я хотел узнать, как устроен гигантский мир Google, богатый талантами и средствами и отвечающий высочайшим требованиям к программному обеспечению (ПО). Их разнообразные ответы познакомили меня с неожиданными аспектами.

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

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

Камиль Фурнье, автор книги «От разработчика до руководителя» (М.: МИФ, 2018)

Вступление

Что именно мы подразумеваем под программной инженерией? Что отличает «программную инженерию» от «программирования» или «computer science»? И как подход Google связан с другими подходами в этой области, описанными во множестве книг в последние пятьдесят лет?

Термины «программирование» и «программная инженерия» используются в отрасли взаимозаменяемо, хотя каждый из них имеет собственное значение. Студенты университетов, как правило, изучают computer science и работают как «программисты».

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

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

Программирование в долгосрочной перспективе

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

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

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

Время и изменения

Как код должен адаптироваться на протяжении срока действия.

Масштаб и рост

Как организация должна адаптироваться по мере своего развития.

Компромиссы и издержки

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

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

Точка зрения Google

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

Темы, обсуждаемые в этой книге, мы разделили на три основных аспекта ландшафта программной инженерии, сложившихся в Google:

• культура;

• процессы;

• инструменты.

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

Методики, описанные в части III «Процессы», знакомы большинству инженеров-программистов, но мы отметили, что большой размер кодовой базы Google и долгий срок ее действия обеспечивают надежную основу для выработки оптимальных практик. Мы научились учитывать время и масштаб, а также определили области, где у нас пока нет удовлетворительных ответов.

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

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

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

Что не отражено в книге

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

Заключительные примечания

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

Том Маншрек

Условные обозначения

В этой книге приняты следующие обозначения:

Курсив

Используется для обозначения новых терминов.

Моноширинныйшрифт

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

 

Так обозначаются советы, предложения и примечания общего характера.

Благодарности

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

Также мы благодарим Мелоди Мекфессель (Melody Meckfessel) за поддержку этого проекта на начальном этапе, а также Дэниела Джаспера (Daniel Jasper) и Дэнни Берлина (Danny Berlin) за помощь в его завершении.

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

• Что такое программная инженерия? Санджай Гемават (Sanjay Ghemawat), Эндрю Хаятт (Andrew Hyatt).

• Успешная работа в команде: Сибли Бэкон (Sibley Bacon), Джошуа Мортон (Joshua Morton).

• Обмен знаниями: Дмитрий Глазков, Кайл Лимонс (Kyle Lemons), Джон Риз (John Reese), Дэвид Симондс (David Symonds), Эндрю Тренк (Andrew Trenk), Джеймс Такер (James Tucker), Дэвид Колбреннер (David Kohlbrenner), Родриго Дамацио Бовендорп (Rodrigo Damazio Bovendorp).

• Инженерия равенства: Камау Бобб (Kamau Bobb), Брюс Ли (Bruce Lee).

• Как стать лидером в команде: Джон Уили (Jon Wiley), Лоран Ле Брун (Laurent Le Brun).

• Масштабируемое лидерство: Брайан О’Салливан (Bryan O’Sullivan), Бхарат Медиратта (Bharat Mediratta), Дэниел Джаспер (Daniel Jasper), Шайндел Шварц (Shaindel Schwartz).

• Оценка продуктивности инженеров: Андреа Найт (Andrea Knight), Коллин Грин (Collin Green), Кетлин Садовски (Caitlin Sadowski), Макс-Канат Александер (Max-Kanat Alexander), Илай Янг (Yilei Yang).

• Правила и руководства по стилю: Макс-Канат Александер (Max-Kanat Alexander), Титус Винтерс (Titus Winters), Мэтт Аустерн (Matt Austern), Джеймс Деннетт (James Dennett).

• Код-ревью: Макс-Канат Александер (Max-Kanat Alexander), Брайан Ледгер (Brian Ledger), Марк Баролак (Mark Barolak).

• Документация: Йонас Вагнер (Jonas Wagner), Смит Хинсу (Smit Hinsu), Джеффри Ромер (Geoffrey Romer).

• Основы тестирования: Эрик Куфлер (Erik Kufler), Эндрю Тренк (Andrew Trenk), Диллон Блай (Dillon Bly), Джозеф Грейвс (Joseph Graves), Нил Норвитц (Neal Norwitz), Джей Корбетт (Jay Corbett), Марк Стрибек (Mark Striebeck), Брэд Грин (Brad Green), Мишко Хевери (Miško Hevery), Антуан Пикар (Antoine Picard), Сара Сторк (Sarah Storck).

• Юнит-тестирование: Эндрю Тренк (Andrew Trenk), Адам Бендер (Adam Bender), Диллон Блай (Dillon Bly), Джозеф Грейвс (Joseph Graves), Титус Винтерс (Titus Winters), Хайрам Райт (Hyrum Wright), Оги Факлер (Augie Fackler).

• Тестирование с дублерами: Джозеф Грейвс (Joseph Graves), Геннадий Цивил (Gennadiy Civil).

• Крупномасштабное тестирование: Адам Бендер (Adam Bender), Эндрю Тренк (Andrew Trenk), Эрик Кюфлер (Erik Kuefler), Мэтью Бомонт-Гай (Matthew Beaumont-Gay).

• Устаревание: Грег Миллер (Greg Miller), Энди Шульман (Andy Shulman).

• Управление версиями и ветвями: Рейчел Потвин (Rachel Potvin), Виктория Кларк (Victoria Clarke).

• Code Search: Дженни Ван (Jenny Wang).

• Системы и философия сборки: Хайрам Райт (Hyrum Wright), Титус Винтерс (Titus Winters), Адам Бендер (Adam Bender), Джефф Кокс (Jeff Cox), Жак Пиенаар (Jacques Pienaar).

• Critique: инструменты обзора кода в Google: Миколай Додела (Mikołaj Dądela), Герман Луз (Hermann Loose), Ева Мэй (Eva May), Элис Кобер-Соцек (Alice Kober-Sotzek), Эдвин Кемпин (Edwin Kempin), Патрик Хизель (Patrick Hiesel), Оле Ремсен (Ole Rehmsen), Ян Мацек (Jan Macek).

• Статический анализ: Джеффри ван Гог (Jeffrey van Gogh), Сиера Джаспан (Ciera Jaspan), Эмма Седерберг (Emma Söderberg), Эдвард Афтандилиан (Edward Aftandilian), Коллин Винтер (Collin Winter), Эрик Хо (Eric Haugh).

• Управление зависимостями: Расс Кокс (Russ Cox), Николас Данн (Nicholas Dunn).

• Крупномасштабные изменения: Мэтью Фаулз Кулукундис (Matthew Fowles Kulukundis), Адам Зарек (Adam Zarek).

• Непрерывная интеграция: Джефф Листфилд (Jeff Listfield), Джон Пеникс (John Penix), Каушик Шридхаран (Kaushik Sridharan), Санджив Дханда (Sanjeev Dhanda).

• Непрерывная поставка: Дэйв Оуэнс (Dave Owens), Шери Шипе (Sheri Shipe), Бобби Джонс (Bobbi Jones), Мэтт Дафтлер (Matt Duftler), Брайан Шутер (Brian Szuter).

• Вычисления как услуга: Тим Хокин (Tim Hockin), Коллин Винтер (Collin Winter), Ярек Кузьмиерек (Jarek Kuśmierek).

Также мы хотим поблагодарить Бетси Бейер за то, что поделилась опытом работы над книгой «Site Reliability Engineering. Надежность и безотказность как в Google»1. Спасибо Кристоферу Гузиковски (Christopher Guzikowski) и Алисии Янг (Alicia Young) из O'Reilly, которые запустили наш проект и довели его до публикации.

Кураторы также хотели сказать отдельное спасибо:

Том Маншрек (Tom Manshreck): «Маме и папе за то, что помогли мне поверить в себя и решали со мной домашние задания за обеденным столом».

Титус Винтерс (Titus Winters): «Папе за мой путь. Маме — за мой голос. Виктории — за мое сердце. Рафу — за мою спину. А также мистеру Снайдеру, Ранве, Зеду (Z), Майку, Заку, Тому и всем Пейнам, Меку (mec), Тоби, Кгд (cgd) и Мелоди за уроки, наставничество и доверие».

Хайрам Райт (Hyrum Wright): «Маме и папе за поддержку. Брайану и завсегдатаям Бейкерленда за мое первое погружение в мир ПО. Дюэйну (Dewayne) за продолжение этого путешествия. Ханне, Джонатану, Шарлотте, Спенсеру и Бену за их дружбу и интерес. Хизер за то, что все это время была рядом».

От издательства

Ваши замечания, предложения, вопросы отправляйте по адресу comp@piter.com (издательство «Питер», компьютерная редакция).

Мы будем рады узнать ваше мнение!

На веб-сайте издательства www.piter.com вы найдете подробную информа­цию о наших книгах.

1Бейер Б., Джоунс К., Петофф Д., Мёрфи Н.Р. Site Reliability Engineering. Надежность и безотказность как в Google. СПб.: Питер, 2021. 592 с.: ил.

Бейер Б., Джоунс К., Петофф Д., Мёрфи Н.Р. Site Reliability Engineering. Надежность и безотказность как в Google. СПб.: Питер, 2021. 592 с.: ил.

Также мы хотим поблагодарить Бетси Бейер за то, что поделилась опытом работы над книгой «Site Reliability Engineering. Надежность и безотказность как в Google»1. Спасибо Кристоферу Гузиковски (Christopher Guzikowski) и Алисии Янг (Alicia Young) из O'Reilly, которые запустили наш проект и довели его до публикации.

Часть I. Тезисы

Глава 1. Что такое программная инженерия?

Автор: Титус Винтерс

Редактор: Том Маншрек

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

Хорхе Луис Борхес

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

Мы в Google иногда говорим: «Программная инженерия — это программирование, интегрированное во времени». Программирование, безусловно, является важной частью программной инженерии: в конце концов, именно в процессе программирования создается новый софт. Но если мы разделяем понятия, то нужно разграничить задачи программирования (разработку) и программной инженерии (разработку, изменение, сопровождение). Время — это новое важное измерение в программировании. Куб — это не квадрат, расстояние — это не скорость. Программная инженерия — это не программирование.

Чтобы понять, как время влияет на программу, задумайтесь: «Как долго будет жить2 код?» Крайние оценки в ответах на этот вопрос могут отличаться в 100 000 раз. Легко представить код, который просуществует несколько минут, или другой код, служащий десятилетиями. Как правило, короткоживущий код не зависит от времени: едва ли нужно адаптировать утилиту, которая проживет час, к новым версиям базовых библиотек, операционной системы (ОС), аппаратного обеспечения или языков программирования. Недолговечные системы фактически являются «мимолетными» задачами программирования и напоминают куб, который сжат вдоль одного измерения до вида квадрата. Но с увеличением продолжительности жизни кода изменения становятся более важными для него. За десяток лет большинство программных зависимостей, явных или неявных, почти наверняка изменятся. Понимание этого явления помогает отличать программную инженерию от программирования.

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

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

Организация команды, состав проекта, а также стратегия и тактика его развития — важные компоненты программной инженерии, которые зависят от масштаба организации. Растет ли эффективность производства софта по мере увеличения организации и расширения ее проектов? Растет ли эффективность рабочего процесса по мере развития организации и насколько пропорционально этому растет стоимость стратегий тестирования и управления версиями? Проблемы масштаба, связанные с увеличением числа сотрудников и налаживанием коммуникации между ними, обсуждались с первых дней программной инженерии, начиная с появления мифического человеко-месяца6. Часто они имеют политический характер, и от их решения во многом зависят устойчивость ПО и ответ на вопрос: «Как дорого обойдется то, что придется делать снова и снова?»

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

Универсальные решения в программной инженерии встречаются редко, как вы увидите и в этой книге. Учитывая разброс в 100 000 раз между ответами на вопрос «Как долго будет жить ПО?» и в 10 000 раз — между ответами на вопросы «Сколько инженеров работает в компании?» и «Сколько вычислительных ресурсов доступно для проекта?», опыт Google почти наверняка не будет соответствовать вашей ситуации. Поэтому в этой книге мы постарались показать, как в Google искали правильные пути в разработке и сопровождении ПО, рассчитанного на десятилетия, имея десятки тысяч инженеров и вычислительные ресурсы мирового масштаба. Большинство методов, применение которых мы считаем обязательным в таком масштабе, также хорошо подойдут для меньших организаций: считайте эту книгу отчетом одной инженерной экосистемы, который может вам пригодиться. Иногда сверхбольшие масштабы связаны с повышенными расходами, и, возможно, благодаря нашим предупреждениям, когда ваша организация вырастет до таких масштабов, вы сможете найти более удачное решение по издержкам.

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

Время и изменения

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

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

С другой стороны, есть успешные проекты с практически неограниченным сроком службы: трудно предсказать, когда прекратит свое существование Google Search, ядро Linux или Apache HTTP Server. Большинство проектов Google должны существовать неопределенно долго и периодически претерпевать обновления зависимостей, языковых версий и т.д. С течением времени такие долгоживущие проекты рано или поздно начинают восприниматься иначе, чем задачи по программированию или развитию стартапа.

На рис. 1.1 показаны два программных проекта на противоположных концах спектра «ожидаемого срока службы». Как обслуживать проект с ожидаемым сроком службы, измеряемым часами? Должен ли программист бросить все и заняться обновлением, если во время работы над сценарием на Python, который будет выполнен всего один раз, вышла новая версия ОС? Конечно, нет: такое обновление некритично. Но если проект Google Search, находящийся на противоположном конце спектра, застрянет на версии ОС 1990-х годов, обслуживание станет проблемой.

 

Рис. 1.1. Срок жизни и важность обновлений

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

• обновления еще не выполнялись в этом проекте: по ним есть только предположения;

• инженеры едва ли имеют опыт проведения обновлений;

• большой объем обновлений: одномоментно приходится применять обновления, накопившиеся за несколько лет, вместо постепенного применения небольших обновлений.

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

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

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

Закон Хайрама

Если вы поддерживаете проект, который используется другими инженерами, то между «работающим по счастливой случайности» и «удобным в сопровождении» есть одно важное отличие, которое мы назвали законом Хайрама:

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

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

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

Пример: упорядоченный хеш

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

>>> for i in {"apple", "banana", "carrot", "durian", "eggplant"}: print(i)

...

durian

carrot

apple

eggplant

banana

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

• Атаки переполнения хеша (hash flooding)11 стимулируют недетерминированный характер хранения данных в хеше.

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

• Согласно закону Хайрама, программисты по возможности пишут программы, зависящие от порядка обхода хеш-таблицы.

Если спросить эксперта: «Можно ли положиться на конкретный порядок обхода элементов в хеш-контейнере?» — он наверняка ответит: «Нет». Это правильный ответ, но слишком упрощенный. Более точный ответ мог бы звучать так: «Если код недолговечный и не предполагает будущих изменений в аппаратном или программном окружении или структуре данных, то это вполне допустимо. Но если известно, что код будет жить долго или нельзя гарантировать, что зависимости никогда не изменятся, то предположение неверно». Более того, даже если ваша собственная реализация не зависит от порядка хранения данных в хеш-контейнере, этот порядок может использоваться другим кодом, неявно создающим такую зависимость. Например, если ваша библиотека сериализует значения перед вызовом удаленной процедуры (RPC, remote procedure call), вызывающая сторона может оказаться в зависимости от порядка следования этих значений.

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

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

Между кодами, написанными для «работы сейчас» и для «работы всегда», можно выделить четкие взаимосвязи. Рассматривая код как артефакт с переменным (в широких пределах) временем жизни, можно определить стили программирования: код, зависящий от хрупких и недокументированных особенностей, скорее всего, будет классифицирован как «хакерский» или «хитрый», тогда как код, следующий передовым практикам и учитывающий возможность развития в будущем, вероятно, будет считаться «чистым» и «удобным для сопровождения». Оба стиля имеют свои цели, но выбор одного из них во многом зависит от ожидаемого срока службы кода. Мы привыкли использовать термин программирование, если характеристика «хитрый» — это комплимент, и программная инженерия, если слово «хитрый» имеет отрицательный оттенок.

Почему бы просто не «отказаться от изменений»?

Все наше обсуждение времени и реакции на изменения связано с неизбежностью изменений. Верно?

Как и все остальное, о чем говорится в книге, принятие решения об обновлении зависит от обстоятельств. Мы готовы подтвердить, что «в большинстве проектов, существующих достаточно долго, рано или поздно возникает необходимость обновления». Если у вас есть проект, написанный на чистом C и не имеющий внешних зависимостей (или имеющий только зависимости, гарантирующие стабильность в течение долгого времени, такие как стандарт POSIX), вы вполне можете избежать рефакторинга или сложного обновления. Разработчики языка С прикладывают значительные усилия, чтобы обеспечить его стабильность.

Но большинство проектов подвержены изменениям в базовой технологии. В основном языки программирования и среды выполнения меняются активнее, чем язык C. Даже библиотеки, реализованные на чистом C, могут меняться для поддержки новых функций и тем самым влиять на пользователей. Проблемы безопасности есть во всех технологиях, от процессоров до сетевых библиотек и прикладного кода. Каждый элемент технологии может стать причиной критической ошибки и уязвимости безопасности, о которых вы не узнаете заранее. Если вы не применили исправления для Heartbleed (http://heartbleed.com) или не смягчили проблемы с упреждающим выполнением, такие как Meltdown и Spectre (https://meltdownattack.com), потому что полагали (или были уверены), что ничего не изменится, последствия будут серьезными.

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

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

Масштабирование и эффективность

Как отмечается в книге Бетси Бейер и др. «Site Reliability Engineering. Надежность и безотказность как в Google» (СПб.: Питер, 2019) (далее Site Reliability Engineering — SRE), производственная система в компании Google относится к числу самых сложных систем, созданных человеком. Формирование такой машины и поддержание ее бесперебойной работы потребовали бесчисленных часов размышлений, обсуждений и проектирования с участием экспертов со всего мира.

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

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

Наконец, самый ценный актив организации, производящей ПО, — кодовая база — тоже нуждается в масштабировании. При сверхлинейном росте системы сборки или системы управления версиями (VCS, version control system) (возможно, в результате увеличения истории изменений) может наступить момент, когда работать с ней станет невозможно. Многим аспектам, таким как «время для полной сборки», «время для получения новой копии репозитория» или «стоимость обновления до новой языковой версии», не уделяется должного внимания из-за того, что они меняются очень медленно. Но они с легкостью могут превратиться в метафорическую сварившуюся лягушку (https://oreil.ly/clqZN): медленно накапливающиеся проблемы слишком легко усугубляются и почти никогда не проявляются в виде конкретного момента кризиса. Только имея полное представление об организации в целом и стремясь к масштабированию, вы, возможно, сможете оставаться в курсе этих проблем.

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

Плохо масштабируемые политики

Даже небольшой опыт разработки позволяет легко определять политики, плохо поддающиеся масштабированию, чаще всего по изменению объема работы, приходящемуся на одного инженера, при расширении компании. Если организация увеличится в 10 раз, увеличится ли в 10 раз нагрузка на одного инженера? Увеличится ли объем работы, которую он должен выполнять, при увеличении кодовой базы? Если на какой-то из этих вопросов будет дан положительный ответ, найдутся ли механизмы для автоматизации или оптимизации работы этого инженера? Если нет, значит, в организации есть явные проблемы с масштабированием.

Рассмотрим традиционный подход к устареванию (подробнее об устаревании в главе 15) в контексте масштабирования. Представьте, что принято решение использовать новый виджет вместо старого. Чтобы мотивировать разработчиков, руководители проекта говорят: «Мы удалим старый виджет 15 августа, не забудьте перейти к использованию нового виджета».

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

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

Еще один пример плохо масштабируемой политики — традиционное использование ветвей разработки. Если слияние крупных изменений с главной ветвью дестабилизировало продукт, можно сделать вывод: «Нужно более жесткое управление слиянием. Слияния должны производиться реже!» и для каждой команды (или функциональной возможности) создать отдельные ветви разработки. Когда такая ветвь достигнет конечной точки разработки, она будет протестирована и объединена с главной ветвью, из-за чего другие инженеры, работающие над другими ветвями, будут вынуждены повторно синхронизировать репозитории и проводить тесты. Такой способ управления ветвями можно использовать в небольшой организации, где одновременно разрабатывается 5–10 подобных ветвей. Но по мере роста организации (и количества ветвей) этот подход увеличивает накладные расходы на многократное выполнение одной и той же задачи. Более эффективный подход обсудим в главе 16.

Хорошо масштабируемые политики

Какие политики помогают оптимизировать затраты по мере роста организации? Точнее, какие виды политики можно внедрить, чтобы обеспечить суперлинейный рост ценности при росте организации?

Одна из наших любимых внутренних политик позволяет командам поддержки инфраструктуры безопасно вносить изменения в инфраструктуру. «Если в работе продукта есть сбои или другие проблемы после изменений в инфраструктуре, но их причины не выявлены тестами в системе непрерывной интеграции (CI, continuous integration), значит, эти причины не связаны с изменениями». Другими словами: «Если вам что-то понравилось, добавьте соответствующий тест в систему непрерывной интеграции». Мы называем это «правилом Бейонсе»13. С точки зрения масштабирования правило Бейонсе подразумевает, что сложные одноразовые специализированные тесты, которые не запускаются системой непрерывной интеграции, не нужно учитывать: инженер инфраструктурной команды может найти другую команду, добавившую код, и спросить, как этот код тестировать. Это удобно, когда в команде сто инженеров, но со временем нам пришлось расширить эту стратегию.

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

Пример: обновление компилятора

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

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

Самое сложное обновление компилятора за всю историю Google было проведено в 2006 году. На тот момент мы уже несколько лет имели в штате тысячи инженеров и не обновляли компиляторы около пяти лет. Большинство инженеров не имели опыта смены компилятора, а большая часть кода компилировалась только одной версией компилятора. Обновление стало трудной и утомительной задачей для (в основ­ном) добровольцев, которая в конечном итоге свелась к поиску коротких путей обхода изменений с проблемами адаптации14. Внедрение изменений происходило болезненно: многие проблемы, согласно закону Хайрама, проникли в кодовую базу и углубили его зависимости от конкретной версии компилятора, сломать которые было очень трудно. Инженеры пошли на риск и применили изменения, четко не представляя последствия и не зная правила Бейонсе и вездесущей системы непрерывной интеграции.

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

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

Мы выявили множество факторов, влияющих на гибкость кодовой базы.

Опыт

Мы знаем, как это сделать. Для некоторых языков мы провели сотни обновлений компиляторов на множестве платформ.

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

Благодаря регулярному обновлению версий нам приходится вносить меньше изменений. Для некоторых языков мы внедряем обновления компиляторов раз в 1–2 недели.

Согласованность

Объем кода, не прошедшего обновление, постоянно уменьшается, опять же благодаря регулярным обновлениям.

Осведомленность

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

Стратегия

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

Мы осознали не частоту или сложность обновления компилятора, а необходимость обновлений и проводим их с постоянным числом инженеров даже при постоянном росте кодовой базы16. Если бы мы решили, что эта задача слишком дорогостоящая и ее следует избегать в будущем, мы могли бы до сих пор использовать версию компилятора десятилетней давности и из-за упущенных возможностей оптимизации заплатить за вычислительные ресурсы на 25 % больше. А наша центральная инфраструктура могла бы подвергнуться значительным рискам безопасности, поскольку компилятор 2006 года, безусловно, не смягчил бы уязвимости упреждающего выполнения. Стагнация — это вариант, но не самый разумный.

Сдвиг влево

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

 

Рис. 1.2. Временная шкала процесса разработки

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

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

Компромиссы и затраты

Если вы умеете программировать, знаете, как долго будет служить ПО и как его поддерживать с увеличением штата инженеров, производящих и сопровождающих новые функциональные возможности, вам остается только научиться принимать правильные решения. Очевидно, что в программной инженерии, как и везде, хороший выбор ведет к хорошим результатам. Однако на практике эту истину легко упустить из виду. В Google неприемлема фраза: «Потому что я так сказал». В любом нашем обсуждении по любой теме участвуют человек, принимающий решения, и люди, не согласные с этими решениями. Наша цель — согласие, а не единогласие. Это нормально, и я привык слышать фразу: «Я не согласен с вашими метриками/оценками, но я понимаю, как вы могли прийти к такому выводу». В основе этого подхода лежит идея, что всему должна быть причина, а аргументы «просто потому», «потому что я так сказал» или «потому что все так делают» — это признаки плохих решений. Мы всегда должны уметь объяснить и обосновать выбор между затратами двух инженерных решений.

Что мы подразумеваем под затратами? Не только деньги, а сумму издержек, включающую любые или все следующие факторы:

• финансовые затраты (например, деньги);

• затраты ресурсов (например, процессорное время);

• затраты на персонал (например, инженерный труд);

• операционные издержки (например, стоимость принятых мер);

• издержки упущенных возможностей (например, стоимость непринятых мер);

• социальные издержки (например, влияние нашего выбора на общество в целом).

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

Затраты также зависят от предубеждений: стремления сохранить текущее положение дел, нежелания что-то потерять и др. Оценивая затраты, мы должны иметь в виду все перечисленные факторы. Здоровье организации — это не только наличие денег в банке, но также осознание ее сотрудниками своей ценности и продуктивности. В творческих и прибыльных областях, таких как программная инженерия, в первую очередь нужно оценивать не финансовые затраты, а затраты на персонал. Увеличение эффективности труда от того, что инженеры довольны, сосредоточены и вовлечены, требует контроля, потому что показатели сосредоточенности и продуктивности настолько изменчивы, что легко представить себе разницу от 10 до 20 %.

Пример: маркеры

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

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

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

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

• мы будем делать так, потому что обязаны (по требованиям законодательства или клиента);

• мы будем делать так, потому что это лучший вариант (как определено кем-то, наделенным правом решения), в чем можно убедиться, основываясь на текущих данных.

Решения не должны обосновываться фразой: «Мы будем делать так, потому что я так сказал»17.

Основа для принятия решений

Оценивая данные, мы используем два основных сценария:

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

• Некоторые величины незначительны или мы не знаем, как их измерить. Например, иногда «мы не знаем, сколько времени нужно инженерам». Работать с такими величинами иногда сложнее, чем «оценить затраты на разработку плохо спроектированного API» или «оценить влияние выбора продукта на общество».

В первом случае не должно быть недостатка в исходных данных. Любая организация, занимающаяся разработкой ПО, может и должна контролировать текущие затраты на вычислительные ресурсы, трудозатраты инженеров и др. Если вы не хотите публиковать точные суммы финансовых затрат, создайте таблицу для пересчета: какое количество процессоров стоит столько же, сколько стоит данный объем ОЗУ или данная пропускная способность сети.

Имея согласованную таблицу пересчета, каждый инженер сможет провести собственный анализ: «Если я потрачу две недели на преобразование связного списка в структуру с более высокой производительностью, то использую на 5 ГБайт больше оперативной памяти, но сэкономлю две тысячи процессоров. Стоит ли овчинка выделки?» Ответ на этот вопрос зависит не только от относительной стоимости оперативной памяти и процессоров, но и от затрат на персонал (две недели поддержки инженера-программиста) и стоимости упущенных возможностей (что еще этот инженер мог бы произвести за две недели?).

Выбрать решение во втором случае сложнее. Обсуждая трудноизмеримые величины, мы полагаемся на опыт, лидерство и прецедент и вкладываем средства в исследования, которые помогут количественно оценить то, что трудно поддается количественной оценке (глава 7). Главное, осознавать, что не все измеримо или предсказуемо, и подходить к решениям с осторожностью. Часто трудноизмеримые величины не менее важны, чем измеримые, но сложнее в управлении.

Пример: распределенная сборка

Рассмотрим пример сборки. Согласно ненаучным опросам в Twitter, 60–70 % разработчиков выполняют сборку ПО (даже большого и сложного) на локальном компьютере. Это стало предметом множества шуток, как в комиксе «Compiling» (https://xkcd.com/303). Сколько рабочего времени вы теряете в ожидании окончания сборки? Сравните это с затратами на использование чего-то вроде distcc в небольшой группе или с затратами на создание маленькой сборочной фермы для большой группы. Сколько недель/месяцев потребуется, чтобы эти затраты окупились?

Еще в середине 2000-х сборка (проверка и компиляция кода) в Google выполнялась исключительно на локальных компьютерах. Да, были огромные локальные компьютеры (позволяющие собирать Google Maps!), но с ростом кодовой базы время компиляции все росло и росло. Неудивительно, что увеличивались затраты на персонал (из-за потерянного времени), а также на ресурсы (из-за закупки более мощных локальных машин). Затраты на ресурсы были особенно заметны, поскольку большую часть времени высокопроизводительные машины простаивали. Мы посчитали неправильным вкладывать деньги в невостребованные ресурсы.

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

Итак, мы создали новую систему, внедрили ее в производство и ускорили процесс сборки для всех. Можно ли назвать это счастливым концом истории? Не совсем: со временем распределенная сборка стала замедляться, поскольку в граф сборки стали бесконтрольно проникать лишние зависимости. Раньше каждый отдельный инженер страдал от неоптимальной сборки, был заинтересован в ее ускорении и стремился что-то улучшить. Избавив инженеров от проблемы оптимизации процесса сборки, мы создали ситуацию, в которой потребление ресурсов вышло из-под контроля. Это было похоже на парадокс Джевонса18 (https://oreil.ly/HL0sl): потребление ресурса может увеличиться в ответ на повышение эффективности его использования.

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

Пример: выбор между временем и масштабированием

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

Но иногда время и масштабирование вступают в конфликт, и особенно четко это проявляется в базовом вопросе: лучше добавить зависимость или создать (заимствовать) новую ветвь, чтобы удовлетворить локальные потребности?

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

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

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

Пересмотр решений, совершение ошибок

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

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

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

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

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

Конечно нет. Мы не считаем, что программная инженерия лучше программирования. Это две разные предметные области с разными ограничениями, ценностями и методами. Мы осознаем, что некоторые инструменты хороши в одной области и непригодны в другой. Едва ли имеет смысл внедрять интеграционные тесты (глава 14) и непрерывное развертывание (continuous deployment, глава 24) в проект, который просуществует несколько дней. Точно так же наши достижения в области семантического управления версиями (SemVer) и управления зависимостями в программной инженерии (глава 21) не применимы к краткосрочным проектам, в которых можно смело использовать все, что доступно.

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

Заключение

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

Итоги

• «Программная инженерия» более широкое понятие, чем «программирование». Программирование — это создание кода. Программная инженерия добавляет к этому понятию обслуживание кода для увеличения срока его использования.

• Продолжительность жизни короткоживущего и долгоживущего кода может отличаться как минимум в 100 000 раз. Было бы неправильно полагать, что одни и те же практики применимы на обоих концах спектра.

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

• Закон Хайрама: при достаточно большом количестве пользователей API не имеет значения, что вы обещаете в контракте: любое наблюдаемое поведение системы будет зависеть от чьих-то действий.

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

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

• Опыт окупается особенно быстро в сочетании с экономией за счет масштабирования.

• «Потому что я так сказал» — это плохое обоснование решения.

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

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

2 Мы не имеем в виду «продолжительность выполнения», мы имеем в виду «продолжительность поддержки» — как долго код будет продолжать развиваться, использоваться и поддерживаться? Как долго это ПО будет иметь ценность?

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

4 Тут вполне уместен вопрос: как заранее узнать, что проект будет долгосрочным?

5 Сейчас трудно установить авторство определения: одни считают, что впервые оно было сформулировано Брайаном Рэнделлом (Brian Randell) или Маргарет Гамильтон (Margaret Hamilton), другие — что автором является Дейв Парнас (Dave Parnas). Это определение часто приводят как цитату из отчета «Software Engineering Techniques: Report of a conference sponsored by the NATO Science Committee», Рим, Италия, 27–31 октября 1969 г., Брюссель, отдел по научным вопросам, НАТО.

6Брукс Ф. Мифический человеко-месяц, или Как создаются программные системы. СПб.: Питер, 2021. — Примеч. пер.

7 Как заявляют в компании Appcelerator, «ничто в мире не определено, кроме смерти, налогов и короткого срока службы мобильных приложений» (https://oreil.ly/pnT2_, блог Axway Developer, 6 декабря 2012 года).

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

9 Надо признать, что сам Хайрам собирался назвать этот закон «законом неявных зависимостей», но в Google предпочли более краткое название «закон Хайрама».

10 См. комикс «Workflow» (http://xkcd.com/1172) на сайте xkcd.

11 Разновидность атак типа «отказ в обслуживании» (DoS, denial-of-service), при которых злоумышленник, зная внутреннюю организацию хеш-таблицы и особенности хеш-функции, может сформировать данные таким образом, чтобы снизить алгоритмическую производительность операций над таблицей.

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

13 Это отсылка к популярной песне «Single ladies», в которой рефреном звучит фраза: «If you liked it then you shoulda put a ring on it». («Если я тебе нравилась, так надел бы мне на палец колечко».)

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

15 Site Reliability Engineering. Надежность и безотказность, как в Google, глава 5 «Избавляемся от рутины». — Примеч. пер.

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

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

18https://ru.wikipedia.org/wiki/Парадокс_Джевонса.Примеч. пер.

13

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

18
17

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

14

Организация команды, состав проекта, а также стратегия и тактика его развития — важные компоненты программной инженерии, которые зависят от масштаба организации. Растет ли эффективность производства софта по мере увеличения организации и расширения ее проектов? Растет ли эффективность рабочего процесса по мере развития организации и насколько пропорционально этому растет стоимость стратегий тестирования и управления версиями? Проблемы масштаба, связанные с увеличением числа сотрудников и налаживанием коммуникации между ними, обсуждались с первых дней программной инженерии, начиная с появления мифического человеко-месяца6. Часто они имеют политический характер, и от их решения во многом зависят устойчивость ПО и ответ на вопрос: «Как дорого обойдется то, что придется делать снова и снова?»

Разновидность атак типа «отказ в обслуживании» (DoS, denial-of-service), при которых злоумышленник, зная внутреннюю организацию хеш-таблицы и особенности хеш-функции, может сформировать данные таким образом, чтобы снизить алгоритмическую производительность операций над таблицей.

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

См. комикс «Workflow» (http://xkcd.com/1172) на сайте xkcd.

Site Reliability Engineering. Надежность и безотказность, как в Google, глава 5 «Избавляемся от рутины». — Примеч. пер.

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

Это отсылка к популярной песне «Single ladies», в которой рефреном звучит фраза: «If you liked it then you shoulda put a ring on it». («Если я тебе нравилась, так надел бы мне на палец колечко».)

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

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

https://ru.wikipedia.org/wiki/Парадокс_Джевонса.Примеч. пер.

16

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

Мы не имеем в виду «продолжительность выполнения», мы имеем в виду «продолжительность поддержки» — как долго код будет продолжать развиваться, использоваться и поддерживаться? Как долго это ПО будет иметь ценность?

Сейчас трудно установить авторство определения: одни считают, что впервые оно было сформулировано Брайаном Рэнделлом (Brian Randell) или Маргарет Гамильтон (Margaret Hamilton), другие — что автором является Дейв Парнас (Dave Parnas). Это определение часто приводят как цитату из отчета «Software Engineering Techniques: Report of a conference sponsored by the NATO Science Committee», Рим, Италия, 27–31 октября 1969 г., Брюссель, отдел по научным вопросам, НАТО.

Тут вполне уместен вопрос: как заранее узнать, что проект будет долгосрочным?

Как заявляют в компании Appcelerator, «ничто в мире не определено, кроме смерти, налогов и короткого срока службы мобильных приложений» (https://oreil.ly/pnT2_, блог Axway Developer, 6 декабря 2012 года).

Брукс Ф. Мифический человеко-месяц, или Как создаются программные системы. СПб.: Питер, 2021. — Примеч. пер.

Надо признать, что сам Хайрам собирался назвать этот закон «законом неявных зависимостей», но в Google предпочли более краткое название «закон Хайрама».

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

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

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

11
10

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

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

Чтобы понять, как время влияет на программу, задумайтесь: «Как долго будет жить2 код?» Крайние оценки в ответах на этот вопрос могут отличаться в 100 000 раз. Легко представить код, который просуществует несколько минут, или другой код, служащий десятилетиями. Как правило, короткоживущий код не зависит от времени: едва ли нужно адаптировать утилиту, которая проживет час, к новым версиям базовых библиотек, операционной системы (ОС), аппаратного обеспечения или языков программирования. Недолговечные системы фактически являются «мимолетными» задачами программирования и напоминают куб, который сжат вдоль одного измерения до вида квадрата. Но с увеличением продолжительности жизни кода изменения становятся более важными для него. За десяток лет большинство программных зависимостей, явных или неявных, почти наверняка изменятся. Понимание этого явления помогает отличать программную инженерию от программирования.

15
12

Часть II. Культура

Глава 2. Успешная работа в команде

Автор: Брайан Фитцпатрик

Редактор: Риона Макнамара

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

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

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

Но не будем забегать вперед и начнем с наблюдения за обычным поведением инженеров-программистов.

Помоги мне скрыть мой код

За последние двадцать лет мы с моим коллегой Беном19 не раз выступали на разных конференциях по программированию. В 2006 году мы в Google запустили услугу хостинга для проектов с открытым исходным кодом (OSS, open source software) (в настоящее время не поддерживается) и получали много вопросов и просьб. Но примерно в середине 2008 года мы начали замечать определенную направленность запросов:

«Не могли бы вы добавить в поддержку Subversion в Google Code возможность скрывать определенные ветки?»

«Не могли бы вы добавить возможность создать проект с открытым исходным кодом, который изначально закрыт, а потом открывается, когда будет готов?»

«Привет, я хочу переписать весь свой код с нуля, не могли бы вы стереть всю историю?»

Заметили, что объединяет эти просьбы?

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

Миф о гениальности

Многие неосознанно творят себе кумира и поклоняются ему. Для инженеров-программистов это могут быть: Линус Торвальдс, Гвидо Ван Россум, Билл Гейтс — все они выдающиеся личности, изменившие мир. Линус в одиночку написал Linux, верно?

На самом деле Линус написал всего лишь начальную версию Unix-подобного ядра для проверки идей и опубликовал его код в списке рассылки. Безусловно, это большое и впечатляющее достижение, но оно было только началом. Современное ядро Linux в сотни раз больше той начальной версии и разрабатывается тысячами умных людей. Настоящее достижение Линуса в том, что он сумел взять на себя руководство этими людьми и скоординировать их работу. Linux — блестящий результат, но не его первоначальной идеи, а коллективного труда сообщества. (И ОС Unix была написана не только Кеном Томпсоном и Деннисом Ритчи, а группой умных людей из Bell Labs.)

Аналогично: разве Гвидо Ван Россум один создал весь Python? Да, он написал первую версию. Но в разработке последующих версий, реализации новых идей и исправлении ошибок принимали участие сотни других людей. Стив Джобс руководил командой, которая создавала Macintosh. И хотя Билл Гейтс известен тем, что написал интерпретатор BASIC для первых домашних компьютеров, его самым большим достижением стало создание успешной компании вокруг MS-DOS. Все они стали лидерами и символами коллективных достижений своих сообществ. Миф о гениальности — это общая тенденция, следуя которой мы, люди, приписываем успех команды одному человеку.

А что насчет Майкла Джордана?

Та же история. Мы идеализировали его, но он не сам выиграл каждый баскетбольный матч. Его истинная гениальность в том, как он взаимодействовал с командой. Тренер Фил Джексон был чрезвычайно умен, и его приемы стали легендарными. Он понимал, что один игрок никогда не выигрывает чемпионат, и поэтому собрал целую «команду мечты» вокруг Майкла. Эта команда работала как исправный механизм — играла столь же впечатляюще, как и сам Майкл.

Итак, почему мы постоянно стремимся найти кумира? Покупаем товары, одобренные знаменитостями, хотим купить платье, как у Мишель Обамы, или обувь, как у Майкла Джордана?

Тяга к известности — вот одна из причин. У людей есть естественный инстинкт находить лидеров и образцы для подражания, преклоняться перед ними и пытаться подражать им. Нам всем нужны герои для вдохновения, и в мире программирования тоже они есть. Феномен «технократической знаменитости» почти перетек в мифологию. Мы все хотим написать что-то, что изменит мир, как Linux, или спроектировать еще один потрясающий язык программирования.

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

• у вас возникает потрясающая новая идея;

• вы запираетесь в своем убежище на несколько недель или месяцев, создавая совершенное воплощение этой идеи;

• затем «выпускаете» в мир готовое ПО и шокируете всех своей гениальностью;

• ваши коллеги преклоняются перед вашим умом;

• люди выстраиваются в очередь, чтобы заполучить ваше ПО;

• слава и удача преследуют вас.

А теперь остановимся и посмотрим, что мы имеем в реальности. Вы, скорее всего, не гений.

Не обижайтесь! Конечно, мы верим, что вы очень умный человек. Но понимаете ли вы, насколько редки настоящие гении? Конечно, вы пишете код, и это сложный навык. Но даже если вы гений, этого для успеха недостаточно. Гении, как и все, делают ошибки, а блестящие идеи и редкие навыки программирования не гарантируют, что ваш софт станет хитом. Хуже того, вы можете обнаружить, что способны решать только аналитические проблемы, но не человеческие. Быть гением не означает быть «не от мира сего»: любой человек — гений он или нет — с плохими социальными навыками, как правило, является плохим партнером по команде. Для работы в Google (и в большинстве других компаний!) не требуется иметь гениальный интеллект, но точно требуется обладать минимальным уровнем социальных навыков. Взлет или падение вашей карьеры, особенно в такой компании, как Google, во многом зависит от того, насколько хорошо вы умеете сотрудничать с другими людьми.

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

Вот что однажды сказал мой друг:

«Я знаю, что КРАЙНЕ не уверен в людях, и опасаюсь показывать им что-то, что еще не закончено, как будто они осудят меня или подумают, что я идиот».

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

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

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

На самом деле — да, плохо. Мы утверждаем, что так работать — это неправильно, и это очень важно. И вот почему.

Сокрытие вредно

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

Подумайте сами: как, работая в одиночку, вы сможете понять, что выбрали верный путь?

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

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

Раннее выявление

Если вы скрываете свою прекрасную идею от мира и отказываетесь показывать что-либо кому-либо, пока реализация не будет отшлифована, вы фактически пускаетесь в авантюру. На ранней стадии разработки легко допустить фундаментальные ошибки. Вы рискуете заново изобрести колесо20. А также лишаетесь преимуществ совместной работы: обратите внимание, насколько быстрее продвигался сосед, сотрудничая с друзьями. Люди пробуют воду, прежде чем нырнуть: убедитесь, что движетесь в правильном направлении и ваш проект не был создан раньше. Шансы допустить ошибку в начале пути высоки. И чем больше отзывов вы получаете на ранних этапах, тем меньше рискуете21. Вспомните проверенную временем мантру: «Ошибки должны выявляться как можно раньше, как можно быстрее и как можно чаще».

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

Фактор автобуса

Фактор автобуса определяет, сколько участников проекта должно попасть под автобус, чтобы проект провалился.

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

Помимо фактора автобуса существует проблема общего темпа развития. Легко забыть, что работа в одиночку — это сложная задача, которая решается гораздо медленнее, чем хотелось бы. Как много вы узнаете, работая в одиночку? Как быстро вы движетесь к цели? Google и Stack Overflow являются отличными источниками мнений и информации, но они не могут заменить реальный человеческий опыт. Работа с другими людьми напрямую увеличивает коллективные знания. Когда вы остановились из-за абсурдной проблемы, сколько времени вы потратите, чтобы вытащить себя из ямы? Подумайте, насколько изменится ваш опыт, если пара коллег будет смотреть вам через плечо и сразу указывать на ошибки и варианты их устранения. Именно поэтому в компаниях, занимающихся разработкой ПО, члены одной команды часто сидят вместе (или даже занимаются парным программированием). Программирование — сложная наука. Программная инженерия — еще сложнее. Вам нужна эта вторая пара глаз.

кейс: инженеры и офисы

Двадцать пять лет назад считалось, что единственный способ работать над решением задачи, не отвлекаясь на посторонние дела, — иметь отдельный кабинет с закрытой дверью.

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

К сожалению, многие современные технологические компании (включая Google) качнули маятник в другую крайность. Зайдите в их офисы — и найдете сотни инженеров, сидящих вместе в огромных залах. В настоящее время ведутся жаркие споры о целесообразности опен-спейсов и, как следствие, растет неприятие их. Там, где самый малозначительный разговор становится публичным, люди перестают общаться, чтобы не раздражать соседей. Это так же плохо, как отдельные кабинеты!

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

Конечно, инженерам нужна возможность фильтровать шум. И они придумывали способы сообщить, что их не следует прерывать. Например, использовали протокол голосового прерывания — фразу «Прервись, Мэри», где Мэри — имя человека, с которым нужно поговорить. По возможности Мэри поворачивалась лицом и слушала. Если она была занята, то отвечала: «Не сейчас».

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

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

Темп развития

Еще одна аналогия. Вспомните, как вы используете компилятор. Тратите несколько дней, чтобы написать 10 000 строк кода, а затем нажимаете кнопку «компилировать». Так? Конечно нет. Представьте неприятные последствия такого подхода. Программисты увереннее работают, когда пишут код небольшими фрагментами, используя короткие циклы с обратной связью: написали новую функцию — скомпилировали, добавили тест — скомпилировали, выполнили рефакторинг участка кода — скомпилировали. Это позволяет быстро выявлять и исправлять опечатки и ошибки в коде. Компилятор нужен нам для проверки каждого маленького шага. Некоторые среды программирования могут даже компилировать код сразу после ввода. Современная философия DevOps, направленная на повышение продуктивности, четко говорит о целях: получать отзывы как можно раньше, тестировать как можно раньше и начинать думать о безопасности в продакшене как можно раньше. Все это связано с идеей «сдвига влево» в рабочем процессе разработчика и удешевлении устранения ошибки.

Короткий цикл обратной связи необходим не только на уровне кода, но и на уровне всего проекта. Амбициозные проекты развиваются быстро и должны адаптироваться к меняющимся условиям. Они могут сталкиваться с непредсказуемыми архитектурными ограничениями, политическими препятствиями или техническим несоответствием. Требования могут меняться неожиданно. Как обеспечить быструю обратную связь, чтобы вовремя узнавать, когда следует менять планы или решения? Ответ: работать в команде. Большинству инженеров известна истина: «Чем больше глаз, тем заметнее ошибки». Но ее можно перефразировать иначе: «Чем больше глаз, тем успешнее проект справляется с вызовами». Люди, работающие в затворничестве, рискуют однажды обнаружить, что мир изменился, и несмотря на полноту и правильность первоначальных представлений, проект стал неактуальным.

Проще говоря, не прячьтесь!

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

Не становитесь частью печальной статистики.

Весь секрет в командной работе

Итак, давайте оглянемся назад и соберем воедино все рассмотренные идеи.

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

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

Сформулируем эту идею проще: программирование — это командная работа.

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

Подумайте, сколько есть примеров широко используемого ПО, написанного одним человеком? (Кто-то вспомнит «LaTeX», но вряд ли этот продукт «широко используется», если только вы не считаете, что число людей, пишущих научные статьи, является статистически значимой частью всех пользователей компьютеров!)

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

Три столпа социального общения

Итак, если командная работа — лучший путь к созданию блестящего ПО, как создать (или найти) хорошую команду?

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

Столп 1: смирение

Вы не центр Вселенной (как и ваш код!). Вы не всезнающий и не безгрешный. Вы открыты для самосовершенствования.

Столп 2: уважение

Вы искренне заботитесь о тех, с кем работаете, относитесь к ним по-доброму и цените их способности и достижения.

Столп 3: доверие

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

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

Почему эти столпы так важны?

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

Вот цитата из известной лекции Ричарда Хэмминга (http://bit.ly/hamming_paper):

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

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

Смирение, уважение и доверие на практике

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

Усмирите свое эго

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

Скромным быть важно, но это не значит, что можно показывать слабину — в уверенности в себе нет ничего плохого. Просто не стройте из себя всезнайку. Думайте о «коллективном» эго — старайтесь поддерживать командный дух и коллективную гордость. Например, Apache Software Foundation имеет долгую историю создания сообществ вокруг программных проектов. Эти сообщества отличает невероятно сильное самосознание: они отвергают людей, озабоченных саморекламой.

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

«Джон Тьюки почти всегда одевался очень небрежно. Когда он приходил в офис, руководители не сразу понимали, что перед ними первоклассный специалист, к мнению которого стоит прислушаться. Джон тратил много времени и сил на преодоление такого неприятия! Я не говорю, что вы должны соответствовать окружению, но обращаю ваше внимание, что “видимость соответствия здорово помогает”. Если вы будете утверждать свое эго, заявляя: “Это будет по-моему”, то будете расплачиваться за это на протяжении всей своей карьеры. И в других сферах жизни это будет приводить к огромному числу ненужных неприятностей. <...> Столкнувшись с необходимостью использовать систему и изучая возможные способы заставить систему делать вашу работу, вы учитесь менять систему под себя. В противном случае вам придется бороться с ней постоянно и всю свою жизнь вести маленькую необъявленную войну».

Учитесь критиковать и принимать критику

Несколько лет назад Джо устроился на новую работу программистом. Спустя неделю он начал копаться в кодовой базе. Его заинтересовало, какой вклад в код внес каждый член команды. Он стал отправлять им простые обзоры кода по электронной почте, вежливо спрашивая о проектных решениях или указывая места, где можно улучшить логику. Через пару недель его вызвали в кабинет директора. «В чем проблема? — спросил Джо. — Я сделал что-то неправильно?» «У нас было много жалоб на ваше поведение, — сказал директор. — По-видимому, вы были очень резки по отношению к своим товарищам по команде, критикуя их налево и направо. Они расстроены. Вам следует быть вежливее». Джо был совершенно сбит с толку. Конечно, он думал, что коллеги оценят и с радостью примут его обзоры кода. Однако Джо должен был проявить большую осторожность и уважительность к членам команды и использовать более тонкие средства для внедрения код-ревью в культуру — возможно, предварительно обсудить идеи с командой и предложить попробовать новый подход в течение нескольких недель.

В профессиональной среде программной инженерии критика почти никогда не бывает личной — обычно она просто является частью процесса улучшения проекта. Хитрость в том, чтобы убедиться, что вы (и те, кто вас окружает) понимаете разницу между конструктивной критикой творческих результатов и откровенным оскорблением чувств. Последнее — мелочно и недейственно. Первое может (и должно!) быть полезным, если содержит рекомендации по улучшению. И самое главное, конструктивная критика проникнута уважением: человек, выступающий с такой критикой, искренне заботится о других и хочет, чтобы они совершенствовали себя или свой труд. Научитесь уважать своих коллег и вежливо подавать конструктивную критику. Если вы действительно уважаете кого-то, у вас будет мотивация выбирать тактичные и понятные формулировки — навык, приобретаемый с опытом (глава 9).

С другой стороны, нужно учиться принимать критику. Не только скромнее оценивать свои навыки, но и верить, что в глубине души коллеги действуют в ваших интересах (и в интересах проекта!) и на самом деле не считают вас умственно отсталым. Программирование — это обычный навык. Если коллега указал вам пути улучшения мастерства, разве вы воспримете это как оскорбление и принижение вашего достоинства? Надеемся, что нет. Точно так же ваша самооценка не должна быть связана с кодом, который вы пишете, или любым творческим проектом, над которым вы работаете. Вы — это не ваш код: повторяйте это снова и снова. Вы — это не то, что вы делаете. Поверьте в это сами и заставьте коллег считать так же.

Например, если у вас есть неуверенный в себе коллега, вам точно не следует говорить ему: «Дружище, ты совершенно неправильно понял поток управления в этом методе. Ты должен использовать стандартный шаблон xyzzy, как и все остальные». Так поступать не следует: говорить человеку, что он «не прав» (как если бы мир был черно-белым), требовать изменений и заставлять его чувствовать себя хуже других. Коллега вне всяких сомнений обидится, и его реакция наверняка окажется чрезмерно эмоциональной.

То же самое можно сказать более тактично: «Знаешь, меня смущает поток управления в этой части. Интересно, сможет ли применение шаблона xyzzy сделать его понятнее и проще в поддержке?» Обратите внимание, как в этом случае проявляется смирение, как акцент ставится на себе, а не на собеседнике. Вы утверждаете, что не коллега ошибся, а вы не поняли код. Этой фразой вы предлагаете лишь прояснить ситуацию для вас, что, возможно, поспособствует достижению цели устойчивого развития проекта в долгосрочной перспективе. Вы также ничего не требуете — даете коллеге возможность мирно отклонить предложение. Обсуждение сосредоточено на коде, а не на чьих-то умственных способностях или навыках.

Получив отрицательный результат, повторите попытку

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

«Что это?» — спрашивает директор.

«Мое заявление об уходе, — говорит менеджер. — Полагаю, вы вызвали меня, чтобы уволить».

«Уволить? Вас? — отвечает директор недоверчиво. — Зачем мне вас увольнять? Я только что заплатил 10 миллионов долларов за ваше обучение!»24

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

Один из наших любимых девизов в Google: «Неудача — тоже вариант». Как известно, «не ошибается тот, кто ничего не делает» и «кто не рискует, тот не пьет шампанское». Неудача — это прекрасная возможность учиться и совершенствоваться25. На самом деле Томас Эдисон часто повторял: «Если я попробую 10 000 способов, которые не сработают, я не потерплю неудачу. Я не отчаюсь, потому что каждая неудачная попытка — это еще один шаг вперед».

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

Культура подробного анализа причин неудачи

Извлечению уроков из ошибок главным образом способствует документирование неудач с помощью анализа основных причин и описания «результатов вскрытия» проблем (как это называют в Google и многих других компаниях). Будьте особенно внимательны: документ с описанием результатов вскрытия не должен быть бесполезным списком оправданий — он должен содержать объяснение причин проблем и план дальнейших действий и быть доступным всем, чтобы команда действительно следовала предложенным изменениям. Правильное документирование ошибок помогает сохранить понимание того, что произошло, и избежать повторения истории. Не стирайте следы — освещайте их, как взлетно-посадочную полосу, для тех, кто следует за вами!

Хорошее описание результатов вскрытия должно включать:

• краткое описание события;

• историю развития события от его обнаружения до расследования и получения выводов;

• основную причину события;

• оценку влияния события и ущерба;

• перечень действий и мероприятий, предпринятых для немедленного исправления проблемы;

• перечень действий и мероприятий, направленных на предотвращение повторения события;

• уроки и выводы.

Учитесь терпению

Несколько лет назад я работал над инструментом для преобразования репозиториев CVS в Subversion (а позже в Git). Из-за капризов CVS я все время натыкался на странные ошибки. Поскольку мой давний друг и коллега Карл хорошо знал CVS, мы решили поработать вместе и исправить эти ошибки.

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

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

Будьте открыты для сотрудничества

Чем больше вы открыты для сотрудничества, тем выше ваша способность влиять на других и тем сильнее вы кажетесь. Это заявление выглядят противоречивым. Но практически каждый может вспомнить коллегу-упрямца — кто бы что ему ни говорил, он еще больше запирался в своем упрямстве. Что в итоге происходит с такими членами команды? Люди перестают прислушиваться к их мнению или возражениям, начинают «обходить» таких коллег как препятствие, от которого никуда не деться. Вы наверняка не захотите быть таким человеком, поэтому помните: это нормально, когда кто-то хочет вас переубедить. В первой главе этой книги мы говорили, что инженерия — это компромиссы. Нельзя быть правым во всем и всегда, если у вас нет неизменного окружения и совершенных знаний. Поэтому вы должны менять свою точку зрения, когда вам представят новые доказательства. Тщательно расставляйте свои приоритеты: чтобы быть услышанным, сначала выслушайте других. Соберите аргументы коллег, прежде чем остановить обсуждение и твердо объявить свое решение, — если вы будете постоянно колебаться, меняя свою точку зрения, люди подумают, что вы слабовольный и нерешительный.

Идея уязвимости может показаться странной. Если кто-то признается в своем незнании рассматриваемой темы или путей решения проблемы, на какое доверие он может рассчитывать? Уязвимость — это проявление слабости, которое разрушает доверие, верно?

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

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

Действовать по-гугловски

У нас в Google есть собственная внутренняя версия принципов «смирения, уважения и доверия».

С самого начала существования нашей культуры мы называли действия «по-гуг­ловски» (googley) или «не по-гугловски». Ни в одном словаре вы не найдете это слово, но оно означает «не будь злым», «поступай правильно» или «будь добр к другим». Со временем мы начали использовать термин «по-гугловски» как неформальный признак соответствия нашей культуре у кандидатов на должность инженера или у коллег. Люди часто выражают мнение о других, используя этот термин, например «человек пишет хороший код, но действует не совсем по-гугловски».

В конце концов, мы поняли, что термин «по-гугловски» перегружен смыслом и может стать источником неосознанной предвзятости при найме или оценке работы. Если для каждого сотрудника выражение «по-гугловски» будет означать что-то свое, есть риск свести его к «совсем как я». Очевидно, что это не лучший тест для найма новых сотрудников — мы не хотим нанимать людей, которые «совсем как мы», нам нужны люди из разных слоев общества, с разными мнениями и опытом. Личное желание интервьюера выпить пива с кандидатом (или коллегой) никогда не должно рассматриваться как признак, что кто-то является хорошим кандидатом или сотрудником и сможет добиться успеха в Google.

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

Развитие в неопределенности

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

Бережное отношение к обратной связи

Умение уважительно принимать критику и давать обратную связь и понимание ценности обратной связи для личного (и командного) развития.

Стремление изменить текущее положение вещей

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

Пользователь прежде всего

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

Заботливое отношение к команде

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

Правильные поступки

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

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

Заключение

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

Итоги

• Помните о недостатках работы в изоляции.

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

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

19 Бен Коллинз-Сассмэн, один из авторов этой книги.

20 В прямом смысле, если вы конструируете велосипед.

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

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

23 Это невероятно сложно, если в прошлом вы погорели, передав управление некомпетентным людям.

24 В интернете можно найти десятки вариантов этой легенды, приписываемых разным знаменитым менеджерам.

25 Если вы снова и снова продолжаете делать одно и то же и раз за разом терпите неудачу, то это не неудача, а некомпетентность.

20
25
24
19
21
23
22

Бен Коллинз-Сассмэн, один из авторов этой книги.

Это невероятно сложно, если в прошлом вы погорели, передав управление некомпетентным людям.

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

Если вы снова и снова продолжаете делать одно и то же и раз за разом терпите неудачу, то это не неудача, а некомпетентность.

В интернете можно найти десятки вариантов этой легенды, приписываемых разным знаменитым менеджерам.

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

В прямом смысле, если вы конструируете велосипед.

Глава 3. Обмен знаниями

Авторы: Нина Чен и Марк Баролак

Редактор: Риона Макнамара

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

Сложности в обучении

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

Отсутствие чувства психологической безопасности

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

Информационные островки

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

Фрагментация информации

Каждый островок представляет лишь часть общей картины.

Дублирование информации

На каждом островке изобретается свой способ решения одной и той же задачи.

Информационный перекос

На островках по-разному используется одно и то же решение.

Единая точка отказа (ЕТО)

Узкое место, возникающее, когда важная информация поступает только от одного человека (вспомните фактор автобуса (https://oreil.ly/IPT-2) из главы 2).

Она может появиться из самых благих намерений вроде предложения «давай я сделаю это вместо тебя» и давать кратковременное увеличение эффективности («так быстрее») в ущерб долгосрочной перспективе развития (команда не учится выполнять работу). ЕТО приводит к победе принципа «все или ничего».

Принцип «все или ничего»

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

Попугайство

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

Кладбища с привидениями

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

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

Философия

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

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

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

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

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

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

Создание условий: психологическая безопасность

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

Чтобы учиться, вы должны сначала осознать, что есть что-то, чего вы не понимаете. Мы должны приветствовать такую честность (https://xkcd.com/1053), а не наказывать ее. (В Google эта работа поставлена довольно хорошо, но иногда инженеры не хотят признавать, что они чего-то не понимают.)

Значительная часть обучения — это способность пробовать что-то и чувствовать себя в безопасности. В здоровой среде люди чувствуют себя комфортно, задают вопросы, ошибаются и приобретают новые знания. Исследование в Google (https://oreil.ly/sRqWg) показало, что психологическая безопасность является самым важным условием создания эффективной команды.

Наставничество

Мы в Google стараемся задать тон общения, когда к компании присоединяется «нуглер» (новый гуглер). Чувство психологической безопасности мы создаем с помощью назначения наставника — человека, который не является членом команды, менеджером или техническим руководителем, в обязанности которого входит отвечать на вопросы и оказывать помощь нуглеру. Наличие официально назначенного наставника для обращения за помощью облегчает новичку работу и избавляет его от страха, что он может отнимать время у коллег.

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

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

Психологическая безопасность в больших группах

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

Самый действенный способ создать такую безопасную и гостеприимную среду — заменить состязательность групп их сотрудничеством. В табл. 3.1 приведены некоторые примеры рекомендуемых паттернов (и соответствующих им антипаттернов) групповых взаимодействий.

Эти антипаттерны могут возникать непреднамеренно: кто-то, возможно, пытается помочь, но случайно проявляет снисходительность и неприветливость. Мы считаем, что здесь уместно перечислить социальные правила сообщества Recurse Center (https://oreil.ly/zGvAN):

Никакого притворного удивления («Что?! Я не могу поверить! Ты не знаешь, что такое стек?!»)

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

Никаких «на самом деле»

Скрупулезные исправления, которые, как правило, связаны с игрой на публику, а не с точностью.

Никаких подсказок из задних рядов

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

Никаких «-измов» («Это так просто, что даже моя бабушка справилась бы!»)

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

Таблица 3.1. Паттерны групповых взаимодействий

Рекомендуемые паттерны (сотрудничество)

Антипаттерны (состязательность)

Простые вопросы или ошибки правильно воспринимаются и находят ответы и решения

К простым вопросам или ошибкам придираются, и человек, задавший вопрос, наказывается

Объяснения направлены на обучение человека, задавшего вопрос

Объяснения направлены на демонстрацию своих знаний

На вопросы даются полезные ответы с терпением и доброжелательностью

Ответы даются свысока, в язвительной и неконструктивной форме

Взаимодействия принимают форму общего обсуждения для поиска решений

Взаимодействия принимают форму спора между «победителями» и «проигравшими»

Расширение знаний

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

Задавайте вопросы

Главный урок этой главы: постоянно учитесь и задавайте вопросы.

Мы говорим нуглерам, что на раскачку может уйти до шести месяцев. Этот длительный период необходим для освоения большой и сложной инфраструктуры Google, но он также подтверждает идею о том, что обучение — это непрерывный итеративный процесс. Одна из самых больших ошибок, которую допускают новички, — не просят помощи в сложной ситуации. Возможно, вам нравится преодолевать проблемы в одиночку или вы боитесь, что ваши вопросы «слишком просты». «Я должен попробовать решить проблему сам, прежде чем просить о помощи», — думаете вы. Не попадайтесь в эту ловушку! Часто ваши коллегия являются лучшим источником информации: используйте этот ценный ресурс.

Не заблуждайтесь: день, когда вы вдруг обнаружите, что знаете все, не наступит никогда. Даже у инженеров, годами работающих в Google, возникают ситуации, когда они не знают, что делать, и это нормально! Не бойтесь говорить: «Я не знаю, что это такое, не могли бы вы объяснить?» Относитесь к незнанию как к области возможностей, а не страха28.

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

Моделировать такое поведение особенно важно для тех, кто играет руководящую роль: важно не приравнивать «руководство» к «знанию всего». На самом деле чем больше вы знаете, тем больше понимаете, что ничего не знаете (https://oreil.ly/VWusg). Открыто задавая вопросы29 или показывая пробелы в знаниях, вы подтверждаете, что для других это тоже нормально.

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

Вникайте в контекст

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

Рассмотрим принцип «забора Честерсона» (https://oreil.ly/Ijv5x): перед тем как удалить или изменить что-то, сначала разберитесь, зачем это «что-то» здесь находится.

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

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

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

Масштабирование вопросов: вопросы к сообществу

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

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

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

Групповые чаты

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

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

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

Списки рассылки

Для большинства тем в Google есть список рассылки topic-users@ или topic-discuss@ в Google Groups, к которому может присоединиться любой сотрудник компании. Вопросы в общедоступной рассылке задаются так же, как в групповом чате: их видят множество людей, знающих и не знающих ответ. В отличие от групповых чатов, общедоступные списки рассылки распространяют информацию среди более широкой аудитории: они упакованы в архивы, лучше структурированы и предусматривают возможность поиска. В Google списки рассылки также индексируются и их легко найти с помощью Moma — поисковой системы во внутренней сети Google.

После получения ответа на вопрос может возникнуть соблазн немедленно продолжить работу. Не торопитесь! Возможно, в будущем кому-то пригодится полученная вами информация (https://xkcd.com/979), поэтому опубликуйте ответ в списке рассылки.

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

Электронная почта в Google

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

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

YAQS: система вопросов и ответов

...