Information
- Rating
- 1,935-th
- Location
- Москва, Москва и Московская обл., Россия
- Date of birth
- Registered
- Activity
Specialization
Backend Developer, Руководитель отдела разработки
Lead
From 450,000 ₽
C#
.NET
Software development
Database
High-loaded systems
Designing application architecture
Creating project architecture
Design information systems
Monitoring
42.ToString() выполняется на стеке только благодаря костылю .NET, в виде ValueObject, который с одной стороны наследуется от Object, с другой стороны не является ссылочным типом, пока его не присвоили в object (boxing). И это простой пример, потому как обычно, в стек много не положишь, а объектов нужно всяких много. Где же им ещё размещаться, как не в куче?
А что мне делать, если мне нужен результат этой отправки? Или хотя бы я должен убедиться, что событие получено и обработано, потому что если я продолжу логику, то будет рассинхрон. Например, отправляю событие создать пользователя, а следом, пользователь кладёт в корзину... а пользователя-то ещё может не оказаться к тому моменту.
Противоречие в том, что из класса часто пытаются смоделировать поведение "как в жизни". А это неправильно, от этого в конце концов уходят в анемичные модели и потом ругают ООП. Хотелось бы сказать, что ООП используют неправильно, но всё глубже. Это программирование используют неправильно, не понимая основных базовых концепций. Что в БД у нас не договор, и не клиент, не юзер, не склад, не товар, а записи об их существовании. И всего лишь проводим изменения в БД, или делаем запросы чаще всего, из подавляющего количество работы это учётные системы.
Представьте, что бумажный паспорт имеет функцию "получить деньги на кассе" или "заключить сделку". Абсурд? Но когда мы пишем класс, с подобными методами, уже не абсурд :)
Только если это безопасно и вычисляется на этапе компиляции. Он может не использовать виртуальный вызов для точно известного на момент вызова типа и его метода. Но в примере выше так не будет, так как я как разработчик привёл значение к ссылке на общий объект.
Если отправка события некоему объекту это синхронное действо, то разницы никакой нет, кроме того, каким словом это называть. А вот если отправка события летит в очередь, то это уже совсем-совсем другое дело.
В любом мало-мальском современном ЯП можно использовать такой подход, но удовольствия в этом мало, если применять вообще везде. Такое нужно применять когда в этом есть необходимость. Например, для распределённых вычислений, берём Akka или Orleans. Для стримов берём кафку, если синхронный реквест/реплай нужен, то городим огород на AMQP или берём Nats. Ну а если это монолит, то очереди в памяти, в гошке те же ченнелы.
Я хочу сказать, что мы ничего не лишились. Вы описываете один из тех случаев, когда подход строится по принципу "всё есть....": всё есть объект, все структуры и переменные неизменны, все взаимодействия это события, всё есть функция с каррированием. Конечно это даёт определённые преимущества, например, для параллелизма, но и в то же время награждает существенными болезненными ограничениями, где казалось бы простые вещи приходится городить костылями.
Мне по душе мульти-парадигменный подход, который даёт возможность выбирать наиболее подходящие паттерны под задачу.
"Извне" работает только если программист реализует компонент, который используется другими программистами, при реализации логики. А зачастую это компонент, который уже зацеплен к презентации, не будет это использовать другой программист, это конечная логика для пользователя. Т.е. это JSON для фронта, или отображаемая форма с контролами, или HTML.
Договор это зафиксированные юридически отношения с кастомером, в котором прописывается комплекс услуг, товаров, физических действий, осуществляемых в реальности, и только часть из них фиксируется в информационной системе.
И когда пытаются создать класс "Договор" или "Клиент", и описать в нём методы 1 в 1 соответствующие реальности, это не работает просто из-за нарушения понятий.
В информационной системе "Договор" это запись, отображающая какую-то часть бизнеса в реальном мере, а точнее какие-то аспекты этого состояния. И мы работаем с состоянием, а не с сами договором. Мы не можем "Подписать" договор в системе, мы можем изменить статус с "Не подписано" на "Подписано" в его состоянии. Поэтому метод "Подписать" в классе это искажение реальности. Новички об это часто спотыкаются, и некоторые с завидным упорством пытаются смоделировать реальный мир в классе. Получается это плохо, и, самое главное, инфраструктура, синтаксис языка, особенности используемого фреймворка смешиваются с терминологией бизнеса. И получается каша, которую сопровождать потом сложно.
Не знаком к сожалению с синтаксисом D. Вижу тут выведение типа через
auto, нет объекта как такового, это структура и компилятор явно вызывает известные на момент компиляции методы применительно к конкретной структуре известного типа, поэтому это работает на стеке. А давайте в общий базовый тип и вызовем метод, общий для всех объектов. Получится?Пример на C#
Компилятор "не знает" чей
ToString()я вызываю, в рантайме вызывается метод, вычисляемый для конкретного экземпляра, через vtable.Если я не пользуюсь самолётами, а езжу только поездами, можно ли считать, что в моём мире не существует самолётов?
Согласен, для формошлёпства и перекладывания из DTO в JSON, ООП не нужен, всё это от лукавого.
Ну например, если в общих чертах, то физический реальный договор это не тоже самое, что запись в БД. Под действием "подписать" может пониматься, проставить в записи о договоре отметку, что клиент собственноручно расписался на обоих бумажных экземплярах, и приложить фотографию. Т.е. мы говорит про изменение состояние записи в приложении, которое отвечает за какой-то аспект договорных отношений. Нет никакого "договора" в приложении. Есть запись, отражающая информационное состояние. И как показала моя практика (в различных проектных командах), это создаёт у разработчиков путаницу в определениях и сложному и совершенно не нужному дизайну классов. Там где нам надо было управлять состоянием, мы пытаемся вести себя как объекты реального мира, имитировать их. Это приводит к тому, что мы пытаемся контролировать на уровне класса, что контролировать там не нужно. Например, то же самое подписание, это с точки зрения бизнеса атомарное действия, либо подписал, либо нет, а с точки зрения операционного учёта, это транзакция с комплексом событий, оркестрация всего этого добра с подтверждениями и согласования между разными системами.
Хах :) Вопрос с подвохом.
Ну далеко не только в Java же. Но везде есть свои, как говорится, приколы.
Про посылку сообщений объекту, ну это как бы тоже уровень абстракции. Чем строчка с вызовом метода у объекта по его ссылке не "отправка сообщения"? Если метод виртуальный, или вообще ЯП динамический, то в ответ также получим либо исключение, либо какой-нибудь
undefined. Почему от абстракции посылки сообщений вообще везде ушли, наверное потому что это дико неудобно и сложно. Но также, не ручаюсь за именно такое объяснение. Однако имеем что имеем. На языках ООП, написаны горы полезных продуктов, в том числе те, которыми мы ежедневно пользуемся.Стоит всё же кое что добавить к сказанному. Споры вокруг ООП чаще всего напоминают спор глухого со слепым. Огромный пласт работы, в которой задействованы программисты, это императивная логика, построенная на вызове методов, аннотациях и условиях, а классы это 99% контейнеры данных, контейнеры логики (контроллеры например), просто наборы методов для внедрения в DI. Нет тут никакой потребности в инкапсуляции, что и от кого скрывать? Это верхнеуровневая логика, прямо за ней уже находится пользователь, а не другой программист. Код призван решать конкретную бизнес задачу. Он типовой, похож на копипасту, но для бизнеса он крайне важен, так как закрывает таску в джире и открывает новую фичу. В этих условиях нужно понять разработчика, ему этот ООП как филькина грамота. Даёшь функциональщину! Вот это дело. Паттерн матчинги, лямбды, вот это всё нужно. А ваши ООП, это для дедов :)
Всё зависит от применения. Прикладная логика редко требует разработки классов. В основном это чистый императив и DTO. На этой почве чаще всего и звучат "ООП нинужен", когда основная часть работы это перекладывание данных из JSON в DTO и запросы в БД. При чём на плечах огромной кучи библиотек и платформы, с кучей классов под капотом. По той же логике можно с уверенностью сказать, что микроэлектронника не нужна. Да, у меня есть телефон, куча аппаратуры, я просто кнопки жму, зачем мне нужна ваша микроэлектронника? :)
Из своего опыта, когда начал разрабатывать библиотеки, свои расширения платформы, а потом и платформу, то все возможности ООП в такой разработке используются на 100%. И всё это очень нужно.
Утверждения про "побеждает", это примерно как щупать в слепую слона за хобот и утверждать, что хобот, это всё что нужно, хобот победил :)
Классика :)
Почему не норм? Это одна из эффективных форм познания. Сначала делаем глобальное обобщение, потом находим нарушения и несоответствия. Или надо сразу всё знать и говорить всегда только правильные вещи, и не дай бог ошибиться?
Нельзя стать экспертом, не пытаясь им стать. Или как должно быть. 30 лет программируешь, а потом просыпаешься и понимаешь, вот теперь кажется я и стал экспертом, теперь мне можно писать на хабр, и меня не заклюют и не заклеймят новичком :)
А если назначение было переосмыслено? Сколько вещей в мире было создано с одним назначением, а оказалось, что для этого оно подходит плохо, но зато хорошо подходит для другого? В разработке это наблюдается сплошь и рядом. А без холиворов не будет переосмысления, конечно имеются в виду аргументированные холиворы, а не набрасывание на вентилятор.
Вот самый банальный пример: "всё есть объект". Попытка глобального обобщения разбивается о суровую реальность. Когда "всё объект", технически это приводит к необходимости вот это "всё" держать в куче, чтобы была ссылка на объект. Но это не всегда рационально, местами крайне избыточно и сильно бьёт по производительности. И начинаются пляски, ну ладно "не всё объект" или по крайней мере не всегда, давайте вот отдельно выделим примитивы (Java), или объекты-структуры (ValueType, C#).
ООП не просто инструмент в вакууме. Это инструмент, который позволяет снизить сложность большого спектра задач. Но когда с помощью ООП начинают моделировать объекты реального мира, от банальных "кошек/собак" с их реализацией "мяукать/гавкать", до более сложных "договор" с методами "подписать", "принять", "отклонить" — то очень быстро приходит понимание, что ООП с этим справляется просто отвратительно и в целом для этого не подходит. Если конечно, находясь под эйфорией, не начинать подгонять молотком и зубилом любую задачу под ООП. Вот здесь самая суть проблемы, которую и превратили во зло.