Pull to refresh

Comments 63

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

Вот со стандартизованной сложностью все не так страшно. Да, используемая библиотека может быть мега-сложной внутри, но если она уже была оттестирована и отлажена на сотнях проектов, то проблем от нее обычно мало.
А с уникальной сложностью по-возможности надо бороться, либо переводя ее в стандартизованную (используя готовые блоки), либо максимально упрощая архитектуру проекта, чтобы он был четкий и понятный.
С одно стороны всё так. С другой, стандартизованная сложность может восриниматься уникальной для человека, который только входит в предметную область. А таких большинство (и, на мой вгляд, всегда будет большинство).
Это не совсем так, правильно организованный инструмент скрывает эту сложность давая тому кто его использует простой и понятный интерфейс.
Да, кто-то должен заниматься поддержкой и на самом глубоком уровне, но:
— таких людей нужно значительно меньше, по сравнению с теми кто просто использует инструмент
— такие люди имеют более узкую специализацию, каждый в своей сфере

Примеры такой стандартизованной сложности:
— JQuery для новичка будет очень сложен, если лезть в его внутренности, но в этом новичку нет необходимости, он может им пользоваться через простые методы.
— Точно также и автомобиль, например, внутри устроен очень сложно, но для того чтобы просто ездить, знать его внутренности досконально нет необходимости, достаточно освоить достаточно простые органы управления и знать ограниченя (углы поворота, тормозной путь и т.п.).
Как не странно, подумал совершенно наоборот. Если решение разовое — оно может быть сложным, потому что делается быстро, и вся сложность вполне умещается в голову. Как кино — снимается один раз, и вполне можно ради одного кадра нагородить огород.
А вот если решение на года/на много раз — тот тут я сложности боюсь. Из головы это вылетит, и потом будет сложно дорабатывать/поддерживать/эксплуатировать. Тут лучше иметь простое решение. Каждый раз городить огород дорого.
Смотря что понимать под «разовым». Если сделал и забыл, как фильм, то да, очень верная мысль.
А если оно уникальное и разовое, но его надо поддерживать после годами, то все не так радужно уже получается. Особенно это актуально для всякого уникального научного оборудования.
Согласен с вашим вторым абзацем. Главный инструмент борьбы со сложностью в инженерии (а особенно в IT) — абстракции. Описанная и документированная абстракция — интерфейс. Либо просто спецификация (то есть документ, а не фрагмент кода). Реализованная в коде — модуль (это может быть класс, или целове приложение, или железка). Если вся система корректно работает через эти интерфейсы, замена одного модуля на другой с тем же интерфейсом не повлияет на работопособность системы, в этом прелесть и красота хорошо спроектировнной системы. И это (правильно выделенные абстракции) — единственное, что позволяет человеческому мозгу, способному одновременно удержать в голове всего лишь около 7 понятий, создавать такие сложные инженерные произведения.
Из этой же оперы — готовые решения (код, алгоритмы, формулы, методики — это может быть любая инженерная сущность), которые можно применять, не понимая, как они работают внутри.

Какое-то странное у вас понимание борьбы со сложностью. Получается что технологии, созданные для борьбы со сложностью, вдруг начали делать решение сложнее — а технологии, которые сложность "принимают", делают все проще… Какая-то борьба в минус получается.


Правильная борьба со сложностью — это когда решение становится проще для реализации и для понимания, а не сложнее.

И новый и старый подход призваны справляться со сложностью. В этом у них нет отличия. Просто они справляются с ней по-разному.

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

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

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

Вы не правы.

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

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

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

Проект на реляционных базах данных и XML-ках со схемами гораздо проще сопровождать и дорабатывать, чем проект на NoSQL и JSON без оных!


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

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

Правильная борьба со сложностью — это когда решение становится проще для реализации и для понимания, а не сложнее.


Все зависит от точки отсчета.
Смотрите, допустим есть математическая задача.
Для ее решения можно написать уникальное решение, допустим в 100 строк кода.
А можно взять математический пакет в котором 100 000 строк кода, но лично нам для решения задачи надо написать 1 строку.
Вот если оценивать общую сложность системы — решение с математическим пакетом на порядки сложней, а в практической реализации оно на порядке проще, так как решение в нем уже фактически есть, его надо просто вызывать.
Надо добавить, что чтобы написать эту одну строку, может потребовать изучить работу всего пакета.
Зачем? Достаточно вызвать одну функцию.
Для этого надо знать какие параметры в неё передавать, как их сформировать, какие на них ограничения, что эта функция возвращает, какие есть особенности её поведения. Если она далает что-то сложнее простого сложения, то по цепочке можно залезть достаточно глубоко.
Но врятли это будет 'весь пакет'. Как правило, это сотни функций, иногда тысячи. Описания же параметров, вполне возможно, есть в хэлпе. Я, если честно, вообще не представляю вашего случая. Ни разу такого не видел за почти 20 лет написания кода.
Про весь пакет я утрировал.
100 строк самописного кода в котором легче сделать ошибку чем в одной строке. Тут нужно учитывать цену ошибки.

Нельзя говорить, что XML — "жесткий" формат, а JSON — "гибкий". На самом деле все совсем наоборот. Возьмем для примера вот такие фрагменты:


<products>
    <product ... />
    <product ... />
    <product ... />
</products>

{ products: [ ..., ..., ... ] }

И там, и там — сериализованный массив из трех элементов. Теперь попробуем добавить немного метаданных:


<products m:foo="foo">
    <product ... />
    <product ... m:bar="bar" />
    <m:baz />
    <product ... />
</products>

{ 
  products: { 
     foo: 'foo' , 
     items: [ {
         type: 'product',
         data: ...
       }, {
         type: 'product',
         bar: 'bar',
         data: ...
       }, {
         type: 'baz'
       }, {
         type: 'product',
         data: ...
       }
     ]
  }
}

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


Именно XML является гибким форматом, который из-за своей гибкости бывает довольно сложен. А JSON — это простой жесткий формат, в котором, во-первых, нет ничего лишнего — а во-вторых, он хорошо укладывается именно в задачи сериализации простых структур данных, за что он и получил распространение.


Переход от XML к JSON — это именно продолжение борьбы со сложностью, а не ее принятие.

Спасибо за пример.

Это разные гибкости. В приведённом Вами коде XML действительно более гибкий, если рассматривать изменение минимального примера.

В то же время, описание минимального примера на XML дольше и сложнее, чем на JSON.

Поэтому сравнивать минимальный JSON и XML некорректно. Надо сравнивать структуры одинаковой сложности. В этом случае первый пример с JSON будет выглядить следующим образом:

{ 
  products: { 
     items: [ {
         type: 'product',
         data: ...
       }, {
         type: 'product',
         data: ...
       }, {
         type: 'product',
         data: ...
       }
     ]
  }
}


Добавление параметров в этом пример не сложнее, чем в XML. В то же время JSON позволяет не писать лишнего, если оно не надо.

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

Я сравнивал два фрагмента, которые требуют от разработчика одинакового времени на придумывание и реализацию. В то же время как раз явное добавление type: 'product' требует от разработчика лишний усилий и съедает его время.

Лишние усилия потребуются только у новичков. Причём новички с XML накосячат куда больше чем с JSON, поскольку в голове больше держать надо.

Фактически же, type: 'product' является аналогом <product/>, который писать не обязательно, а если необходимо, то можно записать несколькими разными способами, в зависимости от потребностей.

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

Немного конкретизирую. Тут встаёт вопрос гибкости при реализации против гибкости при сопровождении.

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

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

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

Выходит, чистый код, SOLID, и т.п. — это «старая школа борьбы со сложностью», а "$%-як, $%-як и в продакшен" — новая школа.
Если доводить до абсурда, то выходит именно так. Но доводить до абсурда не надо :-)

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

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

Потому как не ясно что с ними будет. Может потом вообще исчезнет понятие вида продукта, или будет несколько разных наборов видов, может через год потребуется добавить 1 вид и этим всё ограничится.

Жаль, революции не получилось :)
Привычки старой школы очень сильны. То есть, фактически вы предлагаете делать на N видов продуктов, но подешевле (только без UI для справочников, а в остальном код заранее знает, что типов много и в будущем легко добавить новые).
"$%-як, $%-як и в продакшен" — это экстремальное программирование. Именно эта идея и была положена в его основу. Делаем минимальную функциональность и потом рефакторим. Тот же TDD изначально был частью XP, которую ввели для баланса к быстрой разработке.

И по XP именно так — вначале прибиваем гвоздями два вида. Появился ещё один вид — делаем рефакторинг. Поскольку у нас уже есть все тесты, при рефакторинге мы не теряем качество.

Разумеется, XP не универсален. Но к каким-то задачам он подходит.
Преждевременные абстракции такое же зло, как и преждевременные оптимизации.

Совершенно согласен. Более того, в случае например XML чрезмерно сложным иногда является вовсе не сам формат (именно гибкий, а не жесткий), а скорее попытки его описать, а именно XSD. Но при этом существует например RelaxNG, где все вовсе не так сложно.

XSD — на самом деле тоже довольно простая вещь. Сложным является сам XML когда библиотека для работы с ним не абстрагирует программиста от низкоуровневых тонкостей формата.


Например, популярной ошибкой тех, кто работает с XML, является завязывание на конкретные имена префиксов вместо пространств имен. Откуда рождаются веселости вроде "наш сервис работает с любой версией SOAP, главное чтобы корневой элемент имел префикс soap:". А если бы библиотека вообще не показывала префиксы у элементов, а показывала только локальные имена и пространства имен — такой ошибке было бы неоткуда взяться.

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


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

языки с динамической типизацией

Но почему-то по мере взросления Python обзавелся type hiting,
появился TypeScript и т.п.

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

На мой взгляд, заигрыванание со статической типизацией без чёткого плана (а его нет) — самая большая проблема Python.
Проще переписать на каком-нить JVM языке со статической типизацией чем костыли прибивать к велосипеду и ездить на этом. Если люди не понимают этого — то у них будут проблемы, но вовсе не из-за питона или типизации, как вы понимаете.
UFO just landed and posted this here
Из моего опыта программирования следует, что сложную систему построить проще, а простую сложнее.
Аналогично из жизни — УАЗик проезжает там, где ЛендКрузер вязнет. Сложное удобно, а простое надежно.
Крузак восьмидесятка. Но да, по комфорту двухсотке уступает, в целом вывод корректный  )
Сложность — это чувство и одновременно проблема восприятия.
Взято из рекомендованной вами книги — «Путешествие по системному ландшафту»
Т.е. со сложностью можно бороться чисто психологически.
Еще известен такой феномен как возрастной кризис, ускорение субъективного времени и страх потери производительности.
Это все складывается и тогда возникают теории катастрофического разрыва Йадерлунда (взято из той же книги)
Я в это не верю. Тот же ИИ как раз и не допустит разрыва.
UFO just landed and posted this here
Не уверен, что это проблема отрасли, а не отдельного человека.

Всегда были люди, которые копипастили с условного SO, и оно работает — «магия». А были люди, которым непременно надо разобраться на 3 слоя глубже, чем используемый уровень абстракции.

Автор, возможно, переходит из 1-й категории во 2-ю, т.к. не успевает за всем следить.

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

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

Да, вполне возможно :-) Нужно искать баланс между этими двумя крайностями.
Раньше разработкой руководили программисты, теперь — менеджеры. Менеджеру не понять зачем нужно рефачить сложный код, ему проще нанять по программисту на каждую кнопочку.

Плюс, молодые да зеленые не понимают зачем вообще нужны фреймворки, либы и языки. Они думают это чтобы было круто и весело, «зацените какой я странный способ запилил», для того чтобы придерживаться какой-то идеологии «ООП/ФРП это круто, все это поток, все живое» и т.п. Они тупо не понимают истории — это все было сделано для того чтобы бороться со сложностью.

Многие сложности, такие как нехватка памяти или скорость были решены на железном уровне, многие методологии потеряли актуальность, и вместо решения проблемы сложности они наоборот усложняют. Взять ООП. Когда-то это был прорыв, он помогал как-то решить проблему пользовательского интерфейса в условиях ограниченной памяти. Теперь памяти достаточно, а идея расшаренных изменяемых объектов стоит поперек дороги к многозадачности. В то же время у нас до сих пор есть идеологи ООП, которые строчат книги и курсы о том как это здорово когда к переменной можно присобачить функции и анимировать ее, каким умным можно выглядеть произнося «это паттерн „стратегия“».

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

Но в стартапах и ИТ-компаниях спрос на упрощение все еще теплится, взять тот же стековерфлоу, когда я узнал сколько у них серверов, то хохотал до слез. Компании вроде убера — это по сути не ИТ компании. Это обычные бизнесмены которые научились получать прибыть используя ИТ как канал. Их продуктом не является софт.
Хм… В итоге у нас есть:
— сложность построения;
— сложность системы как таковой.
Может быть сложность построения снижается за счет возрастающей стандартизации, универсальности. Которая в свою очередь является следствием возросшей сложности систем как таковых.
Это в свою очередь позволяет строить (мириться со сложностью) все более сложных систем. И так далее.
Данных просто стало сильно-сильно больше. А будет еще больше, всё только начинается.
Краткость, конечно, сестра таланта — но не настолько же! Едва заварил какао, приготовился к большой статье с анализом, красивыми графиками, разными примерами и аналогиями из иных наук и инженерных приложений, как она внезапно оборвалась. В общем, я даже не понял, что это было.
UFO just landed and posted this here
UFO just landed and posted this here

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

Мир (в лице заказчиков, бизнеса) ставит сложные задачи, сложность решения его (их) мало интересует, их интересует эффективность этого решения (ROI). А вот для повышения эффективности наша, разработчиков, подзадача управлять сложностью.

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

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

Если появится идея во что полезное эти мысли можно развить, постараюсь это сделать.

А не кажется ли Вам, что сложность и гибкость — суть понятия ортогональные?
Вполне возможно. Скорее всего каждое из этих понятия нужно разбивать на несколько более точных и те уже могут быть ортогональны.
Я к тому, что из простоты системы не обязательно следует ее гибкость.

Скорее наоборот, простейшая система обладает минимальной гибкостью — любое изменение требований повлечёт переписывание кода.

К сожалению, чем ниже порог вхождения в какую-то сферу разработки, тем больше она напоминает Hype Driven Development. На волне страхов перед проектированием у многих разработчиков, легко принимаются на вооружение разного рода хайп-фреймворки, мотивируя это тем, что:
«такие гиганты, как гугл и фейсбук разработали %FrameworkName% или %PseudoLibName% и используют это у себя, значит и у нас с коллективом в сто раз меньше человек это тоже подойдёт». А решения, зарекомендованные временем клеймят «устаревшими». Живой пример — веб фронтенд. Грустно.

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

>Живой пример — веб фронтенд.

откровенно говоря во фронте сейчас хорошо как никогда. Да и в целом мир javascript и ноды сейчас неплохо держится. То о чем вы говорите — это скорее результаты использования js там где его не использовали ранее. А во фронте — перенос приложений с десктопов в облака и всякие SPA. Тут да, есть немного, но это не следствие желания быть модными — это всего лишь поиск путей. А вот «решения, зарекомендованные временем» никто не будет списывать только во возрасту — бизнес умеет считать деньги а программисты — время и нервы. Если решение дает результат — оно в обойме, если нет — ничего личного )
Sign up to leave a comment.

Articles