(java || kotlin) && devOps
367 subscribers
6 photos
1 video
6 files
307 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем привет!

Продолжается перерыв в теме микросервисов.
Сегодня будет немного холивара)

Можно ли использовать static методы?

Исторически static-и прошли 3 стадии в своем восприятии.

1 этап: о круто, можно не создавать объект, давайте все методы делать статическими.
Если что - я конечно утрирую насчет всех, но static-и активно использовались, это факт, который легко увидеть в legacy коде. Еще факт: static-и есть во многих языках, что как бы намекает. Даже в Kotlin они есть, просто выглядят странно - я про companion object.

2 этап: static-и трудно тестировать, это антипаттерн, не надо их использовать. Ну разве что для Util классов, и то ...
Вот пример, демонстрирующий почему возникают такие мысли.
Возьмем другой антипаттерн - синглетон.

class Singleton {
private static final instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
....
}
Сразу скажу - это не одна из простейших реализаций, не потокобезопасная, взятая для примера, так делать не надо.

Предположим, мы хотим сделать вместо Singleton заглушку для теста. Ну например, он ходит в БД или читает данные из файла, а мы хотим, чтобы тесты работали быстро.
Можно сделать так:
class TestSingleton extends Singleton {
private static final testInstance = new TestSingleton();
public static Singleton getTestInstance() {
return testInstance;
}
....
}
Но это работает только если Sigleton можно как-то передать в тестируемый класс, он же System under Test (SUT).
А если это зависимость зависимости SUT? Или в более общем случае его нельзя передать через public API?
Основная проблема в том, что static методы не наследуются, а следовательно переопределить их нельзя. Можно создать метод с тем же именем, но вызываться будет метод того класса, который указан в конкретном куске кода. Или декларируемого, а не фактического класса переменной, поля или параметра, если static вызывается на объекте. В этом плане Java позволяя вызывать static метод из объекта только путает людей( К слову, в Kotlin так нельзя.

Есть конечно грязные хаки с мокированием static методов, даже Mockito это умеет. Но тот факт, что для включения этой фичи нужно добавить настройку в classpath https://www.baeldung.com/mockito-mock-static-methods говорит о том, что авторы Mockito не рекомендуют так делать.

3 этап, наше время: все не так однозначно. Точнее однозначно вот что: если static метод используется в паре со static полями - это точно зло.
И самостоятельное создание синглетонов тоже зло) Это я на всякий случай уточняю)
Но если присмотрется к вот такому static методу:
1) он не имеет доступа к полям объекта по определению
2) в классе нет static полей как я писал выше
3) пусть метод не имеет побочных эффектов. Т.е. не лезет в БД, в файловую систему, в другие сервисы
Т.е метод получает что-то на вход, вычисляет что-то и возвращает результат.
Это типичный метод Util класса, да.
Но еще это определение функции из математики. А функция - это функциональное программирование. А Java начиная с 8 версии умеет передавать ссылки на функции. И хотя в ней нет функциональных типов, но есть функциональные интерфейсы, которые делают тоже самое, просто немного с большим количеством кода. Java же, все как мы любим)

Подводя итог - считать static злом не надо. Надо лишь правильно его использовать.

#interview_question #holy_war #java #kotlin
Всем привет!

Сегодня хочу поднять вопрос анемичной доменной модели. Давно холиварные вопросы не поднимал)

Одним из первых это понятие ввел Мартин Фаулер, см. https://martinfowler.com/bliki/AnemicDomainModel.html
Анемичной модели противопоставляется т.наз. "богатая" или, как я бы ее назвал, полноценная доменная модель.
В чем разница?
В анемичной доменной модели объекты по сути аналогичны DTO, их можно реализовать в виде Java records или Kotlin value object.
В полноценной - в объектах кроме данных есть бизнес-логика.
Вот аргументы сторонников полноценной модели:
https://www.baeldung.com/java-anemic-vs-rich-domain-objects
https://www.youtube.com/watch?v=lfdAwl3-X_c - особенно рекомендую, Егор как всегда подходит к теме "с огоньком")
Вот - сторонников анемичной модели: https://habr.com/ru/articles/346016/

Я в этом споре все же склоняюсь к полноценной модели.
Т.к. доменный объект - это не DTO, он должен содержать нечто большее. А именно - бизнес-логику. А вынося логику в отдельные сервисы легко так сильно ее размазать по коду, что это приведет к дублированию и ухудшению читаемости.
Более того: если модель становится анемичной - это может быть признаком, что модель не нужна, сервис является простым и можно вполне себе работать с DTO.
Особенно актуальна "богатая" доменная модель, если вы пытаетесь следовать практике DDD - Domain Driven Design. Собственно, ее автор, Эрик Эванс, сторонник этого подхода.
Да и есть смотреть определение класса в ООП - это не просто хранилище данных. Объект - это отражение сущности из реального мира. А в реальном мире объекты - кот, автомобиль, заказ - являются не только набором характеристик, но и могут что-то делать)

Но есть один нюанс.
Если логика не требует данных, не содержащихся в объекте - ей место в этом объекте.
Если требует данных извне, но не вызывает методы внешних объектов - аналогично.
А вот дальше простые правила заканчиваются и решения от сервиса к сервису могут отличаться. Как минимум стоит принять во внимание принцип SOLID, удобство переиспользования кода и удобство тестирования.
Да, и точно не стоит запихивать в модель инфраструктурный код - деление приложения на уровни никто не отменял.

Идея в том, что не надо боятся добавлять методы в объекты доменной модели. Более того, при проектировании стоит изначально думать о том, какими будут эти объекты.

Что касается нарушения принципов S и I из SOLID.
Не надо относится к этим принципам догматично. Если так делать - то у нас в итоге будет куча DTO с парой полей, куча интерфейсов с одним методом и взрыв мозга у людей, которые попытаются вникнуть в этом код с нуля) Важен баланс.

#anemic-vs-rich-domain-objects #holy_war #solid #oop