Воображаемые проблемы — корень плохого ПО

https://medium.com/@george3d6/imaginary-problems-d4f2921bd1b8
  • Перевод
Есть много обстоятельств, которые могут быть катализаторами создания плохого ПО: используемые инструменты, качество коммуникаций в команде, персональные качества разработчиков, методологии и т.д. И есть среди них одна вещь, которая является корнем почти всех остальных: воображаемые проблемы.

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

История о подкастах


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

И вот вы решаете нанять людей, которые сделают для вас этот сайт. Вы пишете для них абсолютно чёткие требования:

  • Быстрая загрузка сайта в Северной Америке
  • Поддержка загрузки прошлых выпусков подкастов и трансляции в реальном времени текущих
  • Трансляция не должна падать или замирать в течении первых 15 минут для 99.99% пользователей. Желательно вообще никогда, но хотя бы так.
  • Интеграция с Google Adwords (а в будущем, возможно, и с аналогами)
  • Интеграция с трансляциями Facebook, поскольку там вы проводите свои передачи. Если можно создать альтернативное решение, которое будет позволять стримить более удобно — ещё лучше.

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

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

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

  • Восхитительную систему рекомендаций
  • Алгоритм распознавания речи, выводящий субтитры под вашей трансляцией В РЕАЛЬНОМ ВРЕМЕНИ!!!
  • Главная страница сайта загружается за 200 мс в любой точке планеты
  • Вещательный протокол и клиент написаны с нуля, а Facebook в них добавлен плагином. В любой момент можно добавить плагины для других платформ!
  • Есть возможность интеграции с 20 разными рекламными платформами

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

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

Механизм избегания реальности


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

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

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



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

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

Архитектура «испорченного телефона»


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

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

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

Большинство компаний любят иметь на отдельных выделенных должностях «продажников». Это специальные люди, которые ищут потенциальных клиентов, обсуждают с ними задачи, сроки и цены. Именно эти люди могут выяснить больше всего полезного и задать больше всего вопросов. Но это не те люди, которые будут писать данный проект. Между продажниками и программистами стоит 2, 3, 4 или больше слоёв менеджеров среднего и низшего звена, архитекторов, аналитиков и тимлидов. Да, это могут быть очень квалифицированные люди. Но всё же — это дополнительные слои. Как бы они не старались, информация, проходя через них, будет меняться. Кто-то отбросит что-то (на его взгляд) неважное, другой уточнит что-то неуказанное, но (по его мнению) очевидное, третий заменит дурацкую формулировку на правильный (как он уверен) термин — и вот первоначальную задачу уже не узнать. Продажник может бросить заказчику фразу типа «а за 39 999 сверху мы это можем и на блокчейне сделать». Если клиент клюнет — команде разработчиков двумя уровнями ниже придётся ломать голову, а как же вот ЭТО возможно сделать на блокчейне. Но ведь уже продано и оплачено, будем делать.

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

Искусственная усложнённость и натуральный отбор


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

«Люди, отобранные для решения сложных задач, не имеют стимулов решать простые» — Талеб

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

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

И это, понятное дело, не потому, что переместить цифру из одной колонки в другую так сложно, нет. Это не сложно. Вот проиндексировать весь Интернет, а после этого выдавать релевантные поисковые результаты за долю секунды — вот это сложно. Однако пара ребят в гараже это сделала. А для отката транзакции нужно 1000 человек и полгода.

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

«Тяжело заставить человека что-то понять, если он получает свою зарплату за то, чтобы этого не понимать» — Эптон Синклер

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

И мы продолжаем решать воображаемые проблемы.

Инфопульс Украина

125,07

Creating Value, Delivering Excellence

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

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


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

    Это там, где сначала был поиск слов? Нет, это не сложно. Современные алгоритмы google — вот что сложно, но пара парней в гараже их не писала.


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

      0
      сложно найти баланс между расширением и сложность архитектуры и производительностью

      Нет — это не так сложно. Есть простые принципы KISS, DRY и YAGNI
      Чем проще написан код, тем проще его расширять и поддерживать. Многие программисты страдают от «универсальности». К примеру пришла задача обработать данные по протоколу (К примеру команды по MODBUS или CAN) Некоторые разработчики начинают задавать себе вопрос, а что если завтра нужно будет добавить ещё один протокол или изменить получателя… В результате вместо простой связки интерфейса и класса рождается монстр, близкий по функционалу к BizTalk с возможностью изменения протоколов в конфигурации. Только часто бывает, что день, когда вас попросят добавить 2ой протокол так и не наступит, а вам придётся поддерживать и исправлять ошибки в десятках тысяч строк ненужного кода (а ведь могло быть всего пара сотен строк...) Если бы у меня была такая задача, то я бы сделал интерфейс (для возможной расширяемости в будущем) и его реализацию в виде класса, который делает только то что нужно для данного протокола. Закинул бы его через DI или ServiceLocator и всё…
        +5

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


        Что бы не быть голосновным:


        KISS — довольно абстрактный принцип, который можно еще записать "не усложняйте сверх меры", но опять же, проблема в том, что бы найти эту меру, а это не тривиальная задача.
        DRY — принцип, который можно рассматривать очень по разному. Некоторые программисты считают строчки кода, которые повторяются и если их больше трех, сразу начинают обобщать. Некоторые более опытные описывают DRY в связке с SRP, и говорят, что если для одного изменения для одного актора в программе нужно менять код в двух местах — вот тут проблема в DRY может быть.
        YAGNI — Не очень популярный принцип опять же, потому что никогда не понятно, когда на самом деле нужно, а когда нет. Я не знаю бывало ли у вас такое, но я бывал в ситуациях, когда абстракции или какого-то усложнения сверху не было, а изменения понадобились. И все было очень плохо.


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

          0
          По поводу абстрактного класса — всё зависит от того — внешний это интерфейс или внутренний. Если интерфейс реализован только для расширяемости / юнит тестирования, либо если это API и наружу виден только интерфейс в виде json-объекта, то вынесение абстрактного класса на данном этапе лишнее, т.к. не факт что 2ой потомок вообще появится. (получается что это будет лишнее усложение. Когда появится — тогда и вынесем). Если же реализована система плагинов или планируется возможность переиспользования и расширения модуля, то тогда абстрактный класс — must have…
            +1
            По поводу красивых аббривиатур:
            Для себя выработал следующие правила
            KISS — Поставленная задача должна решаться самым простым из возможных способов. Код должен быть легко-читаемым, легко-модифицируемым и расширяемым, но должно быть реализовано только то, что нужно на данный момент.

            DRY — Изменения должны происходить в минимальном количестве мест (не всегда получается сделать что только в одном). При внесении изменений не должен меняться одинаковый код (например поиском и заменой по коду).

            YAGNI — Не пиши лишний код и удаляй ненужный (если он есть в системе контроля версий конечно).

            По поводу необходимости изменения кода там, где нет абстракций — значит пришло время их добавить… (Что соответствует данным принципам). Если код написан по KISS и DRY — добавление абстракции произойдёт в одном месте и затронет минимальное количество кода.
              0
              KISS — Поставленная задача должна решаться самым простым из возможных способов. Код должен быть легко-читаемым, легко-модифицируемым и расширяемым, но должно быть реализовано только то, что нужно на данный момент.

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


              DRY — Изменения должны происходить в минимальном количестве мест (не всегда получается сделать что только в одном). При внесении изменений не должен меняться одинаковый код (например поиском и заменой по коду).

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


              YAGNI — Не пиши лишний код и удаляй ненужный (если он есть в системе контроля версий конечно).

              Класс. А какой код нужный и какой код ненужный?


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

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

                0
                У вас всего лишь три параметра, которые довольно часто обратнозависимы
                Чаще всего там нет обратной зависимости. Чем меньше кода написано, тем проще его понимать, расширять и модифицировать. (Это конечно не значит, что всё нужно писать в Code-Behind onclick)

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

                А какой код нужный и какой код ненужный?
                Ненужный в данном случае — неиспользуемый/мёртвый или закомментированный.

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

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

              0
              Иначе можно было бы просто следовать принципу ППП (Просто пиши правильно) и не парится.

              На самом деле, все очень просто — принципы фиксируют стандартное поведение. Стандартное поведение — это такое, которому стоит следовать, если не получается четко и ясно сформулировать причины, по которым ему следовать не надо.


              KISS — не надо делать систему сложнее, если вы не можете объяснить, почему она должна быть сложнее


              DRY — стоит избегать дублирования во всех случаях, в которых вы не можете объяснить, почему дублирование необходимо


              YAGNI — не стоит добавлять функциональность, если вы не можете аргументировано пояснить, почему ее следует добавить прямо сейчас

          +3
          А для отката транзакции нужно 1000 человек и полгода.

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

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

          В общем ваш пример полный шлак. Не знаете как оно работает, лучше не пишите. Мне же довелось в написании примерно такого же участвовать.
            +2
            Нельзя еще забывать об огроменной зарегулированности всех околофинасовых компаний, особенно имеющих дело с чужими деньгами — брокеров, банков и тд.
              0
              Да, поддерживаю. При работе с деньгами такие вроде-бы простые на первый взгляд вещи как откат транзакций (да и транзакции вообще), закрытие операционного дня и т.д. превращаются в очень сложные процессы (особенно, когда это происходит для каждого отделения в отдельности). Там очень много тонкостей начиная от округления при расчёте итогов и до конвертации валют. Простой пример: при расчёте пени можно сначала округлить до копеек, а потом посчитать итог, а можно сначала посчитать итог, а потом его уже округлить — а в результате разница в отчёте может оказаться в несколько сотен тысяч рублей…
              А вот про единую банковскую платформу — это конечно интересно, но скорее всего невозможно из-за разных процессов в каждом банке (которые они чтят и берегут как традиции), да и сейчас преимущество в софте — это почти единственная разница между банками. Так что единую систему мы ещё очень не скоро увидим…
              0
              Я так понимаю это специально в пятницу опубликовали? Пятнично.
              Мне вот по опыту чаще приходилось встречаться с софтом, который писался как «простой инструмент для решения одной маленькой частной задачи». А когда задача расширилась — превратился в зверя с обложки книги про perl 6.
              А когда придумали слово Agile, написание софта таким способом стало модным.
                0
                После перехода всех на Agile общее качество продуктов ухудишлось (зато стала быстрее скорость доставки — что нужно бизнесу). Всё дело в том, что в стандартной водопадной модели проектирования очень много внимания уделяется проектированию, архитектуре и пишутся технические задания и т.д. Т.е. система рассматривается и разрабатывается от целого к частному. В Agile же система — это набор фич. И в результате получается что лепится ядро, а потом к нему начинают прилеплять фичи. А так как о большинстве фич изначально даже и не думали, то появляются монстры которые трудно поддерживать…
                Я конечно не агитирую за возврат к водопадной модели, но даже с аджайлом можно уделять больше внимания проектированию и архитектуре.
                0
                «простой инструмент для решения одной маленькой частной задачи» — ну это unix-way )
                  0
                  Вспоминается пример из промышленной автоматизации — протокол OPC DA. Не знаю как сейчас обстоят дела, но лет 10 назад каждая контора билась над созданием собственного сервера OPC для своего оборудования. Серверы эти стоили не мало и создавались большим трудом. В то же время, протокол по сути решает простейшую задачу доступа к массиву чисел с указанием признаков качества значения и времени его обновления.
                    0
                    Не цеплясь к отельным примерам, статья очень правильная!
                      0
                      У меня был случай, когда менеджмент на столько запутался, что в один прекрасный момент (за пару месяцев до краха стартапа) выкатил задачу быть лучше конкурентов по всем подряд аспектам… Пару раз я даже попытался достучаться до инвесторов, а потом расслабился и получал удовольствие.
                        0

                        Надо простую задачу пдавать как вызов для разработчиков: ааот сделайте это просто и надежно...


                        Что реально сложно (или невозможно) — предусмотреть все возможные точки расширения функционала.

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

                        Самое читаемое