Блог itMegastar

Почему всё ломается даже у хороших программистов? Часть 1/2

Полезные статьи
После несерьёзной статьи на серьёзную тему Job Safety Driven Development стоит рассказать о том, почему даже опытные и добросовестные программисты волей случая могут попадать в схожие ситуации. Сначала захотелось написать, почему программисты ошибаются вообще («Почему ошибаются программисты?» Часть 1 и Часть 2), но оказалось, что это слишком разные темы. Потом оказалось, что и на эту тему получился очень длинный текст. Пришлось разбить его на части. В первой части мы рассмотрим случаи, которые знакомы многим крупным компаниям. И дополним понятие «серебряная пуля» понятием «золотая шестерёнка». Во второй части поймём, какую цену вам, скорее всего, придётся заплатить за «золотую шестерёнку», я приведу немного своего опыта. Как всегда, попробую писать простым языком, понятным широкой аудитории.


Меня зовут Константин Митин, я сооснователь и руководитель компании АйТи Мегастар/АйТи Мегагруп. Когда-то был простым разработчиком, работал в L3, дорос до тимлида, затем и до руководителя филиала разработки крупной ИТ-компании. Теперь я в АйТи Мегагруп.

В своё время какой-то мудрый человек (к сожалению, первоисточника я не знаю) на хорошо понятном всем языке раскрыл тему: «Откуда берутся ошибки на крупных проектах». Привожу объяснение, как оно есть.

Маркетолог спрашивает программиста: в чём сложность поддержки большого проекта?
Программист: ну, представь, что ты писатель и поддерживаешь проект «Война и мир». У тебя ТЗ — написать главу, как Наташа Ростова гуляла под дождём по парку. Ты пишешь «шёл дождь», сохраняешь, вылетает сообщение об ошибке «Наташа Ростова умерла, продолжение невозможно». Почему умерла? Начинаешь разбираться. Выясняется, что у Пьера Безухова скользкие туфли, он упал, его пистолет ударился о землю и выстрелил в столб, а пуля от столба срикошетила в Наташу. Что делать? Зарядить пистолет холостыми? Поменять туфли? Решили убрать столб. Получаем сообщение «Поручик Ржевский умер». Выясняется, что он в следующей главе облокачивается о столб, которого уже нет…

Это все действительно так. Чем выше сложность ИТ-системы, тем менее устойчиво и предсказуемо она себя ведёт. В этом ли дело, стоило ли об этом начинать писать целую статью? Конечно нет, дело не в этом.

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

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

Источник дефектов кодирования и проектирования очень часто находится вне программного кода.


Простой случай


Что мы имеем в самом простом случае. Допустим, у нас есть проект либо продукт, который живёт уже 3−4 года. Это большой срок. Скорее всего, требования несколько раз заметно изменились. Технические и архитектурные решения, которые закладывались на старте разработки, могут оказаться не то чтобы неудачными, они могут начать откровенно мешать.


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

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

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

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

Именно в такой ситуации родилась шутка: «…ну, представь, что ты писатель и поддерживаешь проект „Война и мир“…». Система становится слишком сложной и непредсказуемой.

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

Золотые шестерёнки: знакомство


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


Нам нужен реинжиниринг и обеспечение перехода архитектуры приложения из состояния «as is» к состоянию «to be». Звучит просто, но ведь мы это собираемся сделать на живую, не останавливая работу пользователей, не останавливая разработку нового функционала, причём в системе, которая разваливается от регресса.

Знаете анекдот про кардиохирурга и моториста? Он очень хорошо описывает ситуацию. Если не знаете, то вот он…

Кардиолог приезжает в автосервис, ему работяга машину чинит, потом говорит:
— Слышь, мужик, вот я мотор перебираю — и ты мотор перебираешь, только человеческий — почему тебе платят на порядок больше?
Кардиолог кивает, идёт к машине, включает зажигание и говорит работяге:
— А попробуй при работающем движке теперь перебери!

То есть такой человек:

  1. Знакомится с больной системой.
  2. Восстанавливает историю принятия решений и разработки.
  3. Выявляет неочевидные места, где нельзя терять обратную совместимость.
  4. Строит в своей голове систему, как она есть.
  5. Знакомится с новыми требованиями.
  6. Представляет себе ветки вариантов дальнейшего развития системы.
  7. Строит в своей голове систему, какой она должна стать под новые и старые требования одновременно.
  8. Строит в своей голове карту шагов от состояния «как есть сейчас» к «как должно быть». При условии, что на каждом новом шаге не наступает отказ от обратной совместимости, но удовлетворяются новые требования.
  9. Каким-то образом договаривается с бизнесом.
  10. Каким-то образом втягивает в эту авантюру техническую команду.
  11. Всю дорогу защищает от бизнеса техническую команду и выбранный путь.
  12. Всю дорогу защищает от технической команды бизнес и выбранный путь.
  13. Но не теряет способность слышать других и гибко маневрировать на выбранном пути.

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

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


Аварийная ситуация


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


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

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

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



В случае если со стороны этого самого «главного архитектора» недостаточно контроля за ситуацией либо его вообще нет, начинают происходить аварийные ситуации. Как это происходит? Например, у вас есть сервис, который предоставляет наружу какое-то API. Рядом с вами без предупреждения выскакивает какой-то очень-очень важный для бизнеса сервис, который начинает генерить на вас нагрузки столько, сколько все остальные системы вместе взятые. А о вас просто при планировании забыли. Нет, ну правда. И бюджет на расширение ваших мощностей заложить забыли. Не потому, что программисты плохие, а потому, что менеджер либо владелец системы свой KPI улучшает.

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

А ещё у инфраструктуры сетевая связанность периодами отказывает, из-за чего у вас кластера разваливаются. Но все сетевые инженеры клянутся вам, что всё стабильно и классно работает. Причин такого поведения инфраструктуры просто неисчислимое количество, от непрофессионализма до объективных и весомых причин.

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

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

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

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

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

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

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

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


Высокая квалификация: побочное действие


Оценка уровня разработчика — непростая тема. Достаточно просто отличить джуна и мидла. Не так сложно отличить мидла от сеньора. А вот дальше мы встречаемся с неожиданным явлением, у двух разных «senior developer», которые занимают одинаковые позиции, уровень и эффективность работы могут отличаться в десятки раз. Оба молодцы, оба достойны, но вот как-то так. Причём мы не говорим о технических лидерах, которые глубоко знают и понимают технологии, с которыми работают. Мы говорим о способности человека быстро, легко и эффективно решать задачи, способности сложное делать простым и работать с большими объёмами данных у себя в голове.


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

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

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

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

Опытные разработчики, наоборот, упрощают конструкции в своём коде, помня, что они не одни и не навсегда.

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

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

Почему это всё важно? Потому что существует организационный антипаттерн «Рыцарь на белом коне» (Knight in shining armor, KISA), который приходит, решает проблемы, которые никто не может решить. Но потом он уходит и больше не возвращается. В результате может получиться уникальный код, созданный божественным разумом, который никто вокруг не может поменять. А бывает надо, бизнес же не стоит на месте.

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

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

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

Подводя промежуточные итоги


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


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

Если вы дочитали до конца и что-то для себя поняли, то спасибо вам.