Эванс в книге про DDD так и писал: избегайте методов с побочными эффектами (В его определении — методы, меняющие внутреннее состояние объекта). Как раз оно
Я написал несколько курсовиков про UML, учавствовал в доработке редакторов и кодогенераторов. И затем защитил диплом на тему создания редактора, на котором можно нарисовать сам UML :)
UML — не нужен.
Я понял. Вы говорите про data-centric приложения. О них ещё в середине 2000х Майкрософт везде писал.
Сейчас, в большинстве случаев, БД — мешок для прятания объектов и не более того. От СУБД не требуется много параллельных соединений и запросов. И реляционная модель с её нормализациями и прочими прелестями — только мешает. А те минусы, о которых вы пишете — здесь не актуальны. Все подобные проблемы решены, всё-таки.
Ваши изречения имеют право на существования, но просто в другом контексте, где применение NoSQL даже и не всплывает.
Я не отгораживаюсь, вроде. Просто реально пытаюсь понять их смысл. Если нужно перелопатить тучу данных, в несколько этапов — да, смысл в хранимках вижу: не нужно по сети гонять кучу данных туда-сюда, а сразу всё происходит в одном месте. В других случаях же вообще не могу понять их смысла. Я уже спрашивал: назовите хотя бы парочку плюсов такого подхода? Кроме мифической инкапсуляции внутренней структуры, которая мало того что мифическая, так ещё и есть зло.
Я думаю комментатор выше хотел сказать, что это выглядит действительно странно — класть в хранимки логику, если ровно тот же SQL-запрос можно послать на БД из самого приложения. Только при этом, будет меньше ограничений для разработчика. В чём здесь профит от хранимок то? Я реально из ваших объяснений не вижу.
Вроде бы верно излагаете: не стоит впадать в крайности, нужно выбирать правильный инструмент, но в конце концов всё-равно «И по максимуму бы использовал хранимки».
Зачем то, что можно вызвать из кода приложения — загонять внутрь хранимки и давать наружу только сигнатуру? Кроме ограничений, мы (авторы комментов) здесь больше ничего не видим.
Иначе в шарпе придется повторять всю исходную структуру таблиц. Разница только в объеме кода и где лучше, быстрее исправлять.
А она там итак будет, практически в неизменном виде.
Извиняюсь, что не отвечаю так же развёрнуто на ваш объёмный комментарий. Просто вижу, что мы не спорим, а излагаем одну и ту же мысль, но разными словами. Для каждой задачи — свой инструмент. Фанатики, пихающие совершенно всю логику в ХП — не правы. Я их за свою карьеру видел достаточно много, чтобы начать эмоционально реагировать на любое упомянание ХР. При этом, на шарпе всю логику тоже эффективно не опишешь (как минимум поиск, фильтры, отчёты). Должен быть разумный симбиоз. При таком раскладе, в большинстве случаев, полноценная навороченная СУБД уже становится не нужна и хватает какого-нибудь легковесного NoSQL. С чем вы, похоже, тоже не спорите.
А если данных ну очень много и мы готовы смириться с eventual consitency, их использование становится ещё более оправданно, в разрезе скорости работы (не разработки). ИМХО
Ну, задача поиска это тоже, знаете ли. Не всегда хорошо ложится и на SQL. Но да, руками (в т.ч. через ОРМ) такое делать тоже не стоит :)
Private в коде классов и инкапсуляция модели данных приложения внутри СУБД — это всё же разные вещи. Зачем прятать от приложения то, что является его частью?
Я думаю, на этот вопрос зачастую отвечает предметная область. Если я один раз купил себе Renault Clio (когда он ещё был только седаном), а затем его переименовали в Renault Symbol, то всё же в договоре купли-продажи всё-равно будет написано Clio. А когда через 5 лет он у меня развалится и я пойду в автосалон, в новом договоре уже будет обновлённое название…
Начну с конца: да никто и не кидается в NoSQL. В нашем треде идёт холивар на тему «логика в БД» vs «БД — лишь хранилище данных» :)
Нет, всё же вы не угадали. Я побывал и в проектах, где ни один чих не обходился без ХП, и в проектах, где кроме NHibernate не было ни строчки SQL-кода. Да, плохо было везде :-) Но в итоге мне показался эффективнее второй вариант. (Как раз дело в том, что в детстве я не верил в нужность математики, окончил математический факультет и в итоге укрепился в своих первоначальных суждениях, но уже без фанатического экстремизма, сместившись чуть ближе к балансу.)
Про динамические запросы я понимаю вашу мысль. Да, это так. Про циклы и ветвления тоже согласен. Именно это я и хотел сказать — если в ХП всё это есть, значит «Хьюстон, у нас проблема». Но, чёрт возьми, рассчёт перерасхода сотрудника в заданном периоде согласно его лимиту и настройкам бухгалтерии, переход документа дальше по цепочке авторизации — всё это не реализовать на голом SQL, простыми запросами. А если подобную логику тащить на уровень клиентского кода, то будет нужен доступ к недрам модели данных, её особенностям реализации. Идея инкапсуляции логики модели, ограничение прав доступа пользователя только на выполнение ХП — всё это терпит крах. Иначе придётся программировать слишком много процедур, почти полностью повторяя исходную структуру таблиц. Так зачем же тратить на это время (при проектировании, кодировании и поддержке)? Почему люди стараются упрятать максимум в ХП, скрыть все детали от прикладных программистов? Когда есть доступ к полноценной, целостной модели — как и у кода, так и у ХП, разработка же становится на порядок проще!
По поводу сложности реализации описанных мною срезов на шарпе — вы меня не совсем поняли. В этом треде витает спор между «ВСЯ логика в ХП» vs «ничего в ХП». Лично я — за золотую середину, смещённую в сторону шарпа :) Не нужно писать на нём сложные запросы, если в SQL их сделать проще. И не нужно оборачивать в ХП запросы вида select id, name from blah order by id и select id, name from blah order by name. Их будет всё же большинство. Не думаю, что вы с этим будете спорить. И как раз отсюда и пошла, на мой взгляд, идея NoSQL — если в 80% случаев нам не нужна вся мощь SQL, зачем тратить процессорное время на лог транзакций, ACID и внешние ключи? Зачем ограничивать зазря прикладных программистов? Вот банковские системы и иже с ним пускай как писали на J2EE + Oracle, так и продолжают. Но сейчас наконец-то появилась альтернатива. И кому-то хватит даже key-value… Но в том, что их можно реализовать самому за день — вы не правы. Вон Ayende уже сколько пилит свою RavenDB :)
2. По сути, разницы нет. Изначально моя мысль заключалась в том, можно обойтись без транзакций, хранимок на стороне СУБД. В принципе, если опустить нюанс с тем, что прикладной программист должен быть чуточку умнее, нежели при использовании SQL — не думаю, что вы всё же против этой мысли.
3. Не недо «не надо про ОРМ» :-) Это понятно, что не стоит пихать их везде и всюду, стоит иметь голову на плечах. Но разве вы со мной не согласитесь, что почти все сложные запросы, которые с трудом осилит ОРМ — это скорее всего будут отчёты? Даже я бы не советовал их делать с использованием чего-либо, отличного от SQL. Он здесь естественно на коне и совершенно в тему. Можно даже reporting database денормализованную подготовить, нагенерить её по триггерам из основной NoSQL/реляционной базы…
4. Ну здесь я уже не знаю что сказать. Не встречал примеров, когда это оправданно (защищаться от коллег!). Видимо, мне повезло :-)
Я уже ответил на этот вопрос выше. Отвечу чуть более развёрнуто. Только предупреждаю: это мой личный опыт, основанный на тех десятках проектов, которые я лично (в составе команды) реализовал. Пишу не ради холивара, а для обмена мнениями и опытом.
Допустим, в приложении есть много данных. Мы решили их инкапсулировать в СУБД и ограничить доступ к ним из клиентского кода. Сделали кучу хранимок по базовым операциям, CRUD, поиск, отчёты, ещё что-нибудь. Окей, молодцы. Что мы имеем в сухом остатке?
Сложную логику SQL'ем (декларативно) не описать — нужны циклы, условия. динамические запросы и т.д. Выходит, необходим поверх языка запросов ещё и язык программирования. Лично мне кажется, C#/Java с этим справятся лучше. Это то, ради чего их создали и свою задачу эти языки выполнят лучше — там есть и коллекции, и мощные библиотеки базовых типов, операций. (Да, большие объёмы данных лучше перемалывать максимально близко к этим самим данным. Давайте писать на Java/C# прямо внутри хранимок. И отсылать электронные письма. Работать с ХМЛ, вебсервисами, файловой системой. Всё это — функционал современных СУБД. NoSQL появились как раз по этой причине — в 80% софта всё это не нужно. Но даёт некислый оверхед, потому что поддержка — есть. В NoSQL это всё повыкидывали и часть оставшихся задач осознанно перекинули на плечи разработчиков клиентского кода. Получилось быстро, но — сложно, да. Нужен адекватный мозг).
Что ещё? Хранимые процедуры — это некий срез модели данных, лежащей внутри БД. Что-то трансформировали, что-то — слили воедино для простоты. Кто гарантирует, что клиентский код удобно ляжет на этот срез и не захочет в каких-то случаях получать данные в другом срезе? Доступ к некоторой сущности, которую для простоты объединили с другой или вообще спрятали. Или сгруппированные данные по другому полю? Список сущностей, но немного не так отфильтрованный? Результат — ещё больше хранимых процедур. Одна работает так, другая выдаёт те же данные, но с другой сортировкой, в третью мы добавили параметр «отсылать ли уведомление по завершению», четвёртая возвращает статус обработки запроса и т.д. При этом, первоначально, табличка всего-лишь одна. Или две. (Утрирую). Но срезов, необходимых приложению — больше. И на каждый из них необходимо родить процедуру, потому что процедура = ограничение. В итоге, чтобы сделать простую вещь, мы вызываем 5 процедур подряд, затем первые три ещё раз, но уже с результатом из последних двух. И т.д.
Зачем тратить на это всё своё время, если мы не пишем распределённого (в т.ч. географически) монстра? Спроектировать систему в целом, нежели разбить её на два независимых (!) модуля через узкую прослойку-интерфейс — проще (речь не о декомпозиции задач на более мелкие). Лично мне идея защищать (инкапсулировать) свой код от коллег кажется неоправданной. В огромных проектах, возможно, это уже обретает смысл. Но не в 80% остальных.
1. Это не зависит от наличия\отсутствия хранимых процедур. Весь SQL (будь это даже просто вызовы хранимок) итак нужно держать в одном месте
2. Сомнительный плюс, ИМХО. Если инкапсулировать логику и схему внутри БД и дать приложению только API — да, некоторые вещи сможет дорабатывать БД-специалист, без изменения кода приложения. Но при этом, стоимость первоначальной разработки всё же будет выше — ибо мы вводим дополнительный слой API, который резко ограничивает пространство для манёвра. На любой чих придётся пинать БД-шников и просить новую хранимку. Как результат — со временем это может вылиться в неподдерживаему кашу из процедур, делающих одно и тоже, но со своими нюансами. При этом, клиентский код будет ограничен спецификой БД и некоторые вещи будут выполняться неоптимально. Примеров из моей профессиональной практики — пруд пруди.
3. А в процедуре такое невозможно? :-) В большинстве приложений SQL-запросы будут генериться автоматом (ORM) или забиты в код методов репозиториев. Вероятность бага там всё же презрительно мала и будет отловлена на этапе тестирования, после убивания всего-лишь никому не нужных тестовых данных.
4. Сперев пароль от базы, кто мне запретит сделать select * from users?
Да, в классических реляционных СУБД мы можем загнать всю логику в транзакции в хранимых процедурах и ограничить права доступа приложения только вызовом этих процедур. Но так делать на самом деле не нужно. И опа, NoSQL-подход становится не так уж и плох.
UML — не нужен.
Сейчас, в большинстве случаев, БД — мешок для прятания объектов и не более того. От СУБД не требуется много параллельных соединений и запросов. И реляционная модель с её нормализациями и прочими прелестями — только мешает. А те минусы, о которых вы пишете — здесь не актуальны. Все подобные проблемы решены, всё-таки.
Ваши изречения имеют право на существования, но просто в другом контексте, где применение NoSQL даже и не всплывает.
Вроде бы верно излагаете: не стоит впадать в крайности, нужно выбирать правильный инструмент, но в конце концов всё-равно «И по максимуму бы использовал хранимки».
Зачем то, что можно вызвать из кода приложения — загонять внутрь хранимки и давать наружу только сигнатуру? Кроме ограничений, мы (авторы комментов) здесь больше ничего не видим.
А она там итак будет, практически в неизменном виде.
Извиняюсь, что не отвечаю так же развёрнуто на ваш объёмный комментарий. Просто вижу, что мы не спорим, а излагаем одну и ту же мысль, но разными словами. Для каждой задачи — свой инструмент. Фанатики, пихающие совершенно всю логику в ХП — не правы. Я их за свою карьеру видел достаточно много, чтобы начать эмоционально реагировать на любое упомянание ХР. При этом, на шарпе всю логику тоже эффективно не опишешь (как минимум поиск, фильтры, отчёты). Должен быть разумный симбиоз. При таком раскладе, в большинстве случаев, полноценная навороченная СУБД уже становится не нужна и хватает какого-нибудь легковесного NoSQL. С чем вы, похоже, тоже не спорите.
А если данных ну очень много и мы готовы смириться с eventual consitency, их использование становится ещё более оправданно, в разрезе скорости работы (не разработки). ИМХО
Private в коде классов и инкапсуляция модели данных приложения внутри СУБД — это всё же разные вещи. Зачем прятать от приложения то, что является его частью?
Нет, всё же вы не угадали. Я побывал и в проектах, где ни один чих не обходился без ХП, и в проектах, где кроме NHibernate не было ни строчки SQL-кода. Да, плохо было везде :-) Но в итоге мне показался эффективнее второй вариант. (Как раз дело в том, что в детстве я не верил в нужность математики, окончил математический факультет и в итоге укрепился в своих первоначальных суждениях, но уже без фанатического экстремизма, сместившись чуть ближе к балансу.)
Про динамические запросы я понимаю вашу мысль. Да, это так. Про циклы и ветвления тоже согласен. Именно это я и хотел сказать — если в ХП всё это есть, значит «Хьюстон, у нас проблема». Но, чёрт возьми, рассчёт перерасхода сотрудника в заданном периоде согласно его лимиту и настройкам бухгалтерии, переход документа дальше по цепочке авторизации — всё это не реализовать на голом SQL, простыми запросами. А если подобную логику тащить на уровень клиентского кода, то будет нужен доступ к недрам модели данных, её особенностям реализации. Идея инкапсуляции логики модели, ограничение прав доступа пользователя только на выполнение ХП — всё это терпит крах. Иначе придётся программировать слишком много процедур, почти полностью повторяя исходную структуру таблиц. Так зачем же тратить на это время (при проектировании, кодировании и поддержке)? Почему люди стараются упрятать максимум в ХП, скрыть все детали от прикладных программистов? Когда есть доступ к полноценной, целостной модели — как и у кода, так и у ХП, разработка же становится на порядок проще!
По поводу сложности реализации описанных мною срезов на шарпе — вы меня не совсем поняли. В этом треде витает спор между «ВСЯ логика в ХП» vs «ничего в ХП». Лично я — за золотую середину, смещённую в сторону шарпа :) Не нужно писать на нём сложные запросы, если в SQL их сделать проще. И не нужно оборачивать в ХП запросы вида select id, name from blah order by id и select id, name from blah order by name. Их будет всё же большинство. Не думаю, что вы с этим будете спорить. И как раз отсюда и пошла, на мой взгляд, идея NoSQL — если в 80% случаев нам не нужна вся мощь SQL, зачем тратить процессорное время на лог транзакций, ACID и внешние ключи? Зачем ограничивать зазря прикладных программистов? Вот банковские системы и иже с ним пускай как писали на J2EE + Oracle, так и продолжают. Но сейчас наконец-то появилась альтернатива. И кому-то хватит даже key-value… Но в том, что их можно реализовать самому за день — вы не правы. Вон Ayende уже сколько пилит свою RavenDB :)
2. По сути, разницы нет. Изначально моя мысль заключалась в том, можно обойтись без транзакций, хранимок на стороне СУБД. В принципе, если опустить нюанс с тем, что прикладной программист должен быть чуточку умнее, нежели при использовании SQL — не думаю, что вы всё же против этой мысли.
3. Не недо «не надо про ОРМ» :-) Это понятно, что не стоит пихать их везде и всюду, стоит иметь голову на плечах. Но разве вы со мной не согласитесь, что почти все сложные запросы, которые с трудом осилит ОРМ — это скорее всего будут отчёты? Даже я бы не советовал их делать с использованием чего-либо, отличного от SQL. Он здесь естественно на коне и совершенно в тему. Можно даже reporting database денормализованную подготовить, нагенерить её по триггерам из основной NoSQL/реляционной базы…
4. Ну здесь я уже не знаю что сказать. Не встречал примеров, когда это оправданно (защищаться от коллег!). Видимо, мне повезло :-)
Допустим, в приложении есть много данных. Мы решили их инкапсулировать в СУБД и ограничить доступ к ним из клиентского кода. Сделали кучу хранимок по базовым операциям, CRUD, поиск, отчёты, ещё что-нибудь. Окей, молодцы. Что мы имеем в сухом остатке?
Сложную логику SQL'ем (декларативно) не описать — нужны циклы, условия. динамические запросы и т.д. Выходит, необходим поверх языка запросов ещё и язык программирования. Лично мне кажется, C#/Java с этим справятся лучше. Это то, ради чего их создали и свою задачу эти языки выполнят лучше — там есть и коллекции, и мощные библиотеки базовых типов, операций. (Да, большие объёмы данных лучше перемалывать максимально близко к этим самим данным. Давайте писать на Java/C# прямо внутри хранимок. И отсылать электронные письма. Работать с ХМЛ, вебсервисами, файловой системой. Всё это — функционал современных СУБД. NoSQL появились как раз по этой причине — в 80% софта всё это не нужно. Но даёт некислый оверхед, потому что поддержка — есть. В NoSQL это всё повыкидывали и часть оставшихся задач осознанно перекинули на плечи разработчиков клиентского кода. Получилось быстро, но — сложно, да. Нужен адекватный мозг).
Что ещё? Хранимые процедуры — это некий срез модели данных, лежащей внутри БД. Что-то трансформировали, что-то — слили воедино для простоты. Кто гарантирует, что клиентский код удобно ляжет на этот срез и не захочет в каких-то случаях получать данные в другом срезе? Доступ к некоторой сущности, которую для простоты объединили с другой или вообще спрятали. Или сгруппированные данные по другому полю? Список сущностей, но немного не так отфильтрованный? Результат — ещё больше хранимых процедур. Одна работает так, другая выдаёт те же данные, но с другой сортировкой, в третью мы добавили параметр «отсылать ли уведомление по завершению», четвёртая возвращает статус обработки запроса и т.д. При этом, первоначально, табличка всего-лишь одна. Или две. (Утрирую). Но срезов, необходимых приложению — больше. И на каждый из них необходимо родить процедуру, потому что процедура = ограничение. В итоге, чтобы сделать простую вещь, мы вызываем 5 процедур подряд, затем первые три ещё раз, но уже с результатом из последних двух. И т.д.
Зачем тратить на это всё своё время, если мы не пишем распределённого (в т.ч. географически) монстра? Спроектировать систему в целом, нежели разбить её на два независимых (!) модуля через узкую прослойку-интерфейс — проще (речь не о декомпозиции задач на более мелкие). Лично мне идея защищать (инкапсулировать) свой код от коллег кажется неоправданной. В огромных проектах, возможно, это уже обретает смысл. Но не в 80% остальных.
1. Это не зависит от наличия\отсутствия хранимых процедур. Весь SQL (будь это даже просто вызовы хранимок) итак нужно держать в одном месте
2. Сомнительный плюс, ИМХО. Если инкапсулировать логику и схему внутри БД и дать приложению только API — да, некоторые вещи сможет дорабатывать БД-специалист, без изменения кода приложения. Но при этом, стоимость первоначальной разработки всё же будет выше — ибо мы вводим дополнительный слой API, который резко ограничивает пространство для манёвра. На любой чих придётся пинать БД-шников и просить новую хранимку. Как результат — со временем это может вылиться в неподдерживаему кашу из процедур, делающих одно и тоже, но со своими нюансами. При этом, клиентский код будет ограничен спецификой БД и некоторые вещи будут выполняться неоптимально. Примеров из моей профессиональной практики — пруд пруди.
3. А в процедуре такое невозможно? :-) В большинстве приложений SQL-запросы будут генериться автоматом (ORM) или забиты в код методов репозиториев. Вероятность бага там всё же презрительно мала и будет отловлена на этапе тестирования, после убивания всего-лишь никому не нужных тестовых данных.
4. Сперев пароль от базы, кто мне запретит сделать select * from users?