[Из песочницы] Вы разрабатываете эффективные или антихрупкие системы?
Давайте поговорим о high-load, high-extensible, ООП, DDD & EDA.
Речь пойдет о разнице между high load & high extensibility — это разные цели и задачи. Для которых нужны принципиально разные подходы. Которые часто вызывают когнитивный диссонанс среди программистов, предвещающий бурную полемику.
На Хабре много статей про high-load, а вот тема high-extensible как-то упускается из внимания.
Хайлоад это хайлоад. Это быстрые ответы на запросы и постоянные соединения. Обычно тут php RoadRunner или Go или Rust, с асинхронностью и event loop. Проблема 10k и т. д.
ООП было придумано как решение задачи расширения или High Extensible. Тут лучше работают DDD (domain driven design) & EDA (event driven architecture).
Это две крайности одной и той же сущности.
В книге Антихрупкость, автор Нассим Талеб пишет о том что погоня за эффективностью всегда влечет рост хрупкости. Если мы ставим себе цель делать систему антихрупкой, нам придется жертвовать эффективностью. Иного не дано.
Антихрупкость любит случайность и неопределенность, что означает — и это ключевое свойство антихрупкости — любовь к ошибкам, к определенному классу ошибок. Уникальность антихрупкости состоит в том, что она позволяет работать с неизвестностью, делать что-то в условиях, когда отсутствует понимание, что именно делается, — и добиваться успеха.
Вам нужна система которая будет эффективной или антихрупкой?
Ответ на этот вопрос влияет на решения о том какие технологии следует использовать.
Цитата Алана Кея, автора ООП:
«Я придумал термин «объектно-ориентированный», и могу сказать, что я не имел в виду С++». Алан Кэй, конференция OOPSLA, 1997.Ключ к созданию хороших масштабируемых систем это проработка механизмов общения модулей, а не проработка их внутренних свойств и поведения.
Я не против типов, но мне не знакома ни одна система типов, которая не вызывала бы боли. Так что мне все еще нравится динамическая типизация.
Позднее связывание позволяет с меньшими усилиями встраивать в проект идеи, которые возникли позже в процессе разработки (по сравнению с системами с более ранним связыванием вроде C, C++, Java, и пр.)
Я считал объекты чем-то вроде модулей, биологических клеток, и/или отдельных компьютеров в сети, которые могут общаться только через сообщения.
Я сожалею о том, что давным-давно придумал термин «объекты» для этого явления, так как его использование приводит к тому, что многие люди уделяют основное значение идее, которая не так важна, как основная. Основная идея — это обмен сообщениями
ООП для меня означает лишь обмен сообщениями, локальное сохранение, и защита, и скрытие состояния, и крайне позднее связывание
Итак, если взять эти идеи, то тезисами это можно сделать так:
- Масштабируемые и расширяемые системы состоят из модулей
- Модули общаются друг с другом через сообщения
- Это обеспечивает позднее связывание — крайне позднее связывание — код и логику можно менять в любой момент не меняя уже существующий код в модулях
- Для работы такой системы важна динамическая типизация, а не статическая
В книге Мифический человеко-месяц, автор Фредерик Брукс описывает момент когда ООП разбилось на 2 мира. Часть «Объектно-ориентированное программирование:, а медна пуля не
подойдет?»
Разработка из больших частей. Если осуществлять сборку из частей, которые достаточно сложны и имеют однородные интерфейсы, можно быстро образовывать довольно богатые структуры.
Согласно одному из взглядов на объектно-ориентированное программирование эта дисциплина осуществляет модульность и чистые интерфейсы. Другая точка зрения подчеркивает инкапсуляцию — невозможность увидеть и еще менее изменить внутреннюю структуру детали. Еще одна точка зрения отмечает наследование и сопутствующую ему иерархическую структуру классов с виртуальными функциями. И
еще один взгляд: важнейшей является сильная абстрактная типизация данных вместе с гарантиями, что конкретный тип данных будет обрабатываться только применимыми к нему операциями.
В настоящее время не нужен весь пакет Smalltalk или C++, чтобы использовать любой из этих дисциплин — многие из них поглотили объектно-ориентированные технологии. Объектно-ориентированный подход привлекателен, как поливитамины: одним махом (т.е. переподготовкой программиста) получаешь все. Очень многообещающая концепция.
Получается что идея ООП зародилась в 60е годы, в 80е годы уже были разные точки зрения на то что есть ООП.
Сегодня под ООП чаще всего имеют ввиду классы. Хотя Алан Кей и Дэвид Уэст говорят что это ошибка. И что классы это всего лишь структуры данных. Это не про ООП. C++ & Java в базе не имеют ничего общего с ООП.
Речь идет про то ООП которое про модули и обмен сообщениями. Сегодня эта идеология чаще всего встречается со словами DDD & EDA. Ты пишешь модули, которые обмениваются сообщениями через чистые интерфейсы (события, хуки, триггеры) с крайне поздним связыванием.
Если вам нужен HighLoad, вам надо топить за эффективность, масштабирование скорости исполнения, статическую типизацию, асинхронность, события и eventloop.
Если вам нужен HighExtensible, вам надо топить за антихрупкость, масштабирование скорости изменений, динамическую типизацию, модули и домены (DDD) и события как EDD (обмен сообщениями между модулями).
Проблема в том что программисты спорят о том что ООП плохо (классы это медленно и хрупко, а функции быстро и круто, ну или как то там наоборот), о том что вот в PHP не хватает асинхронности и event loop.
Например эти темы поднимались на недавнем митапе SkyEng https://www.youtube.com/watch? v=QrlWrFILjMk
Но не понимают что это разговор о разных идеологиях, парадигмах и архитектурах. Это все равно что говорить что у дома нет колес или у автомобиля не хватает 3 го этажа с ковром. Вот бы ложка была вилкой или вилка была бы ложкой. Вообще есть конечно вилка-ложки, но часто ли мы ими пользуемся вне горных походов?
Если вы создаете прикладную бизнес систему, где есть куча реальных пользователей, бизнес требования, бизнес аналитики, никто не знает что хочет, а требования меняются каждый день — вы очень сильно попадете в засаду если пойдете по пути HighLoad, будете делать статическую типизацию, асинхронность, без доменов и событий — вам будет больно. Тут нужно двигаться ближе к архитектуре для HighExtensible.
Если вы создаете микросервисы, которым надо отрабатывать 100 000 операций в секунду, то попытка пойти по пути динамической типизации, доменам, без асинхронности — тоже сделает очень больно. Тут стоит копать в сторону архитектуры под HighLoad.
Сделать одновременно HighLoad & HighExtensible — не реально или очень близко к не реальному. Попытки совместить эти две идеологии приводят к диким проблемам, большим затратам и часто к провалу.
Ну, а программисты готовы спорить об этом до посинения. Не понимая что говорят про разные контексты, задачи и механизмы проектирования архитектур.
Про high-load:
- NodeJS — пошел с вектором в event loop & асинхронные механики. Есть много интересных кейсов с построением highload микросервисов и REST API.
- Туда же можно отнести Go, Rust и разные механики PHP типа RoadRunner и PHP Swoole.
Про high-extensible
- Можем взять Redmine, это типа система управления задачами, на базе RoR, там также есть модули (плагины), а общение модулей и обмен сообщениями строится на хуках.
- Ребята из FreeScout решили делать систему хелпдеск на Laravel. Это прикладная система с кучей бизнес логики. Они реализовали свою архитектуру модулей (DDD) и обмена сообщениями (EDA) применив Eventy.
- Eventy в свою очередь взял идею хуков из WordPress. Надо ли представлять этого зверя? Который держит более 30% рынка веб сайтов. Его архитектура также базируется на идеи модулей (плагинов, DDD), которые взаимодействуют друг с другом через сообщения (хуки, EDA).
Очень интересный опыт у ребят из iSpring:
https://www.youtube.com/watch? v=xT25xiKqPcI
Там речь о том чем отличается монолит от копролита. О том что если уметь готовить монолит, с DDD & EDA, то можно получить много преимуществ. А если не уметь — то и микросервисы не факт что помогут.
В общем, ребята ступили на путь освоения DDD & EDA. И это радует.
Мир технологий в целом и разработок в частности очень многогранен. Если есть какая то технология — значит на то есть причины. Не знание этих причин еще не значит что технология плохая сама по себе.
Динамическая и статическая типизация — обе правильные, если их применять в соответствующих задачах.
ООП тоже очень разное может быть и есть много разных точек зрения на то что это такое. И все они правильные. Просто там разные контексты.
Вилка или ложка — не плохие и не хорошие. И если человек ест спагетти ложкой, а суп вилкой, а потом пишет о том что ложка это плохо, потому что спагетти вываливаются, и вилка плохо потому что суп хлебать ей не удобно — то разве это проблема в вилке или ложке?
Ну и под конец, хочется больше примеров. Кто какие еще примеры знает грамотного применения DDD & EDA?
Особенно интересует опыт построения HighExtensible систем в РФ. Потому что на западе его хватает. А тема high-load на Хабре и так перегрета. Хочется больше поговорить о практиках high-extensible.