Не имеет значения, что, по вашему мнению, может случиться потом.

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

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

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

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

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

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

И тут ни с того ни с сего у компании меняются приоритеты.

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

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

Вашим девизом должно стать YAGNI (You aren’t gonna need it – Вам это не понадобится). Забегать слишком далеко в будущее опасно и контрпродуктивно. Существует большая вероятность того, что этот код вам не пригодится. В итоге он обернется техническим долгом, кое-как поддерживаемым хламом, с которым вашей команде придется какое-то время жить. Понимаю, что соблазн велик, но пожалуйста, не создавайте то, чего никто не просит. Сделайте то, что прописано в требованиях, и остановитесь на этом.

Что делать вместо этого? Позвольте я еще разок залезу на табуретку:

Напишите наиболее простую версию кода, которая будет удовлетворять требованиям.

Небольшие порции изменений, быстрые релизы – вот самый лучший путь.

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

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

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

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

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

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


  1. vzhilin
    26.04.2023 08:30

    Не совсем согласен с таким подходом. О будущем думать нужно. Пример: в Jira SDK нет нормальной поддержки транзакций, хотя если бы о них подумали заранее, боли было бы гораздо меньше. Вот история вопроса для тех, кому интересно: https://jira.atlassian.com/browse/JRASERVER-25808


  1. 18741878
    26.04.2023 08:30
    +1

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


    1. BlackSCORPION
      26.04.2023 08:30
      +2

      Как Вы это находите, я даже в вашем комментарии не сразу понял что не так )

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


  1. kalbas
    26.04.2023 08:30
    +5

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


  1. NeoNN
    26.04.2023 08:30
    +1

    А теперь скажите то же самое банкам, которые ищут COBOL-пенсионеров для новых фич в ПО.


  1. hardtop
    26.04.2023 08:30
    -1

    В последнее время наблюдаю поворот "обратно к истокам", когда начинают ругать чрезмерный ООП подход, большую иерархию классов и over-engineering. Вон, новый-модный Rust без классов и наследования живёт и многим нравится.

    Но нужен опыт. Пусть у нас есть Заказ и телефон. И нам потребовался добавить ещё один телефон.

    И можно к полю user_phone добавить что-то вроде user_phone_alt и все.

    А можно по-взрослому: делать список, в базе 1-ко-многим, динамическую форму с кнопками "добавить доп. телефон", "убрать телефон"...

    Кто какой подход выберет? Чем обоснуете?


    1. CrazyElf
      26.04.2023 08:30
      +2

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


      1. d-stream
        26.04.2023 08:30

        Правда в реалиях итераций может быть больше:

        • Один номер, зуб даю

        • Да, два, больше ни в жисть

        • Почту бы

        • ICQ номер надо

        • Мдя, да лучше бы это были "контактные данные"

        • ...

          Притом стоит отметить что это пример не из вариантов прокручивания фарша назад


        1. CrazyElf
          26.04.2023 08:30

          Вполне возможно, что именно так всё и будет. А может и не будет. Задачи нужно решать здесь и сейчас и теми средствами, которые на это выделены. Всё предусмотреть заранее всё-равно невозможно.


          1. DMGarikk
            26.04.2023 08:30

            а потом смотришь в код и кровавые слезы


            1. CrazyElf
              26.04.2023 08:30

              Если код сразу был хорошо отрефакторен, то нет )


              1. DMGarikk
                26.04.2023 08:30

                тогда простые задачи не будут попадать в сроки
                Я работал в одном месте с таким подходом
                там добавить два поля в какойнить объект вызывало огромный рефакторинг половины проекта на целый спринт


    1. mayorovp
      26.04.2023 08:30

      Вообще-то, в новом-модном Rust иерархия всего навёрнута такая, что классическим ООП языкам и не снилось.


      Где в Java у любого объекта есть hashCode() — там в Rust есть трейт Hash с методом hash, принимающим внешний Hasher.


      Или взять реализацию sid::io::stdin(), которая возвращает Stdin, реализованный внутри как &'static Mutex<BufReader<StdinRaw>>. А у StdinRaw внутри лежит std::sys::stdio::Stdin, реализация которого зависит от платформы. Так, у std::sys::windows::stdio::Stdin внутри структура IncompleteUtf8, являющаяся буфером переменной длины от 0 до 4х байт и 16х-битный временный суррогат.


  1. andrey_novikov
    26.04.2023 08:30
    +1

    О, люди открыли для себя экстремальное программирование


  1. Yukr
    26.04.2023 08:30

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