Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×
Java Developer в Rakuten Kobo
  • Асинхронна відповідь HTTP

    Інстанс один? Як вирішили

    А кто дает гарантии что чтение с топика будет на том же инстансе что и обрабатываемый «/comp»?
  • Асинхронна відповідь HTTP

    Шкода, що піздно (і то й випадково) побачив топік.
    Цілком реальна (і неприємна) задача, не розумію токсичність коментаторів.

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

    Підтримав: Alexandr
  • Місце ORM у загальній архітектурі застосунку

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

    Это не так, вот в меру своих скромных сил пытаюсь объяснить.

    Что именно тестировать?

    Бизнес-логику, вестимо.

    В том-то и проблема, что каждая догрузка пропертей — это проход в базу и тормоза.

    А как по-другому?

    Чтобы не перебрасываться общими фразами, предлагаю задачу-иллюстрацию, копи-паст из соседнего треда.

    Есть таски с сабтасками и сабтасками сабтасок, иерархия не ограничена.
    Статусы: new -> in progress -> done
    Юзкейсы: в done можно переводить, только если сабтаски закрыты.
    Но с force=true можно перевести в done весь подграф.
    Проблемы юзкейсов: сложно отделить DAO от бизнес-логики.

    Вот моё решение, вот подход ТС-а, который я называю процедурным, вот моя критика этого подхода. Расскажите своё видиние, пожалуйста, поделимся опытом.

  • Місце ORM у загальній архітектурі застосунку

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

    Расскажите, пожалуйста, подробнее, какую проблему решаете «разным набором блокировок»? Write Skew?

    Как раз апдейты — самое слабое место в ОРМах

    Ок. А как и чем вы апдейты делаете?

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

    Ок. А как вы бизнес-логику тестируете?

    Если проект под страшным NDA, могу предложить свою задачу.
    Есть таски с сабтасками и сабтасками сабтасок, иерархия не ограничена.
    Статусы: new -> in progress -> done
    Юзкейсы: в done можно переводить, только если сабтаски закрыты.
    Но с force=true можно перевести в done весь подграф.
    Проблемы юзкейсов: сложно отделить DAO от бизнес-логики.
    Без всяких блокировок.

    Вот моё решение, вот подход ТС-а, который я называю процедурным, вот моя критика этого подхода. Расскажите своё видиние, пожалуйста, поделимся опытом.

    для MVP только и хорош, и для книжек для начинающих

    С вашего позволения, процитирую прямо из профиля с минимальными изменениями.

    «Топовый способ свести дискуссию о программировании к демагогическому и догматическому холивору — ввернуть аргумент о „(не)продуманной архитектуре пригодности только для MVP и начинающих“. Произносить надо с придыханием небрежным презрением, и можно смело предавать анафеме сомневающегося. Сам же за умного сойдешь.»

  • Місце ORM у загальній архітектурі застосунку

    я буквально казав спробуй розвернути код усьої логіки.

    Це не декоратори, а анотації.

    З таким кодом можеш процювати тільки ти або якійсь мідл+. Джун без досвіду з Hibernate нічого зробити не зможе.

    Будь-яка технологія — це трейд-оф між витратами на її опанування і користю, яку вона надає. Можно легко навести протилежні екстреми.

  • Місце ORM у загальній архітектурі застосунку

    Приходить продакт овнер і каже, в нас міні чендж реквест, вкладеність тепер нескінченна.

    Або просто уважніше придивитись до README.md

    getALLOpenSubtasks(parentID):Task[] {
    // SQL пошук я зараз не придумаю але думаю що це реально,
    //як мінімум в циклі шукати через декілька запитів
    //по навантаженню на базу це буде те саме шо твій лейзі лоад у циклі private void markDone

    Не те саме. Витягувати всю ієрархію — це вкрай погана ідея з точки зору перформанса і пам’яті. Можна спочатку надовго задуматись, а потім вилетіти з OutOfMemoryException.
    Для force=false достатньо витягти тільки «безпосередні» сабтаски, весь граф не потрібен.
    І при апдейті з force=true не треба завантажувати сабтаски, якщо чергова таска вже в DONE. Ось я поправив цей момент, тест поруч.

    На всяк випадок, нагадаю: обговорюємо не конкретну задачу — та скільки там тих тасок? максимум 100! — а загальний підхід, коли бізнес-логіка вимагає дозавантаження даних.

    тепер троти TDD inda house

    Ні-ні-ні, не треба, будь ласка, займатись самообманом. Ніякого TDD не було, тест писався після реалізації, про що також свідчить оговорочка по Фрейду

    джун штампує тести для TaskService і робить їх зелененькими

    Мій поінт не в тому, що треба писати спочатку — тести чи код — без різниці, а в тому що хороший тест — тестує black-box. А твої тести спочатку зазирають в код, щоб знати який мок підкласти.

    mockStorage.getTask.mockReturnValue([main])
    mockStorage.getALLOpenSubtasks.mockReturnValue([sub1, sub2])

    Звідки тест знає що буде викликатись getALLOpenSubtasks?

    Зверни увагу як мало мені довелось змінити в порівнянні з попереднім рішенням.

    А тепер дивимось на рішення — до чого я вів з самого початку — це суміш бізнес-логіки з DAODategateway-ем.
    Ще тобі треба в залежності від флага force викликати getALLOpenSubtasks чи getJustDirectSubtasks, ну і оптимізувати перший метод, щоб він не тягнув геть усе. А потім виправляти весь тест сют, тому що моки помінялися. Гадаю, ти з цим постійно стикаєшься, тому і питаєш

    а якшо в тебе тест сют та класс Task з сотнею тестів, в ще є тести інших сутностей де таск використовується?(це я вже перегібаю)

    Крім того є ще одна проблема.

    task.status= status

    Ти вільно апдейтиш статус. Тобто Таска — це просто структура, а не об’єкт; її внутрішній стейт виставляє сервіс інтерактор, і нема ніяких гарантій, що це робиться консистетно. Всі інваріанти таски — як відбувається перехід в DONE, можемо нафантазувати ще — розмазані в методах сервіса. Слово «інкапсуляція» залишилось на співбесіді, її — нема.

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

  • Місце ORM у загальній архітектурі застосунку

    Скажите, пожалуйста, а с update (в широком смысле слова) как быть?

    Если позволите, скопирую из соседнего треда.

    Для мене основна супер-сила ORM Hibernate не в селектах, а в апдейтах, тобто

    @Transactional
    class Service {
        public void someMethod(Changes changes) {
            CompexEntity compexEntity = repository.findById(id).orElseThrow();
            complexEntity.updateBy(changes);
        }
    }
    
    CompexEntity може бути яким завгодно складним об’єктом з внутрішніми колекціями і колекціями колекцій. В update(...) може відбуватись складна логіка, яка потребує (або ні) дозавантажання внутрішніх пропертей, створює або видаляє нові елементи тощо. Тестується це все добро unit-тестом без жодних контекстів, а решту робить ORM.
    А потом уже в публичных методах вызываешь нужную комбинацию над результатами запроса.

    А тестировать как этот процедурный стиль? Моками?

  • Місце ORM у загальній архітектурі застосунку

    Спробуй розверни усі декоратори які навішані на класс таски

    Не зрозумів. Про які декоратори йде мова?

    наскільки перегружений логікою цей обєкт

    Знову не зрозумів. Ось клас. Два конструктори-аліаси, три публічних метода — addSubTask, updateStatus, patch. Про яке перевантаження йде мова?

    В твоїй реалізаціїї, клас = таблиці.

    Коли зв’язані дані розмазані по різних сховищах — це в любому випадку буде непросто. Але буває і таке, що у додатка одне сховище — реляційна БД.

    Під lazy-loading-ом (у контексті ORM) я мав на увазі, що замість завантаження даних в properties створюються проксі, які відпрацьовують при звертанні до тих.
    Догнав. ІМХО це страшне зло, але то вже персональні вподобання.

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

    Service — це інтерактор, тут описуються юзкейси маніпуляцій над таском, або над таском та іншими сутностями повязаними цим юзкейсом, які від нас просить продактовнер.

    Чудово. Тобто Task — це структура сутність, а Service — це набір процедур інтерактор. У процедурно-орієнтовному програмуванні як такому нема нічого погано, але постає питання, як тестувати цей інтерактор.

    Ти ось написав метод

    changeStatus(taskID:number, status:TaskStauts, forcce?:bool)

    ... там if-и, цикли — такі речі треба тестами покривати.

    Як буде виглядати тест?

    З моками? Чи з in-memory DB?

    Я свої тести вже написав.

    Так само в обох варіантах ... чи я шось не розумію.

    Мабуть недостатьо зробив акцент. У тасок можуть бути сабтаски, в тих — ще, вкладеність графу — необмежена.

    class TaskWithSubs extends Task{
    subtasks:Task[]
    }

    ... не підходить, там знову має бути subtasks:TaskWithSubs[]

    Це приклад складного об’єкта, який вимагає дозавантаження даних, на одному класі, щоб не плодити багато сутностей. Ілюстрація

    Шоб позбутись тої проблеми коли завантажеється лишня інфа де її не треба.

    ... цієї проблеми.

    при зміні статусу таски треба ще якісь діії виконувати, наприклад відправити листа асайні сабтаски

    Це гарне питання, я буду передавати лямбду/колбек/consumer в updateStatus метод.

  • Місце ORM у загальній архітектурі застосунку

    Таке враження, що у нас сильно відрізняються світи, це буде або цікава або безглузда дискусія.

    С втруктурі вашого проєкту все завязано на визначенні Таски. Більше 120 рядків коду. А репозиторій — 2 рядка.

    Ем, а що тут поганого-то? Я так розумію ООП — є клас, його проперті та методи. Що не так?

    це прям монолітний моноліт.

    (витріщає очі) Чому моноліт?!

    Я вже боюсь питати, як ти розумієш coupling, бо невідомо куда зайдем.

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

    З цим категорично згоден.

    І я наївно сподівався шо хтось з читачв ДОУ під цею статтею напише шось на кшалт: "О, а ми в себе теж використовували datagatewy, тіки в нас то repository

    Мені так само цікаво, як з Datagateway(DAO?) вирішується питання, коли в залежності від бізнес-логіки треба дозавантажувати (або ні) додаткові дані з SQL DB.

    тут в твому коді циклічна залежність яку на проді жоднен адекватний архітектор не дозволить, тому замість обєкту таски просто ID parent:number

    (знову витріщає очі) По-перше, це не циклічная залежність, а ієрархічна. А хай би і циклічна залежність — у доменній моделі може бути що завгодно, якщо так є по бізнесу. Ніяких обмежен. У чому проблема?

    І чому архітектор рев’юіть код? ;-)

    class TaskWithSubs extends Task

    Для чого два класи на одну бізнес-сутність?

    Class Service

    Що робить сервіс? Це просто проксі до storage?

    З такми підходом файл Task.js тепер короткий а storage.js здоровий.

    Тобто Task.js — це тільки структура даних? А бізнес-логіка де? В сервісі? Чи в сторажі?

    Закон збереження енергії в дії.

    Ага. А тестуємо що? Storage? З моками? Чи з in-memory DB?

    Спочатку бізнес логіка, потім імплементація джерел данних.

    А що робити, коли в залежності від бізнес-логіки треба (або не треба) завантажувати дані?
    В якому шарі це робити?

    Як тільки згадується SQL, питання, що робити з lazy-loading-ом. Як будуть виглядати оці всі getUser, getDog при умові, що там будуть більш-менш складні структури, а не навчальні три поля з ID? Будемо витягати з бази все одразу (страждає перформанс) або при потребі (ускладнюється код, змішується власне бізнес-логіка з DAO)?

    Не зовсім вдало сформулював, спробую ще раз. Для мене основна супер-сила ORM Hibernate не в селектах, а в апдейтах, тобто

    @Transactional
    class Service {
        public void someMethod(Changes changes) {
            CompexEntity compexEntity = repository.findById(id).orElseThrow();
            complexEntity.updateBy(changes);
        }
    }
    

    CompexEntity може бути яким завгодно складним об’єктом з внутрішніми колекціями і колекціями колекцій. В update(...) може відбуватись складна логіка, яка потребує (або ні) дозавантажання внутрішніх пропертей. Тестується це все добро unit-тестом без жодних контекстів, а решту робить ORM.

    що робити з lazy-loading-ом
    Те саме шо робили 5-10-15 років тому: використовувати або курсор або офсети.

    Під lazy-loading-ом (у контексті ORM) я мав на увазі, що замість завантаження даних в properties створюються проксі, які відпрацьовують при звертанні до тих.

    Отой

    в живу побачиш як @ManyToOne(fetch = FetchType.LAZY) данні підтягує.

    ... або не підтягує, якщо не треба.

    Щоб проілюструвати про що йде мова, такий юзкейс: зміна статусу таски.
    У complete переводимо, якщо всі дочірні сабтаски закриті. Або з force=true закриваємо всю ієрархію. Питання — скільки даних завантажити з БД для цього?

  • Мікробібліотека для роботи з конкатенацією в Java

    Щось я про потокобезпечність не зрозумів... що таке LazyHolder.instance підпертий this.strBuilder.setLength(0);?

        @Test
        void multipleInstances() {
            SBB sbb1 = sbb().add("111");
            SBB sbb2 = sbb().add("222");
            assertEquals("222", sbb2.bld());
        }
    
    ... падає, bld)
    Expected :222
    Actual   :111222
    
  • Місце ORM у загальній архітектурі застосунку

    Дисклеймер. Я палкий прихильник Hibernate, і коли чую ORM, насамперед маю на увазі цю імплементацію. Я в курсі, що є інші, з не таким багатим функціоналом.

    Колись на співбесіді мене спитали: «А як ти вчишся?». І нічого іншого, як відповісти «На практиці», я не придумав.

    Аналогічно.

    поділись досвідом у коментарях.

    Стадіон так стадіон.

    ORM — object relational mapper. Приблуда, яку придумали ліниві розробники, які не хотіли вчити SQL

    Перепрошую, не mapper, а mapping. Це я не прискіпуюсь до слів, а хочу сказати, що ORM — це більш широка абстракцію/технологія.

    А якщо я веду розробку від бізнес-логіки? То мене не цікавить, як саме імплементовано рівень сховища

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

    Відокремлення джерела отримання об’єкта означає, що цих джерел може існувати нескінченна кількість і вони можуть мати будь-які реалізації.

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

    Як тільки згадується SQL, питання, що робити з lazy-loading-ом. Як будуть виглядати оці всі getUser, getDog при умові, що там будуть більш-менш складні структури, а не навчальні три поля з ID? Будемо витягати з бази все одразу (страждає перформанс) або при потребі (ускладнюється код, змішується власне бізнес-логіка з DAO)?

    Я з NoSQL не працював, схоже, там такої проблеми нема, або вона не така гостра.

    Щоб краще проілюструвати проблему, навіть наваяв маленький проект з ієрархією тасок. З нетерпінням чекаю його кращої реалізації без ОРМ, але з DataGateway (хоча б на рівні ідеї).

  • Spring JDBC проти Spring Data JPA

    Скажіть, будь ласка, а для чого у вас

    зʼявляється columnDefinition в @Column

    ?

  • Как правильно извлечь связанные данные без ORM?

    транзакцией уровня Repeatable Read, что на современных MVCC БД недорого.

    Например, у MySql InnoDB такой уровень по дефолту.

  • Предметно-орієнтоване проєктування (DDD): у чому користь підходу і хто його використовує

    І при цьому об’єкт потрібно зібрати з декількох баз або навіть сервісів. В одному випадки ви лише змінюєте внутрішню реалізацію репозіторію

    Може, ми з різними кейсами стикались...

    І при цьому об’єкт потрібно зібрати з декількох баз або навіть сервісів.

    З одного боку, я усіляко підтримую і заохочую тримати логіку в домені, з іншого — виключно за lazy-loading, бо все інше дорого. Дякуючи JPA/Hibernate, в межах реляційної БД виходить два-в-одному, хоча, звісно, є нюанси (на кшалт, що робити з httpCall всередині транзакції?).

    Якщо забути про JPA, то, мабуть, робив би те саме — переводив домен на інтерфейси (по-хорошому, це треба робити зразу) і підсовував проксі-класи.

    OrderItems завжди завантажуються? Навіть для completeOrder?
    Якщо ви маєте на увазі кінцевий стан, то у вас вже немає мутацій, читайте як хочете використовуючи рид модель.

    Ні, ні, тут принциповий момент. completeOrder() — це мутація, виставляє статус.
    Викликаючи метод, я ж не повинен знати, які дані йому потрібні?
    Тому читаю один й той самий aggregate root? З усім шо там є? Знову повертаємось до lazy-loading

    Дякую, здається порозумілись.

  • Предметно-орієнтоване проєктування (DDD): у чому користь підходу і хто його використовує

    Дякую, принаймі для себе я дещо прояснив.

    Тут у іншій гілці навели наче непогану базову статтю.

    Якщо правильно зрозумів, ДДД/гексональна архітектура кажуть: «Дивіться, як класно! Домен з логікою окремо, репозиторій окремо, хопа — монго на касандру поміняли! Будь яке сховище може бути!»

    Будь яке key-value сховище, чую я.

    Та ні, таких обмежень немає, репозиторій може й у реляційну БД зберігати, хоч за допомогою JPA/Hibernate, хоч на чистому JDBC.

    Рілі, перепитую я? От реально зможете

    1. Завантажити агрегат.

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

    Щоб проілюструвати практичну нездатність такого підходу, я і питаю про ієрархію тасок.
    Ви і самі відчуваєте проблеми перфомансу, тому і пропонуєте завантажувати всю базу весь граф, змінюючи структуру БД

    Наявність ProjectId дозволить швидко за допомогою одного плейн запиту завантажити увесь Project.

    або сподіваючись

    А на практиці у 99% юзерів буде не більше 50-100 тасок.

    До статті з її прикладом з Order та OrderItems те саме питання: OrderItems завжди завантажуються? Навіть для completeOrder? У key-value БД може і не проблема весь документ витягувати, але для реляційних БД це занадто дорогий підхід.
    До речі, комент під статтею про те саме питає.

    Якщо продовжуєте наполягати, що зможете

    1. Завантажити агрегат.

    з цікавістю послухаю.

    Будь ласка, гляньте ще сюди
    dou.ua/...​rums/topic/45909/#2721579
    dou.ua/...​rums/topic/45909/#2721597

    Якщо запропонуєте проксі-класи з lazy-loading-ом в домені використовувати, повернемось до розмови про транзакційність.

    Також хочу висловити проміжкову подяку за дискусію.

  • Предметно-орієнтоване проєктування (DDD): у чому користь підходу і хто його використовує

    Давайте визначимось з терміном Entity.

    Так, дякую, це слушне зауваження. Якщо правильно зрозумів, у ДДД домен — це бізнес-суть, ентіті — це домен + id (і, скоріш за все, version), а Data Model — відноситься до репозиторію. Якщо це JPA, то там є свої ентіті, що створює плутанину.

    Чи є догмою що Data Model і Domain Model повинні бути розділені? Загальна відповідь — ні, це не догма. У простих випадках ви можете мапити Domain Model на базу напряму, і не мати проміжної Data Model.

    Зрозумів, згоден.

  • Предметно-орієнтоване проєктування (DDD): у чому користь підходу і хто його використовує

    А, ні, з оцим

    Скоріш за все на етапі операції (сервісний рівень, use case) ви вже знаєте які дані вам будуть потрібні. А значить й мапити JPA Entity в домен можна тільки частину даних.

    Це ж те саме?
    ...
    погодитись тяжче.

  • Предметно-орієнтоване проєктування (DDD): у чому користь підходу і хто його використовує

    Думаю так само, немає предмету суперечки, тисну руку

  • Предметно-орієнтоване проєктування (DDD): у чому користь підходу і хто його використовує

    Це гарна стаття, але, нажаль, не відповідає на мої питання.

    У статті

    public class DomainOrderService implements OrderService {
        @Override
        public void completeOrder(UUID id) {
            Order order = getOrder(id);
            order.complete();
    
            orderRepository.save(order);
        }
    }
    

    Переваги:

    • домен не прив’язаний до конкретної БД чи навіть сховища, що чудово ілюструє стаття
    • гарно виглядає для простих пласких об’єктів

    Недоліки:

    • домен завантажується повністю, незалежно від юзкейса; як це відобразиться на перфомансі — неясно, але навряд чи добре
    • що робити з ієрархіями — відкрите питання (принаймі, поки що ніхто не прийшов і не сказав)
    • рівень ізоляції скоріш за все READ_COMMITED з відповідними phenomas
    • ніхто не заважає робити проксі-класи, але, так розумію, ніхто і не допомагає

    Я б зробив (і постійно роблю) (у припущенні, що все прив’язане до JPA)

    public class DomainOrderService implements OrderService {
        @Transactional
        @Override
        public void completeOrder(UUID id) {
            Order order = getOrder(id);
            order.complete();
        }
    }
    

    Недоліки:

    • домен прибитий цвяхами до JPA. Відповідно, одну реляційну БД на іншу замінити ще якось можна, а от переїхати на Mongo/Cassandra — набагато тяжче (тут, звісно, практичне питання — як воно в реальному житті?)

    Переваги:

    • Lazy Loading з коробки JPA, який може покращити перформанс
    • Нема проблем з ієрархіями, циклічними посиланнями, так хоч з чим проблем нема)
    • рівень ізоляції можна підняти до REPEATABLE_READ, або JPA Provider його і так частково зробить за рахунок кеша 1-ого рівня
  • Предметно-орієнтоване проєктування (DDD): у чому користь підходу і хто його використовує

    це не по принципам ДДД бо база данних має бути окремо від домена.

    Якщо ви таке не стверджуєте, то нам далі нема про що продовжувати) Мені цікаво, як вирішують цю задачу ті, для кого розділення домену та ентіті — це догмат.

← Сtrl 123456...18 Ctrl →