metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2012-10-19 10:23 pm
Entry tags:

Бизнес-логика: Структура данных vs код

[livejournal.com profile] plumqqz доставил нам очередную ссылку на ужасы обсуждения БД на хабре. Сама статья еще куда ни шло, за исключением представления constraints как мега-фичи (вроде это основа основ любой БД). В комментариях, само собой, дикий ад, трэш, угар, содомия, коровники, заборы, катаформизм хабракармы и голые бизнес-аналитекши.

Самое ужасное там - это когда структуре данных отказывают в праве считаться частью бизнес-логики, упирая на то, что "надо же абстрагироваться от хранилища".
При этом, даже если добится этого абстрагирования - то все равно структура данных будет в памяти, в виде графа объектов, будет нужен дополнительный код по интеграции этой структуры с тем, что живет в БД, и никуда мы от структуры данных не денемся. А уж про то, можно ли считать констрейнты (в т.ч. и сложные, выражаемые только в виде триггеров) частью типов данных - можно дискутировать вечно. По крайней мере, check и foreign key constraints это точно часть типа данных, в случае FK - это еще и зависимые типы, реализованные в понятном виде. В случае unique constraints - уже сложнее, но по идее, тоже зависимый тип (зависит от данных таблицы, в которой он используется).

Так вот, я считаю, что структура данных для бизнес-логики гораздо более важна, чем собственно код. Если вам скажут, что теперь операция с кодом "777029" не облагается НДС - вам всего лишь нужно добавить веточку в паттерн-матчинг. Структура программы от этого не изменится и коллегам вы билд нахрен не сломаете.
А если окажется, что для того, чтобы узнать, как обрабатывается операция, вам нужно заглянуть в настройки в СУБД - то внезапно, в гламурно-причесанной функционально-иммутабельной функции проверки условий появляется грязная монада IO, провайдеры коннектов к БД, автоматическое управление транзакциями, пул коннектов, кэши и прочая черняга и структура данных (к коей я отношу так же и сигнатуры функций) меняется весьма заметно. Альтернативный вариант - оставить функцию чистой, но добавить к ней еще параметров, передаваемых извне, проверить код коллег, записать в трекер и рассказать, что теперь без передачи в нее оккультного набора параметров функция больше не заработает.

[identity profile] theiced.livejournal.com 2012-10-20 12:53 pm (UTC)(link)
какой МОЙ запрос. запрос генерит орм-или-его-аналог. я тупо пишу что то вида: `Point.where(:created_at => Time.now.beginning_of_day .. Time.now).where(:customer_id => [1, 2, 10]).order(:name).all` и мне реально похер какая там база и какой говносрез недострандарта сикль она умеет. кампутир железный, пусть он думает.

[identity profile] theiced.livejournal.com 2012-10-20 12:58 pm (UTC)(link)
и да - в 99% случаев оно сгенерит оптимальный запрос. да, оно умеет и джоины-хуёины и всё что надо. при этом никто не запрещает при попадании в тот 1% когда запрос не совсем оптимален и когда важна скорость написать селект какой руками. за последние 6 лет я сделал такое один раз и то по причине того что не знал что тот орм умеет вложенные прелоады.

[identity profile] stdray.livejournal.com 2012-10-20 02:39 pm (UTC)(link)
Ага, потом для того, чтобы обновить поле у 100500 записей, все они ОРМом подтягиваются на клиент, потом в цикле у них изменяется значение, и , наконец, все это дело летит обратно на сервер. Потом начинает это все начинает тормозить, жрать память и тд, потом изобретается что-то вроде обновлений партиями по 500 штук и прочая ерунда.

[identity profile] vp.livejournal.com 2012-10-20 03:07 pm (UTC)(link)
А вот тут мы подошли к самому интересному моменту нашего обсуждения. 83% продуктов на рынке на фазе своей разработки имеют только одну цель: быть завершенными. Что там будет дальше в жизненном цикле - никого не волнует. А если мы о стартапе, целью которого будет продажа дальше по цепочке, то о таком вообще запрещено думать, чтобы не мутить воду.

[identity profile] stdray.livejournal.com 2012-10-20 06:10 pm (UTC)(link)
Я придерживаюсь мнения, что сначала надо сделать самым простым наивным способом, чтобы работало и можно было тестировать. У меня какие-то похожие с Айседом значения, что 98-99% задач делается ОРМом, а остальное можно и руками похардкодить. Просто он говорит, мол мощные хранимки и специфичные особенности конкретной СУБД - зло, потому что если вендер субд поехал, то все дружно попали ад. По мне так, это не аргумент ни разу. Какбы если с ума сойдут (или просто забьют на развитие и поддержку) разрабы ОРМ, то проблем будет гораздо-гораздо больше. И что теперь паниковать и воротить слой абстракции над ОРМами? Не думаю. Это ни к чему хорошему не приведет. Когда растут нагрузки придется спускаться к СУБД-специфичными фичам, когда надо делать бэкапы базы тоже чаще всего надо пользоваться СУБД-специфичными тулзами, когда надо секьерность-пользователи-права тоже все СУБД-специфичное, апдейты для базы я тоже руками пишу, хотя вроде есть какие-то там миграторы, но я опять же им не верю. Ко всему прочему, когда это дело год или два на конкретной СУБД работает, то оно оттестировао, пробелемы известны и саппорт умеет их чинить, без пробрасывания геморроя в наш отдел. А если там зверинец поддерживаемых СУБД развести, то нам, наверное, придется человека выделять. который будет рулить все енти вопросы. СУБД же все по разному работают, разные планы запросов строят, по-раному нуллы трактуют, еще с датавременем и гуидами какие-то проблемы у меня были. То есть вопрос масштаба, я считаю. Когда там code-first и надо прототип слепить, пофиг что там за постоянное хранилище, а когда пошла реальная работа с загрузкой ресурсов, то все эти абстракции прилетают бумерангом по башке.

[identity profile] theiced.livejournal.com 2012-10-20 09:22 pm (UTC)(link)
именно. поэтому получаются продукты с лок-ином на файрбёрд. абы выпустить, дальше похуй.

[identity profile] metaclass.livejournal.com 2012-10-20 03:17 pm (UTC)(link)
Вроде ормы уже научились апдейты на сервере генерить. Простые, во всяком случае, потому как общее подмножество фич разных серверов достаточно узкое.

[identity profile] stdray.livejournal.com 2012-10-20 05:35 pm (UTC)(link)
Я такого поведение не наблюдал, а вот "тысячи объектов материализуются лишь для того, чтобы по ним нагерерился update" правил буквально на днях. Я ОРМам не верю, потому любое свое предположение относительно их работы приходится тестирвоать, потому если время поджимает, я лучше руками нарисую SQL-зпапрос и заверну его в метод репозитория в модели, а еще лучше сделаю из ентого запроса такую-то хранимку, потому что у нее выше шанс реиспользования.

[identity profile] firebie.livejournal.com 2012-10-20 07:19 pm (UTC)(link)
Обновление на сервере:

db.Employee
.Where(e => e.Title == "Spectre")
.Set(e => e.Title, "Commander")
.Update();

[identity profile] stdray.livejournal.com 2012-10-20 07:39 pm (UTC)(link)
Люди написали один единственный ОРМ-фреймворк, ага.

[identity profile] firebie.livejournal.com 2012-10-20 07:46 pm (UTC)(link)
В тех, в которых такое невозможно - да, ручной запрос.
Если уж говорить за ОРМ - то правильные являются тонкой надстройкой над базой и не занимаются самодеятельностью по созданию и загрузке данных.

[identity profile] theiced.livejournal.com 2012-10-20 09:21 pm (UTC)(link)
это хуёвые ормы, нормальные сгенерят правильный апдэйт.

[identity profile] vp.livejournal.com 2012-10-20 09:30 pm (UTC)(link)
Как выглядит такой апдейт? можешь привести пример?

[identity profile] theiced.livejournal.com 2012-10-20 09:35 pm (UTC)(link)
Foo.where(:bar => 'bee').update_all(:huj => 'хуй')

[identity profile] vp.livejournal.com 2012-10-20 09:38 pm (UTC)(link)
Я не про апдейт, я про апдейт схемы базы.
У вас была версия 1.1, вы апдейтите изделие на 1.8
Как ваш чудо орм автоматически обновит ту базу, на которой работает?
в 1.8 у вас удалили половину полей, который были в 1.1 и создали другую половину.

[identity profile] theiced.livejournal.com 2012-10-20 09:41 pm (UTC)(link)
а мне вот интересно - как вы базу обновляете? я вообще принципиально апдейт схемы делаю только миграциями. а ормам похуй какая там схема - они метаданные вытягивают прямо оттуда.

[identity profile] metaclass.livejournal.com 2012-10-20 09:49 pm (UTC)(link)
Я делаю sql cкриптами.
А схема и прочее для ормов генерируется из модели, т.к. полное описание предметки в виде модели слишком сложное, чтобы его запихивать в любой частный язык программирования (за исключением разного рода лиспов, разве что)

[identity profile] vp.livejournal.com 2012-10-21 07:38 am (UTC)(link)
Ну дык для того, чтобы сделать апдейт схемы, необходимо эту схему представлять. И необходимо понимать, на каком состоянии у тебя находится обновляемая система к твоей текущей версии, до которой ты собираешься ее догнать.
Как ты это делаешь без понимания того, как устроена база? (мы только что постулировали, что только так и нужно и нам пофиг что там)

[identity profile] metaclass.livejournal.com 2012-10-21 08:08 am (UTC)(link)
В рубях ВСЯ схема базы делается в виде классов и миграций, т.е. вообще вся. И в базе есть таблица, аналогичная нашей, для трекинга версий
Т.е. оно банально один раз запускаешь rake db:migrate и апдейты на базу накатывается.

(no subject)

[identity profile] theiced.livejournal.com - 2012-10-21 08:54 (UTC) - Expand

(no subject)

[identity profile] metaclass.livejournal.com - 2012-10-21 09:05 (UTC) - Expand

(no subject)

[identity profile] metaclass.livejournal.com - 2012-10-21 09:05 (UTC) - Expand

[identity profile] metaclass.livejournal.com 2012-10-20 09:45 pm (UTC)(link)
Что ты несешь, мы же обсуждаем апдейты данных, а не метаданных.

Для метаданных есть миграции в рубевой activerecord, а поскольку в базе логику и вообще хоть что-то осмысленное делать у них не принято, то функций типа "добавить/удалить таблицу" и "добавить/удалить поле" более чем достаточно :)

Т.е. вообще говоря, все эти ORM и прочая чернь - это способ упростить себе работу с базой, не вникая в ее тонкости. При этом приходится выкидывать все, что СУБД умеет делать сама, т.к. другие сервера это делают по другому.

[identity profile] theiced.livejournal.com 2012-10-20 09:50 pm (UTC)(link)
вот, до вас доходит же потиху. именно - ВЫКИНУТЬ К ХУЯМ всю это ненадёжную поебень.

[identity profile] metaclass.livejournal.com 2012-10-20 10:07 pm (UTC)(link)
А зачем ее выкидывать?
Констрейнты в виде FK,Unique и собственно структуры БД я оставлю по любому (по крайней мере, пока базы с ACID и типизированной функциональщиной не появится на горизонте).

Вот триггера и хранимые процедуры, похоже, придется оставить только для очень узких по производительности мест. Сложная логика нормальным повторно используемым образом туда не складывается, даже если SQL генерировать из нормальных языков. Разрабатывать семантику трансляции лиспа в императивные SQL-расширения разных серверов - ну его нахер, я лучше с нуля напишу.

(no subject)

[identity profile] theiced.livejournal.com - 2012-10-20 22:15 (UTC) - Expand

(no subject)

[identity profile] metaclass.livejournal.com - 2012-10-20 22:30 (UTC) - Expand

(no subject)

[identity profile] blackyblack.livejournal.com - 2012-10-22 06:36 (UTC) - Expand

[identity profile] vp.livejournal.com 2012-10-21 07:40 am (UTC)(link)
То есть как обычно есть золотая пуля и на самом деле вопрос выеденого яйца не стоит. Ок.

[identity profile] metaclass.livejournal.com 2012-10-21 08:09 am (UTC)(link)
Я более чем уверен, что если мы возьмем эту "золотую пулю", мы через неделю в накопаем в ней чернейших багов, а через месяц упремся в то, что "ДА ЭТОГО ЖЕ НИКТО ТАК НЕ ДЕЛАЕТ".

(no subject)

[identity profile] vp.livejournal.com - 2012-10-21 08:16 (UTC) - Expand

(no subject)

[identity profile] theiced.livejournal.com - 2012-10-21 08:54 (UTC) - Expand

(no subject)

[identity profile] metaclass.livejournal.com - 2012-10-21 09:06 (UTC) - Expand

(no subject)

(Anonymous) - 2012-10-22 08:35 (UTC) - Expand

[identity profile] norguhtar.livejournal.com 2012-10-22 03:23 am (UTC)(link)
Если у вас такое наблюдается, не используете в этом месте ORM. ORM удобен в оперденях с тысячами CRUD.