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

Где-то я читал (к сожалению, сейчас не могу найти источник) такую мысль: «Чем дольше что-либо остается неизменным, тем меньше вероятность, что оно изменится в будущем». Иными словами, начиная с того момента, как мы отправили в релиз «костыль», шансы на то, что он будет исправлен, неуклонно снижаются с течением времени. Если сегодня мы его не устраним, завтра вероятность станет ниже. Послезавтра она еще снизится, через неделю – еще, через месяц – еще…

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

Утрата контекста и уверенности


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

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

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

Нормализация


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

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

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

Приоритетные задачи


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

Выбор представляется очевидным. И так каждый раз.

Теперь вы зависите от плохого кода


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

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

А вот более серьезный, архитектурный пример. «Для начала мы возьмем неструктурированную базу данных (вроде mongoDB), так как пока не представляем, какие у нас будут данные. Мы хотим располагать возможностью быстро и легко менять их форму. Когда модель данных стабилизируется, можно будет вернуться к этому вопросу».

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

  • Сейчас, спустя годы они по-прежнему сидят на mongoDB.
  • Они в высшей степени недовольны mongoDB.

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

И что дальше?


Итак, теперь мы понимаем: если не исправить проблему сразу, то существует большая вероятность, что всё так и останется. И что? Почему это так важно было понять?

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

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

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

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

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

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

Комментарии (17)


  1. panzerfaust
    07.12.2022 15:47
    +7

    И тогда я задумался: когда же будет устранен этот «костыль»?

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

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


    1. bevertax
      07.12.2022 16:16
      +9

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


      1. Mishootk
        07.12.2022 16:22

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


      1. panzerfaust
        07.12.2022 16:27
        +3

        Вы не поняли механизм.
        Ревьюер: Так не делается, надо исправить.
        Кодер: Ок, сделаю туду.
        Ревьюер: Без таска на туду реквест не одобряется.
        У кодера вариант или таки заводить таск или исправлять сейчас.


        1. laatoo
          07.12.2022 19:43
          +2

          беру на вооружение, спасибо.
          как часто это приводит к конфликтам типа:

          Менеджер: нам нужна фича ещё вчера!
          Тимлид: нам нужно оформить таски на техдолг, потому что инженерная культура
          Команда/разработчик: фича сделана, там опять этот душнила упёрся со своим оформлением техдолговых тикетов, которые никто никогда не разгребёт!
          

          Как решаются?


          1. Loggus66
            07.12.2022 21:39
            +4

            Элементарно. Делается задача, кладётся в backlog, никогда не выполняется.


            1. panzerfaust
              08.12.2022 08:01
              +3

              Да, но я потому и написал про культуру. Культура это когда договоренности выполняются. А когда все дружно вертят любые договоренности, то код тоже будет выглядеть, как будто его вертели.


          1. Dair_Targ
            08.12.2022 00:21
            +1

            Менеджер и техлид запихиваются в комнату (можно виртуальную). Как примут совместное решение - можно выпускать.


          1. panzerfaust
            08.12.2022 07:08
            +1

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


          1. Racheengel
            08.12.2022 22:20

            Делается релиз план на следующий мажорный релиз и расписываются желаемые фичи с приоритетами. А дальше всё зависит от ресурсов разработки. Какие то фичи уйдут в следующий релиз, какие то отпадут со временем. Какие-то заказчик таки получит :)


            1. laatoo
              09.12.2022 03:00

              и расписываются желаемые фичи с приоритетами

              Которые тоже нужны вчера, на которых тоже техдолг, на который тоже нужны тикеты... ну вы поняли, рекурсия )


  1. Neom1an
    07.12.2022 16:40
    +3

    А почему откладывать дела так легко? Мне нравится одна из идей, которые я ранее где-то читал. А именно: человек считает себя будущего не собой, а как бы другим человеком. Нет полной внутренней идентичности. На другого легко свалить выполнение задачи. Легко представить, что у него нет того миллиона причин, которые ты имеешь сам, чтобы эту работу не делать. А когда наступает будущее и это опять оказываешься ты сам, то у тебя опять оказывается миллион причин не делать отложенное. Ибо у тебя и в прошлом этих причин было миллион и ты их не смог пересилить. Они все на месте. И вот ко всему этому ещё добавлется то, что уважаемый автор описал в своей статье. Что усиливает желание ещё отложить


    1. Mishootk
      07.12.2022 18:55

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


    1. mikelavr
      07.12.2022 22:35
      +1

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


    1. scream_r
      08.12.2022 16:03
      +1

      Было в Симпсонах:
      Гомер: "Это проблема Будущего Гомера! Ох и не завидую я этому чуваку..."


  1. dprotopopov
    09.12.2022 15:05
    -1

    Господи, какие все божие одуванчики - работают за идею и интерес.

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

    Бабло победит зло.