Final countdown. DevOps Stage 2018. Book your ticket today.
×Закрыть

Переходим на Java 10: проблемы и решения

Итак, прошел уже месяц с выхода Java 10. Уже даже успел подойти первый апдейт. А это значит — пора переходить и нам :) Вслед за переходом на Java 9.

Установка

Джаву, как всегда, можно скачать и установить вручную. Но это не мой путь. Я обычно предпочитаю устанавливать из готовых пакетов (которые, к сожалению, выходят месяц-два спустя). Например, так:

sudo add-apt-repository ppa:linuxuprising/java
sudo apt-get update
sudo apt-get install oracle-java10-installer

Проблема с IntelliJ IDEA

Первая проблема, с которой я столкнулся, была в IDE. Я сидел на IntelliJ IDEA 2017.3. И при добавлении JDK 10 в проект идея отказывалась признавать корневую директорию JDK как «The selected directory is not a valid home for JDK». Проблема легко решается переходом на 2018.1.2. Но должен предупредить — в новой версии идеи довольно много неприятных мелких багов. Надеюсь, ситуация в Эклипсе получше.

Проблема с maven-compiler-plugin

Первым делом после подключения JDK 10 я попробовал собрать проект мавеном. Не получилось:

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project push: Execution default-compile of goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile failed.: IllegalArgumentException -> [Help 1]</em>

Гуглинг помог быстро найти проблему, а именно в maven-compiler-plugin. Как оказалось, этот плагин использует внутри старую версию библиотеки asm, которая не поддерживает Java 10. К счастью, ее легко можно пофиксить, изменив зависимость в плагине:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>3.7.0</version>
   <configuration>
       <source>10</source>
       <target>10</target>
   </configuration>
   <dependencies>
       <dependency>
           <groupId>org.ow2.asm</groupId>
           <artifactId>asm</artifactId>
           <version>6.1.1</version>
       </dependency>
   </dependencies>
</plugin>

Проблема с maven-surefire-plugin

Проект собрался. Настало время билда с тестами. И опять получился нежданчик. Теперь уже в maven-surefire-plugin:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.20.1:test (default-test) on project Blynk: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.20.1:test failed.: NullPointerException

Я особо не искал причину, а по опыту переезда на девятку — просто проапдейтил плагин к последней версии 2.21.0, что и решило проблему.

Опять IDE

Сборка с тестами прошла успешно, и ничего не отвалилось, что уже довольно неплохо (в отличие от девятки). Теперь я попробовал запустить тесты из идеи. И получил довольно странную ошибку:

Release version 11 not supported

Выяснилось вот что. Во-первых, «Language Level» в модулях проекта оказался на Level 11. Во-вторых, настройка «Module JDK» в каждом из модулей была на 9-ке. Похоже на какую-то багу новой Идеи. В общем, после проставления корректных версий вручную — тесты запустились и успешно прошли.

Travis CI

Так как наш проект open-source, мы используем бесплатный и публичный Travis Cloud для прогонки тестов. 10-ка все еще не имеет нативной поддержки от Тревиса, поэтому пришлось искать обходные пути.

Travis.yml:

language: java

before_install:
 - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh

matrix:
 include:
     - env: JDK='OpenJDK 10'
       install: . ./install-jdk.sh -F 10 -L GPL</em>

Lombok

Если вы используете или собираетесь использовать библиотеку Lombok в вашем проекте, то с десяткой придется подождать. Так как Lombok fails with JDK 10. Хотя, с другой стороны — это отличный повод выпилить его из вашего проекта.

P. S. 10-ка уже 2 дня крутится на наших продакшн-серверах. Пока никаких проблем выявлено не было. В отличие от 9-ки, никакого изменения по перформансу или потреблении памяти замечено не было.

Я уже перевел часть кода на var. Пока хорошо. Вот, например, кусок кода, который мне нравится больше всего:


А вы уже попробовали Java 10?

Для тех, кто же все-таки решил перейти на 10-ку, — вот отличная рекомендация, когда использовать var:

LinkedIn

187 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.
Хотя, с другой стороны — это отличный повод выпилить его из вашего проекта.

Ох, если бы все так просто решалось =)

Эх, старая шутка устаревает:
Приходит Java-программист в столовую и говорит:
— Дайте мне, пожалуйста, Борщ борщ нью Борщ!

Спасибо за статью, жаль, что не упомянули про Shenandoah, а то получается, что в JDK 10 только одна фитча — var переменные.

что не упомянули про Shenandoah

Ну он нужен 0.0001% людей, имхо.

Ну это спорный вопрос, кому что нужно. Мне, например не нужны var переменные. А вот добавили бы case классы, value types или реактивный JDBC драйвер — это было бы круто

case классы, value types или реактивный JDBC драйвер

Все это будет со временем. И быстрые релизы первый шаг на пути к этому.

реактивный JDBC драйвер

для чого ? є проблеми, які не вирішує connection pool ?
P.S.
У Postges же щось таке було, здається виявилось не надто потрібним.

Почему connection pool? Текущий JDBC драйвер блокирующий, поэтому если мы хотим построить приложение на реактивных принципах(например, с помощью Spring Web Flux), то у нас это не получится, если мы используем JPA/Spring Data.

то у нас это не получится

У вебфлюкса есть АПИ для блокирующих вызовов.

для чого ?

Зручність.

є проблеми, які не вирішує connection pool ?

Яким боком конекшн пул до реактивного АПІ?

У вебфлюкса есть АПИ для блокирующих вызовов.

A simple way to evaluate an application is to check its dependencies. If you have blocking persistence APIs (JPA, JDBC), or networking APIs to use, then Spring MVC is the best choice for common architectures at least. It is technically feasible with both Reactor and RxJava to perform blocking calls on a separate thread but you wouldn’t be making the most of a non-blocking web stack.

зрозуміло що блокуючий. але ж «построить приложение на реактивных принципах» — не самоціль ? тому і запитав, які проблеми з конектом до бази даних це вирішить.

Получится, если нарисовать свой переходник к пулу, который будет звать коллбэки. Но это куча громоздкой возни...
(я её делал в обе стороны, но не с Rx*)

Категорически не согласен с пунктом № 4 в гайдлайне от snyk. Неужели то, что с var читабельнее? По мне вариант с цепочкой вызовов выглядит гораздо понятней и презентабельней.

Советую автору посмотреть такой классный проэкт как SDK MAN (sdkman.io)...

Хз почему всем так var не нравится. В скалке вон, везде пишут val или var и ничего)

Так могли бы и val тоже прикрутить

Консерваторы-с. Типичная ситуация для любого языка при внедрении нового синтаксического сахарка.
И в C# пишут var, и в C++ пишут auto — это удобно.
Кому не нравится — пусть банят у себя на проекте в кодстайле.

...мы все пытаемся быть immutable... И это того стоит! ...mutable только когда уже «ну совсем по другому никак...»

А в Скалі теж є UserFactoryFactorySingletonGenerator?

У Scala можна імпортувати та використовувати будь-який клас із Java.

Я це розумію. Я мав на увазі те що в Жабі любителі плодити тисячі типів з довжиною ідентифікаторів на пів екрана. Мені й самому цікаво наскільки var буде зручний при такому підході.

Мав би покращувати читабельність коду (див. 3, 5, 6 на картинці у кінці статті).

Такі приклади занадто синтетичні. Звісно, тут справа одразу видно тип і дублювати його смислу жодного. Наприклад ситуація що обведена червоним у пункті 3.

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

А зачем, собственно, переходить на Java 10? Не вижу ни одной нормальной причины кроме пофикшенной работы с ресурсами ОС из-под докера. А весь этот сахарный var оставим хипстерам джаваскриптизерам :)

А зачем, собственно, переходить на Java 10?

1) Потому что они были на 9-ке, которая уже не поддерживается.
2) Потому что у кого-то много свободного времени :)

Да всё это сахар, переходим на goto.

В 10-ке появился новый параллельный сборщик мусора от G1, который по идее должен уменьшить время пауз

В отличие от 9-ки, никакого изменения по перформансу или потреблении памяти замечено не было.

Graal не пробовали использовать в качестве C2 компилятора ? Учитывая что он теперь есть в JDK 10 без специальных приседаний было бы интересно увидеть графики различия на вашем ворклоаде.

Давно слежу за этим проектом. Пока что, приседания есть :). Пока я бы выждал более зрелого решения.

Даёшь let, const в java 11 :)

це недостатньо.
пропоную просто писати змінну і присвоювати їй значення — хай компілятор сам розбирається.
P.S.
і всі ці зайві фігурні скобки викинути.

і буде пайтон

Цікаво було б глянути на структурні конструкції через присвоєння змінної. (І я не про регістр PC чи його аналог)

...и динамическую типизацию.
...и шоб файл .java работал прямо из браузера

Посмотрев на скриншот вначале подумал что Java код переписали на JavaScript.

Есть такое. Но очень быстро привыкаешь. Уже за неделю начинаешь писать переменные с var...

Скорее на C# 10 летней давности)

final int и var — это не одно и тоже, Java поддерживает final var

Не одно и тоже. Но в целом в final var нету смысла, так как компиляторы достаточно умны, чтобы самим определить «final ли» переменная. final var можно использовать в случае явного индикатора для человека. Пока ни разу так делать не приходилось.

Да, компиляторы умны когда определяют файнал для замыкания, но они понятия не имеют когда человек переопределяя переменную ломает код, а файнал это решает. То что вы так не делаете еще не значит что это правильно и что всем остальным тоже так надо делать. Лично я за максимально понятный выразительный и минималистичный код, если переменная файнал то она должна быть отмечена как таковая чтобы избежать багов еще на этапе IDE/компиляции и всяких непоняток. По хорошему, должен быть val конечно, но это совсем про другое и к type inference отношения не имеет.

но они понятия не имеют когда человек переопределяя переменную ломает код

И часто у Вас такое бывает?

В таком примере по Вашему нужны файналы:

public void doit(final String message) {
final int value = calculate();
final Item item = create(value, message);
executorService.submit( new Runnable() {
public void run() {
handle(item);
}
} );
}

?

Я не говорил что это часто бывает, просто в примере стояло final int — если переменная так помечена значит на то была причина и либо переменная изначально неправильно описана либо надо var тоже ставить final чтобы смысл не менялся. Пример у вас так себе — я же писал что надо здравый смысл использовать. Вполне могу представить себе случай где поле класса маркируется как final чтобы потом где-то в потомках не поломать или не нарушить тред сейфти. К тому же код должен быть самодокументируемый и когда человек видит что переменная файнал то ему более понятно ее назначение и способ использования.

и если уж совсем задротить то когда мы указываем final то компилятор на основе этого по-идее может оптимизировать код

и если уж совсем задротить то когда мы указываем final то компилятор на основе этого по-идее может оптимизировать код

Старый миф из джавы до 1.5. Сейчас это часть escape analysis (если речь про локальные переменные).

вроде как там больше всего и это не только про локальные переменные а и про поля класса stackoverflow.com/...​m_campaign=google_rich_qa

Мы же тут про var все-таки. При чем тут поля класса? Мое утверждение — final в локальных переменных не имеет смысла, с точки зрения перформанса.

Сейчас бы на var’ы переписывать все в 2к18 :)

навіщо переписувати на var? в чому сенс?

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

var можна використовувати не у всіх місцях оголошення змінних, а тільки там, де є надлишковість. У кінці статті є картинка з рекомендаціями, коли варто переходити на var і коли ні.

Да, я думаю var надо использовать в случаях похожих на
var somelist = new ArrayList<String>
но не в
var result = someMethod()
Автор же использовал второй стиль, после которого читаемость кода снизилась.

Автор же использовал второй стиль

Где?

var rootPath = getAdminRootPath()
Вроде понятно что тут вернётся String, но вдруг вернётся File, я бы сходил перепроверил. Опять же выше по коду — получение лимитов в int, с первого взгляда непонятно что там. Вдруг лимиты большие и там long.

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

Когда вы пишете
f(a+b);

вы не задаёте тип этого a+b, компилятор вычисляет его сам и обычно правильно это делает ;)

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

Изменения идут только там, где есть переприсвоение и автовывод даёт не то (например, var a = b+c; дал целое, а вы потом присваиваете ей дробное значение). Вот от такого имеет смысл защищаться уже через полиси, что var обязано быть final. (Кстати, в статье этого нет, и это существенный недостаток.)

Что непонятно в предыдущем объяснении?

дал целое, а вы потом присваиваете ей дробное значение

Разве компилятор в таком случае не выдаст ворнинг?
А если уже программист игнорит ворнинги — ССЗБ, тут никакие полиси не помогут :)

если то что стоит справа не говорит вам о том что приходит в переменную, то возможно вы что-то делаете не так

Если что-либо может быть понято неправильно, то оно обязательно будет понято неправильно ©

Следуя такой логике вообще трудно будет программированием заниматься. Есть ведь еще здравый смысл и например если создатели JDK пишут что коллекция не тредсейф то ожидается что ее будут применять соответствующим образом. И вообще мы сейчас говорим не о дуракоустойчивости, а о том что например гораздо понятнее что приходит из метода orderService.getOrder() нежели от какого-нибудь repository.handle() или worker.process().

Странно, что еще никто не вспомнил C# :) Абсолютно те же (контр-)аргументы звучали в свое время, но как показала практика, при наличии нормальной IDE это не имеет значения. Ну и без фанатизма конечно — var уместен там, где тип очевиден из контекста. А читается и пишется код в таком виде заметно легче/быстрее. Как и на C++ с auto, к слову.

Именно что на первый взгляд :)
Почитайте дискуссии 7-летней давности про auto в C++. Там уже обсосали этот аргумент (и некоторые другие) со всех сторон.

tl;dr
Во-первых, не всегда требуется знать точный тип переменной, чтобы сильно париться на этот счёт — особенно когда в контексте окружающего кода вы видите, как именно она используется, какие методы вызываются и т.д.
Во-вторых, если всё-таки есть необходимость узнать точный тип, любая современная IDE вам без труда позволит навести мышкой на эту переменную и посмотреть, какой тип компилятор для неё вывел.

ні, важче читати код. фішка var в швидкому говнокодігу. Дуже зручно. аЛе навіщо переписувати код який працює? Аби було?

фішка var в швидкому говнокодігу.

Тут я довірюсь вашій експертизі.

сурйозно ?
було
final int hardTimeoutSecs
стало
var hardTimeoutSecs
кому це легше читати ???
P.S.
а, знаю — програмісту на JS :)

var hardTimeoutSecs

не легче, а вот какой-нибудь Hashmap> map = new Hashmap<... — совсем другое дело

Так, варіанти типу
InternationalCustomerOrderProcessor<AnonymousCustomer, SimpleOrder<Book>> orderProcessor = createInternationalOrderProcessor(customer, order);
виглядають страшнувато.
З іншого боку, більшість роботи виконує IDE.

К сожалению IDE код не читают в человеческом понимании — им не надо «въезжать» в код :)

var orderProcessor = createInternationalOrderProcessor(customer, order);
с моей точки зрения гораздо хуже, поскольку неизбежно вызовет желание контекстной подсветки а шо ж там за типы, это раз.

Второе — у вас напрочь исчезли из восприятия дженерики <AnonymousCustomer, SimpleOrder<Book>> .
Из (customer, order); они ваще ни разу не очевидны.

Но код в стиле
var processor = createCustomGenericOrderBookSortedTransactionalListenerProcessor();
будут валить все хипстеры на районе, и это жопа.

Чтобы говнокодить, не обязательно быть хипстером. И не обязательно иметь в своём арсенале эту чудесную фичу var. Говнокодер всегда найдёт способы наговнокодить.

var иногда делает код более читабельным, иногда — менее читабельным. It depends.
Просто используйте его в первом случае и не используйте во втором, и будет вам счастье.
Притягивать за уши один пример, где var бьёт по читабельности, и поднимать панику, что теперь все «хипстеры» начнут говнокодить, — это как-то несерьёзно.

А код в духе
HashMap<String, Integer> cache = new HashMap<String, Integer>();
содержит тавтологию и только отвлекает программиста, заставляя его читать больше текста, чем нужно.
В то время как аналогичная строчка с var воспринимается гораздо легче и не теряет никакой информации по сравнению с оригиналом.

содержит тавтологию и только

Причём настолько что придумали decltype чтобы это хоть как-то «обойти в зад» ))

Не очень понял, при чём здесь decltype. В плюсах аналогичная var фича — auto. Которая, кстати, используется очень часто и пока ни разу ни мне, ни моим коллегам проблем не доставляла.
Может, потому, что мы не лепим её везде, где только можно. Но тем не менее.

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

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

Не очень понял, при чём здесь decltype. В плюсах аналогичная var фича — auto. Которая, кстати, используется очень часто и пока ни разу ни мне, ни моим коллегам проблем не доставляла.

Сорьки бес попутал почудилось за плюсы...

Может, потому, что мы не лепим её везде, где только можно.

Дык я так прямо с падаванами речью и выступил когда пришёл ко мне ихний код чисто сплошными авто вообще всё ну а чё можно же ж? И если на трёхэтажный и даже попроще жаблон я на авто вполне согласен то в ключе

auto i = 0;

— уже как-то сомнительно а в записи

auto s = Something(1);

— уже совсем не торт компилятор конечно же ж знает кто такой этот Something но вот для меня старого пердуна опытного ыксперта уже не очевидно то ли это функция то ли создания экзепляра класса наверное если мышечкой навести да ещё в идешечке и станет торт да вот у клиента там вообще всё в вим-консоли и опять же ж лично я щетаю код должен быть лаконичным и внятным и читаемым в себе самом.

На практике decltype используется в совершенно другом контексте и с auto обычно никак не связан.

Сирёзно?

auto somebullshit = GetBullshit(justanotherbullshit);
std::list < decltype(somebullshit) > keepbullshithere;
keepbullshithere.push_back(somebullshit);

Или об каком «другом контексте» идёт вообще речь?

А ну да расширим контекст:

template < typename T >
auto GetBullshit(T justanotherbullshit)
{
  struct {
    T bullshit;
    int howmany;
  } s1 = {justanotherbullshit, 1};
  return s1;
}

О! Об каком ещё «расширенном контексте» речь?

ЗЫ: сорьки не с первого разу текст заборол пришлось с угловыми скобками сообразить а то хтмл ломается...

ЗЫ: возвращаясь к аналу опять же лично я не понимаю почему первая форма записи вдруг хоть сколь лучше формы второй:

auto s = Something(1);

<=>

Something s(1);

Не лучше. И не хуже. Это уже вкусовщина. Такие вещи должны определяться кодстайлом.

Лично я пока не видел, чтобы вариантом
auto s = Something(1);
злоупотребляли.
Встречал его довольно редко и только там, где он чисто эстетически смотрелся красивее рядом с окружающими строчками кода.

Объективно у классического варианта
Something s(1);
преимущество в том, что он будет работать даже для объектов, у которых нет move или copy конструктора (например, std::lock_guard).

Сирёзно?

Да, твой пример нереалистичен и притянут за уши. В реальной жизни никто не станет так писать (если он не грёбаный извращенец, но такие обычно долго на работе не держатся).
В реальной жизни человек не будет лепить «Волдеморт-тип» внутри функции, а сделает именованную структуру с осмысленным названием — и в месте вызова (раз уж там нужен list из объектов этого типа, а не просто один объект) напишет этот тип явно, вместо извращенства с decltype.

Об каком ещё «расширенном контексте» речь?

О том, который я не смогу разнести так, как сделал это абзацем выше :)

Лично мне приходилось использовать decltype в библиотечном коде для дополнительных проверок, связанных со свойствами типов.
А ля «можно ли для такого-то типа написать такое-то выражение, скомпилится ли оно вообще, и, если да, будет ли его результат удовлетворять таким-то свойствам».

К примеру, вот тайп трейт, проверяющий, есть ли у типа T метод ToStdString() const, возвращающий std::string или что-то, из чего можно создать std::string:

template<typename T, typename = void>
struct IsConvertibleToStdStringByMemFun
    : std::false_type
{
};

template<typename T>
struct IsConvertibleToStdStringByMemFun<T, decltype((void)(std::declval<const T&>().ToStdString()))>
    : std::integral_constant<bool, std::is_constructible<std::string, decltype(std::declval<const T&>().ToStdString())>::value>
{
};

Ещё как-то велосипедил шаблон сортировки произвольного контейнера со специфичным, удобным для бизнес-логики компаратором (работающим не по тем правилам, что стандартный «true если lhs < rhs, иначе false»).
Мне нужно было убедиться, что переданный компаратор, вызванный с двумя ссылками на элементы этого контейнера, вернёт мне результат, удовлетворяющий нужным мне требованиям (а не обычный bool).
И для получения типа элемента сортируемого контейнера — так, чтобы это работало и для обычных массивов, а не только для классов контейнеров с вложенным тайпдефом value_type — я заюзал decltype:
using ValueType = std::decay_t<decltype(*std::begin(my_container))>;

Ну и ещё разок, было, заиспользовал decltype в не «библиотечном» коде — когда лезли баги из-за перевода большого куска подсистемы с типа float на double ради увеличения точности.
Члены классов тогда поменяли, а локальные переменные в некоторых функциях — забыли. Это породило некоторое количество багов.
Я психанул и попереводил эти локальные переменные на decltype(поле_класса): и пусть там потом хоть на long double переводят, ничего уже не сломается.
Кроме мозга тех программистов, которые не знают, что такое decltype :)
Но объяснить им это, если придут с вопросом, — дело пяти минут. В то время как отлавливать и фиксить подобные баги иногда отнимает по несколько часов.

А, вспомнил ещё один пример.

Работал в компании, которая не использовала RTTI и имела свой собственный шаблон для dynamic_cast’а (назовём его DynamicCast).

Использование следующее:
auto* ptr_result = DynamicCast<Derived*>(ptr_base);
, где ptr_base — либо «сырой», либо «умный» указатель на базовый класс; результат — всегда «сырой» указатель на производный класс.

Этот шаблон изначально не умел работать с входными указателями на const.
То есть, программистам для «правильного» динамик_каста базового указателя на const приходилось писать следующие некрасивости:

const Derived* ptr_result = DynamicCast<Derived*>(const_cast<Base*>(ptr_base));
, или, в случае со смарт поинтерами,
const Derived* ptr_result = DynamicCast<Derived*>(const_cast<Base*>(ptr_base.get()));

Что, естественно, мало кому нравилось.

Я, используя свои навыки velosiped-driven development, покращил этот шаблон, чтоб он работал и с констами тоже. Но при этом чтобы не снимал константность сам по себе (т.е., чтоб const Base* нельзя было скастить к не-const Derived*). Для этого была нужна некоторая компайл-тайм интроспекция.

Вдаваться во все подробности не буду. Просто скажу, что здесь пригодился decltype, чтобы узнать тип (с cv-квалификаторами или без оных), на который ссылается входной поинтер:
using ValueType = std::remove_reference_t<decltype(*ptr_base)>;

В случае с «сырыми» указателями необходимости использовать decltype бы не было, но так как клиентскому коду нужно было иногда кастить и смарт поинтеры, такое решение помогло красиво и универсально решить поставленную задачу.

сурйозно ?
було
final int hardTimeoutSecs
стало
var hardTimeoutSecs
кому це легше читати ???
P.S.

Зрада!

ти ще венгерську нотацію згадай :)

Один з недоліків java — verbosity. var частково усуває цей недолік.

Помоему о джава вербосити плачут в основном не те, кто пишет собсно джаву, а хипстеры, которые не пропускают ни один новый фреймворк.

Лично я никакого вербосити вообще не ощущаю и с самых первых слухов не понимал хайпа вокруг var

Помоему о джава вербосити плачут в основном не те

В JEP был отсыл к опроснику. В нем var это фича которой нехватает почти всем новым людям, которые приходят в джаву. То есть по сути var — это community driven решение для популяризации платформы.

То есть по сути var — это community driven решение для популяризации платформы.

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

В нем var это фича которой нехватает почти всем новым людям, которые приходят в джаву.

Когда люди переходят из языка А в Б, то им не хватает в Б всех фич которые были в А.

в общем это не очень хорошо.

Это очень даже хорошо. Без маркетинга ни одна технология не проживет долго. Никто не работает бесплатно.

без маркетинга и хайпа будет как с перлом, из популярного превратился в инструмент старперов с полуторапроцентной долей рынка

без маркетинга и хайпа будет как с перлом,

А че сразу перл? Давайте поговорим про Скалу, которая с маркетингом и хайпом даже до перла не дотянул.
Проблема в том что маркетинг должен быть направлен на правильную аудиторию. Ужас в том что самая громкая аудитория, как раз наименее полезна :)

За кількістю розробників не дотягнула, але ніби знайшла свою нішу і непогано себе почуває. :-)

Для Spark, який стає стандартом у Big Data обробці, рекомендується використовувати Scala. Наприклад, сьогодні, досліджуючи, як збільшити швидкодію наших мікросервісів для Spark, виявив, що Scala API у Spark Core дає деякі можливості для оптимізації, недоступні для Java API (а саме, використання iterator-to-iterator трансформації після виклику groupByKey, якщо комусь цікаво).

Та і судячи по статистиці на Dou, у Scala-програмістів найвищі зарплати. :-)

За кількістю розробників не дотягнула, але ніби знайшла свою нішу і непогано себе почуває. :-)

Так перл с коболом тоже хорошо себя чувствуют :)

Для Spark, який стає стандартом у Big Data обробці, рекомендується використовувати Scala.

А можно ссылку на рекомендации. Тот же Спарк многие используют с ... питоном.

Scala API у Spark Core дає деякі можливості для оптимізації, недоступні для Java API (а саме, використання iterator-to-iterator трансформації після виклику groupByKey, якщо комусь цікаво).

И тут появляется 1 интересный момент:
А зачем сделали джава АПИ? БигДата — это же ниша скалы.

Так перл с коболом тоже хорошо себя чувствуют :)

Big Data, одне з місць активного використання Scala, показує темпи росту. Попит на розробників тут зростатиме. Так як клієнти, що можуть собі дозволити Big Data, мають гроші, зарплати мають залишатися приємними. :-)
Якщо навіть сталося б щось непередбачуване, Scala-програміст легко зможе перейти у Java.
А як ситуація в перла і кобола: динаміка сфер застосування, легкість у знаходженні нової роботи? ;-)

А можно ссылку на рекомендации. Тот же Спарк многие используют с ... питоном.

Якщо на рекомендацію використовувати Scala, то, наприклад, пару сторінок з книжки, яку зараз читаю: books.google.com/...​glDwAAQBAJ&pg=PA3&lpg=PA3
Якщо Java API для Spark більш-менш еквівалентний Scala API, то ситуація з іншими гірша: й обмежені у функціональності, і швидкодія гірша.

И тут появляется 1 интересный момент:
А зачем сделали джава АПИ? БигДата — это же ниша скалы.

Думаю, щоб дати можливість використовувати Spark у більшій кількості існуючих Java проектів. Хоч не проблема мати в одному проекті суміш Java і Scala коду, але для роботи зі Scala API треба знати Scala.

А як ситуація в перла і кобола: динаміка сфер застосування, легкість у знаходженні нової роботи? ;-)

По перлу не знаю, с коболом люди не жалуются. Переписать (получить все сертификаты) фин систему дороже чем поддерживать кобол версию.
И тут уж никто не сделает джава или питон АПИ ;)

Big Data, одне з місць активного використання Scala, показує темпи росту.

Показывала, несколько лет назад. Сейчас надо питончег. Наверное потому что БигДата уже никому не надо, сейчас модно МЛ и ИИ. А скале остается ЕТЛ, который маркетологи называют БигДатой.

Думаю, щоб дати можливість використовувати Spark у більшій кількості існуючих Java проектів.

Угу, надо вкладываться в разработку и поддержку АПИ ради того чтобы вашу систему втянули в легаси проект. Это сколько же бабла в этом легаси.
Проблема то в том что новые проекты таки начинают на джаве, а не на скале. А почему? Не потому ли что основная область пременения скалы — это получить доступ к лоулевел функциональности библиотек и тулов, которые __уже__ написаны на скале.

Якщо на рекомендацію використовувати Scala, то, наприклад, пару сторінок з книжки, яку зараз читаю: books.google.com/...​glDwAAQBAJ&pg=PA3&lpg=PA3

Вот я там не увидел рекомендаций (в смысле указаний) использовать, а лишь за и против. И те в основном «поверьте на слово авторам».

По перлу не знаю, с коболом люди не жалуются. Переписать (получить все сертификаты) фин систему дороже чем поддерживать кобол версию.

А, тоді згоден, кобол теж себе непогано почуває. :)

З вакансіями і зарплатами виглядає якось не дуже. У зарплатному віджеті DOU нема Cobol. На Indeed — 30 тис. вакансій із середньою зп $84K. Подивився на php — 300 тис. вакансій із середньою зп $99K.

Big Data, одне з місць активного використання Scala, показує темпи росту.

Показывала, несколько лет назад. Сейчас надо питончег. Наверное потому что БигДата уже никому не надо, сейчас модно МЛ и ИИ.

Нагуглив таке: www.statista.com/...​a-market-growth-forecast Не знаю, наскільки дані цього сайту коректні, але пишуть, що ріст ще є. :-)

А скале остается ЕТЛ, который маркетологи называют БигДатой.

ETL буває різний. ;-) Наприклад, у нас один мікросервіс робить нескладну очистку і валідацію даних. А інший використовує Machine Learning (для дедублікації).

Проблема то в том что новые проекты таки начинают на джаве, а не на скале.

А там, де я, починають на скалі. Маю на увазі для Spark.
Можливо, компанії, у яких вже багато java-коду і java-програмістів, вибирають java. Бо спробуй-но знайти Scala-розробника)
А добре профінансовані стартапи, які можуть дозволити собі наймати кращих спеціалістів і не очікують, що ті будуть мати N-надцять років досвіду у саме тих технологіях, що використовуються у компанії, вибирають Scala.

Вот я там не увидел рекомендаций (в смысле указаний) использовать, а лишь за и против.

Напевно, це виглядало б занадто, якби розробники Spark вказували використовувати Scala для Spark))) Тому вони і пишуть: «More importantly, it is the belief of the authors that „serious“ performant Spark development is most easily achieved in Scala.» і т. п. Переваги Java над Scala для Spark зводяться до «Python and Java are more commonly used languages», чи не так? ;-)

А добре профінансовані стартапи, які можуть дозволити собі наймати кращих спеціалістів і не очікують, що ті будуть мати N-надцять років досвіду у саме тих технологіях, що використовуються у компанії, вибирають Scala.
А там, де я, починають на скалі. Маю на увазі для Spark.

1) Вы осознаете что спарк — это инструмент, а не сфера деятельности?
2) Если выбирают скала и все такие «хорошо профинансированные», то зачем разработчики спарка распыляются на джава/питон АПИ?

Напевно, це виглядало б занадто, якби розробники Spark вказували використовувати Scala для Spark))) Тому вони і пишуть: «More importantly, it is the belief of the authors that „serious“ performant Spark development is most easily achieved in Scala.»

Ну почему же, если у них было бы что-то большее чем «the belief of the authors», то вполне можно было бы и __рекомендовать__ и эти рекомендации были бы не «занадто».

Переваги Java над Scala для Spark зводяться до «Python and Java are more commonly used languages», чи не так?

Угу, а о чем должен думать бизнес? О том как удобно будет решать проблемы людям которых они наняли для решения проблем?

---

Фактически из нашего разговора может сложится впечетление что написание скриптов под спарк (тул написанный на скале) — это единственная сфера где нужна скала :)

1) Вы осознаете что спарк — это инструмент, а не сфера деятельности?

Звичайно.

2) Если выбирают скала и все такие «хорошо профинансированные», то зачем разработчики спарка распыляются на джава/питон АПИ?

Spark — некомерційний продукт, і ті, хто його використовує, не платить розробникам Spark. А open-source проект, тому його майбутнє у значній мірі залежить від того, наскільки великим буде його community і наскільки це community буде активно брати участь у розвитку продукту. Підтримка Java, Python, R, SQL дозволяє залучити багато людей, у яких теж Big Data задачі.

Ну почему же, если у них было бы что-то большее чем «the belief of the authors», то вполне можно было бы и __рекомендовать__ и эти рекомендации были бы не «занадто».

Крім «the belief of the authors», там у наступних 2 секціях є півдесятка аргументів. ;-)

Угу, а о чем должен думать бизнес?

Думаю, щоб максимізувати прибуток. А якими засобами, пробують вирішити по-різному. Одні — без проблем знайти багато програмістів для проекту. Інші — знайти програмістів, які зможуть швидко писати ефективний код і розрулювати будь-які проблеми. Зрозуміло, в реальному житті все не так поляризовано...

Фактически из нашего разговора может сложится впечетление что написание скриптов под спарк (тул написанный на скале) — это единственная сфера где нужна скала :)

Є думка, що функціональне програмування дозволяє зменшити кількість помилок при написанні коду. Тому, можливо, не така вже й погана ідея використовувати Scala, наприклад, у web-розробці (Play Framework). :-)

Spark — некомерційний продукт, і ті, хто його використовує, не платить розробникам Spark
Matei Zaharia is a Romanian-Canadian computer scientist specializing in big data, distributed systems, and cloud computing. He is a co-founder and chief technologist of Databricks,

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

Крім «the belief of the authors», там у наступних 2 секціях є півдесятка аргументів. ;-)
Вот я там не увидел рекомендаций (в смысле указаний) использовать, а лишь за и против. И те в основном «поверьте на слово авторам».

---

Є думка, що функціональне програмування дозволяє зменшити кількість помилок при написанні коду.

Которая подтверждается только «the belief of the authors» (классная формулировка)

Тому, можливо, не така вже й погана ідея використовувати Scala, наприклад, у web-розробці (Play Framework). :-)

Почитайте про историю компании lightbend.
Если кратко, то они выяснили что скала никому не надо.

Почитайте про историю компании lightbend.
Если кратко, то они выяснили что скала никому не надо.

Разочарованные программисты на Scala не захотели возвращаться на Java, т.к. там не было var. Поэтому они перешли на Go. Ведь там даже var не обязателен:

var a = doHype()

можно сократить до:
a := doHype()

Странно, что никто не жалуется на ухудшение читаемости кода. За исключением олдскульных Java-программистов, для которых

SingletonShit<FactoryShit<VistitorShit>> x = doShit()
милее глазу, чем
var x = doShit()
.
Ведь там даже var не обязателен

За таке богохульство років 5 тому вас би JS-екзорцисти розіп’яли та спалили на багатті...

якщо що, lombok плагін має var/val та інші зручності.

А чим погано «не пропускати ні один новий фреймворк», якщо є така можливість? Чим більше інструментів буде розглянуто, тим кращий (чи принаймні не гірший) для розв’язуваної задачі буде вибрано, хіба не так?

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

У моїй теперішній команді це в певній мірі практикується. Зрозуміло, вивчаються не всі нові фреймворки, а ті, які на перший погляд здаються такими, що може бути користь від їхнього впровадження.

Якщо деякого суспільно потрібного функціоналу фреймворку нам не вистачає, робимо pull request у цей фреймворк (напр., у spark-cassandra-connector) і в одній з наступних версій його маємо цей функціонал. :-)

Да у вас много свободного времени на работе, я смотрю )

Та я не сказав би... Просто приємніше потратити час на вивчення і проби інструментів, ніж на придумування і реалізацію «костилів» до вже написаного коду. ;-) Хоча, мушу визнати, повністю уникнути останнього не вдається. :-)

навіщо взагалі переписувати існуючий код?
можливих причин декілька:
1. значно швидше виконується
2. радикально легше читається
3. код ніде не використовується, автору цікаво
4. код використовується, автор — пихатий мудак

Спасибо за статью, мне как-то 10-ка пока вообще не зашла... Пошло какое-то копирование с С#

Зачем выпиливать Lombok?

Может просто подождать когда Lombok станет подерживать 10ку?

У Lombok дебильные правила работы с версиями. Вместо того, чтобы выкладывать баг-фиксы в Maven репозиторий, как делают все остальные вендоры, они придумали edge версию, которую нужно вручную скачать с сайта(как во времена Ant).. А официальная версия обновляется раз в полгода. Вот и с JDK 10 вышла 20 марта, а Lombok все еще ее официально не поддерживает.

релізна версія не підтримує десятку, треба брати снапшот але проблема в тому що снапшота немає на публічних репозиторіях і його треба заливати вручну

Что не так с Lombok?

— Увеличивает время сборки
— Дополнительная зависимость
— Нужны плагины в ИДЕ
— Повторяет функционал ИДЕ

В остальном — на любителя.

Как интересно ИДЕ сможет убрать из исходного когда весь бойлер-плейт который убирает Lombok?

ну, не «убрать», а «сгенерировать и свернуть, чтоб больше не трогать»

Особенно круто выглядит private Constructor() {} в утильных классах

Особенно круто выглядит private Constructor() {} в утильных классах

А проблема где?

вот в этом всём бойлер-плейт коде.

вот в этом всём бойлер-плейт коде.

Так не пишите его.

private Constructor() {} в утильных классах

Это просто доп перестраховка, а не что-то без чего система не будет работать.

ну эт понятно, а куча геттеров сеттеров?

а у вас никогда не возникало ситуации типа

public void setField(Field field) {
this.doSomethingOnFieldSet();
this.field = field;
}

Ломбок тут никак не поможет.

Пожалуй, сокращение геттеров-сеттеров — единственная серьезная польза от ломбока. Да и то это если сильно нечего делать — иде сгенерирует геттеры-сеттеры хоть для миллиона полей. И не надо говорить о том что большой файл, переход по строке или поиск по тексту есть в любой иде. Т.е. на самом деле ломбок героически решает проблему, которой по сути нет. Она видится проблемой только для хипстероориентированных людей.

Я даже больше скажу — ломбок неудобен именно этим. Если вам нужно сделать find usages... MyClass.setMyField() ломбок не всегда справится с этим, если ткнуть на поле private myField. А самого сеттера-то у вас и нет.

Так себе идея в поджо на сет что-то еще делать, не находите?

Так себе идея в поджо на сет что-то еще делать, не находите?

Так себе идея использовать поджо, не находите?

UPD. Здесь поджо — это класс который содержит только поляти и аксессоры к ним (+ возможно екьюалс/хешкод и туСтринг)

Ооо, нажористый камент :) Бъет по наболевшему.

Кто вам сказал, что джава ограничивается поджо? Information expert pattern слышали?

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

Более того, оказывается, что в классе можно иметь много статических методов, которые приспособлены к stateless обработке структур данных внутри сущности. А то бывают граждане, которые считаю злом сам модификатор static.

Внезапно, оказывается, что сущность содержит внутреннюю логику, по поддержке собственного консистентного состояниия, для чего нам нужно явно контролировать, регистрировать или мутировать ее состояние на сетах. Вы хотите примеров? Их есть у меня. Представим Client, у которого есть поля name, firstName, middleName, lastName. При этом есть логика, согласно которой name = fN + mN + lN с пробелами. Вы конечно можеет сделать

clientService.concatAllNamesIn(client)

и засорить этим методом кучу строк в сервисе. И тем самым вы неправомерно отдадите ответственность за поддержание консистентного состояния кудато вовне, чем создадите error-prone design. А можете внедрить логику, там, где ей и место:

private void collectNames() { ... }

public void setFirstName(String fN) {
this.fN = fN;
this.collectNames(); *
}

* да, я знаю про нюанс с self-invocation и проксей. Но это является проблемой далеко не всегда. И на персистентных менеджед сущностях это как раз проблемой не является.

Нездоровое стремление к поджо+сервис есть результат массового употребления спринга и хиба, которые стали аналогом золотого молотка. А как известно, если ты молоток, то все проблемы выглядят как гвозди. Поджо (с ломбоком, дада) + бездумно перегруженные логикой сервисы и боязнь выйти за эти рамки — это гвозди джавистов.

Даже больше. Многи джава программиты, даже не в курсе, что код можно писать без геттеров и сеттеров :).

Можно. Нужно ли — вопрос дискуссионный )

На правах оффтопа и ереси :). Меня вообще раздражают геттеры как таковые на уровне конвеншна. Я принципиально не согласен с неймингом getFieldName(), поскольку гет подразумевает какое-то активное действие, а геттер чаще всего это действительно просто доступ. С моей точки зрения, гораздо лучше писать просто entity.fieldName(), потому что 1) это отражает основную суть — доступ к проперти, а не какое-то содержательное действие. 2) ощутимо визуально сокращает код и уменьшает количество словКемелКейса.

Ну вот же оно, рядом:

entity.fieldName

entity.fieldName

Об это сломано много копий. Я считаю что аксессоры лучше по многим причинам. Я говорил за стиль нейминга, а не за то, чтобы выбросить аксессоры.

Я вот тут сегодня в одном хитром месте вместо бинарника вставил скрипт, который запускает тот же целевой бинарник, но при этом ещё и пишет вывод env и ps в лог.
Потому что иначе ну никак не понять, что происходит во взаимно рекурсивной цепочке баш-скриптов с виртуальными функциями, и взаимодействием объектов через файлы и косвенными вызовами по имени, записанном в атрибуты другого объекта где-то на 5 уровней по стеку тому назад.

Это в качестве намёка к тому, зачем в Кровавом Энтерпрайзе (tm) почти всегда лучше делать сеттер, чем прямую запись в поле.

А можете внедрить логику, там, где ей и место:

? ніфіга не пойняв — тобі потрібно fullName — напиши метод getFullName, поверни з нього «fN + mN + lN с пробелами»

нейм должен быть полем в сущности, а не результатом возврата левого метода, неужели не понятно? А сущность должна находится в консистентном состоянии в каждый момент времени, и ее консистентность не должна зависеть от того, забыл ли девелопер дернуть метод или нет.

Или мсье предлагает в сервисе

client.setName(client.getFullName());

? мсье знает толк.

Чого раптом fullName став «полем в сущности», якщо він складається з fN + mN + lN ???

Чого раптом fullName став «полем в сущности»

Потому что кто-то не читает сначала:

Представим Client, у которого есть поля name, firstName, middleName, lastName. При этом есть логика, согласно которой name = fN + mN + lN с пробелами.

name — персистентное поле, как и другие, кототорое всегда должно содержать в себе конактенацию трех других полей и так и храниться и сохраняться. Это сильно упрощенный кейс для примера, если шо.

ще і «сохранятся» так ? тобто в базі у вас теж чотири поля, одне з яких є об’єднанням трьох інших ? Ок, фіг з нею, нормалізацією, отримуємо проблеми з забезпеченням цілісності даних на рівні СУБД.
INHO, повинні бути дуже серйозні причини, щоб тримати в об’єкті поля, що по-суті є похідними. Саме тому, що суттєво виростають затрати на підтримання консистентності його стану. Це виправдано у випадку реалізації алгоритму якогось дерева, де ми зберігаємо в ноді кількість вузлів, але для випадку ентерпрайзу і бізнес-сутностей — сумніваюсь.

тобто в базі у вас теж чотири поля, одне з яких є об’єднанням трьох інших ?

Да. Я думал, что это было вроде как очевидно с самого начала.

Ок, фіг з нею, нормалізацією

А что с ней?

отримуємо проблеми з забезпеченням цілісності даних на рівні СУБД

Нет.

повинні бути дуже серйозні причини, щоб тримати в об’єкті поля, що по-суті є похідними

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

ентерпрайзу і бізнес-сутностей — сумніваюсь.

Сомнение вещь конечно благородная, но сомневаетесь вы зря.

В целом, у меня такое впечатление, что вы представляете себе логику ентерпрайза на уровне сложности туториал-левел, там где студент-курс многие-ко-многим и три сервисных метода в пять строк типа файндСтудентБайКурс. К сожалению, ентерпрайз несколько сложнее. И далеко не всегда уютной базой вашей веб-апликухи пользуетесь только вы :)

1) ніфіга не очевидно, оскільки це bad design
2) з нормалізацією те, що таблиця навіть не в 3НФ
3) що в свою чергу приводить до потреби забезпечення консистентності взаємозалежних полей на рівні кортежу, шляхом прикручування трігеру на апдейт.
4) таке враження, що хтось намагається переконати мене, що є набагато більше сортів гавна, ніж я пробував.Я в курсі, просто не треба намагатися видавати гавно за щось інше.
Одна справа саппорт легасі, інша — переносити це гавно в новостворену систему, яка це легасі обслуговує, 1:1.

оскільки це bad design

Bad design — это то, что вы не понимаете элементарных вещей — что есть бизнес-логика сложнее чем сущность Student(age, name) на два поля и что необходимо поддерживать консистентность соблюдая очень много условий.

переносити це гавно в новостворену систему, яка це легасі обслуговує

Гавно — это то, что получится у вас с таким подходом, когда вам нужно будет смоделировать сущность с 50 полями, 20 из которых — вложенные структуры, некоторые на 8 уровней глубины вложенности и несколькими тысячами строк логики, валидации, дефолтных значений, собственными исключениями, и перечнем бизнес-рулов на 15 страниц документации. Да, это ентерпрайз-реалии. Да, я понимаю что вы к ним не готовы.

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

Дмитро, не треба мені про ентерпрайз-реалії розповідати, і про якісь курси програмування — з вашого боку це вигладає смішно.
І чесно, ніколи не бачив "

вложенные структуры, некоторые на 8 уровней глубины вложенности

", ні в базах з даними геологорозвідки/буріння, ні в телеком-біллінгу. От ненормалізованих даних скільки завгодно — raw data є raw data. От тільки мапити це на об’єктний рівень, на щастя, ніхто не додумався.
Велкам, реальний приклад — в студію.

не треба мені про ентерпрайз-реалії розповідати

Увы, приходится. Потому что вы явно не понимаете простых вещей.

І чесно, ніколи не бачив

То, что вы никогда не видели работы с сложными и большиим графами данных и так видно. Вы мыслите бизнес логикой уровня сложности Student s = new Student();. Делали ли вы дедупликацию графов данных? Я вас еще больше шокирую — внутри таблицы Client может храниться целый граф строк, связанных ссылками на одну из них. Золотые записи, слышали?

базах з даними геологорозвідки/буріння, ні в телеком-біллінгу

Предметная область ни о чем не говорит. Возможно, у вас было приложение из 3 таблиц с 10 полями в сумме и вся логик сводилась к тому, что поля 1, 3 и 7 должны быть нот нулл.

То, что вы никогда не видели работы с сложными и большиим графами данных и так видно. Вы мыслите бизнес логикой уровня сложности Student s = new Student();. Делали ли вы дедупликацию графов данных? Я вас еще больше шокирую — внутри таблицы Client может храниться целый граф строк, связанных ссылками на одну из них. Золотые записи, слышали?

А які «шаловливые ручки» всю цю фігню туди напихали ? Чи спроектували систему так, що дозволили це зробити ?
P.S.
Все ще чекаю на реальний приклад :)

Вы походу реально ментально далеки от корпоративной сферы. Я не имею желания читать вам лекцию о том, что такое клиент-ориентированность, MDM и откуда происходят те или иные корпоративные потребности. А если бы имел желание, брал бы за это деньги. Могу только посоветовать поработать в каком-нибудь истинно-кровавом ентерпрайзе с высокопрофессиональными ПМами и не сидеть на написании какихнибудь джсонов и веб ендпойнтов, а нырнуть в дизайн моделей и хранение данных. Если вас туда пустят.

А які «шаловливые ручки» всю цю фігню туди напихали ?

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

Чи спроектували систему так, що дозволили це зробити ?

Прием ненормализованных и дублирующихся данных возможен и абсолютно нормален на уровне общения всей системы с внешним миром. Система должна управлять этими данными внутри. Вы не знаете елементарных вещей, погуглите хотябы что такое master data management, очевидно, что вы с этим не знакомы совершенно.

Все ще чекаю на реальний приклад :)

Наше по не открытое, и я не могу приводить реальные кейсы. Только общие примеры. Надеюсь, хоть что такоt коммерческая тайна, вы слышали?

Задохрена апломбу як для людини, яка почали писати на Java два роки тому.
ок, все глибоко секретно, зрозуміло :)

Задохрена апломбу як для людини

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

Ще раз: задофіга припущень. Не треба мені це розказувати, я це і без вас прекрасно знаю.
Завдання вашої системи ці неконсистентні і дублюючіся дані відфільтрувати на етапі імпорту або покласти в окремі таблиці, які ви потім будете обробляти і фільтрувати, а не засовувати в базу з даними консистентними.
P.S.
«Непонятно» мені було в тому плані, в якому «непонятно», навіщо справляти нужду в під’їзді. Я знаю, що такі факти мають місце бути, але таки непонятно, нафіга це робити, якщо ну ду-уже сильно не приперло. ;)

я це і без вас прекрасно знаю.

Не знаете. Или думаете что знаете. Ваши слова прямо этому противоречат:

неконсистентні і дублюючіся дані відфільтрувати

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

але таки непонятно, нафіга це робити

Кому-то понятно, вам нет. Это не проблема тех, кому понятно :) чтобы стало понятно, расширяйте кругозор. Да, можно конечно выбрать альтернативный путь — утверждать что все непонятное лично вам является говнокодом/говносистемой. Это путь настоящего джедая.

Не вижу уже смысла в дальнейшем разговоре.

name = fN + mN + lN с пробелами.
але для випадку ентерпрайзу і бізнес-сутностей — сумніваюсь.

Байки из кровавого:
1) name должно быть редактируемо, но при этом иметь деволтное значение
2) на поле name в БД завязаны ЕТЛи (которые никто не будет переписывать) и оно должно быть заполнено, по формату указанному в спеке :)

ну якщо ми вже маємо легасі з цим полем і воно в базі, плюс його частини теж в базі окремо — прийдеться якось підтримувати.
знову ж таки, не факт, що обов’язково його 1:1 на об’єкт мапити.
P.S.
У нас в одній базі кусок адреси був в форматі CHAR фіксованої довжини, типу: сім символів — номер будинку (три цифри / три цифри), символ — буква будинку, символ — цифра корпуса, символ — буква корпуса і т.д. Дурдом, причому в реалі нафіг все це було потрібно — оператори заносили адреси як прийдеться. :)

? ніфіга не пойняв — тобі потрібно fullName — напиши метод getFullName, поверни з нього «fN + mN + lN с пробелами»

1) Остается проблема что теперь уже геттер не геттер, а вычисляемый метод
1.1) Может приводить к деградации производительности.
2) Если более сложные случаи когда сет одного поля должен устанавливать определенное знание другого. И если это не сделать, то нужно постоянно помнить что объект в не полностью консистентном состоянии.

1) я не схильний трактувати геттер виключно як такий, що тільки повертає значення поля, зокрема й тому що «гет подразумевает какое-то активное действие»
продуктивність — це вже від ситуації залежить. Але зразу таке будувати — так ми дійдемо до того, що будемо окремими полями тримати shortName, fullName i PIB — а раптом буде потрібно.
2) звичайно бувають. Для цього сеттери і призначені — теж не схильний їх трактувати як встановлення значення тільки одного поля. Але якщо тримати в об’єкті поля, які по суті своїй агрегати інших полів, то роботи в сеттерах прийдеться робити набагато більше.

Але зразу таке будувати — так ми дійдемо до того, що будемо окремими полями тримати shortName, fullName i PIB — а раптом буде потрібно.

Если надо будет — будете. И держать, и следить за соблюдением консистентности.

Потому что есть клиентские данные, их могут быть десятки полей, сотни. И это не просто поля, они логически зависят друг от друга, иногда целыми графами. Завтра ваш клиент может стать юр.лицом, и вы введете колонку типа. И для тех, у кого тип -
юрлицо, вы должны будете поддерживать в middleName, lastName — null, потому что у юрлица не может быть отчества и фамилии, и это в том числе отразится на вашей бизнес-логике в коде, как

public void setMiddleName(String mN) {
if (this.type.equals(COMPANY)) {
throw «Company cannot have middle name»;
}
....
}

Потому что клиент — это сложная сущность с большим количеством гипотетических состояний.

в сеттерах прийдеться робити набагато більше.

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

я навіть не знаю, як цю дурню з полями на ПІБ для юрособи і однією таблицею для фізосіб і юросіб прокоментувати.
мені в цьому плані анекдот згадується:

В России сконструировали супервездеход и пригласили иностранцев для его оценки. Западные спецы долго и с восхищением осматривали чудо техники. И, наконец, сказали: — И чего только эти русские не придумают, лишь бы дороги не делать!
однією таблицею для фізосіб і юросіб прокоментувати

Т.е., вы предлагаете разнести на две таблицы таблицу, в которой 40 других полей будут идентичными, ради 3 полей с разной логикой, и которые на самом деле содержат информацию об одной и той же сущности, с разным полем type? Прям каминг-аут.

я навіть не знаю, як цю дурню з полями на ПІБ для юрособи

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

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

У вас по клієнту є куча інформації, яку ви зберігаєте в окремих таблицях (сподіваюся) — адреси, контактні особи, переписка, контракти, замовлення і т.д. і.т.п.
У фізособи частини цих даних немає. Зате є інші, яких немає в юрособи — ПІБ, паспорт, ІПН, громадянство і т.д. і т.п.
Так якого ... інформація про клієнта-фізособу повинна лежати в головній таблиці Client ? Як це випливає з бізнес-логіки ?

адреси, контактні особи, переписка, контракти, замовлення і т.д. і.т.п.

Все, что вы сказали, лежит в других таблицах и отделено от клиента километрами логики.

У фізособи частини цих даних немає. Зате є інші, яких немає в юрособи — ПІБ, паспорт, ІПН, громадянство і т.д. і т.п.

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

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

інформація про клієнта-фізособу повинна лежати в головній таблиці Client ?

Даже в вашем вопросе содержится прямое указание на то, что у вас плохо с моделями. Перефразирую ваш же вопрос — «почему клиент хранится в таблице клиента», подумайте над этим.

Як це випливає з бізнес-логіки ?

Непосредственно.

ще раз — ми почали з того, що name (ПІБ) у вас в основній таблиці. Тепер виявляється, що решта інформації, специфічної для фізособи — в інших. Так яким чином ПІБ є інформацією, "

которая общая для всех типов

" ?

(ПІБ) у вас в основній таблиці. Тепер виявляється, що решта інформації, специфічної для фізособи — в інших.

Во-первых, вы невнимательно читаете.
Во-вторых, вы не мыслите абстракциями. Вы написали паспорт, поэтому ваш дизайн плох, т.к. вы даже в уме не выделили абстракцию «документ». Абстракцию «документ» может заполнять любое лицо, поэтому эти данные не являются специфическими для физ.лиц.
В-третьих, вы совершенно не мыслите предметной областью даже в такой простой сфере как хранение клиента. Есть ФОП, который, внезапно, является юр.лицом, имея И фио И отдельно редактируемое name для которого, внезапно, конкатенация ФИО не нужна, т.к. name = ФОП «%lastName%», нежданчик? Для него тоже предложите создать отдельную таблицу?

Млін, ми один одного не розуміємо ???
Поле Name — цілком легітимне поле для клієнта. В ньому зберігається інформація про ім’я клієнта. Вона може відповідати якимось правилам по відображенню інформації з полів Name1+ .. + NameN таблиць юросіб і фізосіб.
Але інформація про фізосіб і юросіб зберігається окремо.
Приклад з біллінгу:
III.1.244.4 List of columns of the table BSCLIENT Name Code КОД КЛИЕНТА NCLIENT_ID НАИМЕНОВАНИЕ VNAME КОД ФИЗ ЛИЦА NPERS КОД ФИРМЫ NFIRM КОД ПОДРАЗДЕЛЕНИЯ NDEPT КОД ПОЛЬЗОВАТЕЛЯ NUSER ДАТА ВВОДА DINPUT КОД ЕДИНИЦЫ NFCONFIG КОД КЛИЕНТА СПЕЦ NSPEC КОММЕНТАРИЙ VNOTE ЗОНА NZONE ВХОДИТ В АБОНОТДЕЛ NDEPTCLIENT АДРЕС NADDRESS

III.1.244.2 List of incoming references of the table BSCLIENT Name Code Child Table Foreign Key Columns Parent Role Child Role BSCLINSTCL BSCLINSTCL BSCLIENTINST NCLIENT BSS2PCLIENT BSS2PCLIENT BSSUBS2PERS NCLIENT CLIENTDEB CLIENTDEB BSDEBGRAPH NCLIENT FK_BSDEBDOC_R799_BSCLIENT FK_BSDEBDOC_R799_BSCLIENT BSDEBDOC NCLIENT FK_BSDEBTOR_R799_BSCLIENT FK_BSDEBTOR_R799_BSCLIENT BSDEBTORLOG NCLIENT FK_BSPAYER_CLIENT_BSCLIENT FK_BSPAYER_CLIENT_BSCLIENT BSPAYER NPAYER_ID FK_BSSUBSCR_CLIENT_BSCLIENT FK_BSSUBSCR_CLIENT_BSCLIENT BSSUBSCRIBER NSUBS_ID III.1.244.3 List of outgoing references of the table BSCLIENT Name Code Parent Table Foreign Key Columns Parent Role Child Role FK_BSCLIENT_BSADDRESS_AUADDRES FK_BSCLIENT_BSADDRESS_AUADDRES AUADDRESS NADDRESS FK_BSCLIENT_CLIENTSPE_BSCLIENT FK_BSCLIENT_CLIENTSPE_BSCLIENT BSCLIENTSPEC NSPEC FK_BSCLIENT_DEPT4_DEPARTME FK_BSCLIENT_DEPT4_DEPARTME DEPARTMENTS NDEPT FK_BSCLIENT_FCONFIG7_FIRMCONF FK_BSCLIENT_FCONFIG7_FIRMCONF FIRMCONFIG NFCONFIG FK_BSCLIENT_FIRM4_AUFIRM FK_BSCLIENT_FIRM4_AUFIRM AUFIRM NFIRM FK_BSCLIENT_PERS3_AUPERS FK_BSCLIENT_PERS3_AUPERS AUPERS NPERS FK_BSCLIENT_REFERENCE_DEPARTME FK_BSCLIENT_REFERENCE_DEPARTME DEPARTMENTS NDEPTCLIENT FK_BSCLIENT_RES_AURES FK_BSCLIENT_RES_AURES AURES NCLIENT_ID FK_BSCLIENT_ZONE_BSZONE FK_BSCLIENT_ZONE_BSZONE BSZONE NZONE USER USER13 TUSER NUSER
Біллінг чудобо обслуговувує мільйони клієнтів, в тому числі ФОП-и.

Мля, я не знаю, як це нормально вставити.
ibb.co/hWySm7
ibb.co/mVYSm7

Але інформація про фізосіб і юросіб зберігається окремо.

Итак, вы предлагаете хранить клиентов и их имена отдельно от самих клиентов. Супер. Т.е. для 3 типов клиентов имеем 4 таблицы, да? +1 тип = +1 таблица, верно? Если бы вашей таблицей пользовалась только ваша аппликуха, этот подход имеет право на жизнь.

Но, теперь фокус — вашей таблицей пользуются 2, 3, 5, 10 других систем, которые только выбирают оттуда данные. И вместо того, чтобы выбрать из таблицы консистентные данные через SELECT * FROM Client WHERE.... в вашей схеме для получения аналогичного результата нужно будет делать какойто адский запрос. Помимо этого, вы существенно усложнили дизайн кода, введя 3 разных вложенных сущности вместо 3 полей с небольшим количество логики на них. Вот прям дизайн победы.

Кроме того, оказалось что система Х все равно присылает вам данные о клиенте в едином формате для всех 3 типов. Бинго! Вам нужно делать мост между единым входящим форматом и своим поделием с разделением на 3 таблицы, чтобы другие системы потом, превозмогая последствия вашего архитектурного таланта, соединили что-то из 4 таблиц опять в единый формат.

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

Даже в вашей же модели, которую вы привели на скриншотах, применяется мой, а не ваш подход — поля наименование, код физлица и код фирмы, скорее всего подчиняются той логике, которую я же описал. Например, физлицо не имеет кода фирмы, а фирма не имеет кода физлица.

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

Таблиця «примітивна», тому що дані рознесені, як і повинні бути. Коди фізособи і юрособи є одночасно FK на відповідні таблиці і т.д.
ibb.co/dVgEin
ibb.co/e3bmw7
«Адский запрос» всього-то буде містити в собі INNER JOIN ;)
А іноді і багато INNER JOIN-ів. Цілком пормальна ситуація в ентерпрайзі.
В біллінгу на станом на 2017 рік було 560 таблиць. Не кажучи вже про решту всього. I бізнес-логіки з головою.
І так, до біллінгу прив’язана куча інших систем, які успішно з ним взаємодіють, як на загрузку так і на вигрузку даних.
P.S.
І немає ніяких «трьох типів» — тільки фізособи і юрособи.

«Адский запрос» всього-то буде містити в собі INNER JOIN ;)

Уверены? Возможно, я лох в SQL, допустим.
Напишите-ка мне схематически запрос через иннер джойн, который в зависимости от типов A, B, C в колонке table_1.type сделает иннер джойны с таблицами table_A, table_B, table_C, чтобы результирующий набор содержал только 1 колонку name, в котором

if table_1.type = A then result.name = table_A.name
else if table_1.type = B then result.name = table_B.name
else if table_1.type = C then result.name = table_C.name

Я что-то не помню, как это сделать всего-навсего иннер джойном. Жду примера.

Через CASE это можно сделать, да. Только вот теперь мне объясните, зачем этой мутью должны заниматься те, кто потребляет эти данные из вашей системы? Они должны потреблять эти данные, а не думать, как скомпановать их в единое целое.

Таблиця «примітивна», тому що дані рознесені, як і повинні бути.

Рискую сломать вам вселенную, но разнесение данных не является золотым молотком. Иногда их лучше НЕ разделять. А иногда разделять. А иногда — даже в некотором роде дублировать. Все зависит от конкретных кейсов.

Напишите-ка мне схематически запрос через иннер джойн, который в зависимости от типов A, B, C в колонке table_1.type сделает иннер джойны с таблицами table_A, table_B, table_C, чтобы результирующий набор содержал только 1 колонку name, в котором

Ну это скорее такой view. У которого есть формула на чтение как union трёх других view, которые уже включают в себя join’ы, и правило, в какие таблицы пишется при модификации (если вообще она делается через этот view; может оказаться, что и нет. в любом случае подобное обычно заворачивают через процедуру)

Это я к тому, что в принципе представить кому-то такую объединённую сущность, не имея её в хранимом виде, вполне возможно (хотя в мелочах тут же возникают миллионы голодных дьяволов и съедают человеко-месяцы проработкой деталей и граничных случаев). Было бы зачем.

Я б, конечно, делал некоторую сущность вида «клиент», для которой тут вообще пофиг, как оно внутри мапится. Но вот то, что у разных подвидов клиентов разные атрибуты, объединять как-то сложно.

Ну это скорее такой view.

Да.

Это я к тому, что в принципе представить кому-то такую объединённую сущность, не имея её в хранимом виде, вполне возможно

Совершенно верно. Так и речь не о принципиальной технической возможности.

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

В данном приведенном случае все решается на уровне джавы несколькими простыми методами, которые аггрегируют поле в нужное состояние в зависимости от подвида сущности. Это позволит 1) хранить все и сразу, в одной таблице, в изначально консистетном состоянии, 2) хранить логику обработки этих данных в коде, не порождая вьюхи и процедуры.

Мой оппонент не понимает этого, и предлагает нагородить кучу доп-таблиц, чтобы потом героически писать вьюхи и процедуры, забывая о

в мелочах тут же возникают миллионы голодных дьяволов и съедают человеко-месяцы

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

Нечаєв вже встиг відписатися.
Більше того, якщо брати всі три умови разом, це буде список всіх клієнтів, тут JOIN з table_1 взагалі не потрібен — просто
select table_A.name from table_A
UNION
select table_В.name from table_В
UNION
select table_С.name from table_С
— як поставив задачу, таку відповідь і отримав — «результирующий набор содержал только 1 колонку name» :)
Якщо ж тобі треба щось складніше, скажімо ще якесь поле з таблиці table_1, тоді буде потрібен INNER JOIN
select table_1.type, table1.zone, table_A.name from table_1 INNER JOIN table_A on table_1.tableA_FK_column = table_A.ID UNION INNER JOIN table_B on table_1.tableB_FK_column = table_B.ID UNION INNER JOIN table_C on table_1.tableC_FK_column = table_C.ID
можна додати WHERE table_1.type = :type
але великого змісту такий запит не матиме, бо кожен тип в окремій таблиці, тоді достатньо джойну table_1 з таблицею, шо містить конкретний тип.
P.S.
Все це прийнятно для випадку, коли у нас два типи клієнтів (ну ок, третій з Альфа-Центавра). Якщо ж вести мову про багато типів, тоді потрібна окрема таблицю TYPES з переліком типів, і таблиці, що міститимуть дані цих типів etc.
P.P.S.
Те. що дані іноді краще не розділяти, ніхто не оспорює. Навіть дядя Дейт в книжці про СУБД про це говорить. А іноді таки розділені таблиці на фізичному рівні тримають разом. Це все і так зрозуміло. Якби від вас прозвучала фраза «це так зроблено з огляду на продуктивність», подальшої дискусії взагалі б не було — цілком зрозуміла причина. Але про продуктивність згадав Богдан, а не ви.

Якби від вас прозвучала фраза "це так зроблено з огляду на продуктивність"

Блин, а эта причина не очевидна с самого начала?!

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

Или вам норм обсуждать вариант решения проблемы, который, как вы заранее знаете из опыта, приведет к созданию запроса, который будет работать 10 минут?

Так якого ... інформація про клієнта-фізособу повинна лежати в головній таблиці Client ? Як це випливає з бізнес-логіки ?

Встречный вопрос — а почему она не должна там лежать?

В принципе, у нас проблема что в лоб, что по лбу: если описать объектно, есть базовый класс клиента, а есть подклассы конкретных разновидностей, которых сильно больше, чем тут названо (например: просто частник, ФОП без НДС, ФОП с НДС, юрлицо). Значит, часть атрибутов будет иметь смысл для одних, а часть — для других.

Классическая концепция реляционок предполагает при этом, что у нас будет, например, таблица client, в которой только основные параметры, а будет также client_physical_details, общая для частников и ФОП с параметрами типа паспорт и код, client_fop_details, у которых всякие коды КВЭД и виписка/витяг/etc., и client_juridical, где параметры устава, ссылка на директора и т.п., с отношением 1:1* к главной таблице.
Но можно их влить и в client, наплевав, что в большинстве полей будет null.

Ну а полное имя клиента вообще будет извращённой функцией, если не дублировать в главной таблице.
Дублируешь — нарушаешь 2НФ. Не дублируешь — накладываешь кучу лишней работы на каждом чихе. Выбирай из двух зол менее извращённое...
я что-то уверен, что 90% выберут дублирование и процедуру реакции на установку/смену имени клиента в конкретном случае.

Можно ли считать бизнес-логикой требование вида «операции с базой должны выполняться за такое время, чтобы операционисты с клиентами разом не поубивали программистов БД»? :xz:

я что-то уверен, что 90% выберут дублирование и процедуру реакции на установку/смену имени клиента в конкретном случае.

Опытным путем было установлено, что Виталий относится к 10% :)

Но можно их влить и в client, наплевав, что в большинстве полей будет null.

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

ключові слова «иногда», «с точки зрения производительности». Ну і єй богу, при прямих руках не все так погано з продуктивністю по замовчуванню — розказуйте, про яку систему йде мова, який об’єм даних, на якій СУБД і на якому залізі. Чи це теж комерційна таємниця ?

який об’єм даних, на якій СУБД

Миллионы записей, оракл. За железо не в курсе, не моя чашка.

при прямих руках не все так погано з продуктивністю по замовчуванню

Я не эксперт в СУБД ни разу, но предположу, что тот мастер-запрос с тремя джойнами и тремя юнионами, который вы написали в конце спора как альтернативу моему варианту SELECT * FROM client, будет медленным тупо везде.

так, він буде повільнішим, наскільки — залежить від ситуації.

Дивись, в даному випадку є фізики і юрики (плюс підкласи юриків). Далі все приблизно як ти кажеш — «Классическая концепция реляционок предполагает при этом...» (я від публікації повної структури таблиць біллінгу, що за це відповідають, утримаюсь).
Ім’я клієнта, як таке, в таблиці client є — так, порушення НФ, фіг з ним. Но нафіга зразу робити оце: «влить и в client, наплевав, что в большинстве полей будет null» ? Так, потім тебе може продуктивність якихось операцій не влаштовувати, прийдеться робити partitioning, materialized views, додавати hints для оптимізатора або таки об’єднувати яцісь таблиці в одну. Але нафіга зразу це робити ?

Можно ли считать бизнес-логикой требование вида «операции с базой должны выполняться за такое время, чтобы операционисты с клиентами разом не поубивали программистов БД»?

Звичайно, 100%
Хоча, схоже, іноді програмісти цю вимогу ігнорують, коли вважають, що живуть далеко від кінцевих користувачів.
P.S.
Буквально тиждень тому розповідали одну історію, як кінцевий користувач «продукту» (не бос і не менеджер фірми-замовника, просто роботяга) зайшов в офіс фірми-розробника на розборки: що це за фігню ви впарили, нею неможливо користуватись. Але це вже тема реально для прекрасного.іт.

Но нафіга зразу робити оце: «влить и в client, наплевав, что в большинстве полей будет null» ? Так, потім тебе може продуктивність якихось операцій не влаштовувати

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

не знаю, як в MS SQL, а в Oracle десь до 11 чи 12 версії, якщо побудувати індекс по колонці з NULL, рядки, де є NULL, в індекс не попадали. Іноді народ ізгалявся, апдейтив всю таблицю, міняючи NULL на ’null’ чи 0 (в залежності від типу колонки).

якщо побудувати індекс по колонці з NULL, рядки, де є NULL, в індекс не попадали

Тю. А навіщо вони в індексі і чому це взагалі хвилює?

select column from table
where column IS NULL
буде йти через full scan

Хм, в контексте предыдущего обсуждения, поиск по IS NULL по этим столбцам, специфичным для конкретного подвига клиента, нафиг не нужен, потому что и так где-то есть указание на его тип (частник/ФОП/etc.)

В общем случае, да, поиск по NULL полезен, но так быстро менять контекст нежелательно :)

А в тех версиях нельзя было строить индекс по NVL(поле, 0) вместо смены самого поля (как бы ни звалась эта NVL в конкретной БД)?

а хз, мені це не було потрібно, треба в інеті читати.

Извините, но я не пользуюсь ни сеттерами, ни геттерами (имьютабл объекты очень упрощают жизнь). Мой комментарий лишь о том, что если вы пользуетесь поджо и сеттерами, то в сеттер как раз лучше ничего лишнего и не дописывать, так как это наоборот только ведет к путанице. Не могу понять к чему вы написали такой длинный комментарий...

(имьютабл объекты очень упрощают жизнь)

Я прям потрясен до глубины сознания. Имьютабл это безмерно круто, согласен. Особенно когда ентерпрай-приложение, где 99,99% стейтов персистентных сущностей мутабельны по природе вещей. Ридонли ентити не считаем.
Писать ентерпрайз на имутбал поджо это явно какое-то очень новое слово в архитектуре, я так не умею.

Не могу понять к чему

Мой оппонент, с которым мы долго и продуктивно спорили, это понял. Правда, он был со мной не согласен, это бывает, но он понял. Прочитайте, чтоли.

Подписаться на комментарии