Анемичные модели, dto vs entity это проблемы не java, а в целом ООП подхода
невозможно говорить за весь ООП, ведь нет чёткого определения что это вообще такое. По этому я говорю о самом популяром варианте — java-style ООП(которое изначально пошло из С++, и корнями уходит бог знает куда).
Возможно, как вы говорите ООП мешает, но какие у нас альтернативы?
У нас, в частности, используется обфускатор. Это боль и без Lombok. Я был бы очень рад воткнуть Lombok, но пока на это просто нет времени(а с полпинка не заводится). К тому же не все такие продвинутые, и во многих проектах просто запрещают его использовать(деды на null проверяли, и нам велели...).
Соглашусь, неудобно. Можете показать пример технологии, где это сделать удобней?
obj1 & obj2 . obj3 . someField .~ "someValue"
Вот только большая часть данных существует только в рантайме, потому статические проверки не будут иметь смысл.
Будут. Статическая проверка позволяет гарантировать консистентность не только в момент валидации, но и на всём протяжении работы логики программы.
Так люди же намеренно пришли от статического к динамическому связыванию. Все реализации фабрик, сервисов, репозиториев можно и сейчас закостылить в лоб, вот только такой код не будет гибким для изменений.
Кто говорит про «закостылить в лоб»? Есть и другие методы, кроме динамического связывания.
Судя по критике — мутабельность, система типов, IoC — мне показалось, что вы больше приверженец ФП, я прав?
Я java программист, и конечно я большую часть времени использую ООП. От этого и критика. ФП только изучаю, но в целом уже сейчас понятны преимущества подхода ФП. Да и в целом размытое понятие ООП для меня теряет ценность. Непродуманность ООП можно обнаружить даже в классических определениях вроде «инкапсуляция, наследование, полиморфизм, (абстракция)». Ведь инкапсуляция присуща всем парадигмам, а наследование всего-лишь механизм конкретных языков. Остаётся полиморфизм подтипов?
Для меня Entity — сущность слоя бизнес-логики, где-то под капотом связанная со слоём данных.
Но по факту это не так. Entity это слой persistence, и я уже объяснил почему.
Где тут нарушение инкапсуляции?
Не очень понял Ваш кейс, т.к. описано что происходит, но не описано где. Если имелось в виду что из слоя бизнес логики возвращаются DTO, то инкапсуляция тут не нарушается(правда получение контракта по id это тоже утечка абстракции, здесь следовало бы использовать номер контракта, либо UUID; но часто это бывает неудобно).
Зато сразу возникают вопросы со ссылками на другие сущности. Как их делать в DTO? Через id? Что-то совсем не ООП получается — у нас просто методы с контекстом(сервисы бизнес логики) и структуры данных(Value Object). Но в целом с таким подходом я согласен.
По JSR-380 валидация происходит не в момент конструкции объекта(или модификации полей), а в момент вызова валидаторов. Т.е. никто не гарантирует что Ваш класс Email валиден в произвольный момент времени(только сразу после вызова валидатора). И, соответственно Email тут не выполняет роль типа, гарантирующего валидность данных. А значит большой разницы как писать в данном случае нет.
Но ведь Entity это сущность слоя данных, причём у этой сущности есть особое поведение. Например, можно помимо слоя бизнес логики поменять значения полей сущности, и hibernate спокойно обновит их в базе данных. Это прямое нарушение инкапсуляции. Сущность, хотя и выглядит как объект, содержащий только данные, на самом деле таковым не является. Например, поля могут загружаться лениво, что вызовет проблемы при передаче такого объекта в другой поток.
Это не говоря уже о том, что многие даже Id из БД считают утечкой абстракции.
А что в ней хорошего? ООП в java изначально предполагало объединение данных и функций в объектах. Но по факту это не работает, и enterprise модели просто вырождаются в анемичные, в которых данные и функции опять разделены.
ООП здесь только мешает, например в момент соприкосновения объектной модели в сущностях hibernate(а это вполне себе объекты, а не просто данные) с анемичной моделью бизнес логики.
Что, например, следует возвращать из сервиса бизнес логики? Entity? Но ведь это прямое нарушение инкапсуляции, утечка абстракций. Какой-нибудь data класс? А как в таком случае стакать ссылки?
Отличная вещь, но не везде он применим. В частности бывают проблемы с hibernate, и далеко не во всех проектах его используют. В legacy проектах его не встретишь.
А подробнее можно о чем речь?
Об устройстве различных фреймворков, и о том, как пишутся enterprise приложения. По сути сплошные абстракции ради абстракций, которые в итоге текут.
Никто вам не запрещает писать безопасный код. Любой язык позволяет писать хорошо или плохо. Не хотите мутабельность — используйте immutable типы и final переменные.
только в Java использовать иммутабельные структуры попросту неудобно. Например, как мне без мутаций поменять поле в цепочке объектов obj1.obj2.obj3.someField? К тому же библиотечный код часто не предполагает ссылочной прозрачности(например hibernate). Отдельного внимания заслуживают коллекции, интерфейс которых никак не может гарантировать иммутабельность. (А без lombok всё выглядит ещё печальнее)
Опять же, можно подробнее о чем речь?
Например, использование аннотаций для валидации полей, вместо специальных типов. Мы могли бы сделать тип Email, а не использовать String с аннотацией. Или проверить статически что в массиве не меньше N элементов. Конечно, многие вещи можно так сделать(а некоторые не позволяет сделать система типов), но так просто не принято делать. Принято использовать аннотации, которые не могут гарантировать консистентность объекта в любой момент времени. Инъекция зависимостей, репозитарии Spring Data, маппинг Hibernate — все эти вещи можно было бы описать статически.
У java довольно простой, лаконичный синтаксис и хорошо проработанный ООП, которым не каждый ЯП похвастается.
Синтаксис даже слишком простой, что выливается в огромное количество бойлерплейта. И да, это огромная проблема, хотя её старательно пытаются не замечать.
ООП в java это по большей части overengineering, который не решает реальных проблем. При этом мутабильность спокойно ломает инкапсуляцию, но это, опять же, стараются не замечать.
У java самодокументируемый код, всегда есть возможность посмотреть не только документацию по методу, но и саму его реализацию с комментариями авторов.
При этом слабая система типов, и нездоровая любовь к рефлексии, которые мешают писать надёжный код. Ну и NPE, да.
Ну, есть CI/CD система, которая в своих шагах запускает контейнеры, которые что-там делают для пайплайна. Как я понимаю, нужен либо контейнер для gradle, который генерирует jar, который потом ляжет в контейнер приложения, либо gradle, котоырй прямо сгенерирует нужный контейнер.
Ну вообще там достаточно запустить ./gradlew dockerPushImage, например. Он в самом проекте есть. Из контейнера или нет — не особо важно, главное что-бы java была установлена.
В последней время канонично я пихаю php-fpm в контейнер, к которому обращается ingress прямо по fastcgi :) А так, для CMS каких-нибудь предпочитаю отдельные контейнеры для php-fpm и nginx и как раздаватель статики, и как адаптер http<->fastcgi. Некоторые ставят apache+mod_php. А некоторые веб-сервер поднимают на ReactPHP и ко.
ну да, я сейчас так и сделал — 2 контейнера, nginx + php-fm. Но не очень-то удобно, что статику нужно отдельно пихать в nginx. Думал может есть каноничный путь какой-нибудь. В принципе и так норм.
То есть нужен контейнер с gradle, в который нужно установить плагин, запустить его как-то и он соберёт другой контейнер с JRE и jar файлом?
Зачем Вам контейнер для Gradle? Gradle это система сборки, с помощью неё вы создаёте jar'ники, запускаете тесты и т.д. Выбор «gradle project» создаст Вам проект с этой системой сборки, выбор maven создаст с мавеном. Там, наверняка, тоже подобный плагин есть, просто я им не пользуюсь. Всё что потребуется — прописать плагин в файле конфигурации gradle.
Наверное, хватит?
Может быть.
Кстати, раз уж тема про контейнеризацию — какой нормальный способ засунуть PHP приложение в контейнер? Что-бы канонично — один контейнер, без всяких отдельностоящих php-fm'ов и nginx'ов?
Как минимум, под вопросом зачем тогда эти языки, если можно изучать Java?
Что-бы чуть поменьше(или гораздо меньше) страдать при написании и проектировании системы.
Scala, например, заточен под более надёжную типизацию. У этого есть профиты, но, конечно, взаимодействовать с Java кодом приходится. И знать стандартную библиотеку java тоже.
А на kotlin, например, стандартная библиотека java активно используется сама по себе.
Java платформа довольно обширна, тут хватает и скриптовых языков. А что может предложить PHP, например, по сравнению с groovy? Чем он лучше(кроме синтаксиса, или чего-то ещё субъективного)? Он проще? Для хелоуворда да, но PHP это давно не хелоуворды.
Или он только для «хелловорлдов» из одного файла без зависимостей от чего либо кроме стандартной библиотеки?
Только для хелловорлдов.
Система сборки должна собрать jar, который затем нужно поместить в контейнер. Для gradle, например, можно использовать плагин com.bmuschko.docker-spring-boot-application, который сам всё соберёт и запушит, если надо.
А есть объективная причина «не связываться с Java экосистемой»?
Зависит от языка. На скале, например, вполне нормально игнорировать java подходы. Даже напротив — часть Scala разработчиков считает плохим тоном их использовать. А kotlin напротив, пытается облегчить написание каноничного java-кода.(но и у него есть собственный подход, к dsl, например)
Достаточно выбрать Springboot, там будет выбор всего остального(со значениями по дефолту). При сборке получится один fatjar, для запуска которого нужна только java. Всё, никаких отдельных настроек nginx, никаких супервизоров не нужно.
Про деплой как-то так, но никаких библиотек тащить не нужно, плагин springboot сам всё запечатает в jar. То же самое и с шаблонизатором, это просто библиотека и она будет в jar. CI/CD обычно делается сборкой докер image, в котором уже будет приложение. Есть плагины для систем сборок, которые добавляют task, собирающий всё приложение в контейнер в один клик. Для запуска достаточно развернуть контейнер. Внутри будет и java и jar, плюс параметры легко передаются через env.
Я уже слышал этот тезис. Непонятно только — зачем нам вторая Java? Я не считаю что java, как язык, подходит для enterprise. Что объектная модель Java чем-то хороша. Напротив, довольно слабый язык, библиотеки и подход к программированию страдают от оверинжинирига. К тому же наиболее близкий к java скриптовый язык уже существует — это groovy.
Что хорошо в Java — это среда исполнения и возможности отладки, но в этом плане PHP в сторону java не движется, насколько я понимаю.
Так в Java достаточно gradle/maven и springboot. Идея сама сгенерирует проект, так что непонятно чем php тут проще. Плюс практически из коробки все готово для микросервисов. И в итоге получится один jar, для запуска которого нужна только java.
А многословность это действительно проблема java, особенно в сочетании с такой простой системой типов.
Здесь стоило бы остановиться на JS. Т.к. js большинство разработчиков на php js знают хорошо, язык имеет большую сферу применения. А странности? Так их и в php хватает. Плюс не придётся костыли делать на том же js для поддержки асинхронности в php.
Хотя может я ошибаюсь, и кто-нибудь объяснит мне в чём профит от php. А то я, как java разработчик, вижу только минусы(которые связаны с вышеописанными костылями, а не с самим языком). Только не надо про ЗП и кол-во специалистов.
Сложность ФП — всякие монады, стрелки, функторы это всего-лишь отображение сложности предметной области. В классическом императивном ООП существуют точно такие-же сложности, просто они не решаются явно. И в итоге это всегда всплывает и становится огромной архитектурной проблемой.
Как пример — классические ОРМ вроде hibernate. Вроде всё просто и понятно, есть таблицы и маппинг. Можно дернуть get для получения значения свойства, set для установки. Но это только в вакууме. В реальном мире сложности начинаются сразу же — как только появляется слой бизнес логики, становится понятно, что полученные красивые объекты невозможно использовать в бизнес логике, а их «красивость» только мешает. Что lazy загрузка ломает всё в самом неподходящем месте. В итоге даже обычный CRUD превращается в головную боль.
Как минимум есть ещё функциональный подход.
Будут. Статическая проверка позволяет гарантировать консистентность не только в момент валидации, но и на всём протяжении работы логики программы.
Кто говорит про «закостылить в лоб»? Есть и другие методы, кроме динамического связывания.
Я java программист, и конечно я большую часть времени использую ООП. От этого и критика. ФП только изучаю, но в целом уже сейчас понятны преимущества подхода ФП. Да и в целом размытое понятие ООП для меня теряет ценность. Непродуманность ООП можно обнаружить даже в классических определениях вроде «инкапсуляция, наследование, полиморфизм, (абстракция)». Ведь инкапсуляция присуща всем парадигмам, а наследование всего-лишь механизм конкретных языков. Остаётся полиморфизм подтипов?
Не очень понял Ваш кейс, т.к. описано что происходит, но не описано где. Если имелось в виду что из слоя бизнес логики возвращаются DTO, то инкапсуляция тут не нарушается(правда получение контракта по id это тоже утечка абстракции, здесь следовало бы использовать номер контракта, либо UUID; но часто это бывает неудобно).
Зато сразу возникают вопросы со ссылками на другие сущности. Как их делать в DTO? Через id? Что-то совсем не ООП получается — у нас просто методы с контекстом(сервисы бизнес логики) и структуры данных(Value Object). Но в целом с таким подходом я согласен.
Это не говоря уже о том, что многие даже Id из БД считают утечкой абстракции.
Нет, это не подход из Java. В Java, обычно, делают так:
https://www.baeldung.com/javax-validation
ООП здесь только мешает, например в момент соприкосновения объектной модели в сущностях hibernate(а это вполне себе объекты, а не просто данные) с анемичной моделью бизнес логики.
Что, например, следует возвращать из сервиса бизнес логики? Entity? Но ведь это прямое нарушение инкапсуляции, утечка абстракций. Какой-нибудь data класс? А как в таком случае стакать ссылки?
Об устройстве различных фреймворков, и о том, как пишутся enterprise приложения. По сути сплошные абстракции ради абстракций, которые в итоге текут.
только в Java использовать иммутабельные структуры попросту неудобно. Например, как мне без мутаций поменять поле в цепочке объектов obj1.obj2.obj3.someField? К тому же библиотечный код часто не предполагает ссылочной прозрачности(например hibernate). Отдельного внимания заслуживают коллекции, интерфейс которых никак не может гарантировать иммутабельность. (А без lombok всё выглядит ещё печальнее)
Например, использование аннотаций для валидации полей, вместо специальных типов. Мы могли бы сделать тип Email, а не использовать String с аннотацией. Или проверить статически что в массиве не меньше N элементов. Конечно, многие вещи можно так сделать(а некоторые не позволяет сделать система типов), но так просто не принято делать. Принято использовать аннотации, которые не могут гарантировать консистентность объекта в любой момент времени. Инъекция зависимостей, репозитарии Spring Data, маппинг Hibernate — все эти вещи можно было бы описать статически.
ООП в java это по большей части overengineering, который не решает реальных проблем. При этом мутабильность спокойно ломает инкапсуляцию, но это, опять же, стараются не замечать.
При этом слабая система типов, и нездоровая любовь к рефлексии, которые мешают писать надёжный код. Ну и NPE, да.
ну да, я сейчас так и сделал — 2 контейнера, nginx + php-fm. Но не очень-то удобно, что статику нужно отдельно пихать в nginx. Думал может есть каноничный путь какой-нибудь. В принципе и так норм.
Может быть.
Кстати, раз уж тема про контейнеризацию — какой нормальный способ засунуть PHP приложение в контейнер? Что-бы канонично — один контейнер, без всяких отдельностоящих php-fm'ов и nginx'ов?
Scala, например, заточен под более надёжную типизацию. У этого есть профиты, но, конечно, взаимодействовать с Java кодом приходится. И знать стандартную библиотеку java тоже.
А на kotlin, например, стандартная библиотека java активно используется сама по себе.
Java платформа довольно обширна, тут хватает и скриптовых языков. А что может предложить PHP, например, по сравнению с groovy? Чем он лучше(кроме синтаксиса, или чего-то ещё субъективного)? Он проще? Для хелоуворда да, но PHP это давно не хелоуворды.
Только для хелловорлдов.
Система сборки должна собрать jar, который затем нужно поместить в контейнер. Для gradle, например, можно использовать плагин com.bmuschko.docker-spring-boot-application, который сам всё соберёт и запушит, если надо.
Зависит от языка. На скале, например, вполне нормально игнорировать java подходы. Даже напротив — часть Scala разработчиков считает плохим тоном их использовать. А kotlin напротив, пытается облегчить написание каноничного java-кода.(но и у него есть собственный подход, к dsl, например)
Про деплой как-то так, но никаких библиотек тащить не нужно, плагин springboot сам всё запечатает в jar. То же самое и с шаблонизатором, это просто библиотека и она будет в jar. CI/CD обычно делается сборкой докер image, в котором уже будет приложение. Есть плагины для систем сборок, которые добавляют task, собирающий всё приложение в контейнер в один клик. Для запуска достаточно развернуть контейнер. Внутри будет и java и jar, плюс параметры легко передаются через env.
Что хорошо в Java — это среда исполнения и возможности отладки, но в этом плане PHP в сторону java не движется, насколько я понимаю.
Так в Java достаточно gradle/maven и springboot. Идея сама сгенерирует проект, так что непонятно чем php тут проще. Плюс практически из коробки все готово для микросервисов. И в итоге получится один jar, для запуска которого нужна только java.
А многословность это действительно проблема java, особенно в сочетании с такой простой системой типов.
Хотя может я ошибаюсь, и кто-нибудь объяснит мне в чём профит от php. А то я, как java разработчик, вижу только минусы(которые связаны с вышеописанными костылями, а не с самим языком). Только не надо про ЗП и кол-во специалистов.
Как пример — классические ОРМ вроде hibernate. Вроде всё просто и понятно, есть таблицы и маппинг. Можно дернуть get для получения значения свойства, set для установки. Но это только в вакууме. В реальном мире сложности начинаются сразу же — как только появляется слой бизнес логики, становится понятно, что полученные красивые объекты невозможно использовать в бизнес логике, а их «красивость» только мешает. Что lazy загрузка ломает всё в самом неподходящем месте. В итоге даже обычный CRUD превращается в головную боль.