Blameless environment: никто не должен писать качественный код
На РИТ++ Никита Соболев (sobolevn) выступил, как он сам назвал это, с проповедью на тему качества кода и процессов в компании. Особо впечатлительных просим налить себе ромашкового чаю, но отойти от экранов не предлагаем. Вы можете не соглашаться ни с одним из тезисов, настаивать, что трёп о сериалах — залог здоровой атмосферы в коллективе, и утверждать, что вам не нужны строгие рамки линтера и CI, чтобы писать хороший код. Но если вы хоть раз винили окружающих в неудачах на работе, вам стоит прочитать или посмотреть рассказ Никиты.
Работали ли вы когда-нибудь на плохой работе?
Я работал и долго. Моя компания была ужасна. Все было очень плохо, за что ни возьмись — все из рук вон. У нас были отвратительные процессы, ненавистные клиенты и неумелые разработчики. С этим ничего нельзя было поделать. Когда все так плохо, просто не знаешь, за что взяться, с чего начать. Чувствуешь себя жалким винтиком, который не может ни на что влиять.
Когда я говорю, все плохо, я имею в виду, что у нас был:
- плохой код — никто не думал о качестве кода, никто не мог даже сформулировать, что такое качество кода.
- плохие процессы.
- мы не могли нормально общаться,
- мы не делали то, что хотел клиент.
Да, это была аутсорс-разработка, но не это делало её плохой. Люди сделали ее такой.
«Люди делают плохой работу, это люди виноваты в том, что процессы плохие, код некачественный и клиенты вредные» — эта мысль терзала меня на протяжении многих лет. Люди виноваты в том, что я не получаю удовольствия от своей работы.
Я списывал на людей все возможные грехи и думал, что они основной источник проблем. Я надеялся, когда-нибудь они изменятся, либо появятся другие, и все станет хорошо.
На полном серьезе я думал о том, что в других компаниях работают принципиально другие люди, которые отличаются по своим внутренним качествам и профессионализму, и что эти другие люди из другого теста.
Но в какой-то момент я начал догадываться, что, возможно, и не люди виноваты — возможно, ошибка на другом уровне, где-то что-то пошло не так сильно раньше. И тогда появляется путь к исправлению. Только тогда можно спасти себя, как разработчика.
Я понял — нужна революция, нужно, чтобы все изменилось: то, как я работаю, как я себя ощущаю, чтобы поход на работу не становился для меня испытанием. Я хотел работать в хорошем месте.
Проблема была только одна — это была моя компания.
Я тот человек, который начал эту революцию.
Я понял, что нужно поменять все, чтобы снова получать удовольствие от любимого дела. Я люблю программировать, готов заниматься им по 12 часов в день и называю его своим отдыхом и своей работой.
Поэтому все неудачи я воспринимал очень болезненно. Мало того, что они были связаны с моим любимым делом, они были связаны с моими финансами, с моим самоощущением и отношениями с другими людьми и сильно отражались на всей моей жизни. Когда у меня что-то не получалось на работе, я не мог отдыхать, не мог ни о чем другом думать.
Я решил, что самое важное, что я могу сделать сейчас для того, чтобы улучшить свою жизнь –сделать свою работу хорошо. Для это мне нужно было переосмыслить весь тот хаос, который у нас был, и внести в него порядок.
Но когда смотришь в хаос, не видно закономерностей — ничего, что бы указывало на то, как должно быть.
Создать порядок из хаоса — это акт творения, который дается тяжело.
Нужно начать с самого-самого начала, чтобы понять, когда все полетело в хаос. Нужно определить новый порядок и объяснить себе, что нужно делать. Это красивые слова: «Давайте все делать хорошо!». Но ты приходишь на работу и на самом деле не понимаешь, за что браться, чтобы все изменить, нет никаких идей.
Полученное образование и прочитанные книжки не помогают, потому что все, что ты делал до этого, ты почерпнул из этих книжек и из этого образования.
Постановка задачи
Тогда я задумался —, а в чем же самая большая проблема? Где самая больная точка, которая не дает жить и работать? Я понял, что это постановка задачи. Для меня постановка задачи всегда была достаточно необязательным делом.
Думаю, многие из вас видели задачку из одного заголовка «Поправить баг на проде». У нас было много таких, я их писал одной строкой, а потом люди делали что-то не то и пытались исправить не так. Я думал: «Почему же они не думают своей головой? Что вы вообще делаете? Нужно поправить простой баг, а не делать всю эту ерунду».
Тогда я не осознавал, что действительно плохо ставлю задачи. Но в какой-то момент я все-таки понял, что нужно делать это абсолютно по-другому, и выработал несколько принципов.
Задачи должны быть короткие. Не в плане описания, как «поправить баг на проде», но короткие по своей сути. Короткие, маленькие задачи удобно делать. Они понятны любому: новичку, среднему, опытному разработчику. Каждый может понять такую задачу и сделать, например, за половину рабочего дня. Можно начать с этого.
Задачи должны быть упорядоченные. Когда ставят задачи, часто не думают, в каком порядке их нужно сделать. Но задачи могут блокировать друг друга, параллелиться или добавлять дополнительную сложность другим задачам, если выполнены вперед, и т.д.
Про упорядоченность задач говорят очень мало: заносят их в Jira или Trello, а потом берут оттуда. Но немногие задумываются, а в каком порядке, почему и зачем порядок именно такой.
Все задачи должны быть индивидуальными. Что это значит? Задачи — это сущности, которые существуют в рамках проекта и всегда кому-то принадлежат. Иногда прямо в описании задачи можно встретить: «Сергей, Маша, пожалуйста, поправьте это. Вы знаете, как это сделать». Так делать нельзя, нужно дать весь контекст, чтобы эта задача стала индивидуальной внутри себя, чтобы любой человек, который ее прочитал, мог ее выполнить. Чтобы не было никаких разрозненных знаний, разбросанных по проекту, и не было никаких скрытых смыслов в рамках этой задачи.
Когда задачи стали индивидуальными, короткими и упорядоченными, люди начали делать их так, как я хочу.
Просто поменяв способ общения, я добился того, что те самые люди, которые до этого делали ерунду, стали делать то, что я хочу — это ли не магия? Это ли не доказательство того, что очень многое легко изменить. И я начал углубляться в этот вопрос дальше.
Мы часто подводили заказчика, делали не то, что принесло бы ему пользу. Я подумал, что если разработчики стали понимать наши задачи и делать их как надо, могут ли они понять, чего на самом деле хочет заказчик, и сделать так, как хочет заказчик?
Я попытался соединить это в некую двуличную фигуру, которая с одной стороны мыслит, как разработчик, с другой стороны — как клиент.
Это задача не новая. В целом такой подход называется Domain-Driven Design и успешно применяется на протяжении многих лет. Я решил взять лучшее — способ общения, инструментарий, технологии, и постараться сделать так, что разработчики стали понимать, что нужно сделать, чтобы удовлетворить желания клиента.
Задача оказалась очень непростой, и я до сих пор работаю над ее решением. Но я выработал для себя простую формулу.
Требования. С них все начинается, заказчик изъявляет свою волю нам, разработчикам, в виде требований. Клиент условно говорит: «Требую, чтобы страница логина работала». Начинается их осознание, расписывание в виде таблиц, списков, графиков и т.д. Требования остаются с тобой как самая главная часть твоего проекта. Это то, что ты делаешь на самом высоком уровне.
Но эти требования не операбельны для разработчика, они слишком высокоуровневые и сырые. Чтобы начать работать, программисту нужна документация.
Документация и требования — это близнецы-братья, это двуединство. Требования — это ЧТО нужно сделать, а документация — КАК это делать.
Когда я понял, что в принципе из требований можно генерировать документацию, это стало важной частью нашего бизнес-процесса. Мы научились записывать требования в специальном формате и формировать документацию.
Тесты. Следующий логичный шаг — проверить, что это работает. Мы стали тестировать наши требования, чтобы убедиться, что делаем действительно что нужно.
Самое интересное, что я ничего не изобрёл — не написал ни одной строчки кода для того, чтобы это стало работать. Я просто взял существующие технологии и получил: требования, они же документация, они же тесты.
Следующим логичным шагом было натянуть на все это дело код, потому что код — это то, чем мы непосредственно занимаемся.
Код — ради чего все собственно и затевается. Для того чтобы заказчик и разработчик соединились, казалось бы, нужно залезть одному из них в голову и сделать так, чтобы они поняли друг друга. Но чтобы залезть в голову, можно взять те же инструменты и соединить их так, чтобы разработчик начал понимать, что происходит. Здесь можно прочитать, как я это делаю на практике.
Как только мы объединили (Код един!) разработчиков и заказчика при помощи таких хитроумных переплетений разных сущностей, мы добились очень важного: наши разработчики наконец-то стали делать то, что нужно бизнесу. Они перестали внедрять что-то просто так, потому что видели требования и понимали их, понимали, что нужно сделать.
Чтобы убедиться в выполнении, у нас есть тесты, которые написаны в виде требований, и эти требования достаточно понятны, чтобы реализовать их понятным языком в коде, и писать хороший код по этим требованиям.
Общение
Я уже очень много раз упоминал «общение». Я люблю общаться со своими друзьями и семьей, но не на работе. На работе я вынужден общаться с людьми — я их не выбирал по этому признаку. Очень часто общение на работе не помогает.
Мы все общаемся с коллегами на нерабочие темы (обсуждаем сериалы и пр.), потому что мы — люди. Этот недостаток, к счастью, исправим. Для того чтобы понять, насколько на самом деле общение губительно для нас, можно посмотреть на разные примеры.
Прежде всего, люди отвлекают друг друга и вырывают из состояния потока. Человек просто подошел и что-то рассказал — что мне теперь с этим делать? Зачем он мне это сказал, что хотел этим донести?
Или митинги. Я их ненавижу, всегда чувствую себя идиотом, когда сижу на митингах. Все вроде бы что-то понимают, у них умные лица, а я один скучаю и думаю, когда же уже это закончится. Мне хочется уйти, потому что все, что мы обсуждаем, можно обсудить гораздо быстрее.
Митинги крадут огромное количество времени и не приносят пользы.
Есть еще несколько важных проблем, например, люди начинают ругаться на этих митингах. Представьте, что вас поселили в маленькую комнатку, набитую людьми, которых вы не очень хотите видеть. Вы хотите оттуда уйти, а эти люди заставляют вас принимать какие-то серьезные решения. Вполне естественно начинается ругань — сначала пассивная агрессия, потом явные оскорбления. К сожалению, с этим ничего нельзя сделать, потому что люди — существа конфликтные. Как бы ты не пытался модерировать ситуацию, как бы не подбирал хороших людей, которые не ругаются — люди будут ругаться, и это нормально.
В нашем бизнесе есть еще одна проблема — люди пропадают. Ваш фронтендер или девопс легко может в один прекрасный день перестать отвечать. Особенно люди, которые работают удаленно, могут просто выключить телефон и закончить общение в одностороннем порядке.
Эти и некоторые другие проблемы кажутся неразрешимыми. Нельзя научить всех людей быть хорошими, неконфликтными, ответственными — это просто невозможно.
Но с этим можно жить. Будучи реалистом, можно понять, что жизнь такая: люди будут исчезать, ругаться, не хотеть с тобой общаться — это нормально. Я решил эту проблему следующим образом — структурировал общение.
Чтобы структурировать общение, достаточно сделать два шага:
- Зайти в Telegram прямо сейчас и удалить его. Как только ты удалишь все свои страницы в социальных сетях, люди не смогут тебе написать.
- После этого завести один канал и сказать, что с тобой можно общаться только так.
Когда ты находишься в позиции, что можешь диктовать свою волю другим людям, ты учишь их общаться. Показываешь, что общение должно быть структурировано и полезно для всех участников.
Мы выбрали общение через GitLab. Если у тебя возник вопрос — задай его в GitLab. Если хочешь задать какой-нибудь странный вопрос, задай его там. Если поймешь, что нет места, где можно задать такой вопрос, возможно, его и не надо задавать.
Мы общаемся только на рабочие темы. Если кто-то хочет обсудить «Игру престолов» — извини, мы работаем, а «Игру престолов» обсуждай со своими друзьями. Если хочешь обсудить новую технологию, создай тикет, давай ее обсудим: возможно, она принесет пользу проекту. Но «Игра престолов» точно не принесет пользы проекту.
Структурированное общение делает разных людей одинаковыми. У GitLab даже аватарки все примерно одинаковые — у одного буква K, у другого C, и я не знаю, кто эти люди. Мне все равно, какие они, главное — они общаются в рамках структуры.
После того, как мы структурировали общение, наладили работу с заказчиком, научились писать понятные тикеты, самое время взяться за код.
Код
И тут подстерегает новая проблема — люди не умеют писать код, и это нормально. Я раньше думал, что остальные пишут плохой код, а я хороший. Но потом понял, что и сам пишу плохой код. А еще через некоторое время до меня дошло, что все люди пишут плохой код, и это нормально.
Люди созданы не для того, чтобы писать код. Программирование — агрессивная среда, к которой человек не предрасположен. В коде много сложного: архитектура и огромный объем информации. В распределенных системах так и вообще ужас. Человеку трудно справиться с потоком информации. И это нормально.
Но раз так, с этим можно что-то делать и научиться работать именно в этих условиях.
Для того, чтобы с этим работать, нужна строгость — CI и тесты, которые будут максимально строги к тому, что ты делаешь. Это должен быть Страшный Суд — инструмент, который ответит на вопрос, хороший код или плохой. Только взглянув на него, всевидящее око CI скажет, попадет ли твоя работа в master или так и останется где-то на stage.
Такой CI, естественно, должен быть неотвратим. Как только кто-то получает исключительное право коммитить в master, все попытки построить процессы разваливаются, потому что этот кто-то начинает делать всякую ерунду.
Неотвратимый и строгий CI дает еще несколько классных возможностей. Это возможность развиваться, потому что теперь есть базовая планка, от которой можно отталкиваться: каждый следующий кусочек кода лучше предыдущего. Каждый следующий кусочек кода повышает ценность проекта и улучшает CI. Каждый следующий кусочек кода — шаг в сторону развития.
Как только фундамент готов, можно двигаться дальше.
Но люди все равно будут совершать ошибки, потому что никаким CI, даже настроенным самым строгим образом, невозможно отловить все ошибки. И они будут появляться в таких местах, про которые никто другой даже не подумает.
Что можно с этим сделать? Можно вернуться к обычной тактике и говорить: «Ты сделал ошибку, исправь ее. Ты написал плохой код — иди научись писать код». Это плохой путь, который не ведет к развитию.
Для того чтобы действительно писать правильно и развивать свой продукт, нужен новый подход и новая ментальность.
Blameless environment
Я назвал этот подход Blameless environment — это значит, что я никогда ни в чем не виню людей. Если баг попал в ваш проект, это проблема проекта. Этот баг должен быть поправлен так, чтобы он больше никогда не случился. Если это баг в коде, нужно написать регрессионный тест. Если это баг в инфраструктуре проекта, нужно написать инструмент, который этот баг предотвратит.
Когда начинаешь не просто фиксить баги и надеяться, что все не развалится на продакшене, но исправляешь их на системном уровне, начинаешь творить и созидать — создавать новые инструменты, вырабатывать новые подходы и архитектурные паттерны. Ты начинаешь думать головой и делать так, чтобы баги не повторялись.
Постоянная работа над ошибками выводит разработчика на принципиально другой уровень. Ты начинаешь изобретать инструменты для разработчиков, внедрять их, продвигать и т.д.
Созидание, о котором я сейчас говорю, масштабно. Когда вы попытаетесь использовать этот подход, то столкнетесь с тем, что все, что сейчас существует, особенно для некоторых языков программирования, недостаточно строгое.
Однажды я задался вопросом, могу ли написать такой линтер, который бы заставлял всех писать одинаковый код. Я был очень строг и включил все возможные правила, которые смог придумать. Но люди все равно пишут разный код. Он очень похож, но я всегда могу понять, что этот код написали разные люди.
Подход сохраняется, мы ждем ответа машины, хорошо сделана программа или нет. И это работает, потому что такие инструменты помогают в работе.
Но нельзя забывать о том, что люди — необходимые участники процесса. Какие бы прекрасные технические настройки вы не сделали, если опытный взгляд человека не прошелся по вашему коду, то все равно там может быть такое, от чего волосы дыбом встают, хотя и прошло CI.
С одной стороны, мы справились с нашей проблемой и отметаем очень плохой код. Но, тем не менее, мы не полностью изолируемся от него. Процесс код-ревью обязателен. Если код не прошел код-ревью, то все, что вы сделали до этого, бессмысленно.
Каждый следующий шаг имеет смысл только тогда, когда есть фундамент предыдущего.
Если вы не понимаете, что делаете, или неправильно поставили задачу, никакой код-ревью и CI не поможет. Все, о чем я говорю, имеет смысл только в системе. Шаг код-ревью необходим только для одного — проверять человека после машины.
Давайте поговорим о дарах — какие дары есть в разработке.
Самый главный дар — это наши баги. В каждом продукте есть баги. Многие люди хватаются за голову: «У нас баги на проекте, представляете?!» Но все же с ними живут, просто есть критичные баги, а есть не очень.
Некоторые люди заводят два трекера: один для заказчика, второй внутренний. В том, который для заказчика, красивые фичи и описания, а внутри — жесть: сплошные баги. Это превращается в кашу очень быстро, про это даже говорить не хочу.
Но почему-то в нашей данности баг — это плохо. Человек, который зарепортил баг, если он не тестировщик, слышит: «Что ты делаешь? Ты срываешь сроки. Мы же фичи должны делать, а ты какие-то баги находишь». Предъявлять баг — значит говорить, что что-то не работает, что-то плохо. Но на самом деле все наоборот.
Скрытый баг — это плохо, найденный баг — это хорошо.
Баги — это дары, которые можно использовать во славу проекта. Это то, что позволяет делать все более и более уверенные шаги в сторону развития.
Естественно, тогда нужно поощрять людей за то, что они репортят баги. Они должны быть героями внутри проекта и должны быть почитаемы. Но добиться этого сложно. Для этого нужно заглянуть еще глубже и начать не с задач, а с оплаты.
Я не хочу углубляться в оплату, потому что в этом вопросе со мной обычно несогласны, причем настолько сильно, что перестают слышать рациональные аргументы, а слышат только эмоции. Я не хочу, чтобы вы слушали эмоции, я хочу, чтобы вы думали головой.
Дальше все зависит от конкретной имплементации того, как мы решили все эти проблемы, какие инструменты выбрали для нашего стека, какие технологии изобрели и написали, какие подходы используем для того, чтобы различать, кто хорош, а кто плох в своем деле.
Главный тезис моего рассказа — виноваты не люди. Виновата система, которая заставляет людей делать неправильно — система, которая поощряет людей отбирать наше общее время на встречах, писать плохой код и делать все то, против чего мы боремся.
Эту систему можно исправить, и сделать это несложно. Вы можете взять все те инструменты, которыми пользуемся мы, поставить их себе и работать. Они все в open source, поэтому вы легко можете начать делать так же.
Имплементация
Совсем без имплементации было бы неинтересно. Я рассказал, чем вообще мы занимаемся, а теперь приведу еще несколько тезисов, чтобы разжечь ваш интерес дальше — как конкретно мы достигаем определенных целей.
Полная свобода. Мы понимаем, что разработчики могут исчезнуть, не хотеть работать и не работать, у них может быть плохое настроение, им нужна полная свобода. Это нормально, поэтому у нас хочешь — работаешь, не хочешь — не работаешь. У тебя полная свобода действий, ты не зависишь вообще ни от чего.
Нет общения. У нас некому сказать, что ты сегодня не собираешься работать или собираешься работать. Фактически нам все равно: собираешься работать — хорошо, не собираешься — тоже ладно. Даже системы информирования об этом нет.
Нет команды. Когда люди соединены полной свободой, они могут делать все, что хотят — какая команда? Это просто люди, которые не общаются, в жизни друг друга не видели, им плевать на общие ценности и требования. Они пришли сюда работать и зарабатывать деньги.
Боты управляют людьми. Но для того, чтобы все это функционировало, не должно быть главного человека — того, кто бы всеми руководил. Если есть кто-то самый главный, то получится не свобода, а ерунда. Поэтому нам нужен бот, чтобы править всеми. Он тоже выложен в open source.
Всё код. Когда работаешь с разработчиками, пишешь требования как код, документацию как код, всё как код, понимаешь, что всё код. Так можно сделать очень и очень многое, потому что код можно линтить, тестировать, отслеживать его изменения во времени и т.д. Код един!
Оплата за результат. Это самая холиварная часть: мы не платим зарплаты. Кто-то пошутил, что мы не платим разработчикам в принципе. Действительно есть люди, которые с нами работали и ничего не заработали, потому что ничего не сделали. Мы платим только за результат. Так как задачки маленькие, понятные, мы можем каждой задачке определить цену. Человек выполняет задачу и получает за это деньги.
Оплата за тикеты и за ревью. Если задачу, которую вы создали, кто-то выполнил, то мы заплатим вам за открытие полезной задачи. Если вы сделали хороший код-ревью, то мы заплатим вам за него.
Все проверяется. Естественно, любое действие в проекте проверяется. Создал тикет или провел код-ревью — мы проверили, насколько хорошо ты это сделал. Все проверяется для того, чтобы люди давали качественный результат.
А теперь я бы хотел, чтобы вы подумали о другом способе работы. Он существует и нравится некоторым людям намного больше, чем привычный уклад. Если он дает лучший результат и нравится людям, то за ним будущее.
С приходом Agile многие команды осознали, что за качество отвечают не только тестировщики. Чтобы рассмотреть все аспекты разработки качественных продуктов мы запустили QualityConf, в этом году в рамках РИТ++, а в следующем — вынесем в отдельное мероприятие. Видео прошедших выступлений смотрите здесь, а чтобы не пропустить информацию о конференциях, подпишитесь на рассылку.