Комментарии 173
Во всем важен баланс. Я думаю, вам сейчас еще десять раз накидают комментов на тему того, почему слабая связанность и interface segregation это хорошо (и будут правы).
Вопрос не в том, что пишут сразу сложно или лепят процессы, которые сразу сложны, а в том, действительно ли они решают больше проблем, чем создают. И на этот вопрос нет универсального ответа. И ваша статья на этот вопрос тоже не отвечает.
действительно ли они решают больше проблем, чем создают. И на этот вопрос нет универсального ответа. И ваша статья на этот вопрос тоже не отвечает.
Статья призывает задуматься, а надо ли тьма абстракций и наследования, где можно было бы обойтись функцией.
Кто определит границу этого "можно было бы"?
Если есть сомнения, то делайте проще. Усложнить всегда успеете.
К сожалению есть еще один момент, который часто присутствует в "корпоративной" культуре. Эксперт либо прав сразу, либо - на него повесим всех собак, особено на fixed scope / fixed price
Да и на "итеративных" подходах надо заранее оформлять такие решения как тех. долг, но все равно осадочек останется. Почему сразу не настояли :)
Поэтому я лично предпочитаю описывать варианты, перенося все в термин денег, скоупа и сроков, и дальше предлагать "продукту/спонсору" выбрать. Ходите быстро доехать, и потом дольше допиливать, или выйти позднее, но с более интересным продуктом.
Главное дать опции именно в "бизнес"-терминах, чтобы люди в привычной им среде могли понять. а чего мы хотим.
----------------
Поэтому я бы чуток исправил на
Дайте две, а лучше три опции, как делать с двумя перспективами, на короткую и на длинную.
А там уже по приоритетам решить
Я для себя выработал следующий подход - можно ли нечто не использовать/удалить, с сохранением бизнес функционала. Если ответ да, тогда удаляем. Кому то это может показаться странным. Обычно людям зараженные одной из идеологий, которая заставляет порождать много абстракций. На практике же реализация подхода выше приводит к тому что код и в целом система становится проще. Простые вещи легче понять, а значит легче понять как добавить в них новый функционал, а также то что человек понимает в том редко делает ошибки(баги).
Определить границу "можно было бы" поможет только опыт. И уровень знаний. Стек тоже сильно влияет на подход. Берёте Java - вы вынуждены использовать интерфейсы. Пишете на Си - там придётся выкручиваться иначе.
Но она не призывает задуматься, а действительно-ли можно было обойтись функцией или нужно было обойтись меньшим числом абстракций и наследований, которые действительно необходимы.
Статья о крайностях, а работа инженера о поиске оптимального варианта.
Проблема в том, что многие даже опытные разработчики боятся менять-рефакторить существующий код. Даже если это напрашивается. И пишут код по аналогии того, что есть, несмотря на то, что вот теперь аналогия не очень-то и подходит. И вот теперь -то надо небольшой кусочек переделать, чтобы все было красиво и аккуратно.
Боязнь менять тоже ведь имеет причины. Нет тестов, например. А как проверить? Руками то не всегда получается.
И иногда лучше сохранить стилистику кодовой базы. Если старый проект использует императивный подход из тьмы функций - стоит ли рефакторить, используя ООП? Это вся команда должна решить, а не только один программист-рок-звезда. И придётся подтянуть всю команду в умении делать абстракции.
С ООП бывает сложно перестроить мозг. Смотрю в небо, там облако, похожее на Лошадь. Другому Рыба видится. А ведь всей команда должна уметь в "синхронное плавание".
Мне кажется, первопричина часто в product-manager. Часто бывает, что человек, ответственный за развитие продукта, вместо того, чтобы создать "нечто, созданное за бюджет, в срок и с целью заработать", начинает реализовывать все свои хотелки и мечты с детства.
Все таки, это первый человек, который отвечает, что продукт "закроет" бизнес цель. Именно он связывает бизнес задачу и разрабатываемый инструмент для ее решения. Если же разработчка превращается в "процесс наряжания новогодней елки детьми" - спасти уже сложно. А перечить ему тяжело, так как обычно он либо представитель заказчика - и тогда надо вообще аккуратно, либо все равно ближе к спонсору, чем остальные
------------------------------
Сложность архитектуры часто также идет оттуда. Я хочу все настравивать, я хочу все конфигурированное ... ну блин, а в итоге половина фич вообще никому не нужна. А вот эта гибкость часто требует усложнения. Ну а как иначе?
Тестами покрыты ключевые участки системы. Простейшая логика не проверяется
Ну такое. По опыту баги могут буть везде, и зашоренная команда не видит, хотя баг реально выглядит как 15ти килограмовый арбуз в центре стола.
За деплой отвечает сам разработчик
В enterprise нет от слова совсем. И не потому что там все переусложнено. Просто за стабильность систем в целом отвечает именно поддержка и она решает, как и что. Да, хочется побыстрее, но практика показывает, что "побыстрее" == мы завалили систему и сейчас быстро решаем, откатить все назад, либо еще чуть-чуть вручную потолкать все вперед.
Разработчик вообще часто живет в мире, где он сам себе нарезал доступа, код выполняется в единственном экземпляре, логи не нужны, так как он все может продебажить :) Последнее кстати самое ржачное, так как некоторые так реально думают и даже говорят
------------------------------
Из моего опыта, как архитектора, самое сложное в смысле принятия решения - это найти грань, между где лучше закодить и если то - поменять/дописать, а где - лучше заложить параметризацию заранее. И не могу сказать, что я всегда правильно решаю с первого раза :(
Ну, кстати вот да. Разработчики часто думают, что код который они запустили у себя, это вот тоже самое, что будет в эксплуатации. Но нет, это ведь не так.
Собственно как раз хорошо, когда продукт, как нечто конечно, формируется всеми, от идей до собственно деплоя, когда сразу все участники могут сказать о возможных проблемах и сразу пустить развитие в нужном направлении. И это не переусложнение, а норма.
Нет, я имею ввиду, что разработчик проверяет функционал без нагрузок, без сетевого взаимодействия, без фаерволов, балансировщиков, WAF и чего угодно ещё. Плюс, скорее все, проверяет ещё и не задумываясь о протоколах, о шифровании траффика и много о чём. Он даже не знает о существовании этих вещей. Его не волнуют очень многие вещи.
Вообще не понимаю, в чём клиника, если есть разница между тем, что у разработчика и тем, что в проде? Это как раз не клиника, это как раз обыденная норма. Разные ОС, разные IDE - это в порядке вещей.
Клиника это пересаживать всех разрабов на идентичное окружение, как и деплой разработчиком, у них вообще нет доступа к серверу, в адекватных командах.
Ещё раз вопрос, в какой момент так произошло, что у разработчика на локальной машине система ведёт себя иначе чем на тесте или проде.
Например, после очередного обновления виндоуз. Или когда размер БД у клиента превысит на несколько порядков размер БД у разработчика (локальной и/или на тестовом стенде). А чаще - с момента установки (из-за другого окружения).
Этого вполне можно добиться, если конфигурация проекта локально отличается от конфигурации на сервере. Например, фиче-флаги выставлены по-другому. С этим надо быть аккуратнее))
Вы умеете ввиду что на машине разработчика и на рабочей среде разные варианты системы?
Странно, когда одинаковые. Потому что, например, в машину(стенд) разработчика(ов) тупо не влезет вся эта тьма взаимодействующих сервисов системы. А еще доступа к системам смежников нет - эмуляторы/заглушки разной степени навороченности стоят.
сразу видны слова опытного архитектора, подпишусь под каждым. Особенно про неуверенность в том, что ты прав - она приходит только с десятилетиями опыта. Всегда правы только дураки либо новички
Переусложненный код
Рассуждать о сложности кода без контекста - не комильфо. И вообще попахивает дилетантством. У дилетантов все всегда объясняется очень просто. "Простейшая" операция check_user
может быть аццки сложной, если мы говорим о банковском приложении со всякими комплаенсами и проверкой по "базам злодеев".
Когда я прихожу на новый проект и вижу дикие спагетти, то я беру таймаут минимум в полгода "на разобраться". Только потом начинаю судить, реально ли это говнокод или сделать проще скорее всего не так-то просто.
Сервис живет 2 года. Любой сервис живет 2, максимум 4 года.
Очень странное заявление.
Или это перевод и имелось ввиду то, что сервис "работает слаженно как организм"...
Я этого пассажа тоже не понял. У нас есть участки кода, которым больше 10 лет, вполне себе работают до сих пор. Ну их иногда облагораживают немного, но в целом живут и не тужат.
Как бы, а чего не жить какой-нибудь простой функции, или простому сервису, который не поменял ни логику, ни функциональность? С чего ему, внезапно, отвалится через 2 года?
Обязательно переписать, а то не стильно не модно и не молодежно же уже, на устаревшем фреймворке! :) Вы мамонты, и не понимаете. :)) А еще KPI выполним!
Тоже странно это все слышать, конечно, когда цикл работы нашего ПО на объекте 10 лет и более, причем иногда поддержка требуется.
Вот для таких людей отдельный котел. Как будто это самоцель- писать что-то. Код - инструмент для решения задач или фабрика инструментов, или фабрика фабрик инструментов на крайний случай
del
Очень интересная и занимательная статья) спасибо)
В стартапе можно\нужно быстро кодить и подзабивать на тесты. В банке никто не позволит творить отсебятину.
Но в целом, идея "сделать быстро" а потом улучшать вполне здравая (минуя банки, конечно). Сюда ещё можно добавить, что технологии быстро развиваются. Я за последние 20 лет сменил операционку, несколько языков, фреймворков, баз данных и подходов к разработке.
Есть не только стартапы и банки. Стартап, который пилит сервис, однажды может вырасти и таки стать тем, кто уже не может ломать свой продукт по 20 раз в день.
Идея сделать быстро и улучшить выглядит здравой, пока это пет-проект.
По факту же обычно это заканчивается на "сделать быстро", а потом ещё 20 задач "сделать быстро". И на улучшение никто не будет стремиться дать ни денег, ни времени, ни рук. итоге проект может так и остаться сделанным на коленке, когда следующим этапом будет "сделать с нуля, нормально". А это означает, что предыдущая работа, т.е. деньги и время, только в мусорку. И хорошо, когда есть новые деньги и время, но ведь часто бывает так, что люды на сделанном пытаются зарабатывать. А не получается.
Плюс если говорим про API, то там вообще не очень хорошо делать "лучше потом". Просто ломать совместимость потом будет болью.
Если проект не приносит денег - то его и не надо переписывать. Так бывает: не угадал. Надо высаживать новые розы и выкорчёвывать засохшие, а поливать засохшие нет смысла.
За 25 лет в веб-разработке поменялось всё. И всё несколько раз переписывали.
У API есть версии именно для таких моментов.
Понятно, что надо сначала думать, а потом делать. И не писать лапшу в старом-php стиле.
Версии то есть в апи, только вот если у вас много внешних потребителей этого апи, на которых вам сложно повлиять, то заставить их переползти на новую версию может быть очень не быстро. Ибо доп. затраты для компании-партнёра, а профит не очевиден, итак же все работает. Так что с версиями надо быть аккуратнее и делать по возможности без них, либо с минимальным из количеством. А то может случиться, что поддерживать их придётся если не вечно, то очень долго.
Да, когда стоит задача разработать АПИ, ищем человека, который их уже штук 10 сделал и поддерживал долгое время. Используем чужой опыт прямо с носителем этого опыта.
Если нет такого человека, читаем, как делают АПИ, смотрим чужой опыт. Можем мы облажаться? - Конечно. Даже если пытались предусмотреть все возможности по расширению - всё равно у нас хрустального шара предсказывать будущее. Делаем хорошо, насколько можем: пишем тесты и документацию. Ведь совсем не делать тоже нельзя.
Поэтому важен баланс. Не пороть лютый говнокод, да. Сделать не плохо, но и не слишком хорошо, так, средненько.
И почти всегда это будет то что надо.
Вот про те самые "тыщу RPS" - это прям очень жизненно. На старте любого сервиса всем (тем кто ставит задачи - т.е. владельцам и авторам идеи) хочется верить в светлое будущее, они полны оптимизма, поэтому сразу заряжают какие-то безумные требования. Ну как же, если через год у сервиса не будет миллиона юзеров и тыщи запросов в секунду, то и не стоит даже начинать.
По факту ни один из проектов, в которых я участвовал, ни разу не доходил даже близко до таких цифр. Или помирали, или реалистичной нагрузкой вполне были 1-2 запроса в секунду. Причем те проекты, где безумные требования продавливались успешно, помирали чаще - в том числе может и потому, что удовлетворение этих требований сжигало бюджет сильно быстрее.
Поэтому я всегда в таких случаях на фонтанирование идеями про масштабирование, балансировку нагрузки и закупку каких-то кластеров, отвечаю - давайте начнем с малого, а если у нас будет тыща RPS - это значит что мы уже стали богатыми и успешными и вот тогда уже сможем себе позволить дорогие решения, тогда и будем думать.
Преждевременное абстрагирование даже хуже, чем преждевременная оптимизация, так как обычно затрагивает бОльшую часть проекта.
Даже если под новые требования придётся переписать часть ядра, то простой код переписывать проще. А угадать, в какую сторону потребуется расширение, в общем случае маловероятно.
Причины переусложения тривиальны - потому что нет естественных ограничителей.
Усложняют не потому что это реально нужно, а потому что никто и ничто не запрещает так делать. У настоящих инженеров и архитекторов (которые строят машины из металла и дома из железобетона) есть как минимум габаритные и весовые ограничения, и законы физики. Никто же не купит автомобиль размером с трехэтажный дом с энергопотреблением в пять мегатонн бензина на сотню км. Но в IT подобное вообще без проблем, ну купим новые серверы с терабайтом оперативки и 128 ядрами, делов то.
И у программистов это норма, они еще и посмеются над тобой, дескать если у тебя в автомобиле нет реактивного SPA салона с многоуровневыми микросервисами поддержки климата, задеплоенными в облако кубернетиса, да с отдельной командой DevOps на поддержке этого всего в гараже, то ты какой-то чепушила малоактуальный. А если ты не дай бог какие суммы по заказу посчитаешь просто в цикле, а не через распределенный MapReduce с асинхронной потоковой сериализацией через лямбда промисы с кастомными аннотациями с применением минимум сразу двух BoostSpringMobxNuxt$mol фреймворков - то все, сразу в джуны разжалуют и даже возле кофе машины перестанут здороваться.
Есть одна проблема - точность оценки. То, что неопытный или не особо компетентный специалист может считать переусложнением, человек более опытный может считать необходимой нормой, так как видит проблемы, которые возникнут, если не "переусложнять".
Мы все немного ограничены своими рамками и некоторые думают, что если ничего не происходит и идёт по плану, то это норма, а не потому, что кто-то предусмотрел проблемы и принял меры.
Притом это касается не только разработки, это касается очень много чего.
Вопрос в том, кто будет нести ответственность за решения и какие риски. Разработчику в вакууме, который не приносит денег и который, в случае неудачи, просто уволится и пойдёт на другое место работы, очень легко рассуждать о каком-то переусложнении. Вы никогда не увидите что такой человек скажет "я бы л неправ". И когда наступят последствия от его дурацких решений, в эпицентре будут другие люди. Разруливать будут другие и оплачивать будут другие. А разработчик будет и дальше плакаться и кричать о переусложнении и необходимости простых схем, но уже в другом месте. от и всего лишь.
И когда наступят последствия от его дурацких решений, в эпицентре будут другие люди. Разруливать будут другие и оплачивать будут другие.
Ой да ладно, разруливать. Там на "модном, правильном и сложном" уже в первый год после выкатки в прод обязательно случится эпическая замятня с банальным обновлением зависимостей и заморозка оных. А через три-четыре года это станет уже реальной проблемой, т.к. придет безопасник и будет уже прям совсем больно бить по рукам за непропатченные древние библиотеки, а пропатчить их не получится от слова совсем.
Т.к. найти людей с компетенцией и желанием ковыряться в каком уже напрочь устаревшем ануляро-джанго-ларавеле не получится за любые деньги, и придется брать вчерашних джунов с горящими глазами, которые все враз "быстро" с нуля перепишут на очередной модный нукст-солид-мобикс. На который на рынке через пять лет тоже не найдешь "специалистов".
Эти латте-смузи архитектурные приколы давно известны и видимо пока снисходительно прощаются бизнесами по лишь той причине, что бизнесу положено примерно раз в эти пять лет тотально с нуля переписывать-перерисовывать весь фронтэнд, чтоб чисто визуально не прослыть совсем замшелыми технолуддитами на фоне конкурентов. Ну и чтоб пользователи не скучали и чувствовали, что о них заботятся, и не разбегались к этим самым конкурентам от скрытой обиды и прочего ощущения обделенности вниманием. Вот так любители переусложненных новомодных архитектур и заказчики и нашли способ гармоничного сосуществования - вы нам позволяете играться от души за ваши немалые деньги, а мы создаем вам имидж технической продвинутости, трендовости и прогрессивности. До очередной пятилетней итерации "а не пора ли обновить нам наш сайт?".
ДА, разруливать.
С чего бы это? Нет, не случится.
Не знаю, какой безопасник придёт через 3-4 года. У меня таких нет. Я сам приду через 3-4 месяца и буду требовать подтягивать. Вот именно чтобы через 3-4 года это не стало реальной проблемой.
Найти получится даже запросто. Вообще-то \то хороших денег стоит.
Да, перепишут на нуктс, который просто фреймворк над вуе, который живёт, здравствует, активно развивается и на который есть и спецы и спрос.
Да, известны. Потому и говорю - есть опытные спецы, которые уже знают, как это нормально делать, а есть дедуганы, которым сложно и они умеют только трындеть.
Вы никогда не увидите что такой человек скажет "я бы л неправ".
А опытный сеньор или архитектор скажет? Ну конечно, ага. Все с точностью до наоборот.
Я скажу. И мои знакомые тоже говорят. Да, а вы как думали? Это называется нести ответственность. Вообще-то свою неправоту и неудачность идей опытные спецы озвучивают очень часто и это норма. Именно эти люди в глазах казуалв от мира ИТ что-то и переусложняют, так как уже имеют опыт и набитые шишки и понимают, к чему это приводит.
Плюс к этому. Не знаю, принято ли у архитекторов домов увольняться до окончания своего проекта. Но в IT такое наблюдал и не раз. Пришел новый сеньор/архитектор/руководитель - весь из себя крутой и в тренде. Дальше он задает стиль проекта: долго, дорого, переусложнено. Проходит год, чего-то начальству демонстрируется, но до полного отказа от старой системы в пользу новой - еще N лет, и это становится очевидно всем. Примерно в это время приходит письмо от вышеупомянутого IT руководителя - мол, спасибо за бесценный опыт, но жизнь не стоит на месте, иду дальше расти в другую компанию.
Почитал и не убедили.
По ряду причин. Во-первых у вас абстрактный конь в жидком вакууме на ложке, которой нет.
Проекты, они разные и это очевидно. Один начинают писать с нуля сегодня, не зная, что ждёт его в будущем. У другого проекта бекграунд в 20 лет.
Один проект это MVP стартапа, у которого есть только идея, а другой это огромная система по решению всего, что хочет заказчик.
В итоге в одних случаях будет переусложнение по одним пунктам, но в других этого не будет.
Как правило, переусложнение возникает не когда вы на ранних этапах пытаетесь лучше понять продукт, а когда вы "просто делаете". Да и вы оказываетеся в моменте, когда ваш проект это куча кода, сшитого из кучи кусков, притом недокументированного и никто не понимает, как он работает, работает оно так себе, а самое главное - дальше уже просто никак.
И вы с вашим подходом как раз и придёте ко всем описанным вами рискам, примтом гарантировано. В смысле я это буквально кучу раз видел.
То, что у вас описано во "вредителях" это прям то, за что надо бить. Во-первых, с какого перепугу вы обзываете кого-то вредителями?
Во-вторых, почему вы всё пытаетесь подогнать под шаблоны? Технари бывают разными, а если человек закладывает риски, это не значит, что он любит всё переусложнять. Человек может просто неверно рассчитывать риски, это да, но остальное чушь.
То, что вы назвали "грамотным подходом" это как раз и есть вредительство и полная хрень.
Дальше вообще забавно:
РПС может вырасти. Что значит вырасти? Он что, растет внезапно? На сколько он может вырасти. Вы делали проект на коленке дома как стартап, бахнули его в гугл-плей и он взял 200 млн юзеров за 2 недели? С какой вер-стью это случится? Надо ли на такие доли процентов создавать сложные системы, способные держать такие нагрузки? Большинство компаний и команд и 10к РПС видели лишь во снах.
Ну, во-первых то и значит - вырасти. На сколько - да хз. Давайте начнём с вопроса, что у вас вообще за сервис. Абстракции обсуждать смысла нет. Если вам надо отдавать статику для фронта, это один вопрос. Если к вам прилетает POST запрос, который запускает динамику на сервисе, это совершенно другой вопрос и проблема тут не в РПС, к которому вы так привязались, а к утилизации мощностей.
Будут добавлять новые фичи. Я не представляю себе синьера или мидла, которому дадут писать сервисы и фичи и он напишет так, что туда невозможно будет добавить фичу. Какие фичи? Перекрасить кнопку? Поменять название? Или новая фича уровня, вчера это был гугл, а сегодня это стал сайт по приюту для собак?
Вы не представляете, а я представляю. Я такие проекты видел. И то? О чём разговор? О реальности или о ваших фантазиях?
Перекрасить кнопку, серьёзно? Это главное, что знаете в разработке? Это у вас ровень синиора или что? Фичи бывают очень разные и работать они могут очень по разному. Я запросто представляю, как приходится костылить, чтобы реализовать новый функционал.
Если ошибемся придется все переписать. Еще раз, если вам пришлось все переписать, то даже 5 лет проектирования и описание каждой строчки аналитиком и тех. писателем - вас бы не спасло. Я не говорю сразу броситься кодить и собрать непонятно что, грумминг 1-2 часа - это ок, не надо только каждую строчку холиварить и каждый новый сервис гонять через 20 комитетов.
Не очень понятна тяга к утрированию. А вы знаете, что для подумать не обязательно планировать каждую строчку и собирать какие-то комитеты? И да, вообще-то нормальные изначально подходы очень даже спасают от необходимости всё переписывать. Например нормальная архитектура, вместо Feature factory вполне спасают от такого. Я понимаю, что некоторые разработчики видят продукт как просто большой набор фич... Ну, результаты я тоже видел.
В общем, я не знаю, к чему там призывает автор в выводе, я просто вижу, что здесь неопытный специалист пытается делать вид, что он опытный и не понимает последствий тех или иных решений. А так же не понимает, сколько времени и сил (ну и нервов) будет выкинуто на помойку, просто потому, что на ранних этапах было лень что-то продумать и что-то показалось сложным.
Согласен. Все зависит от проектов. Было и фича размером с существующий сервис на 130к строк и прыжок нагрузки когда БД легко держала нагрузку на 10rps и умерла на 20rps. Т.к. нагрузка это не про количество запросов, а про количество данных которыми вы оперируете. И если у вас 10rps, но данные которые вы оперируете, растут на 20млн в сутки, то через год 20rps кладут эту БД на колени. И решить проблему добавлением индекса не получится, ибо они уже все есть и вылизаны, а во вторых добавление нового индекса на дает +80-100гб и строится с 50% нагрузкой на CPU сервера 2 дня.
Причины переусложения тривиальны - потому что нет естественных ограничителей.
Тому, кто только что в первый раз прочитал паттерны (условно - Фаулера), обязательно нужно всё это опробовать в первом же самостоятельном проекте. :)
Тому, кто только что в первый раз прочитал паттерны (условно - Фаулера), обязательно нужно всё это опробовать в первом же самостоятельном проекте. :)
Там не только паттерны. Есть масса реальных примеров в вполне боевых проектах. Суть задачи - есть на входе ArrayList, нужно его отфильтровать и сделать другой ArrayList. Куда уже проще. Смотришь код - а там чего только не навалено - и Java Streams, и Spring Batch, лямбды, инъекции, Generics, какие-то бины с кодогенерацией из YAML. Потом берешь commit blame и идешь к "автору" с вопросом: "А на кой хрен ты тогда вот это все наложил тут?" Ответ огонь - "Да просто хотел попробовать Java Streams, но не было другой подходящей задачи". ОООК. Идешь ревьюверу и аппруверу (все же ходы записаны): "Как так, почему ты это все пропустил в мерж?" Ответ почти аналогичен: "Да я тоже всегда хотел попробовать Spring Batch, не мог найти под них задачу, а тут было очень интересно почитать разобраться, потестить, опыт для резюме".
Парни, а что, сделать себе песочницу на гитхабе и там незаметно поиграть всяким друг с дружкой нет, так нельзя было? Этот вопрос впрочем остался без ответа.
Парни, а что, сделать себе песочницу на гитхабе и там незаметно поиграть всяким друг с дружкой нет, так нельзя было?
Можно было. Можно было и Теорию Относительности не изобретать. Ньютоновская физика и так норм была. Планеты крутятся, гравитация мутится.
Как в вашей логике разработчику составить мнение о том же Spring Batch, если он в бою ни разу не видел? В песочнице-то любой хэллоуворлд норм работает.
Видимо, вам знание как "сделать нормально" досталось при рождении или через высшие силы. Менее удачливым разработчикам нужно сначала посмотреть на продукт в бою под нагрузкой и на большей дистанции, а потом делать выводы.
Так и проектировщикам двигателей и механизмов знание как проектировать не досталось при рождении. Однако двигателей с экспериментами люди делают не так уж много.
В смысле не так уж много? Да с двигателями всю дорогу эспериментирут. Рядные четверки, шестерки, тройки, V-двигатели, оппозиты, роторные двигатели, впрыск закиси азота, турбины, суперчарджеры. И это все людям продавали, если что. Именно поэтому мы сейчас прекрасно знаем достинства и недостатки всех типов движков. А ретрограды выше предлагают просто писать как писали деды на K&R си. А с новыми фреймворками только в песочнице играть.
Ретрограды предлагают R&D отдельно, а производство готовых изделий из придуманного - отдельно.
Как в вашей логике разработчику составить мнение о том же Spring Batch, если он в бою ни разу не видел?
Теоретически - на разном обучении/повышении квалификации. Точнее, на одном из его видов. Которое и служит для того, чтобы попробовать то, что в реальном проекте делать не стоит или непонятно, стоит ли. Потому обсудить, поделиться опытом и так далее. А потом попробовать сделать то же самое другим способом и повторить.
Нет, всякие курсы "Выучить XYZ за n дней" к такому виду обучения обычно не относятся.
Смотришь код - а там чего только не навалено - и Java Streams, и Spring Batch, лямбды, инъекции, Generics, какие-то бины с кодогенерацией из YAML. Потом берешь commit blame и идешь к "автору" с вопросом: "А на кой хрен ты тогда вот это все наложил тут?" Ответ огонь - "Да просто хотел попробовать Java Streams, но не было другой подходящей задачи". ОООК. Идешь ревьюверу и аппруверу (все же ходы записаны): "Как так, почему ты это все пропустил в мерж?" Ответ почти аналогичен: "Да я тоже всегда хотел попробовать Spring Batch, не мог найти под них задачу, а тут было очень интересно почитать разобраться, потестить, опыт для резюме"
Посадить того и того на поддержку 3-ей (или 4-й) - у кого как. Которая про то, что "У нас тут система (дремучее legacy) какое-то непонятно что делает, нам хочется, чтобы она перестала". Разбор багов очень способствует исправлению.
Не могу сказать, что там со Spring Batch и бинами с кодогенерацией, но стримы с лямбдами чем не угодили? В Java c 8 версии, выглядит ок:
List<> dstList = srcList.stream()
.filter(o -> o.weight() > 100)
.collect(Collectors.toList());
Эм... Сейчас умеют делать просто.
Не очень понятно "ничего сложного" это что? Окей, допустим кубер не нужен (хотя в чём проблема этот сервис запустить как 1-3 воркера в уже существующем?) но в докере в чём проблема? Он просто пакует окружение. Что тут сложного? ОПять же - а почему не ребит, если он уже под рукой и не надо с нуля поднимать?
Люди и сейчас в блокноте пилут, если надо. Вы крайне сильно утрируете и пытаетесь выдавать ложную альтернативу, т.е. только крайностей. Вариантов многим больше.
но в докере в чём проблема? Он просто пакует окружение. Что тут сложного? ОПять же - а почему не ребит?
Проблема в том, что этих зверьков тоже нужно кому-то обслуживать, обновлять, патчить, мониторить. Если облако с "модной" инфрастуктурой есть уже купленное и работающее на смежных проектах, с приложенной тренированной DevOps командой, то ок, может быть и можно брать сразу на старте под новый проект, если всем так проще.
Но чаще всего проблема высосана из пальца, потому как весь этот докеркуберцирк легко заменяется простыми словами bash, ssh/scp, crontab, zip/unzip, chroot (если прям параноит секурность или зависимости по линковке сильно хитрые).
Да и build.sh, и даже deploy.sh - можно и из putty запускать, никакие teamcity для этого не обязательны. Ну разве что jenkins прикрутить, чтоб начальству веселые картинки показывать с кнопками, ему так менее тревожно, чем смотреть в черные экраны с непонятными буквами в стиле первой Матрицы.
Работают же эти простые слова везде и на старте из коробки, хитрой настройки, компетенций, экспертизы и прочей поддержки не требуют.
Нужно и? В чём проблема их обслуживать? Вам даже не нужно никакой тренированной команды, вам просто надо понять, как работает "модный" инструмент, который на деле уже лет 10 как обыденный. И как работает IaC. А идея там очень простая - мы не ручками делаем окружение, а описываем его в файлике для воспроизводимости. Вы же обновляете систему? Ну вот, там она обновляется так же, только не через команду в консоли, а через команду в файле.
Конечно заменяются. И через Н итераций на паре десятков проектов вы приходите к аду и к необходимости тратить кучу времени на поддержание, к отсутствию идемпотентности и ещё к очень большому количеству проблем.
И да, скрипты можно запускать из putty. Но скрипты из putty это если вы студент или дяденька 40+, который просто не осилил в обучение и устарел лет на 15.
Просто я вам говорю как опытный специалист - все эти штуки, они не просто так получились и чем больше выхотите зарабатывать бабок, тем больше вы задумаетесь об эффективности и надёжности. И поверьте, чем выше уровень, тем меньше баша и putty в ваших проектах. Я бы вообще сказал, что при нормальном развитии баша должно стать 0 какой-то момент. Как и scp, zip и всего прочего хлама, который любят за собой таскать устаревшие, неопытные специалисты.
Просто я вам говорю как опытный специалист
Вот на этом ответе мы и выяснили причины переусложенения в софте, ура. Оказывается виноват банальный человеческий фактор стремления к "лучшим практикам" при отсутствии собственных опыта и решений, достаточных для цинично-рефлективных оценок "лучшести" этих самых чьих-то практик.
И этот поведенческий паттерн повторяется в абсолютно любой задаче.
Вот пример этой задачи деплоя: по сути нужно просто запаковать некий набор файлов и отправить на сервер(ы), там выполнить некий набор команд и перезапустить сервис. Заранее сложив артифакт после билда куда-то в хранилище с целью возможного отката в будущем. И... и все, там ничего больше и не надо.
Как работает циник с парой десятков лет опыта? Да, просто берет ssh+scp+git (svn|cvs|vcs), и deploy.sh с прошлого проекта (или просто загуглив), и вот тут решает эту задачу еще один раз на месте. Перебираем .sh скриптом имена хостов в цикле от строки в конфиге и просто делаем туда ssh коннекты и этим же скриптом выполняем там нужные команды (кстати удивительно мало кто знает что так вообще всегда возможно было делать). Это работало двадцать..тридцать прошлых лет и будет работать через двадцать лет, не требуя своего переписывания, покупки-переустановки всякого при каком обновлении операционки, перестройки сети, продаже бизнеса и прочих революциях. Ну конфиг с именами хостов разве поправить на новом месте. Ничего дополнительно ставить не надо, все идет в составе базового Linux дистрибутива, даже epel репозиторий не нужен.
А что делают горящие глаза и неутомимые руки+ноги "опытного специалиста"? Ну.... ставим RHEL или даже Ubuntu LTS, это понятно и скучно, и сразу по совету очень опытных товарищей туда крутим модные-актуальные K8S, Docker, Kinematic, рядом обязательно ставим Artifactory, Bitbucket, Ansible, Puppet. Не забываем про Logstash, Elastic, Graphana, Kibana, сверху обязательно какой мониторинг за этим всем, Zabbix уже не торт, берем Splunk, ну и все остальные нужные и полезные и обязательные штуки, уже лень их все перечислять (и это все тянет только на старте эдак на 100 гектар на диске и минимум 128 гектар оперативки, ибо там JVM везде), а иначе.... ой ой как страшно, иначе ведь этот самописный .sh скрипт для деплоя на целых 2кбайт размером и полтора экрана кода, написанный еще 15 лет назад, он же приведет к ужас чему:
И через Н итераций на паре десятков проектов вы приходите к аду и к необходимости тратить кучу времени на поддержание, к отсутствию идемпотентности и ещё к очень большому количеству проблем.
К идемпотенции! И потом к наверняка еще большим пока неведомым науке проблемам. Да. И потере какой критической потенции, стратегического фокуса и прочей всякой нужной разной очень важной компетенции. А что, разве поддерживать этот весь адок из установленного третьестороннего инфраструктурного софта совсем не надо, само всегда настраивается, работает и обновляется? И даже лицензий/денег не требует? Вопрос риторический.
И такой сценарий повторяется абсолютно во всем - вместо того, чтоб просто один раз сконцентрироваться на решении какой простой задачи вида "задеплоить пакет на хост и перезапустить там сервис" (и забыть уже на следующий день про нее) начинается эпопея обмазывания гигатонными слоями "лучших практик и отраслевых решений", создание целых отделов по поддержке этого всего, процессов. Митинги, созвоны. И ради чего? Просто ради принципиальной священной войны с непонятными и неприятными для глаз самописными bash скриптами и прочими "антипаттернами" (что не понимаем, то боимся и уничтожаем)? А что, ковыряться в Ansible или Docker скриптах стало уже более понятно и приятно, чем в bash? Или самописных скриптов и всяких странных конфигов прям совсем нигде не станет после установки всего этого великолепия? Да неужели?
все эти штуки, они не просто так получились и чем больше вы хотите зарабатывать бабок, тем больше вы задумаетесь об эффективности и надёжности.
"А вот это уже печально" (с) Тинькофф
Докер унифицирует среду выполнения и процесс сборки и запуска в ней. Это значительно исключает ситуацию бага и разработчика, у которого "все работает локально, ничего не знаю", а там оказывается версии библиотеки в ОС у разраба и на сервере разные. Так что зря вы на докер катите. Это одна из хороших практик и необходимость, нежели переусложнение. Вдобавок докер изолирует все зависимости от системы, и у вас исключается ситуация, когда один проект требует одну версию интерпретатора/компилятора и версии библиотек в системе, а другой -другие, а третий - третьи. И как вы все это будете устанавливать и обслуживать на одной машине без изоляции - большой вопрос и отдельная очень "интересная" тема.
Ну если лично у вас таких проблем не было, это не значит, что их не существует. Это лишь говорит о том, что вы с ними не сталкивались. А я сталкивался и докер эту проблему отлично решает. И ещё много других. Не стоит судить от полезности инструмента только лишь по применимости или не применимости именно в вашей работе. Это как минимум не репрезентативно. Если для вас это избыточная абстракция - замечательно. Но для тех, кто его использует для решения своих задач - это полезный рабочий инструмент.
Не очень понятно, о чем речь. Простые вещи надо делать просто, в этом посыл? Ну да.
А сложные вещи надо проектировать с учётом сложностей, и это может быть сложно. Сложность же невозможно убить. Если у вас проект на годы и с запланированными тысячами точек расширения, то вы не можете сделать просто, иначе вам всю жизнь придётся переписывать всё с нуля.
Есть такой тезис: Сложность должна быть адекватна проекту. Причем адекватна с разных сторон и на разном уровне. Методика, пригодная для создания онлайн-магазина, не подойдет для, скажем, банковской системы - и наоборот. Это, как мне кажется, понимают (практически) все. Проблема в том, что каждый, кто хоть сколько-то проработал в индустрии, наверняка сталкивался с проектами, которые переросли свою исходную базу. Оно по-всякому бывает - неожиданный успех продукта, прототип, засунутый в рабочую систему, накопившийся техдолг - сценариев много, а результат один, весьма болезненный. И всякий, кто с таким сталкивался, хочет этого в дальнейшем избежать. А, поскольку не знают, где именно упадут, то соломку стелят повсюду.
Хороший способ упростить ситуацию — дать кому-нибудь пинка. Потому что не надо страдать фигней.
>Сервис живет 2 года. Любой сервис живет 2, максимум 4 года.
Я в "черный" 22 год прошел пару десятков собеседований, и больше половины рассказывали историю как под копирку: 10 лет назад проект был написан на монолите и до сих пор мы его развиваем и мечтаем полностью переписать или приняли реальность и больше не мечтаем. О каких 2-4 года идет речь непонятно. В коде все время всплывают коммиты 5-7 лет давности.
Попутно помогаю проекту на старом месте работы, там мой же код в основных местах уже за десяток лет перевалил и до сих пор вполне актуален и хорошо работает.
Так что не соглашусь что код 4года живет максимум.
Ошибка выжившего.
Плюс на поддержку легаси часто берут новых сотрудников, а старым поручают новые продукты, которые обычно требовательнее к знанию предметной области.
Ошибка выжившего
Вы имеете в виду, что в природе не существует активных проектов 10+ лет? Это, мягко говоря, не так. Десять лет назад был уже 2014-й год и мир айти уже тогда был довольно большой и значительная часть этих проектов живёт и развивается до сих пор.
Прямо сейчас мы с вами общаемся на сайте 10+ лет, используя броузеры 10+ лет под операционными системами 10+лет, отвлекаясь на месседжеры 10+ лет. Над всеми ними прямо сейчас работают заметное количество программистов.
Я имею в виду, что никто не позовёт вас на проект, который уже умер.
В коде все время всплывают коммиты 5-7 лет давности.
Да. Всплывали бы и 10-15 лет давности, если бы не переход с свн на гит эн лет тому назад.
если бы не переход с свн на гит эн лет тому назад.
Это как-то странно. Переход с SVN-а на GIT с сохранением истории хоть и труднее чем кажется, если история длинная и совершались ошибки при работе с ветками, но не настолько запредельно сложный.
Небольшой оффтоп: https://svnweb.freebsd.org/csrg/share/dict/words?view=log
"Большинство компаний и команд и 10к РПС видели лишь во снах."
Но у всех всегда все высоконагруженное. Мне почему то в целом статья напомнила "парадокс вакансии резюме". Сколько бы и чего не было в резюме, в вакансии все равно надо будет еще и на губной гармошке в присутствии высшего руководства без missed-нот продудеть...
Мой взгляд на тему ...
ПО должно быть разбито на "кубики" (слои, если кому то этот термин больше нравиться). Каждый "кубик" должен иметь очень узкую функциональность и не лезть или дублировать функционал соседнего "кубика".
В качестве примера можно привести 7-и уровневую модель IP стека, где каждый уровень (кубик, слой) выполняет только свою определенную функцию.
При таком подходе можно получить высоко модифицируемое ПО гибкой архитектуры, способное отвечать на любые вновь возникающие требования, порой весьма неожиданные, в процессе всего жизненного цикла без кардинального переписывания проекта и с минимальными ресурсами и сроками.
Для разбиения кода на "кубики" требуется как правило 2 - 3 итерации. Первая итерация, по сути, это "проверка гипотезы" - лишь бы работало. Код здесь плохой, как правило на ней и останавливаются. Вторая итерация - это уже переосмысление кода первой итерации и биение его на кубики. Здесь уже можно получить конечный вариант. Но возможно потребуется и третья итерация переосмысления полученного результата второй итерации.
Кому то может показаться такой подход весьма затратным, но как говориться "трудно в учении, легко в бою". На этапе эксплуатации любая даже незначительная модификация кода при возникновении новых требований может превратиться в большую проблему, если код не побит на "кубики".
В качестве примера можно привести 7-и уровневую модель IP стека, где каждый уровень (кубик, слой) выполняет только свою определенную функцию.
Это прям идеальный пример вы привели, да. В TCP\IP нет 7 уровней, а то что в нём есть на 7-уровневую модель OSI натягивается примерно как сова на глобус. Не всё и не всегда идеально разбивается на кубики.
Все и всегда разбивается на кубики, не нужно только использовать не подходящие даже достаточно популярные технологии и шаблоны проектирования, которые не позволяют это делать. Классический пример плохой технологии ORM, модель данных и программная модель не должны быть связаны и на "кубики" все сразу раскладывается и модифицируемость приложения повышается.
ORM по сути превращает два изолированных друг от друга макро слоя (слой хранения данных и программный слой приложения) в один. Изменения в модели данных требует обязательного изменения программной модели и наоборот. Результат - ужасно плохая модифицируемость приложения.
Само название ORM Вам говорит, что модель данных соответствует модели объектов (программной модели), т.е. накладывает жесткая связь между этими программными слоями.
Когда нет связи между моделью данных и программной моделью переписывать вообще ничего не надо хоть при смене модели данных, хоть при смене программной модели. Более того даже в эксплуатации изменения можно ставить не одновременно, можно менять сперва модель данных и работать со старой версией ПО, а можно и наоборот. И представляете все успешно будет работать.
Более того, модель данных можно смело менять до неузнаваемости (полностью сменить структуру модели данных). И все останется в рабочем состоянии.
модель данных и программная модель не должны быть связаны
Как же тогда поменять данные в базе из программы, если они совсем не связаны? Вот добавили мы новое поле в таблицу, и что, там данные по волшебству появляться будут?
Я отвечал на комментарий "Классический пример плохой технологии ORM, модель данных и программная модель не должны быть связаны". Что означает, что автор этого комментария (1) советует не использовать ORM и (2) считает, что в ORM модель данных и программная модель связаны. Следите за дискуссией пожалуйста, если собираетесь в ней участвовать.
Если Вы задаете такие вопросы "Как же тогда поменять данные в базе из программы, если они совсем не связаны? Вот добавили мы новое поле в таблицу, и что, там данные по волшебству появляться будут?", то и вы считаете что "в ORM модель данных и программная модель связаны".
Естественно. Только я не отвечаю на вопрос "Как менять данные, если модели не связаны?" вариантом "Использовать ORM, где они связаны". Как менять данные, если эти модели связаны, я и так знаю.
Когда Вы связываете структуру данных и программную модель совершенно не важно каким способом с ORM или как то еще, то Вы объединяете два макро слоя ПО в один - уровень хранения и целостности данных с функциональным уровнем приложения. И таким способом значительно ухудшаете модифицируемость приложения, не говоря уже о том что нужно писать значительно больше кода, чем если бы Вы "решили задачу в общем виде".
Вы ответьте на изначальный вопрос пожалуйста, без абстрактных рассуждений с умными словами.
Если модели никак не связаны, то поменять данные в базе невозможно. В приложении я меняю значение в поле "name", а в базе нет такого поля. "Не связаны" означает, что они могут полностью различаться, и одна модель ничего не знает про другую.
Можно, ниже ссылка на универсальный сервис, который можно "повесить" на любою БД.
Да, в этом сервисе есть соглашения, в частости по URL. Но подобные соглашения есть и в любом вашем API.
По поводу "различий". Когда нет связи между моделью данных и программной моделью, то возможна ситуация при установке изменений, когда модель данных не соответствует серверу приложений. Чтобы не создавать пользователю "дискомфорт" с возможными ошибками или сообщениями (не обязательно, что они могут быть), то лучше все же сперва менять модель данных, а затем сервер приложений.
Можно, ниже ссылка на универсальный сервис
Нельзя. Этот сервис предоставляет прямой доступ к базе какому-то другому приложению, в котором содержится логика установки значений полей, и ничем не отличается от прямого подключения через драйвер БД. Связанная модель будет в том другом приложении.
Разговора про модели в драйверах не было, независимо от того, по HTTP они работают или по другому протоколу. Разговор был про приложения, где содержится логика, потому что такие приложения используют ORM для работы с базой.
то лучше все же сперва менять модель данных, а затем сервер приложений
Если есть необходимость делать связанные изменения, значит связь есть, что противоречит вашему изначальному утверждению.
Я же Вам ответил на вопрос секюрити - самый простой способ настроить секюрити в файле web.xml и программировать ничего не нужно вообще. Не устаивает web.xml реализуете Filter (другой кубик), если вам программировать больше нравиться. Не устаивает Filter - реализуйте любое другое удобное для Вас решение. Только не валите все в одну кучу.
Есть программная связь между моделью данных и программными объектами вашего приложения, что собственно и называется ORM, и логическая связь в предметной области. Вы, похоже, путаетесь в этих понятиях. То что Вы выделили термином "связанные" - это логическая связь.
Я же Вам ответил на вопрос секюрити
Вопрос секюрити с моим предыдущим комментарием в этой ветке никак не связан. Такое секюрити можно настроить и в самой базе, веб-сервис для этого не нужен.
В предыдущем комментарии я говорил про логику установки значений - при каких условиях ставить в заказе статус PAID, а при каких PAYMENT_FAILED. ORM используются в приложениях, которые содержат такую логику. Ваш веб-сервис таким приложением не является.
Не устаивает Filter - реализуйте любое другое удобное для Вас решение.
Я вам уже объяснил - для многих людей ORM это и есть такое решение.
То что Вы выделили термином "связанные" - это логическая связь.
Нет, это техническая связь, потому что список и названия полей в базе должны быть такие же, какие используются в SQL-запросах из приложения. Эти названия полей заданы внутри приложения, в его исходном коде, а не приходят снаружи от пользователя.
Естественно, сервер приложений "ходит" в БД под определенной учеткой со своими привилегиями в БД и эта учетка прописывается в конфигурации приложения. Как правило, это учетка имеет все привилегии на все таблицы предметной области сервера приложений. У сервера приложений как правило свой набор учетных записей пользователей, который в общем случае не пересекается с набором учеток в СУБД. Опять же не нужно валить все в кучу. Первый набор ограничивает доступ к объектам базы, второй набор ограничивает доступ к функционалу приложения (если в этом есть необходимость).
По поводу "установки значения в заказе статус PAID" - это внутренняя логика вашего приложения, устанавливаете как Вам удобно. Установили в кубике "запрос платежной системы" и передали в кубик "модификация модели данных". Не пойму ваших затруднений.
"Я вам уже объяснил - для многих людей ORM это и есть такое решение." - Это вовсе не значит, что это правильная трактовка технологии.
Последняя ваша реплика "список и названия полей в базе должны быть такие же, какие используются в SQL-запросах из приложения" - совсем не обязательно. SQL запрос может формироваться динамически, может быть определен в параметрах приложения. В SQL запросе могут быть не все поля таблицы.
У меня есть подозрение, что вы все-таки о разной степени сложности ORM речь ведете.
Вот как тут было:
В приложении я меняю значение в поле "name", а в базе нет такого поля.
Так ведь в самом деле может не быть такого поля, где имя в виде строки (как в приложении) хранится.
А может быть какое-нибудь name_ref, указывающее в табличку всех имен. (Ну не хранить же в самом деле "Иван" миллион раз).
И приложение об этом факте может совершенно не знать. Ну есть имя и есть. Поле типа String в объекте такое.
Это частный случай - отсутствие поля name. Этот частный случай попадает под соглашение/требования программного слоя (в данном примере сервиса). Можно же составить соглашение, что должны передаваться только имена соответствующими полям БД? Можно. Можно составить соглашение что могут передаваться произвольные имена из заранее заданного списка и предусмотреть сопоставления передаваемых имен именам полей в таблицах БД. Можно. И не обязательно такое сопоставление нужно явно кодировать, его можно вынести в параметры приложения.
Опять же не нужно валить все в кучу.
Опять же повторяю, что я говорю исключительно про ту задачу, которую я решаю с помощью ORM. Вы мне советуете использовать вместо нее что-то другое, я спрашиваю как именно. И ожидаю в ответ не абстрактные слова, а конкретный пример.
Не пойму ваших затруднений.
Я вам ниже в другой ветке написал конкретный пример с конкретным вопросом.
Более того, я просил вас написать конкретный код для серверной части еще во втором комментарии, что вы проигнорировали. Конечно вы не будете понимать, если отказываетесь отвечать на вопросы. Вот когда попробуете написать конкретный код, тогда у вас с этим и появятся затруднения.
Первый набор ограничивает доступ к объектам базы, второй набор ограничивает доступ к функционалу приложения
Нет. В вашем сервисе нет никакого функционала, есть только прямой доступ к таблицам. Поэтому ограничить в конфиге можно только доступ, что ничем не отличается от ограничения доступа средствами базы. Что именно в вашем сервисе можно ограничить, чего нельзя ограничить через GRANT?
Это вовсе не значит, что это правильная трактовка технологии.
Нет, извините, термином ORM люди называют то, что они договорились так называть, а не то, что кажется правильным лично вам. Такая трактовка технологии это просто факт, такую технологию люди называют ORM.
"названия полей в базе должны быть такие же, какие используются в SQL-запросах из приложения" - совсем не обязательно.
Обязательно. Иначе у вас запрос работать не будет. Вы не можете запросить из приложения поле name, если в таблице его нет, а есть только поле title.
SQL запрос может формироваться динамически
Да, и? Это никак не противоречит моим словам. Из того, что он формируется динамически, не следует, что названия возможных полей не заданы в приложении.
В SQL запросе могут быть не все поля таблицы.
Я нигде не говорил, что в запросе они должны быть все.
Для сервера приложения - "по волшебству" запросто !!! Со стороны клиентской части - тоже можно обеспечить автоматическое "появление". Если Вы работаете с СУБД то такими программами Вы уже пользуетесь практически ежедневно, которым достаточно указать требуемую БД и можно манипулировать ее содержимым не используя SQL. Степень "автоматизации" и интерфейс пользователя у них разный. При желании, думаю, и Вы можете написать подобную программу, которая на основании метаданных БД будет генерировать какие то диалоговые окна со списками выбора и прочими плюшками пользовательского интерфейса.
Какие еще диалоговые окна? Вот мне пришел запрос на сервер PUT /product/1 { name: "Шуруповёрт 2000" }
, как мне обновить в базе данных название товара с идентификатором 1?
У меня нет на сервере диалоговых окон и вообще графической подсистемы.
При желании, думаю, и Вы можете написать подобную программу, которая на основании метаданных БД
Внезапно, такая программа называется ORM.
Элементарно - https://github.com/java2ee/RestDB
Сервис может с ходу работать с любой БД
Да вы что. То есть по-вашему я должен предоставлять пользователю полный доступ к базе данных, чтобы он мог менять любые поля сам из браузера? Например пометить заказ оплаченным? Поменять пароль администратора? Всё ясно с вашим подходом.
Ну и да, ORM работают примерно так же, как этот сервис, только без взаимодействия с протоколом HTTP. Получение хешмапа "поле - значение" это основная часть любой ORM.
Это пример реализации универсального REST метода. На этой идее Вы можете реализовать подобный сервис под ваши потребности.
Что касается "по-вашему я должен предоставлять пользователю полный доступ к базе данных", то это совершенно другой вопрос, который можно решить по разному. Например, настроить в web.xml секции секюрити (можно настроить множества правил доступа вплоть до отдельно взятой таблицы) или усложнить код примера, добавив нужную функциональность по ограничению доступа.
На этой идее Вы можете реализовать подобный сервис под ваши потребности.
Я вам уже сказал, "неуниверсальные REST-методы" предполагают использование ORM.
то это совершенно другой вопрос
Нет, это именно исходный вопрос. Приложения на сервере делают для того, чтобы контролировать логику. В них надо как-то работать с базой данных программно из приложения. Я спросил вас как, вместо этого вы зачем-то привели в пример веб-сервис с полным доступом к базе.
который можно решить по разному
Да. Самый простой способ это вызывать такой сервис программно из приложения и использовать в приложении типизированные объекты, чтобы не запутаться в бесконечных HashMap<string, Object>. Это и называется ORM.
Например, настроить в web.xml секции секюрити
Даа? Как мне настроить секюрити, чтобы ваш веб-сервис делал HTTP-запрос на сервер платежного провайдера для оплаты заказа, и только после успешного ответа записывал значение в базу данных в поле order.status = OrderStatus.PAID?
Что Вы все время пытаетесь "скрестить ужа с ежом"? Зачем Вы пытаетесь решить все задачи в одном месте? Пример сервиса это "кубик" с узкой функциональностью. Он делает только то, что нужно ему делать - модифицировать любую модель данных без ORM или других подобных технологий. Все остальное должно делаться в других "кубиках" (программных слоях) вашего приложения. Секюрити - отдельный "кубик" (слой) приложения. Запрос платежного сервиса - отдельный "кубик". Делайте запрос в кубике "платежный сервис" и результат вызова при необходимости передавайте кубику "модификация модели данных". И тогда вопросов выше у Вас даже не возникнет.
И по поводу ORM. Как то узковато Вы понимаете, сводя это понятие к объекту (классу) HashMap<string, Object>.
Зачем Вы пытаетесь решить все задачи в одном месте?
Это вы приводите в пример решение какой-то другой задачи. Я говорил про запись значений полей из приложения, а не из браузера. Потому что ORM используется внутри приложения.
Как то узковато Вы понимаете, сводя это понятие к объекту (классу) HashMap<string, Object>
Это вы не понимаете, что пишет собеседник. Я написал, что ORM нужна чтобы "использовать в приложении типизированные объекты" вместо HashMap. ORM делает преобразование из HashMap в объект класса Order или объект класса Product и наоборот.
Он делает только то, что нужно ему делать - модифицировать любую модель данных без ORM
ORM в любых приложениях используется не в этом кубике, а в коде, который его вызывает.
Делайте запрос в кубике "платежный сервис" и результат вызова при необходимости передавайте кубику "модификация модели данных".
Вот я вам и объясняю, что ORM используется в коде, который соединяет эти кубики, а не в кубике "модификация модели данных". Она этот кубик сама вызывает.
Я могу его передавать напрямую в драйвер базы, зачем мне для этого ваш веб-сервис?
Для этой задачи я использую ORM. Вы говорите, что вместо ORM я должен использовать ваш сервис. Я спрашиваю как, вы отказываетесь отвечать.
Вот пример, как оплата заказа делается с ORM.
order = new Order();
order.orderItems = this.createOrderItems(inputData.items);
order.status = OrderStatus.CREATED;
this.entityManager.save(order);
bool isPaid = this.paymentClient.sendPayment(order);
order.status = isPaid ? OrderStatus.PAID : OrderStatus.PAYMENT_FAILED;
this.entityManager.save(order);
Код entityManager
мне писать не надо, это часть ORM.
Вы говорите, что я не должен использовать ORM, а могу использовать для этого ваш сервис. Покажите пожалуйста пример кода, который делает то же самое с использованием вашего сервиса вместо ORM.
Откуда писать из сервиса или приложения совершенно нет какой либо разницы. У вас изменяется только источник. Источник на функционал кубика с записи в БД совершенно не влияет. Вы можете подавать на вход этого кубика параметры из разных источников. Хоть от сервиса, хоть от другого "кубика". Поэтому все мои рассуждения выше справедливы как для примера универсального сервиса, так для ваших специфических требований.
Реализуйте код, в котором складываются все параметры в HashMap, при необходимости выделите какие нибудь специфические параметры, если в этом есть необходимость и отдали все методу записи в БД
Можно что то вроде
public void save(String tableName, String operation, HashMap parameters) {
...
}
и запишите все что угодно куда угодно
Но лучше еще добавить абстракции.
Сколько методов нужно для работы с БД в приложении? Всего ОДИН. С одним работать не удобно, параметров слишком много. Над этим одним методом нужно полтора десятка методов оберток, чтобы было удобно передавать параметры в разных сочетаниях и в разных структурах. А дальше "хоть вдоль, хоть поперек".
Как Вы готовите параметры для вызова этого ОДНОГО метода, совершенно не важно. В результате у Вас получается "слоеный пирог" вашего приложения, где каждый слой выполняет узкоспециализированную функцию.
Пришлось как то отвечать на требования смежников. Было множество однородных баз данных. В каждой БД множество схем таблиц предметной области. Мое приложение собирало виртуальную БД из этого множества БД. В один прекрасный момент было выдвинуто требование, что всё множество БД объединяется в ОДНУ БД в ЦОДе, а так как данных и изменений их очень-очень много смежники решили положить каждую базу в свой набор схем этой одной общей БД. Мне пришлось добавить всего один "кубик" между уже существовавшими "кубиками" примерно с 20 строками кода и модифицированное приложение успешно заработала с новыми требованиями (метод то всего один для работы с БД в коде).
В вашим подходом подобные задачи не решаемы.
В вашим подходом подобные задачи не решаемы.
Прекрасно все решаемо, ORM может работать с любой БД, хоть даже с виртуальной. Похоже вы просто не понимаете, в какой части приложения используется ORM.
Реализуйте код
и запишите все что угодно куда угодно
Я привел конкретный код, в котором используется ORM. Там меньше 10 строк. Вы утверждаете, что я не должен использовать ORM, что ORM все усложняет, и без ORM будет проще. Я вам верю и хочу попробовать ваш подход. Вы можете показать свои 10 строк кода, в котором эта логика будет сделана без ORM, или можно считать ваши утверждения пустыми словами?
Я попросил вас написать код из 10 строк, вместо этого вы зачем-то написали большой коммент. Выглядит так, что код без ORM вам было бы написать сложнее, чем этот коммент. Это противоречит вашему утверждению, что без ORM будет проще.
То что Вы считаете ORM таковым не является. Думаю, что и под виртуальной БД Вы понимаете не виртуальную БД.
У Вас эти "10 строк" применимы только в конкретном месте, в другом месте Вам нужно повторить эти "10 строк" и так везде, где Вы работаете с БД - постоянно повторяете один и тот же код с небольшими отличиями в основном в именах и специализированных типах данных (программной модели - O), которая должна соответствовать структуре таблиц (модели данных - М).
Иными словами - программная модель (O) соответствует (R) модели данных (M), что и называется ORM.
Если отказаться от использования ORM то
не нужно постоянно по сути дублировать один и тот же код
повышается модифицируемость приложения
значительно сокращается объем кодирования
некоторые изменения мидели данных (M) вообще не затрагивают программную модель (O)
То что Вы считаете ORM таковым не является.
Вы делаете много утверждений без доказательств.
Является, откройте определение и прочитайте.
в другом месте Вам нужно повторить эти "10 строк"
Вы делаете много утверждений без доказательств.
Нет. orderItems существует только в order, в других сущностях их нет.
sendPayment() нужно делать только для order, для других сущностей делать оплату не надо.
Статусы PAID и PAYMENT_FAILED надо устанавливать только для order, у других сущностей таких статусов нет, и вообще статуса может не быть.
Это код добавления товара в корзину. Он тоже использует ORM.
Cart|null cart = this.cartRepository.findOne(inputData.cartId);
if (cart === null) {
cart = new Cart();
cart.userId = curretnUser?.id ?? null;
cart.createdAt = new DateTime();
this.entityManager.save(cart);
}
CartItem cartItem = new CartItem(inputData.productId);
cartItem.cartId = cart.id;
this.entityManager.save(cartItem);
Где тут повторение 10 строк, которые я привел ранее? Типы, названия переменных, последовательность вызовов save() полностью отличаются. Значит вы сказали неправду.
Если отказаться от использования ORM
не нужно постоянно дублировать один и тот же код
Так вы можете привести код, который это показывает, или нет? Похоже что нет.
Поймите, я не могу использовать ваш подход, если не знаю, как он выглядит. Я не могу переписать код с ORM, если у меня нет примеров, какой код должен получиться в результате.
Мои доказательства опубликованы в GitHub-е - пример реализации универсального сервиса. Работает с любой БД и не нужно добавлять ни одной строчки кода. В вашем варианте нужно на любой чих писать "10 строк кода". Подчеркиваю НА ЛЮБОЙ. Причина - в том, что вашем коде заложена жесткая связь между моделью данных (предположу, что таблица CART) и программной моделью (классом CartItem). Класс CartItem 100% или с небольшими отличиями повторят структуру таблицы CART - это и есть ORM. При изменении таблицы CART вам нужно изменить класс CartItem или на оборот.
Мои доказательства опубликованы в GitHub-е
Я вам уже ответил про это доказательство, непонятно, почему вы игнорируете аргументы, которые вам пишут. Ваш проект просто пишет в базу все что пришло снаружи. Мне это не нужно, у меня есть требования бизнеса, который не хочет, чтобы в базу можно было писать что угодно. Поэтому мне нужно писать другой код, который будет содержать эти ограничения. ORM нужна в этом другом коде. Поэтому ваше "доказательство" не является аналогом моего кода. Ваш проект это лишь внутренняя часть ORM, аналогичная часть есть в любой ORM, только без работы с HTTP.
В вашем варианте нужно на любой чих писать "10 строк кода". Подчеркиваю НА ЛЮБОЙ.
Подчеркиваю, вы не понимаете, в какой части приложения и для какой цели используется ORM. Хотя я объяснил это уже несколько раз. Ваш проект это не замена ORM, а его небольшая часть. ORM будет находиться в другом коде, который будет вызывать ваш проект. ORM это не средство сохранения данных в базу, а средство для использования в логике.
Этот ЛЮБОЙ чих идет из требований бизнеса. Эти 10 строк это не код сохранения данных в базу, это код обработки данных. Бизнесу надо создание заказа обрабатывать по одним правилам, а добавление товара в корзину по другим. Это просто факт, вы не сможете его изменить любыми технологиями. Можете только спихнуть написание этого кода на кого-то другого.
Код сохранения данных в базу находится в entityManager.save()
, который внутри как раз и работает аналогично вашему проекту. Только названия таблиц он берет не из GET-параметров, а из имени классов.
В вашем варианте нужно на любой чих писать "10 строк кода". Подчеркиваю НА ЛЮБОЙ.
Подчеркиваю, я привел уже 2 разных примера на 10 строк, а вы так и не смогли показать свой код без ORM, который делает то же самое. Подчеркиваю, ТО ЖЕ САМОЕ, в нужной последовательности и соблюдая правила, установленные бизнесом, а не просто который записывает в базу всё, что пришло снаружи.
Если бы вы не игнорировали вопросы, а написали код с нужной функциональностью, вы бы давно это поняли. Непонятно, почему вместо этого вы предпочитаете флудить. Похоже, вы просто тролль.
моделью данных (предположу, что таблица CART) и программной моделью (классом CartItem).
Нет. Есть отдельно таблица "cart" и отдельно таблица "cart_item". Код работает с обоими таблицами сразу в одной транзакции.
Класс Cart 100% или с небольшими отличиями повторят структуру таблицы CART - это и есть ORM.
Да, только это нужно не для сохранения данных в базу, как вы постоянно утверждаете, а для этого кода, который работает 2 таблицами сразу. Я не хочу в нем работать с HashMap<string, Object>
и HashMap<string, Object>
с неизвестным набором существующих ключей, рискуя что-нибудь перепутать, сделать опечатку в названии ключа или обратиться к несуществующему полю. Я хочу работать с классами Cart и CartItem с известным набором полей, у которых есть типы String, Integer, DateTime(), и другие, И использовать Cart и CartItem в аргументах функций и возвращаемых значениях. Чтобы IDE мне показывала список полей после точки, использование несуществующего поля после точки и места использования именно cart.userId а не какого-то другого userId.
Ваш проект может мне это обеспечить? Нет? Тогда это не аналог ORM.
Данные, которыми Вам нужно манипулировать, откуда то же берутся? Берутся. Назовем это "источник данных". Какой именно "источник данных" совершенно не важно, это пользовать, сервис, событие или что то еще. У этого "источника данных" есть соглашения - имена и формат данных каждого поля? Есть. Если Вы в состоянии повлиять на это соглашения, то нужно составить соглашение таким образом, чтобы Вам было удобно с ними работать. Если не влияете, то можно подстроит свою модель данных в БД так, что так же с ними можно было удобно работать. Далее принимаете данные из "источника данных" и передаете их блоку/слою/кубику "манипулирование данных", который сохраняет результат в БД. Все просто. И совершенно не важно из какого источника данные получены и совершенно не важно какие манипуляции выполняются.
Из-за того что Вы не правильно понимаете идеологию ORM и возникает не понимание. Ваши классы Cart, CartItem и любые другие это программная (объектная) модель. Структура хранения данных в БД - это модель данных. ORM задает жесткую связь между двумя разными представлениями одной и той информации в разных макрослоях информационной системы, в частности в слое хранения данных и слое приложения - объект имеет отображение в модели. Это отображение фактически объединяет два совершенно разных макрослоя в одни (один без другого теряют какой либо смысл). Это очень плохо с точки зрения реализации и модифицируемости, писать кода надо много, вносить изменения тяжело.
В моем примере нет этой связи между моделью (БД) и объектами (программным кодом). Мой пример будет работать с любой базой. И еще раз подчеркиваю, ЭТО ПРИМЕР - который демонстрирует возможность работы без ORM. В этом примере используется программный слой манипулирования любыми данными (см поле database класса TableService). Этому программному слою все равно что выполнять, работать с одной таблицей или сразу во множеством.
Бизнес требования - это функциональные требования. Разные разработчики могут совершенно по разному преобразовать эти требования в программную модель приложения и структуры хранения. Так что это к обсуждаемой теме не относится.
В БД есть понятие метаданных, которые описывают всю структуру БД - таблицы, поля, типы, ключи и т.д. БД предоставляет API для получения этой информации. Не нужно гадать какая структура таблицы или какой PK этой таблицы. Можно спросить у БД, она ответит. И все. Необходимость программного описания (создание программных типов) отпадает. Обычно, при старте приложения идет опрос метаданных, по этим данным можно сразу или по мере необходимости генерировать SQL выражения. Смотри сразу сколько кода не нужно писать. И самое интересное, этот код можно использовать повторно в других проектах.
Данные, которыми Вам нужно манипулировать, откуда то же берутся?
Все источники данных указаны в моем коде. Это inputDto, currentUser и системное время.
У этого "источника данных" есть соглашения - имена и формат данных каждого поля? Есть.
Нет. Я уже 10 раз вам объяснил, не все данные приходят снаружи от пользователя в виде хешмапов. Если у вас приходят все, значит это очень простое приложение, и вам не нужна ORM.
Источник некоторых данных это код, который я пишу сам. Имена некоторых полей впервые появляются в моем коде, а не приходят снаружи.
Чтобы установить дату создания заказа, мне надо где-то написать order.createdAt = new DateTime()
или orderHashMap['createdAt'] = new DateTime()
.
Чтобы установить владельца заказа, мне надо где-то написать order.userId = currentUser.id
или orderHashMap['userId'] = currentUserHashMap['id']
, где currentUser загружается из базы автоматически специальными компонентами по id пользователя из сессии, которая загружается по id сессии из cookies.
Первый вариант с объектами и без хешмапов мне удобнее, поэтому я использую ORM.
Связка "сохранить один статус заказа - оплатить - сохранить другой статус" вообще с соглашениями об именах никак не связана. ORM нужна, чтобы было проще ее писать.
Из-за того что Вы не правильно понимаете идеологию ORM и возникает не понимание.
Я привел ссылку на общепринятое определение термина ORM, которым я пользуюсь. Вы можете привести ссылку, где описывается ваше понимание ORM, или вы его сами придумали, и больше про него никто не знает?
Мой пример будет работать с любой базой.
И еще раз подчеркиваю, ЭТО ПРИМЕР - который демонстрирует возможность работы без ORM
Я вам уже ответил на это утверждение. Я серьезно не понимаю, с какой целью вы повторяете одно и то же, игнорируя ответы.
В коде вашего проекта ORM и не нужна, потому что в нем нет никакой логики. ORM будет в том коде, который будет работать с вашим сервисом.
Я вас просил показать пример логики создания заказа без ORM, вы его не показали, а вместо этого показали простой CRUD. То есть спихнули реализацию логики создания на кого-то другого. А в этом и есть весь смысл, почему люди используют ORM.
БД предоставляет API для получения этой информации. Не нужно гадать какая структура таблицы или какой PK этой таблицы. Можно спросить у БД, она ответит. И все.
На это я вам тоже уже ответил, это именно то, что делает ORM. То есть вы предлагаете не использовать готовую ORM, а писать свою недоделанную.
И да, ORM тоже можно использовать повторно в других проектах.
Необходимость программного описания (создание программных типов) отпадает. Обычно, при старте приложения идет опрос метаданных
Вы похоже так и не поняли. Попробую еще один раз объяснить. "Создание программных типов" нужно не для сохранения в базу, а для человека. Чтобы программисту было удобнее работать с кодом. Программист работает с кодом до старта приложения.
Разные разработчики могут совершенно по разному преобразовать эти требования
Ну преобразуйте. Почему вы с вашим подходом 10 строк написать не можете?
С ORM я уже 2 задачи решил, а вы без ORM второй день рассуждаете, и ни одной задачи не решено. Так вы покажете код создания заказа, или официально отказываетесь подтвердить свои слова делом?
Я привел ссылку на общепринятое определение термина ORM
Упомянул, но в явном виде не приводил, на всякий случай вот она.
ORM
ORM - Object Relational Model с моей точки зрения более точная расшифровка, чем Object Relational Mapping. Термин "mapping" Вас похоже и вводит в заблуждение. Даже ваша ссылка дает определение, в котором речь идет о реляционной модели данных и программной модели. Т.е. к различным MAP-классам термин ORM не имеет какого либо отношения.
Я не знаю, что вы имеете виду под MAP-классами, но там во втором абзаце написано "This could be modeled in an object-oriented implementation by a "Person object", где Person является одним из этих "различных классов".
Термин "mapping" Вас похоже и вводит в заблуждение.
Ага, все люди не знают, что они называют этим термином, один вы знаете.
Нет, термин "mapping" там находится не просто так. ORM делает именно mapping. Например, поле "user.user_id" из базы может замапить на "User.user_id", "User.userId" или "User.lalala" в коде.
А вы придумали какое-то свое определение. Все ваши утверждения может быть и верные в отношении того, что лично вы называете "ORM", но другие люди называют этим термином нечто другое, и для их понимания ваши утверждения неверны.
Я не знаю, что вы имеете виду под MAP-классами, но там во втором абзаце написано "This could be modeled in an object-oriented implementation by a "Person object", где Person является одним из этих "различных классов".
MAP классы - это то, что программно реализует соответствие одного другому. И если Вы эти классы не используете явно, то ваш движок, реализующий ORM, без них не будет работать.
Какая разница что это класс Person, Cart, CartItem или любой другой класс аналогичного назначения. Главное, что эту классу Person ставится в соответствие таблица Person, которая по количеству полей может 100% соответствовать полям класса Person. В этом корень проблемы !!! Т.е. Вам нужно для каждой таблицы и возможно представлению создавать собственный класс отображения. И совершенно не важно сгенерирован этот код по структуре таблицы или Вы его напишите в ручную. Этот код есть в вашем приложении.
Добавляете таблицу - добавляете новый класс.
Добавляете поле - добавляете новые методы в класс.
Добавили методы - корректируете другой код для вызова этих методов. Зачем? Если можно это не делать. И сразу куча плюсов. Меньше кода, легче модифицировать ПО, а при добавлении поля можно вообще код не модифицировать. Добавил поле, перезапустил приложения - красота.
Ага, все люди не знают, что они называют этим термином, один вы знаете.
Нет, термин "mapping" там находится не просто так. ORM делает именно mapping. Например, поле "user.user_id" из базы может замапить на "User.user_id", "User.userId" или "User.lalala" в коде.
Да какая разница в какое поле таблицы записывается какое именованное значение? Никакой. Я же Вам писал, что разработка ПО это прежде всего выработка соглашений. Вырабатываете соглашение, что имена значений должны совпадать. Отклонения от соглашения, например, прописали в конфиге приложения. Не нравится конфиг пропишите в коде на худой конец. Целую кучу кода Вам не лень писать, а небольшие отклонения которое отправит эту кучу кода в корзину в лом?
Главное, что эту классу Person ставится в соответствие таблица Person, которая по количеству полей может 100% соответствовать полям класса Person.
Именно поэтому в термине ORM и используется слово mapping, а не model. "Mapping" переводится как "соответствие".
https://translate.google.com/?sl=auto&tl=ru&text=mapping&op=translate
- Нет, термин "mapping" там находится не просто так. ORM делает именно mapping.
- Да какая разница в какое поле таблицы записывается какое именованное значение? Никакой.
Это не разница, а объяснение, почему люди используют слово "mapping".
Я же Вам писал, что разработка ПО это прежде всего выработка соглашений.
А я вам писал, что ORM с соглашениями вообще никак не связана, и нужна для другого.
Зачем?
Я вам 20 раз уже написал зачем. Чтобы мне в этом "другом кубике" с логикой было удобно писать код. С нормальными классами Person, Cart, CartItem. Ваши HashMap<String, Object>
на каждом шагу мне там не нужны.
Все источники данных указаны в моем коде. Это inputDto, currentUser и системное время.
Хорошо, пусть будет источник данных или результат преобразования источника данных.
Нет. Я уже 10 раз вам объяснил, не все данные приходят снаружи от пользователя в виде хешмапов. Если у вас приходят все, значит это очень простое приложение, и вам не нужна ORM.
Хорошо, хешмапы так хешмапы. Если заметили, в моем примере входные данные в виде JSON или XML тоже преобразуются в хешмап, следовательно ваши данные моим "универсальным" кодом тоже успешно могут быть обработаны. Ни что не запрещает Вам в любом программном слое расширять полученный входной набор любыми другими дополнительными атрибутами, если в этом есть необходимость.
Я вам уже ответил на это утверждение. Я серьезно не понимаю, с какой целью вы повторяете одно и то же, игнорируя ответы. В коде вашего проекта ORM и не нужна, потому что в нем нет никакой логики. ORM будет в том коде, который будет работать с вашим сервисом.
Логика приложения это отдельное преобразование входных данных. Еще один кубик/слой. Преобразованные в хешмап (в вашем понимании) входные данные передаются кубику "логика приложения", который либо возвращает модифицируемый хешмап, либо другую структуру программному слою "запись в БД". Все просто. Если Вам или кому то другому вдруг когда придется менять логику приложения, то нужно модифицировать или полностью заменить в коде только кубик.
Вы похоже так и не поняли. Попробую еще один раз объяснить. "Создание программных типов" нужно не для сохранения в базу, а для человека. Чтобы программисту было удобнее работать с кодом. Программист работает с кодом до старта приложения.
Заблуждение. Вам это нужно только из-за того, что Вы используете фреймворк, который реализует идеологию ORM. Смените свой фреймворк.
Ну преобразуйте. Почему вы с вашим подходом 10 строк написать не можете? С ORM я уже 2 задачи решил, а вы без ORM второй день рассуждаете, и ни одной задачи не решено. Так вы покажете код создания заказа, или официально отказываетесь подтвердить свои слова делом?
Мне даже одной сточки писать не нужно. Много раз уже подчеркивал, мой пример будет работать с любой базой и модифицировать любые структуры в них. В том числе и с вашей. вашу логику в него добавить и можно полностью заменить ваше приложение.
Много раз уже подчеркивал, мой пример будет работать с любой базой и модифицировать любые структуры в них.
А я вам уже много раз подчеркивал, что цель именно в том, чтобы сделать не любые, а соответственно ограничениям в требованиях. ORM нужна для этой цели. Мне не нужно написать код для сохранения произвольных структур данных, мне нужно написать именно код создания заказа, вызывая в нем код для сохранения произвольных структур данных. Это будет другой код, а не тот, который вы привели. То, что вы называете "Еще один кубик/слой". В вашем коде создания заказа по нужным правилам нет, он будет создавать заказ по любым правилам, например сразу оплаченным.
вашу логику в него добавить и можно полностью заменить ваше приложение.
Вот я вам и объясняю, что тогда ORM будет в этой логике. И просил вас показать пример, как вы эту логику будете добавлять без ORM. Что вы так и не смогли сделать.
Кода нет, разговаривать не о чем.
А я вам уже много раз подчеркивал, что цель именно в том, чтобы сделать не любые, а соответственно ограничениям в требованиях. ORM нужна для этой цели. Мне не нужно написать код для сохранения произвольных структур данных, мне нужно написать именно код создания заказа, вызывая в нем код для сохранения произвольных структур данных. Это будет другой код, а не тот, который вы привели. В вашем коде создания заказа по нужным правилам нет, он будет создавать заказ по любым правилам, например сразу оплаченным.
Так в чем проблема добавить какую то логику или ограничения? Нет проблемы. Если в вашем коде это реализовано, то почему Вы считаете, что подобную логику нельзя добавить в код моего примера? Я Вам показал идею, как можно уменьшить объем кодирования и повысить модифицируемость приложения. Хотите пользуйтесь, хотите нет. А уж какой логикой наполнить эту идею, извините, это уже ваша "головная боль". В своем же коде Вы это делаете по шаблону вашего движка, думаю и в моем варианте можете справиться.
Вот я вам и объясняю, что тогда ORM будет в этой логике. И просил вас показать пример, как вы эту логику будете добавлять без ORM. Что вы так и не смогли сделать.
В логике вашего приложения не ORM, а реализация ваших классов Cart, CartItem и всех прочих, которые являются некоторым представлением предметной области. Это представление можно реализовать каким то другим программным кодом и на его основе реализовать вашу логику. Можно? Можно.
Кода нет, разговаривать не о чем.
Я понятие не имею какую логику вы хотите чтобы я реализовал. И возникает вопрос, зачем мне это нужно делать?
почему Вы считаете, что подобную логику нельзя добавить в код моего примера?
Потому что я несколько раз просил вас это сделать, а вы не смогли, и вместо 10 строк предпочли написать кучу текста.
В своем же коде Вы это делаете по шаблону вашего движка
В очередной раз повторяю - нет. Вы не понимаете, в какой части приложения и зачем используется ORM. В моих примерах кода реализовано то, что хочет бизнес, никакой движок не требует так делать. Это и есть отдельный кубик с логикой, про который вы говорите.
Я понятие не имею какую логику вы хотите, чтобы я реализовал.
Я уже сказал несколько раз. Ту, которая находится в моем примере кода с Order. Там не просто сохранение данных, которые пришли снаружи.
На входе там приходит массив [{"productId": ..., "count": ...}, {"productId": ..., "count": ...}, ...]
, и из этого списка товаров надо создать заказ и произвести оплату, с установкой нужных статусов. Но для этого примера детали входных данных неважны, там важно другое. Вот попробуете написать, тогда и поймете.
И возникает вопрос, зачем мне это нужно делать?
Чтобы показать мне неразумному, как использовать ваш подход без ORM в реальных задачах. Или чтобы самому понять, где у людей возникает необходимость в ORM, потому что объяснение словами вы не понимаете.
Думаю, вашу логику, которую Вы описали выше, можно не реализовывать в вашем коде вообще. При работе с СУБД это можно выполнить на чистом SQL. В подавляющем числе случаев в своем коде я так и делаю.
Записываем (подготавливаем все для записи - это может быть ArrayList, Vector, массив) ваш JSON в БД. С этим справится и мой универсальный сервис. И дополняем SQL выражениями, которые и отработает вашу логику. И отдаем все на выполнение в одной транзакции.
Для этого нужно только слегка изменить код моего универсального сервиса, который добавить в подготовленный набор модификации базы требуемые SQL. Если эти SQL вынести еще в свойства приложения, то модифицируемость вашего приложения резко повысится. Вы можете часть новых требований отработать только изменениями SQL в свойствах приложения не затрагивая ваш код. Если учесть, что мой код "универсального" сервиса автоматически отработает любые изменения структуры JSON, если таковые возникнут, то вообще сказка получается.
Представляете, возникло требование - увеличить число полей в JSON, то Вы просто добавляете поля в таблицу/таблицы, в случае необходимости меняете SQL в свойствах - и все. Ваш код без каких либо правок работает с новыми требованиями.
Думаю, вашу логику, которую Вы описали выше, можно не реализовывать в вашем коде вообще.
Даа, оплату заказа реализовывать не надо, она сама появится по волшебству?
При работе с СУБД это можно выполнить на чистом SQL.
Даа, а SQL это не код?
Может вы покажете как сделать вызов API платежного провайдера из SQL?
Вы можете часть новых требований отработать только изменениями SQL в свойствах приложения
Я несколько раз уже повторил, я не хочу работать с нетипизированным кодом в SQL, я хочу работать с нормальными классами.
И отдаем все на выполнение в одной транзакции.
То есть вы даже код прочитать не можете. В оплате заказа мне нужны 2 транзакции - до вызова платежного провайдера и после. Чтобы если платежный провайдер не работает, то данные о заказе остались в БД.
В логике вашего приложения не ORM, а реализация ваших классов Cart, CartItem и всех прочих. Это представление можно реализовать каким то другим программным кодом и на его основе реализовать вашу логику.
Отлично, у меня в логике есть класс Cart. Как мне теперь его передать в ваш сервис, чтобы сохранить в БД? Наверно написать какой-то код, который превращает его в JSON и отправляет в ваш сервис? Да еще так чтобы поля в этом JSON соответствовали названиям полей в таблице БД, а не в моем классе. Так?
А еще у меня есть класс CartItem и все прочие. Для них тоже надо написать такой код?
Вы продолжаете мыслить реализацией класса Cart, отсюда и возникает у Вас вопрос как его куда то передать? Вы же где то у себя в коде его создали и заполнили его поля откуда то взятыми данными. Вот "откуда то" и нужно смотреть как это передать на сохранение.
Взгляните на свой класс Cart, CartItem и прочие подобные классы. Взгляните на код, который манипулирует этими классами. Не возникает мысли, что постоянно пишите один и тот же код, в котором отличаются по сути только используемыми именами классов и методов? Если не возникает, ну что ж пишите и дальше.
Вы же где то у себя в коде его создали и заполнили его поля откуда то взятыми данными. Вот "откуда то" и нужно смотреть как это передать на сохранение.
Статусы PAID и PAYMENT_FAILED ниоткуда не приходят, они устанавливаются в моем коде, который работает с классом Order. Как мне их сохранить? Вы 10 строк кода прочитать не можете?
Не возникает мысли, что постоянно пишите один и тот же код, в котором отличаются по сути только используемыми именами классов и методов?
Я вам уже привел 2 примера кода, которые отличаются не только именами классов и методов. Это не моя мысль, это факт. Не возникает мысли, что надо их прочитать внимательно прежде чем вести дальнейшую дискуссию, а не обсуждать собственные фантазии?
Не возникает мысли, что если вы говорите "Создание и оплату заказа можно сделать без ORM, и код будет проще", то надо отвечать за свои слова и показывать код именно с оплатой заказа?
Статусы PAID и PAYMENT_FAILED ниоткуда не приходят, но у них есть логика и эта логика работает на полученных данных или на данных, хранящихся в базе? Да. Почему эту логику нельзя повторить в SQL запросе? Не вижу проблемы написать что то подобное (написал одной строкой)
case when ... then PAID else PAYMENT_FAILED end
Кстати, подобный SQL код можно сгенерировать и для вставки записи в БД
Статусы PAID и PAYMENT_FAILED это и есть сами данные, ни на каких других данных они не работают. Выбор конкретного статуса зависит от результата HTTP-запроса к стороннему API.
case when ... then PAID
Вот там где вас многоточие, должен быть результат вызова web-API платежного провайдера. Проблема в том, что делать HTTP-вызовы из SQL сложнее, чем из кода.
Вам уже надо и ваш сервис доработать, и SQL-запросы написать. Напишите уже полный пример без балабольства, я вам ткну пальцем, где в вашем коде будет ORM.
Вместо многоточия может быть все что угодно, в том числе и результат вызова по HTTP или любому другому протоколу в дополнительном "кубике", если в нем есть необходимость. Различные отклонения от общей логики тоже реализуются. Обычно я делаю это свойствами конфигурационного файла, что позволяет гибко добавлять, изменять или исключать эти отклонения.
В спецификации сервлетов есть Filter, который позволяет изменять, дополнять, удалять что то во входных или возвращаемых данных. Реализованные фильтры обычно добавляются в конфигурацию приложения (web.xml). Вот вам идея как можно реализовать ваши отклонения.
Вам уже надо и ваш сервис доработать, и SQL-запросы написать. Напишите уже полный пример без балабольства, я вам ткну пальцем, где в вашем коде будет ORM.
Еще раз подчеркиваю, я Вам дал ссылку на проект в GitHub, который содержит весь код работающего примера реализации без ORM. Выделяю специально для Вас - РАБОТАЮЩЕГО ПРИМЕРА. Слово "пример", надеюсь, Вы понимаете правильно. На основе кода этого примера или на идее этого примера, можно реализовать и вашу задачу. Но это Вам нужно сделать самостоятельно.
который содержит весь код работающего примера
Это ложь. Работа моего примера заключается в том, что он создает заказ по списку товаров и производит оплату. В нем ничего дописывать не нужно. Ваш этого не делает. Следовательно, он не работает так, как нужно. Меня не интересует, что мне надо еще дописать к вашему сервису, мне он не нужен. Это вы говорите, что я должен его использовать, вы и должны показывать как.
Не бросайтесь словами - некрасиво выглядит. И слово "ПРИМЕР" Вы, похоже, все же не понимаете.
Конечно мой пример не делает вашу специфическую логику. Он про нее ничего не знал на этапе его разработки. У моего демо проекта совершенно другая цель, которую он отлично демонстрирует - работу с БД любой структуры без ORM. И при чем тут ваша специфическая логика, на которую вы Все время упираете мне совершенно не понятно.
Кстати, в моем проекте предусмотрены классы расширения, при реализации которого можно реализовать то, что Вам очень хочется. Замечу - код примера даже править не надо. Нужно реализовать класс расширения всего лишь.
И я вам набросал целую кучу идей как может быть реализована ваша специфическую логика в моем примере. Дерзайте, если интересно. Если не интересно, продолжайте писать один и тот же код из проекта в проект.
Кстати, если Вы так стремитесь чем то "мериться".
Такой вопрос. А может ли ваш код работать с БД без драйвера этой СУБД?
Код моего примера может. :-)
И слово "ПРИМЕР" Вы, похоже, все же не понимаете.
Это вы не понимаете. Если я привел пример создания заказа с оплатой, и вы хотите привести аналогичный пример, то и вы должны привести пример создания заказа с оплатой. Не код сохранения в базу произвольных данных без всяких проверок, не код отправки email, а код создания заказа с оплатой.
Конечно мой пример не делает вашу специфическую логику. Он про нее ничего не знал на этапе его разработки.
Зато вы знали когда отвечали на мой комментарий. Если ваш код не делает то же самое, что мой код, то он не является аналогичным примером, а значит нет смысла его приводить.
А может ли ваш код работать с БД без драйвера этой СУБД?
Я вам уже ответил на этот вопрос. ORM может работать с любой БД, хоть даже с виртуальной, хоть даже без драйвера. Поэтому мой код, который использует ORM, тоже будет работать. Это основа любых юнит-тестов.
И при чем тут ваша специфическая логика, на которую вы Все время упираете мне совершенно не понятно.
Вам непонятно, потому что вы не читаете, что пишет собеседник. Я это сказал прямым текстом - потому что ORM мне нужна для использования в этой логике.
У меня есть серверный код создания заказа, который вызывается из фронтенд-приложения.
Order order = new Order();
order.status = OrserStatus.CREATED;
Вы сказали, что в своем коде я могу использовать класс Order. Статус CREATED не приходит с фронтенда и не должен. Как мне теперь использовать ваш сервис, чтобы сохранить заказ с этим статусом в базу из моего кода, получить id заказа и отправить его на фронтенд? Я сомневаюсь, что вы способны ответить на этот вопрос.
Я вам уже кучу вариантов набросал как можно реализовать выше настойчивое желание что то запрограммировать, выбирайте любой понравившийся.
Не набросали. Мне не нужны ваши рассуждения, насколько это просто, мне нужен конкретный код создания заказа "без ORM". Такой код вы не привели, вариантов ровно 0. Мне он нужен, чтобы ткнуть вас носом, что у вас там все равно будет ORM, либо будет неподдерживаемое месиво SQL-запросов и хешмапов. И судя по тому, как вы пытаетесь уйти от ответа, вы уже сами все поняли, только видимо вы еще недостаточно взрослый человек, чтобы признать свою ошибку.
Откуда что вызывается совершенно все равно, какая должна работать логика то же при разбиении ПО на "кубики"
Сейчас логическую схему моего универсального сервиса можно представить так
прием данных - подготовка данных для записи - Datadase - DataSource - JDBC драйвер - БД
Datadase - это некоторая "хитрая" настройка над спецификаций javax.sql, которая упрощает работу с БД из приложения. Но речь сейчас не о ней.
Для встраивания вашего вызова чего там по HTTP можно выстроить следующую логическую схему
прием данных - запрос по HTTP - подготовка данных для записи - Datadase - DataSource - JDBC драйвер - БД
Повторю варианты реализации
Реализовать Filter в спецификации сервлетов
Реализовать аналог Filter вместо кубика запрос по HTTP
Реализовать класс расширения, который дает переопределить слой подготовка данных для записи и в нем сперва выполнить запрос по HTTP.
Дополнить "универсальный" сервис дополнительными свойствами, определение которых позволит сделать запрос по HTTP
И все будет работать без ORM
Достаточно?
Я уже сказал, что нет. Я написал конкретный код с ORM, и ожидаю в ответ конкретный код, который делает то же самое без ORM. Моему серверу нужен код, а не ваши рассуждения, а я не умею читать мысли, и не знаю, как вы это себе представляете. Я уже прекрасно все понял про ваш сервис, но вы этого не понимаете, поэтому понять вы можете только попробовав решить задачу создания заказа самостоятельно.
запрос по HTTP - подготовка данных для записи
Это и есть "кубик с логикой", в моем примере находится код этой части, поэтому в ответ я ожидаю тоже код этой части.
Даже ваша новая логическая схема неверна. HTTP-запрос вы добавили, а 2 транзакции опять пропустили. Запись в БД должна быть и до HTTP-запроса, и после. В этом и есть основная особенность этой логики.
:-) так устроит
int status = client.getStatus(data);
data.put("status", status);
Даже ваша новая логическая схема неверна. HTTP-запрос вы добавили, а 2 транзакции опять пропустили. Запись в БД должна быть и до HTTP-запроса, и после. В этом и есть основная особенность этой логики.
:-) это вводную Вы озвучили впервые
ArrayList transaction = new ArrayList();
transaction.add(...);
...
transaction.add(...);
database.execute(transaction);
int status = client.getStatus(data);
data.put("status", status);
transaction = new ArrayList();
transaction.add(...);
...
transaction.add(...);
database.execute(transaction);
так устроит?
это вводную Вы озвучили впервые
Эта вводная есть в моем коде из 10 строк. Там 2 вызова save(order).
так устроит?
Я уже сказал, что нет. Ваш код должен делать то же, что и мой, без многозначительных многоточий, чтобы собеседник не додумывал, что вы имели в виду.
Я вот додумал, и у меня получилось так.
HashMap<String, Object> orderData = new HashMap<String, Object>();
orderData.put("status", OrderStatus.CREATED);
ArrayList transaction = new ArrayList();
transaction.add(orderData);
database.execute(transaction);
bool isPaid = paymentClient.sendPayment(orderData);
orderData.put("stafus", isPaid ? OrderStatus.PAID : OrderStatus.PAYMENT_FAILED);
transaction = new ArrayList();
transaction.add(orderData);
database.execute(transaction);
Не вижу тут никакого упрощения по сравнению с моим кодом, которое вы обещали.
- Строк больше, чем у меня
- Класса Order нет, хотя вы сказали что эту логику можно и с ним написать, а HashMap на Order заменить невозможно без значительных изменений
- Автоподсказки полей в IDE не работают, опечатку в названии поля IDE не подчеркнет (вы же заметили опечатку?)
- Непонятно, как после выполнения этих транзакций в ArrayList вернуть id заказа, видимо надо еще какой-то код писать, в моем коде он будет в order.id
после первого save()
В чем упрощение-то?)
Я вам показал логику как это последовательно работает, удовлетворил ваше настойчивая желание и показал, чтобы было хоть что то понятно. Хорошо напишем так :-)
save(date);
client.getStatus(data);
save(date);
Так устроит? :-) Все го три стоки, я чемпион :-)
Мое "настойчивое желание" было получить пример полностью, чтобы можно было сравнить все нужные моменты. Зачем мне ваше "хоть что-то". Также мое настойчивое желание было получить от вас ответ на вопрос "В чем тут упрощение?". Ни то ни другое вы не сделали.
Ваши 3 строки не делают того, что делают мои 10, то есть это неполный пример. Но если вам так спокойнее, то можете считать себя чемпионом. Хотя бы с неполным справились, молодец. Вот когда справитесь с полным, тогда можно будет и ORM обсуждать. А пока что у вас для этого недостаточно опыта, вы никогда не писали такой код, и не понимаете, о чем идет речь.
Пример полностью см в GitHub
А где твой то?
Для человека, который недавно хвастался глубоким пониманием слова "пример", вы понимаете удивительно мало.
https://gramota.ru/poisk?query=пример&mode=slovari&dicts[]=42
"Пример: Конкретное явление, случай, приводимые для объяснения или доказательства чего-л."
Мой пример полностью находится в этом комментарии.
"Пример полностью" не означает "реализация полностью". Это означает, что пример достаточно полный для объяснения или доказательства этого "чего-л.". В моем примере есть 2 транзакции, HTTP-запрос, и установка разных статусов до и после. Поэтому чтобы ваш пример был достаточно полным для демонстрации вашего подхода в решении той же задачи, он должен содержать все эти элементы. А вот потом можно будет сравнивать, насколько ваш пример проще или сложнее. А если вы такой пример не приводите, то это неконструктивное ведение дискуссии.
Пример полностью см в GitHub
Не вижу там HTTP-запросов к платежному провайдеру и 2 транзакций. Я серьезно не понимаю, с какой целью вы пытаетесь доказать свою точку зрения враньем.
Вот скажи мне пожалуйста чем моя строка
save(date);
отличается от твоей
this.entityManager.save(cart);
Я тебе показал, то что так настойчиво просишь меня сделать. Как может быть реализован этот мой метод save, можно увидеть в коде моего примера на GitHub.
ИТОГ !!! Можно работать без ORM и код будет значительно короче твоего текущего.
Вопросы есть?
Вот скажи мне пожалуйста чем моя строка отличается
Я писал выше. У вас date это HashMap с неизвестными полями, а у меня cart это объект класса Cart с известными, что влияет на подсказки в IDE и контроль типов в компиляторе.
По технической функциональности они одинаковые, только у меня есть еще и другие строки, которых у вас нет.
Я тебе показал, то что так настойчиво просишь меня сделать
Нет, полного примера с 2 транзакциями и заполнением полей вы не показали. Я сам его додумал, и возможно неправильно.
Как может быть реализован этот мой метод save
В двадцатый раз повторяю - меня не интересует реализация метода save. Я не знаю, почему вы мне все время ее пытаетесь показать, игнорируя эту информацию.
В моем примере я написал вызов метода save, а не его реализацию. ORM нужна не для реализации метода save, а для кода с логикой, из которого этот метод save вызывается. В нем я хочу работать с объектами, а не с хешмапами, и потом эти объекты надо как-то сохранять. Хоть через ваш сервис, хоть напрямую в БД.
ORM нужна в моем коде, чтобы я мог отправить мой объект класса Cart в ваш сервис с методом save в виде JSON, попутно преобразовав поля наподобие "userId" в "user_id". Всё. Необходимость маппинга объектов в реляции возникает исключительно из существования объектов класса Cart. Если в моем коде не будет таких классов, то мне не нужна ORM, но они для меня удобны, поэтому убирать их я не буду.
код будет значительно короче твоего текущего
В моем текущем коде 9 строк, а в вашем коде с многоточиями 14. Ваш код в полтора раза длиннее, и все равно не содержит всего, что есть в моем. Но вы можете продолжать тешить себя этой мыслью. Ваш код короче, вы молодец.
В каждом конкретном случае все поля известны, что позволяет выполнять любые манипуляции с ними. Если бы было иначе, мой универсальный сервис не был бы работоспособным.
Да ладно?
HashMap<String, Object> data = prepareData();
int userId = data.get(???);
Какие поля находятся в data? Какое название поля мне надо написать, "userId"? А может "user_id"?
Я говорил про поля, которые известны мне при работе с каким-то кодом, а не вашему сервису. Мне удобнее поставить точку и получить список полей в IDE, а не лазить по всему коду, выискивая все места где вызывается put. И при опечатке получить ошибку от компилятора сразу, а не null, из-за которого код упадет где-нибудь в другом месте на проде во время выполнения.
См код сервиса, я ничего не прячу
Еще раз для непонятливых, кто ставит минусы и все прочие ...
ORM это плохо тем, что фактически связывает два программных слоя в один. Программные слои - это слой хранения данных и слой сервера приложения.
Можно строить приложения без ORM? Можно. Данная задача решается в общем виде и основной элемент этого решения выработка соглашений. Соглашения позволяют решить задачу в общем виде не привязываясь к структуре данных и предметной области. Бывают разного рода отклонения? Бывают. Этих отклонений, как правило, не много в конкретной реализуемой задаче и они решаются в подавляющем числе случаев достаточно просто в рамках общего решения.
Кстати, ORM, а точнее реализации ORM, так же построено на соглашениях, только эти соглашения жестко приписываются в коде и состоят из имен классов, имен методов, аннотаций, деклараций и т.п., что выливается в лишний объем кодирования. Лишний объем кодирования затрудняет модификацию ПО (с этим никто спорить надеюсь не будет). Реализация в идеологии ORM привязывает код к предметной области, следовательно повторность использования практически нулевая.
Итак резюмирую недостатки ORM:
избыточный объем кодирования
ресурсоемкость модификации
отсутствие повторности использования кода
программная реализация соглашений
Можно реализовать соглашения как то иным способ, чем в универсальном сервисе? Можно, с учетом ваших потребностей. Можно идею соглашений применить где то еще? Можно. Например идею соглашений применил в реализации конфигурации приложения. Сразу отпала необходимость в каких либо классах фабриках и структура конфигурационного файла может иметь произвольный вид и этот код может быть повторно использован вообще в любых приложения. И в любой момент структура конфигурационного файла может быть модифицирована под новые требования практически ничего не затрагивая в коде.
И в заключении. Все свои приложения разрабатываю исключительно без ORM. Приложения в разных предметных областях, большие и маленькие, распределенные, параллельные, высоконагруженные. При этом повторность использования кода очень высокая.
Жаль, что вы так ничего и не поняли. Поскольку код, где ORM нужна, вы писать отказываетесь, и судя по всему никогда не писали что-то сложнее простых CRUD, то объяснить вам это невозможно, а значит вы так ничего и не поймете.
См код сервиса, я ничего не прячу
На всякий случай - я говорил не про код вашего сервиса, а про мой код с логикой. Над которым кроме меня может работать еще 20 человек. Это вы похоже тоже не поняли.
:-) Если так делают все, это не значит что нельзя делать лучше. Вот ораклисты не могут работать без ID, построчной обработки и ORM. Дай им настоящую реляционную модель данных, а не индексную (ID это по сути номер строки), все у них возникает крушение мира.
Смотрите, любая логика предметной области это "дополнение". Я Вам показывал, как можно решать задачу в общем виде и какие плюсы Вы можете получить при таком подходе. А вы все про логику, да про логику. Логика дело десятое. Как десятое "источник данных". При решении в общем виде Вам все равно какую логику обработки данных навешивать и из какого источника эти данные обрабатывать.
Зациклены на своей логике и понять плюсы других решений уже не в состоянии.
Задача в общем виде у меня и так уже решена, для этого есть драйвер БД, который может сохранять туда произвольные данные. Моя задача именно в том, чтобы навесить логику.
Драйвер ДБ отличный пример решения частной задачи в общем виде создания узкоспециализированного программного слоя, который реализован на разработанной спецификации (соглашении). Кстати, драйвер БД ни как не привязан к предметной области, что обеспечивает высокую повторность его использования. Вы можете заменить драйвер одной СУБД на другой в любой момент времени. И если ваше ПО написано правильно, то оно останется в рабочем состоянии. Как "узкоспециализированный программный слой" драйвер БД всех ваших задач не решает, иначе вам не пришлось писать собственный каждый раз собственный программный код.
Так может все же стоит задуматься над соглашениями собственного программного кода хотя бы для того чтобы самому меньше его писать?
драйвер БД всех ваших задач не решает, иначе вам не пришлось писать собственный каждый раз собственный программный код
Естественно, и я прямо указал в предыдущем комментарии, какую именно он не решает.
Этот код решает задачу реализации логики, которую не решает драйвер, ни для чего другого он не нужен. И как я уже писал, код с хешмапами вместо нормальных классов меня не интересует.
Так может все же стоит задуматься над соглашениями собственного программного кода
Никакими соглашениями она не решается, 2 транзакции с оплатой нужны только для создания заказа. Вы ее соглашениями так и не решили, вам пришлось писать расширение к вашему сервису с конкретным названием поля в его программном коде. Вот когда придумаете, как обойтись только соглашениями, без расширения с программным кодом, тогда и приходите.
В вашем коде логика тесно связана с программной моделью и моделью данных все схлопнуто в один монолитный слой - одно без другого не работает. Не можете заменить модель данных, не можете заменить программную модель. Посмотрите на реализацию драйвера БД, на реализацию собственного кода. О повторности использования вашего кода говорить вообще не приходиться.
Вы зациклились на своем понимании "хешмапам". Если написан универсальный код c "хешмапами", который можно использовать многократно использовать имеет это значение? Нет. Вам не надо же каждый раз повторять этот код? Не надо. Да ваш движок внутри тоже использует "хешмапами", в которых связывает соответствие одного другому. Только ваш движок не обеспечивает повторность использования вашего кода и, еще раз почеркну, объединяет совершенно разные слои вашего и чужого кода в один монолит.
2 ваших транзакции (хотя не понятно почему две, а не одна, получили ошибку при HTTP вызове чего там перед второй транзакцией) это частный случай (отклонение) и если у вас реализован код, который выполняет любую транзакцию, что что вам мешает его вызвать дважды с разными параметрами? Будет две строки.
Если написан универсальный код c "хешмапами", который можно использовать многократно использовать
Вот я и говорю, когда напишете универсальный код с хешмапами и 2 транзакциями, который подходит не только для создания заказа, тогда и приходите.
Будет две строки.
Нет, потому что раз параметры разные, значит между транзакциями они поменялись, значит кроме вызовов транзакций есть код, который устанавливает новые значения параметров. Поэтому будет не 2 строки, а например 10.
и если у вас реализован код, который выполняет любую транзакцию, что что вам мешает его вызвать дважды с разными параметрами
Да ничего не мешает, в примере я так и делаю. Там 2 вызова save(), которые вызывают драйвер БД. Я уже много раз сказал, что ORM мне нужна в коде который делает ваше "вызвать дважды с разными параметрами". Чтобы было удобнее задавать эти разные параметры. Только вы не хотите слышать.
У меня код давно написан и код который выполнят любую транзакцию написан. Мне все равно сколько транзакций выполнять. Одну, две, десять. Абсолютно все равно. У Вас эти "2 транзакции" похоже вызывают большую проблему, что Вы постоянно к ним возвращаетесь.
Мешаете, ибо при изменении одного слоя, Вам нужно обязательно менять другой слой. Иначе все сломается.
Ну так и у вас название поля "status" в коде расширения захардкожено, что я вам и объясняю с самого начала. Если вы его в базе переименуете на "status_id", вам надо будет менять код расширения, иначе все сломается. Даже если вы его вынесете в конфиг, это все равно будет другой слой, который нужно менять синхронно с базой.
Мне все равно сколько транзакций выполнять.
У меня драйвер БД тоже уже написан, и ему все равно сколько транзакций выполнять.
постоянно к ним возвращаетесь
Я к ним возвращаюсь, потому что мне надо написать только код этих 2 вызовов с нужными параметрами. Код, выполняющий одну транзакцию, мне писать не нужно, он уже написан. Я не понимаю, почему вы не можете понять простую фразу.
У меня нет в коде имен, у меня есть соглашение. И в базе я не буду что либо переименовывать. Я назову поле в базе, так как оно приходит от внешней системы. Как я понимаю это имя "status". Этого достаточно, чтобы все отработало автоматически. И в коде не будет ни одного имени поля и отработают две транзакции, если Вам так нужно.
Все и всегда разбивается на кубики
Вы привели пример какой-то "7-уровневой модели IP стека", очевидно смешав 7-уровневую модель OSI с TCP\IP, который не 7-уровневый. Я вам дал ссылку на RFC, в котором спецалисты с мировыми именами делятся своими болями как раз по этому подоводу, не получается у них всё разбить на кубики. Вот теоретики нарисовали модель OSI, а вот практики начинают реализовывать сетевые протоколы, и нифига у них не сходится. То тут то там подтекают абстракции. И пишут что да, в реальном мире приходится идти на компромиссы.
Зачем вы после этого поскакали в сторону ORM?
По поводу "7-уровневой модели IP стека". Если теоретическая 7-уровневая модель на практике по каким то причинам реализуется в 6, 5, 4 - уровня, что это меняет? Главное что каждое ПО нужно пытаться разбить на уровни.
ORM мешает разбивать приложение на уровни, каждый из которых должен иметь узкую специализацию. ORM привел в качестве очень плохого решения.
Чем больше узкоспециализированных уровней в приложении, тем легче отвечать на самые неожиданные требования в процессе всего жизненного цикла этого приложения.
Если теоретическая 7-уровневая модель на практике по каким то причинам реализуется в 6, 5, 4 - уровня, что это меняет?
Что меняет? Ну вот это и меняет, что люди пытались в это ваше "каждый уровень (кубик, слой) выполняет только свою определенную функцию", и у них не получилось. Верхние уровни сетевых протоколов хотят знать что-то о нижних, и это не всегда даже соседние уровни. А вы почему-то приводите этот итоговый компромиссный вариант как пример успешного успеха.
Не получилось сделать 7 кубиков, получилось 6. Это критично? Нет. Да, иногда может не получиться желаемого разбиения по каким либо причинам. В любом случае разбиение на кубики предпочтительнее, это решение более модифицируемо, чем все в одном.
Я уже тут объяснял почему нужно бить на кубики, не хочется повторятся. Успех такого решения в том, что у Вас или ваших коллег появляются возможность отвечать на вновь возникающие требования, порой самые неожиданные, без больших затрат и боязни что либо сломать. Не хотите бить свой код на "кубики", не бейте. Кто вам мешает.
Идеальный код должен быть читаемым, тестируемым и легко-изменяемым.
А каким именно способом мы добиваемся этой цели, не так уж и важно. Если ради этого нужно немного усложнить или упростить код, то это надо и сделать
Примеры, как мне кажется, не релевантные
Переусложнение в планировании - комбинация "пионерского" подхода оставить после себя лучше чем до тебя, и отсутствия понимания целеполагания
Пример с переусложнением кода - reduce ещё ладно, это классическая проблема, а декомпозиция высосана из пальца - можно нормально разбивать методы на составляющие по действиям и все будут довольны, просто в примере нет никакой внутренней логики в действиях
Переусложнение архитектуры - та же проблема - нет четкой цели "сделать MVP" - вот и рождается архитектура мимикрирующая под конкретный тиндер, который уже давно релизнут и поддерживается
Статья получилась больше про симптомы плохого управления, а не про переусложнение
Давно известен принцип проектирования ( мой любимый btw) KISS - keep it simple stupid
Пора вводить новый навык в резюме: "использую DDD, не переусложняя код"
100 из 100. Во многом из-за переусложнения как с технической части, так и с бизнесовой, проекты превращаются в макаранного монстра, где "идеальная архитектура" и за неделю не дает простую фичу добавить, а кол-во непонятно кем используемого функционала продукта тормозит дальнейшее развитие...
Сервис живет 2 года. Любой сервис живет 2, максимум 4 года. Если проекту больше 2 лет, значит скорее всего половины кто его писал уже в команде нет, проект сильно устарел и его поддержка стоит огромных усилий. Платформы меняются, меняются либы, гайдлайны, какие-то проекты взлетают, а какие-то нет. Надо попытаться объяснить, что нет смысла пилить проекты на 100 лет.
Хахахахаха. Автор, конечно, в чем-то прав, но взгляд у него исключительно со стороны крудостартапов. Тут уже была подобная статья о том, как переписывать легаси: дескать, просто сядьте маленькой командой, за выходные сделайте MVP, а потом переносите туда функционал постепенно.
Как перестать переусложнять и начать жить