Сложность это плохо

Влияние сложности

“Простота — это душа надёжности”, — Эдсгер Дейкстра

“Если мы посчитаем количество строк кода, то стоит рассматривать их не как “произведённые строки”, а как “строки потраченные”, — Эдсгер Дейкстра.

“Код легче писать, чем читать”, —  Джоэл Спольски.

“Любой дурак может написать код понятный для компьютера. Хорошие же программисты пишут код, который смогут понять люди”,  —  Мартин Фаулер

Любая работоспособная сложная система является итогом эволюции более
простой работоспособной системы… Сложная система, разработанная «с нуля»,
никогда не работает так, как надо и никакие «заплатки» не заставят ее работать
правильно. Проектирование следует начинать с простой работоспособной
системы
.”  — Буч Г.

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

Сложность ведет к превышению плановых трудозатрат, времени, переработкам и выгоранию. В начале проекта сложности не видно. Разработчики склонны выкинуть все старое и переписать заново, что может пойти не так? Согласно данным, приведенным в книге Роберта Мартина "Чистая архитектура" с ростом сложности резко растет стоимости доработки каждой новой фичи.

Психологические трудности

Обосновать высокие трудозатраты (что может пойти не так?) трудно и себе то, а другим и подавно. Разработчик может дать обещания сделать задачу в излишне оптимистичные сроки. Дальше обязательно возникают непредвиденные трудности и переработки. "Ну ты что же, не профессионал? Задача то простая!" - опасный психологический феномен, даже если не давит заказчик или руководитель. Давит твое эго.

Типы сложности

Внутренняя сложность задачи (inherent complexity) и непреднамеренно привнесённая сложность (accidental complexity).

Типичная ловушка, с которой мы сталкиваемся в процессе проектирования ПО, проявляется в фокусировании на том, насколько "простым" является для нас чтение и понимание конкретного фрагмента кода. Однако фокусирование на простоте чревато множеством затруднений, поскольку сложность не может быть удалена: она может быть только перемещена. Если вы её перемещаете из своего кода, куда она тогда денется?

Отведите ей подобающее место и изолируйте ее.

Сложность вырвалась, сейчас будет катастрофа
Сложность вырвалась, сейчас будет катастрофа

Если сложность реализации значительно больше чем сложность описания это тревожный звоночек.

Если листинг кода в 10+ раз больше чем описание задачи, задумайтесь: что-то здесь не так, вы упоролись! Но это не точно.
Если листинг кода в 10+ раз больше чем описание задачи, задумайтесь: что-то здесь не так, вы упоролись! Но это не точно.

Ментальные ограничения

"Я не буду думать об этом сегодня, я подумаю об этом завтра" Скарлетт о Хара.

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

Когда программа создается специалист может удержать сразу несколько предметных областей и пишет все подряд (программирование снизу вверх - "просто взять и написать").

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

Хватит лить воду, ты мне мясо давай!
Хватит лить воду, ты мне мясо давай!

Методы измерения и контроля сложности

Декомпозиция и отладка по частям, уменьшение числа связей:

  • Разбиение системы на более мелкие, независимые модули, тогда сложность, т.е. количество связей будет равна сумме сложностей компонентов, а не факториалу их числа в случае связей "все зависит от всего"

  • Отладка и тестирование каждого модуля по отдельности.

Композиция проверенных деталей проверенным способом:

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

Абстракция:

  • Ментальная инкапсуляция, скрытие деталей реализации и представление только необходимой информации.

Инкапсуляция:

  • Защита от "прорыва сложности" за пределы одного модуля в другие

  • Ограничение доступа к внутренним деталям реализации модулей ради безопасности.

Эволюционное наращивание сложности:

  • Постепенное добавление новой функциональности с уточнением требований

  • Уточнение границ модулей и ужесточение правил (границ)

 

Баланс между быстро и правильно

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

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

Что на практике?

А на практике были случаи когда я писал код в 10(!) раз более краткий и понятный чем у соседа по цеху.

И вот как я вижу чужой переусложненный код

В видео объясняется, как различные сервисы, такие как бинго, papaya, mbs, ulna, raccoon, wingman, rgs, barbie doll, ringo two, bls и "галактус", работают вместе для предоставления информации о пользователях.

...

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

Не делайте так!

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


  1. gleb_l
    14.05.2024 18:11

    .https://habr.com/ru/articles/668300/comments/#comment_24386038 - вот один из моих комментов про сложность систем - забавно, все заметно коррелирует


  1. AlexunKo
    14.05.2024 18:11
    +5

    Не хочется расстраивать автора что сложность и переусложненность - две большие разницы. Это как при переедании бороться с пищей.


  1. TerraV
    14.05.2024 18:11
    +2

    Разработка через управление сложность - это мое хобби последние лет 5. В среднем мне это дает производительность х4 по сравнению с моими коллегами, плюс очень малое падение скорости разработки на длинном этапе. А в легаси проектах даже прирост скорости (за счет попутного рефакторинга на обычных задачах).
    Я для себя сформулировал следующие подходы для минимизации сложности:

    • Единообразие

    • Минимизация сторонних библиотек

    • Минимизация слоев абстракции

    • Минимизация наследования

    • Изучение и совершенствование базовых технологий, а не производных (совершенствовать SQL лучше чем совершенствовать ORM)

    • Domain Driven Design

    • Управление границами

    • Управления зонами ответственности


    1. kozlov_de Автор
      14.05.2024 18:11

      Слой абстракции полезно вводить как прокладку между программистами. Это и зависимости уменьшает и понимание упрощает.

      А ещё упрощает изменение кода. Ровно до тех пор пока сами абстракции не придется переделывать.

      Одному программисту проще без абстракций.

      По сторонним библиотекам недавно удалось обойтись расширениями к функционалу библиотеки (c# extension methods), очень положительный опыт.

      Наследование вредно потому что зависимость дочернего класса от родительского потом сложно переделать.

      "совершенствовать SQL лучше чем совершенствовать ORM" - согласен. Хотя, orm очень неплох для быстрой разработки прототипа.


  1. aamonster
    14.05.2024 18:11
    +1

    А на практике были случаи когда я писал код в 10(!) раз более краткий и понятный чем у соседа по цеху.

    Я правильно понимаю, что сосед думал то же самое про ваш код, потому что место для упрощения в вашем коде видел, а в своём – нет?


    1. kozlov_de Автор
      14.05.2024 18:11

      Он вздыхал и спрашивал: "когда же будет код?")))

      Я пишу медленно, а красивая идея мне почти через год в голову пришла

      ¯\_(ツ)_/¯


  1. bear11
    14.05.2024 18:11
    +1

    Ха.

    "Внутренняя сложность задачи (inherent complexity) и непреднамеренно привнесённая сложность (accidental complexity)."

    А еще бывает преднамеренно привнесенная сложность. Например, в Linux привнесли systemd.


    1. kozlov_de Автор
      14.05.2024 18:11

      Да, хотел написать про это

      Количество разработчиков UI SnapChat превышает количество кнопок в приложении

      Разработчиков набирали чтобы показать инвесторам что это крутая компания

      Интервью Дурова Такеру посмотри - то же самое про другие компании говорит.


  1. nikolz
    14.05.2024 18:11
    +2

    Задача бывает простой в начале и в конце ее решения.

    В начале - мы дилетанты, в конце - профи.

    -------------------

    Следствие:

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


  1. Batalmv
    14.05.2024 18:11
    +2

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

    --------------------------

    В целом ... я даже не скажу, в чем проблема у автора. Читать код - это не самое критичное. Его сложность - тоже.

    Куда важнее его сопровождение, т.е. возможность внесения изменение БЕЗ ВЛИЯНИЯ на остальное. Это именно то, что нгапрямую влияет на сроки, риски и деньгию

    Простой пример. На "дисковери" разбирали код старого приложения клиента. Это был .NET, в котором я "баран баранчиком", но ... код представлял собой кучу копипейста, вот просто овер до фига, вызов хранимок и SQL прям напрямую, WebForms и т.д.

    Код - полное овно, но читался просто прекрасно даже для меня. Все понятно, очевидно. Бизнес логика понятно. Косяки тоже :)

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

    Но повторюсь - с чтением вообще нет проблем. Как художественную книжку (за ислючением магических констант, тут понятно логика выпадает, и надо просто понять и простить)

    Т.е. важна сопровождаемость, а все остальное - уже производные