7 февраля в 04:48

Охота на мифический MVC. Обзор, возвращение к первоисточникам и про то, как анализировать и выводить шаблоны самому

— Не понимаю, почему люди так восхищаются этим Карузо? Косноязычен, гугнив, поёт — ничего не разберешь!
— А вы слышали, как поёт Карузо?
— Да, мне тут кое-что из его репертуара Рабинович напел по телефону.

Детектив по материалам IT. Часть первая


Я осознаю, что писать очередную статью на тему Модель-Вид-Контроллер это глупо и вредно для «кармы». Однако с этим «паттерном» у меня слишком личные отношения – проваленный проект, полгода жизни и тяжелой работы «в корзину».


Проект мы переписали, уже без MVC, просто руководствуясь принципами – код перестал быть похож на клубок спагетти и сократился наполовину (об этом позже, в обещанной статье про то, как мы применяли «принципы» в своем проекте). Но хотелось понять, что же мы сделали не так, в чем была ошибка? И в течении долгого времени изучалось все, что содержало аббревиатуру MVC. До тех пор пока не встретились исходные работы от создателя – Трюгве Реенскауга…


И тогда все встало на свои места. Оказалось что фактически на основе принципов мы пере-изобретали «original MVC». А то, что зачастую преподносится как MVC, не имеет к нему никакого отношения… впрочем также как и к хорошей архитектуре. И судя по тому сколько людей пишет о несостоятельности «классического MVC», спорит о нем и изобретает его всевозможные модификации, не одни мы столкнулись с этой проблемой.


Более 30 лет собранные в MVC идеи и решения остаются наиболее значимыми для разработки пользовательских интерфейсов. Но как ни странно, несмотря на существующую путаницу и обилие противоречивых трактовок, разработчики продолжают довольствоваться информацией «из вторых рук», черпая знания о MVC из википедии, небольших статей в интернете и фреймворков для разработки веб-приложений. Самые «продвинутые» читают Мартина Фаулера. И почему-то почти никто не обращается к первоисточникам. Вот этот пробел и хотелось бы заполнить. И заодно развеять некоторые мифы.



Мифы: MVC создавался для языка SmallTalk

Концепция MVC была сформулирована Трюгве Реенскаугом (Trygve Reenskaug) в результате его работы в Xerox PARC в 1978/79 годах. Как правило создание MVC связывают с языком SmallTalk, но это не совсем так. На самом деле Реенскауг работал в группе, занимавшейся разработкой портативного компьютера "для детей всех возрастов" Dynabook под руководством Алана Кэя (Alan Kay).


Чтобы оценить масштаб и революционность того проекта, нужно иметь ввиду что это были годы, когда для работы с ЭВМ требовалось штудировать многостраничные мануалы и иметь ученую степень. Задача, которую пытался решить Алан Кэй, состояла в том, чтобы сблизить компьютер и рядового пользователя, «сломать» разделяющую их стену. Он хотел обеспечить пользователя средствами, которые были бы предельно простыми и удобными, но при этом давали бы возможность управлять компьютером и сложными приложениями.


Именно тогда/там закладывались основы графического интерфейса, формировалось понятие "дружелюбного интерфейса". А также разрабатывался язык SmallTalk, вместе с концепциями объектно-ориентированного программирования, чтобы неподготовленный пользователь “мог понимать и писать программы”. Вот как описывает увиденное в Xerox PARC в 1979 году Стив Джобс – How Steve Jobs got the ideas of GUI from XEROX (from 6.30)


Проект велся около 10 лет, группой очень сильных разработчиков. Найденные в результате решения, подходы, принципы и в области пользовательских интерфейсов, и в области объектно ориентированного программирования и вообще в разработке больших и сложных компьютерных систем были в какой-то степени проссумированы Реенскаугом и составили основу MVC. Так что MVC это действительно прежде всего совокупность направляющих архитектурных идей. В SmallTalk-80 эти идеи всего лишь получили свою первую значимую реализацию. Причем сделано это было уже после ухода Реенскауга из Xerox PARC и без его участия.


К сожалению в течении долго времени о «реальном MVC» не было практически никакой доступной информации. Первая серьезная публикация от создателей появилась лишь 10 лет спустя – "A Cookbook for Using the Model-View-Controller User Interface Paradigm in Smalltalk-80". Даже Фаулер упоминает, что он изучал MVC по работающей версии SmallTalk – "у меня был доступ к работающей версии Smalltalk-80, чтобы я мог изучить MVC. Я не могу сказать, что это исследование было тщательным, но оно позволило мне понять некоторые аспекты решения, которые другие описания объяснить не смогли".


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


В результате многие действительно считают MVC схемой или паттерном (из-за чего постоянно возникает вопрос – какая же из множества существующих схем «правильная» и почему их так много?). В более продвинутом варианте MVC называют составным паттерном, то есть комбинацией нескольких паттернов, работающих совместно для реализации сложных приложений (тут обычно упоминаются Observer, Strategy и Composite). И лишь немногие понимают, что MVC это прежде всего набор архитектурных идей/принципов/подходов, которые могут быть реализованы различными способами с использованием различных шаблонов...


К последним относится в частности Мартин Фаулер. Вот что он пишет: “MVC часто называют паттерном, но я не вижу особой пользы воспринимать его как паттерн, поскольку он включает в себя множество различных идей. Разные люди читают про MVC в различных источниках и извлекают от туда разные идеи, но называют их одинаково — «MVC». Это приводит к большой путанице и кроме того служит источником недоразумений и непониманию MVC, как будто бы люди узнавали про него через «испорченный телефон»…. Я уже потерял счет сколько раз я видел что-то, описываемое как MVC, которое им не оказывалось.”[ GUI Architectures]


Рискну предположить, что одна из причин «испорченного телефона» заключается в том, что большинство вторичных источников «за кадром» оставляют самое главное – собственно сами архитектурные идеи, заложенные в MVC его создателями, и те задачи, которые они пытались решить. Как раз все то, что позволяет понять суть MVC и избежать огромного количества подводных камней и ошибок. Поэтому в данной статье я хочу рассказать о том, что обычно остается «за кадром» – MVC с точки зрения заложенных в него архитектурных принципов и идей. Хотя схемы тоже будут. Вернее с них и начнем.


Но сначала ссылки. Исходный доклад Реенскауга – "The original MVC reports". Позже Реенскауг все это более четко сформулировал и оформил в своей последующей работе “The Model-View-Controller (MVC ). Its Past and Present”. Возможно кому-то будет интересна страница, где собраны записи Ренскауга, относящиеся к тому периоду, с его комментариями - MVC XEROX PARC 1978-79.


Уже упоминавшаяся первая публикация о MVC в языке SmallTalk-80 от разработчиков только в улучшенном качестве "A Description of the Model-View-Controller User Interface Paradigm in the Smalltalk-80 System" (Glenn Krasner и Stephen Pope). Хорошим дополнением служит также статья “Applications Programming in Smalltalk-80.How to use Model-View-Controller” (автор SteveBurbeck учавствовал в разработке компилятора SmallTalk для IBM на основе Smalltalk-80, а также в разработке MacApp). Ну и если кто-то хочет полного погружения – “Smalltalk-80. The Interactive Programming Environment” от знаменитой Адель Голдберг в дискуссиях с которой Реенскаугом и создавались термины Model, View, Controller.


Схемы MVC


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


Итак, несмотря на то, что MVC трактуется и изображается очень по разному, во всем этом многообразии все же можно выделить общее «ядро». Общим является то, что везде говорится о неких трех частях — Модели, Виде и Контроллере, которые связаны между собой определенным образом, а именно:


  1. Модель ничего не знает ни о Виде, ни о Контроллере, что делает возможным ее разработку и тестирование как независимого компонента. И это является главным моментом MVC.


  2. Вид отображает Модель. И значит, он каким-то образом должен получать из нее нужные для отображения данные. Наиболее распространены следующие два варианта: 1) Активный Вид, который знает о Модели и сам берет из нее нужные данные. 2) Пассивный Вид, которому данные поставляет Контроллер. В этом случае Вид с Моделью никак не связан.


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


  3. Контроллер является пожалуй самым неоднозначным компонентом. Тем не менее общим является то, что Контроллер всегда знает о Модели и может ее изменять (как правило в результате действий пользователя).

А также он может осуществлять управление Видом/Видами (особенно если их несколько) и соответственно знать о Видах, но это не обязательно.


Отсюда мы получаем базовые (максимально упрощенные) схемы двух наиболее часто встречающихся разновидностей MVC. Перечеркнутой линией обозначена необязательная связь Контроллера с Видом.


Model View Controller


Вот так базовая схема выглядит у Фаулера: "Основные связи между Моделью, Видом и Контроллером. (Я называю их основными, потому что на самом деле Вид и Контроллер могут быть связанными друг с другом непосредственно. Однако, разработчики в основном не используют эту связь.)":


Model View Controller


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


Но обычно, под MVC все таки подразумевают вариант с Активной Моделью.


«Активная Модель» оповещает о том, что в ней произошли изменения. И делает она это посредством шаблона Наблюдатель, рассылая уведомления о изменениях всем своим «подписчикам». «Активный Вид» подписывается на эти сообщения сам и таким образом знает когда нужно заново считать из модели нужные ему данные и обновиться. В случае «Пассивного Вида», подписчиком является Контроллер, который затем уже обновляет Вид.


Шаблон Наблюдатель позволяет Модели с одной стороны информировать Вид или Контроллер о том что в ней произошли изменения, а с другой фактически ничего о них «не знать» (кроме того что они реализуют некий заданный интерфейс «подписчика») и тем самым оставаться независимой. Это называется слабым связыванием и считается вторым ключевым моментом MVC.


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


Таким образом, более продвинутые «схемы MVC» будут выглядеть так:


Model View Controller


Замечание: встречаются авторы, которые в термины Пассивная и Активная модель вкладывают совсем иной смысл. А именно то, что обычно принято называть Тонкой моделью (модель содержащая исключительно данные) и Толстой моделью (полноценная модель содержащая всю бизнес логику приложения).


Ну и последнее. Вообще говоря MVC, в любой своей разновидности, это прежде всего шаблон для разработки приложений с пользовательским интерфейсом и его главное назначение – обеспечить взаимодействие приложения с пользователем. Поэтому в полноценной MVC схеме (явно или неявно) должен присутствовать пользователь. И тут в основном встречаются две трактовки:


  1. Пользователь управляет приложением через Контроллер, а Вид служит исключительно для отображения информации о Модели, и пользователь его лишь видит


    Model View Controller


    Часто указывают/рисуют лишь то, что пользователь действует на Контроллер, а то что он видит Вид опускается.


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


    Model View Controller



Замечание: нужно иметь ввиду, что вариант с Пассивным Видом, когда Вид никак не связан с Моделью и данные для отображения ему поставляет Контроллер, иногда называют MVC, а иногда выделяют в отдельную разновидность — MVP и тогда Контроллер переименовывают в Презентер.


Для иллюстрации всего вышесказанного несколько диаграмм «из интернета» (надеюсь стало понятнее почему они такие разные):


Model View Controller


А теперь самое главное — как применяются, что обозначают и чему соответствует Модель Вид и Контроллер при написании приложений?


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


«Трехуровневый MVC» от веб


Первый подход идет из веб-программирования, где MVC получил самое широкое распространение, и поэтому в нем максимально отразились свойственные веб-программированию черты. А именно, привязка к трехуровневой архитектуре «клиент–сервер–база данных» и преобладание скриптовых языков. В результате компоненты MVC формально привязываются к трем слоям архитектуры и получается что:


  1. Модель = База Данных
    Модель — это просто данные, которыми оперирует приложение


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


  3. Вид = Клиент (как правило тонкий)
    Вид — это пользовательский интерфейс. Причем интерфейс в этом случае, как правило, понимается в основном исключительно как «дизайн», просто набор графических элементов. Логика же работы этого интерфейса, как и логика работы с данными, выносится в Контроллер

image alt text


Про неадекватность этого подхода написано уже так много, что это вошло даже в википедию (MVC. Наиболее частые ошибки). Хорошо и подробно возникающие при этом проблемы рассматриваются в статье, ставшей своего рода классикой "M в MVC: почему модели непоняты и недооценены". Поэтому постараюсь просто кратко просуммировать:


  1. Независимость Модели является главным в MVC. Если Модель тонкая, то есть содержит лишь данные, то возможность ее независимой разработки имеет мало смысла. Соответственно при таком подходе теряет смысл и сам MVC


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


  3. На практике Контроллеру в веб-приложении обычно соответствует один скрипт и вынесение всей бизнес-логики в Контроллер фактически означает еще и то, что большая часть приложения оказывается в одном скрипте. Отсюда и появился термин ТТУК — толстый тупой уродливый контроллер


  4. Поскольку, как правило, тонкой является не только Модель но также и Вид (тупой Вид или тупой интерфейс — Dumb GUI, Dumb View), то, как следствие, в Контроллер помимо всей бизнес-логики приложения помещается также еще и логика управления пользовательским интерфейсом. То есть, вместо разделения бизнес логики и логики представления при таком подходе получается их смешение.

web MVC


Программа, конечно, разбивается на множество MVC, соответствующих страницам веб-приложения, и это спасает ситуацию но, увы, не меняет сути. Проблема эта известна, вот неплохая статья — "RIA Architecture".


Типичные ошибки: смешение в Контроллере бизнесс-логики и GUI-логики

Хорошая новость заключается в том, что «веб-вариант MVC», всего несколько лет назад бывший самым распространенным, сейчас активно сдает позиции. Плохо то, что он по прежнему распространен, только теперь не в явном, а в замаскированном виде. Поскольку за фразы (цитирую): "Модель это обмен данными с БД и т.п. Контроллер логика обработки этих данных и подготовка к View" сейчас активно «минусуют», то стали писать:


  • Модель — это данные и методы работы с ними
  • Контроллер — обработка действий пользователя и вводимой им информации

Дело в том, что в объектно-ориентированном приложении нет данных, а есть множество объектов и каждый из них содержит какие-то данные и методы работы с ними. В том числе и объекы доступа к базе данных (если они имеются). Поэтому когда определение Модели начинается со слова «данные», то оно в сущности имеет мало смысла и нередко в завуалированной форме подразумевает все тот же самый доступ к базе данных. В обработку же действий пользователя нередко помещается львиная доля бизнес логики и в результате по прежнему вся, или почти вся, логика приложения часто оказывается в Контроллере.


«Архитектурный MVC»


Второй подход гораздо ближе к первоисточникам. Поэтому разберем его подробнее.


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


Архитектурные принципы мы постарались собрать и описать в статье "Создание архитектуры программы или как проектировать табуретку". Если же говорить предельно кратко, то суть состоит в следующем: сложную систему нужно разбивать на модули. Причем декомпозицию желательно делать иерархически, а модули, на которые разбивается система, должны быть, по возможности, независимы или слабо связаны (Low coupling). Чем слабее связанность, тем легче писать/понимать/расширять/чинить программу. Поэтому одной из основных задач при декомпозиции является минимизация и ослабление связей между компонентами.


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


«1» Отделение модели предметной области (бизнес логики) приложения от пользовательского интерфейса


Первая и основная идея MVC заключается в том, что любое пользовательское приложение в первом приближении можно разделить на два модуля — один из которых обеспечивает основной функционал приложения, его бизнес логику, а второй отвечает за взаимодействие с пользователем:


MVC


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


Задача же взаимодействия с пользователем выносится в отдельный модуль – пользовательский интерфейс и тоже может решаться относительно независимо.


Именно модель предметной области (Доменная Модель от английского domain model) считается Моделью в «архитектурном MVC» (отсюда и термин). Поэтому так важно чтобы она была независимой и могла независимо разрабатываться и тестироваться.


"Сердцевиной идеей MVC, как и основной идеей для всех последующих каркасов, является то, что я называю «отделенное представление» (Separated Presentation). Смысл отделенного представления в том, чтобы провести четкую границу между доменными объектами, которые отражают наш реальный мир, и объектами представления, которыми являются GUI-элементы на экране. Доменные объекты должны быть полностью независимы и работать без ссылок на представление, они должны обладать возможностью поддерживать (support) множественные представления, возможно даже одновременно. Этот подход, кстати, так же был одним из важных аспектов Unix-культуры, позволяющий даже сегодня работать во множестве приложений как через командную строку, так и через графический интерфейс (одновременно)." — Фаулер


«2» Независимость Модели и синхронизация пользовательских интерфейсов за счет шаблона Наблюдатель


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


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


«3» Разделение Пользовательского Интерфейса на Вид и Контроллер.


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


MVC


У меня сложилось впечатление, что суть этого деления мало кто понимает и соответственно может объяснить. Обычно приводят лишь стандартную обтекаемую формулировку, что Контроллер как-то реагирует на действия пользователя, а Вид отображает Модель (поэтому в большинстве реализаций именно Вид подписывается на извещения об изменениях Модели. Хотя, как уже говорилось, подписчиком может быть и Контроллер, либо Вид и Контроллер вместе).


Поскольку деление пользовательского интерфейса на Вид и Контроллер относится ко второму уровню иерархии, оно гораздо менее значимо чем первичное разделения приложения на доменную модель и интерфейс. Очень часто (особенно когда дело касается простых виджетов) оно вообще не делается и используется «упрощенный MVC», в котором имеется только Модель и единый UI-компонент, представляющий собой объединенный ВидКонтроллер. Более подробно об этом речь пойдет чуть позже.


«Архитектурный MVC» на первый взгляд выглядит вполне разумно. Но как только мы попытаемся применить его не к учебному примеру из трех классов а к реальной программе, то столкнемся с целым рядом проблем и вопросов, о которых редко пишут, но которые чрезвычайно важны. И касаются они не только пользовательского интерфейса, но и самой Модели. Так что предлагаю таки попробовать с ними разобраться и, наконец-то, "послушать Карузо", то есть обратиться к первоисточникам.


«Original MVC»: Реенскауг и SmallTalk-80


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


В общем случае Модель это один объект или множество объектов? И на самом ли деле Модель в «MVC-схеме» тождественна доменной модели, описывающей предметную область и бизнес-логику приложения?


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


Остается второй вариант — Модель это множество доменных объектов, совместно реализующих бизнес логику. Это предположение подтверждает и сам Реенскауг: "A model could be a single object (rather uninteresting), or it could be some structure of objects." Но тогда остается открытым вопрос – кто реализует шаблон Наблюдатель, откуда берет данные Вид, куда передает команды пользователя Контроллер?


И вот здесь нередко встречается попытка обмануть самих себя путем примерно следующего рассуждения: "пусть Модель это множество доменных объектов, но… среди этого множества есть в том числе и «объект с данными», вот он-то и будет реализовывать шаблон Наблюдатель, а также служить источником данных для Вида." Эту уловку можно назвать «Модель в Модели». И по сути это еще один «завуалированный» вариант того, что «Модель это данные».


Тут можно сказать лишь одно: архитектура, в которой один модуль (Вид или Контроллер), должен «лезть» внутрь другого модуля (доменной модели) и искать там для себя данные или объекты для изменения очень нехорошо «пахнет». Получается что Вид и Контроллер зависят от деталей реализации доменной модели, и если структура этой самой модели изменится, то придется переделывать весь пользовательский интерфейс.


Для того же, чтобы понять «а как должно быть» предлагаю вновь обратится к «принципам». Когда говорилось о том, что систему надо разбивать на модули, слабо связанные друг с другом, мы не упомянули главное правило, позволяющее добится этой самой слабой связанности. А именно – модули друг для друга должны быть «черными ящиками». Ни при каких условиях один модуль не должен обращаться к объектам другого модуля напрямую и что либо знать о его внутренней структуре. Модули должны взаимодействовать друг с другом лишь на уровне абстрактных интерфейсов (Dependency Inversion Principle). А реализует интерфейс модуля как правило специальный объект — Фасад.


И если поискать какие же паттерны позволяют добится слабой связанности, то на первом месте будет находится именно паттерн Фасад, и только затем Наблюдатель и тд.


Ну а теперь схема из доклада Трюгве Реенскауга:


MVC Reenskaug


Пояснение: Поскольку во времена создания MVC интерфейсы компьютерных программ были в основном текстовыми, то есть, по сути представляли собой простейший вид редактора, то вместо термина «Пользовательский Интерфейс», который появился позже, Трюгве Реенскауг использует термин «Editor» (редактор).


Таким образом, ключевая идея MVC действительно состоит в том, что пользовательское приложение делится на два модуля – один из которых моделирует предметную область и реализует бизнес логику (доменная модель), а второй отвечает за взаимодействие с пользователем (пользовательский интерфейс). Но при этом Модель в «MVC схеме» вовсе не тождественна доменной модели (которая может быть сколь угодно сложной и состоять из множества объектов), а является всего лишь ее интерфейсом и фасадом.


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


И если уж рисовать схему MVC, то выглядеть она должна следующим образом:


MVC


Давайте рассмотрим данную схему подробнее. Традиционно в клиент серверных приложениях главным считается сервер. Он предоставляет услуги/сервисы и решает в каком виде это должно быть реализовано. Соответственно интерфейс и фасад, как правило, определяются с точки зрения сервера. А клиенты под этот заданный формат подстраиваются.


На практике же более адекватной оказывается не сервер-ориентированная архитектура, а клиент-ориентированная. В ней фокус с сервера смещается в сторону клиента и интерфейс, вернее интерфейсы (и фасад или фасады), определяются исходя из потребностей клиентов. Вместо Предоставляемого Интерфейса (Provided Interface) используются Требуемые Интерфейсы (RequiredInterface).


RequiredInterface


Конкретные реализации могут варьироваться, но это не суть важно


RequiredInterface


Клиент ориентированный подход гораздо лучше соответствует Принципу разделения интерфейсов (Interface Segregation Principle) поскольку в нем вместо единого для всех толстого ProvidedInterface используется множество тонких RequiredInterface.


Если я не ошибаюсь, именно такой подход используется в архитектуре микросервисов. Там для взаимодействия с множеством сервисов введено понятие шлюза, который является ни чем иным как фасадом — “An API Gateway is a server that is the single entry point into the system. It is similar to the Facade pattern from object-oriented design. The API Gateway encapsulates the internal system architecture and provides an API that is tailored to each client. ” Building Microservices: Using an API Gateway.


Причем шлюз этот "вместо того чтобы обеспечивать общий единый для всех API, предоставляет различные API для каждого клиента (Rather than provide a one-size-fits-all style API, the API gateway can expose a different API for each client. For example, the Netflix API gateway runs client-specific adapter code that provides each client with an API that’s best suited to it’s requirements)" API Gateway.


Как мы увидим дальше клиент-ориентированный подход применялся также и в SmallTalk-80. Но вначале давайте просто пере-рисуем схему MVC с учетом вышесказанного:


MVC


Смотрим на фасад… Вот он тот самый клей (glue), объект посредник, прокси, фильтр, адаптер… связывающий между собой доменную модель и пользовательский интерфейс и поставляющий нужные данные в нужном/удобном формате.


Удивительно то, что кроме Реенскауга об этом почти никто не пишет. Хотя некоторые пере-открывают эту идею самостоятельно (пример можно посмотреть тут или тут раздел "Interface-Based Programming Techniques").


Особенно хорошо тема Моделей-интерфейсов раскрыта в статье одного из JavaGuru — Advanced MVC Patterns. Автор подчеркивает, что Модели это не данные, а исключительно интерфейсы/объекты-посредники/фильтры (Models as Proxies, Models as Filters), обеспечивающие удобный доступ к данным, которые могут находится где угодно – на разных машинах, в разных форматах: “О чем большинство программистов не думает, так это о том, что модели являются всего лишь интерфейсами. Они не должны содержать никаких данных!.. Модели-посредники расширяют охват и позволяют использовать уже существующие данные где бы они не находились”.


Из-за того что фасад, присутствующий в original MVC, был «утерян», то его роль зачастую берет на себя Контроллер. Отсюда и проистекают представления что Контроллер находится «между Моделью и Видом», служит клеем между ними и обеспечивает нужные Виду данные.


На форумах нередко встречается вопрос — "Чем контроллер отличается от фасада?". Не смотря на наивность этот вопрос вполне закономерен и на него сложно дать разумный ответ поскольку во многих MVC фреймворках Контроллер на самом деле фактически является фасадом — «Фронт-Контроллер».


Чем плохо такое решение? Если оно граммотно реализовано, то ничем. Но это в теории. А на практике нередко происходит путаница концепций и понятий и в результате Фронт-Контроллер с одной стороны злоупотребляет своими полномочиями и вместо делегирования команд начинает включать в себя реализацию бизнес логики. А с другой – продолжает одновременно выполнять функции пользовательского интерфейса и в результате в нем происходит уже упоминавшееся смешение «бизнес логики» и «GUI логики» (что собственно и делает его код похожим на огромную свалку).


Думаю, что пришло время перейти к Smalltalk. Smalltalk-80 создавался очень талантливыми людьми. С документацией в нем действительно имелись проблемы (тем более что «шаблонов проектирования» тогда еще не существовало) но вот с реализацией в основном все было хорошо и пользовательские интерфейсы, конечно же, не взаимодействовали с доменной моделью напрямую.


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


Например, для работы с кодом в Smalltalk использовались следующие GUI интерфейсы: Inspector, Browser, Workspace,…


smalltalk-80 MVC


Вот что пишет об их устройстве Glenn Krasner:


"Inspector в системе состоит из двух видов. ListView отображает список переменных (слева), а TextView показывает значение выбранной переменной (справа)… Моделью для этих видов служит экземпляр класса «Inspector»… Отдельный класс «Inspector» является посредником или фильтром для того чтобы обеспечивать доступ к любому свойству любого объекта. Использование промежуточных объектов между View и "actual" models является типичным способом изолировать поведение отображения от модели приложения...


Как и в случае Inspector, промежуточные объекты использовались также в качестве моделей для системных браузеров. Экземпляр класса «Browser» является моделью-посредником для каждого системного браузера..."


Замечание: название класса-посредника, описывающего промежуточный объект-фасад, обычно совпадало с названием отображающего его виджета. У Inspector промежуточная модель так и называлась «Inspector», а у Browser соответственно – «Browser».


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


smalltalk-80 MVC


В конце своей статьи Krasner приводит список использовавшихся в SmallTalk Моделей (наследников базового класса Model): StringHolder, Browser, Inspector, FileModel, Icon… А также отмечает что "the models were almost always some sort of filter class".


Позже в VisualWorks Smalltalk идея промежуточных Holder-ов была развита и реализована в полной мере. Там для доступа к каждой переменной, принадлежащей доменным объектам, используется свой интерфейс и фасад – ValueModel и ValueHolder. И, как не трудно догадаться, именно ValueModel реализует шаблон Наблюдатель, извещая GUI о происходящих «в домене» изменениях.


smalltalk Value-Model MVC


Типичные ошибки: обращение к доменным объектам напрямую

Поскольку на практике в любом сколько нибудь серьезном приложении сложно обойтись без фасадов, то не удивительно что во многих фреймворках и "модификациях MVC" аналоги фасада или объекта-посредника между GUI и доменной моделью пере-изобретаются под самыми разными именами. Помимо Front-Controller здесь можно упомянуть также ApplicationModel, ViewModel (подробнее см. дискуссию Model-ModelView-Controller) и Proxy-model.


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


Например, ValueHolder это, как правило, всего лишь обертка вокруг уже существующей доменной переменной, он не должен содержать данные, он содержит ссылку на данные. Вот что пишут: "ValueModel does not need to actually store the value because it is already being stored by another model" (Understanding and Using ValueModels).


А вот цитата из статьи Advanced MVC Patterns: "Одна из самых распространенных ошибок, которую совершают люди когда используют Swing компоненты, заключается в копировании данных в модели этих Swing компонент. Правильный же способ состоит в том чтобы использовать уже существующие данные, адаптируя их при помощи фильтра… Запомните: никогда не копируйте данные которые можно просто интерпретировать!".


Рассмотрим следующий простой пример. Если последовать интернет советам и для "добавления элементов в список" использовать код подобный этому (взято со StackOverflow и Adding and Removing an Item in a JList), то будет происходить как раз то самое копирование данных в модель списка:


Object[] items; // Доменный объект

DefaultListModel model = new DefaultListModel();
JList list = new JList(model);
for (int i = 0; i < items.length; i++){
     // КОПИРОВАНИЕ доменных данных в модель списка!
     model.addElement(items[i]);  
}

Правильнее, конечно же, использовать данные массива просто обернув их в интерфейс ListModel (тем более что для этих целей создана уже почти готовая AbstractListModel):


// создаем фасад-адаптер к доменным данным,
// который просто интерпретирует их нужным образом
ListModel model = new AbstractListModel() {
    public int getSize() {return items.length;}
    public Object getElementAt(int index) {return  items[index];}
};
// передаем созданный фасад списку в качестве модели
JList list = new JList(model);

И если надо объединить данные, отфильтровать или преобразовать каким-нибудь образом, то совершенно не нужны промежуточные массивы. Все делается непосредственно в модели-фасаде


Object[] items1;  Object[] items2; // Доменные объекты

// модель-фасад которая объединяет массивы
ListModel model = new AbstractListModel() {
    public int getSize() { return items1.length + items2.length;}
    public Object getElementAt(int index) {
        return index<items1.length ? items1[index] : items2[index-items1.length];
    }
};
JList list = new JList(model);

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


Ну а если хочется краткости, то тогда уж лучше так:


JList list = new JList(items);

В этом случае Джава сама сделает обертку-адаптер вместо копирования.


Типичные ошибки: копирование доменных данных в модели GUI-компонент

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


Мифы: Модель в «MVC схеме» тождественна доменной модели и данным

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


Но в контексте шаблонов и схем Модель это прежде всего интерфейс и реализующий его объект-посредник (фасад, адаптер, прокси) обеспечивающие удобный и безопасный доступ к доменным данным, которые могут находится где угодно. Реенскауг так и писал: "model object with a façade that reflects the user’s mental model".


Когда MVC преподносится исключительно как «схема», то наличие «промежуточных моделей» кажется сложным и запутанным. Появляются вопросы ("Чем эти модели отличаются друг от друга?", “Как их правильно использовать?”), неоднозначные трактовки и множество возможностей сделать ошибку.


Но если понимать заложенные в MVC архитектурные идеи, то все становится предельно ясным: пользовательский интерфейс не имеет права обращаться к объектам доменной модели напрямую. А значит между доменной моделью и пользовательским интерфейсом должнен находиться фасад/посредник/адаптер..., и взаимодействовать пользовательский интерфейс (Вид и Контроллер) может только с ним. Возможностей сделать ошибку – ноль.


И по большому счету становится все равно каким термином этот объект-посредник называется и какая именно Model-View-Whatever разновидность MVC используется… Начинаешь видеть: какая задача решается, с помощью каких шаблонов и то, насколько хорошо или плохо это делается


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

@cobiot
карма
78,0
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

Комментарии (387)

  • +2
    Я когда-то для своих целей разработки, безотносительно пользовательских интерфейсов — изобрёл для себя модель, которую потом стал называть условно «MVC», хотя это, скорее, «MVDC» — модель-вид-данные-контроллер.
    В ней «Модель» — это данные в ОЗУ, объект, скорее всего составной, возможно содержащий в себе множество объектов (список, коллекцию).
    «Вид» — умеет отображать на экране «Модель», берёт некое «стандартное представление» и отрисовывает его на экране.
    «Данные» — занимаются вводом/выводом из/в файлов, умеет преобразовывать файл в «стандартное представление модели» и наоборот,
    При этом общение все трёх компонентов идёт через интерфейсы, которые, собственно, и оказываются наиболее «неподвижной» частью приложения.
    При этом все три указанные части являются пассивными — а единственной активной частью программы становится Контроллер.
    Контроллер сам не имеет внутренней памяти, не имеет состояний, за исключением «системных» — например, если приложение может работать в нескольких режимах — и занимается только вызывает соотв. методы интерфейсов прочих компонентов.
    • +2

      В силу того, что сказано в посте, надо бы вам определения M и D поменять местами :)

      • 0
        Я бы сказал, что у меня было MCVD. ))
        (Т.е. программы я привык выстраивать вокруг данных в памяти + контроллер, пристраивая остальное «вокруг» этой сладкой парочки. вплоть до того, что контроллер мог сливаться с моделью — в ООП это будет означать, что «Модель» — это поля корневого объекта данных, а «Контроллер» — это его методы. ))
  • +3
    Жду вторую часть
  • +2
    впечатление от статьи: «хорошо, что я познакомился с MVC по Qt»
  • +1
    Спасибо, помогли прояснить некоторые моменты. Например, стало понятно, что контроллер вообще не нужен если используются продвинутые умные элементы управления в представлении, которые сами по себе могут реагировать на уведомления и посылать стандартные команды в модель (например как в WPF/UWP с использованием MVVM).
    • +8
      ) именно по этому в MVVM и нет буковки C. © Кэп
  • +2
    В ходе размышлений о MVC, я пришёл к выводу, что, то MVC что в вебе, можно выделить в отдельную ветвь как минимум по способу работы с событиями. Если в графических приложениях у нас происходит множество событий, и на них должны реагировать множество представлений, то в серверном MVC есть одно событие — http запрос. Второго события, на которое могут реагировать представления просто нет. т.к. как такового объекта представления, который живёт в течение нескольких событий не существует.
    • 0
      А как же всевозможные SPA и просто страницы с большим количеством динамического контента, где различные запросы отправляются на сервер по AJAX и потом меняют отдельные элементы страницы (представления)?
      • 0
        Сервер-то тут при чем? В случае HTTP он просто отвечает на запросы.
        • 0
          Я невнимательно прочитал комментарий.

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

      • 0

        С точки зрения серверной части, AJAX — это такой же http-запрос.

    • +3
      в серверном MVC есть одно событие — http запрос


      А потом мы делаем вебсокеты…
      • 0
        А потом мы делаем вебсокеты…

        а пользователь открывает это в IE 6 )))
        • 0
          В мире, где существует IE 6, вполне себе существуют и вебсокеты.
          • 0
            Веб-сокеты это не HTML5 разве? С миром вэба редко пересекаюсь, мог что-то упустить.
            • 0
              Веб-сокет — это протокол передачи данных поверх TCP. Он не имеет никакого отношения к HTML5.
              • 0

                Веб-сокет — это еще и API, которое должен поддерживать браузер. IE поддерживает веб-сокеты только с 11й версии.

              • 0
                Ну значит меня обманул тов. Мэтью Мак-Дональд в книге «HTML5 недостающее руководство» от 2014 года, в которой он написал, что Веб-сокеты появились в HTML5, но
                … она (технология веб-сокетов, прим. моё) ещё надохится в процессе развития и не имеет хорошего уровня браузерной поддержки. Изначально технология была добавлена в браузеры Firefox 4 и Opera 11, но была удалена через несколько месяцев в связи с проблемой потенциальных нарушений безопасности.
                ©
                • 0
                  Что там курит товарищ Мак-Дональд? WebSocket — это протокол передачи данных поверх TCP, как и HTTP. HTML (5) — это язык разметки, т.е. всего лишь специальным образом структурированный текст, который может передаваться с помощью любого протокола. Браузер — лишь один из возможных участников обмена данными по этому протоколу. А http://learn.javascript.ru/websockets — всего лишь один из возможных API для использования WebSocket и мне совершенно непонятно, какое отношение он имеет к HTML.

                  Это ж какую кашу в голове надо иметь, чтобы написать в книжке, что Веб-сокеты появились в HTML5. Он бы еще сказал, что они появились в JSON.
                  • 0

                    Ну и как вы будете подключаться к веб-сокету из шестого IE?

                    • 0
                      В огороде бузина, а в Киеве дядька. Может, я вообще не поддерживаю IE 6: здоровье дороже, чем полпроцента юзеров. А может, я использую какую-нибудь либу, которая эмулирует веб-сокет для IE 6. Впрочем, какое отношение это имеет к тому, что WebSocket — протокол передачи данных, а HTML — язык разметки?
                      • 0

                        Раз вы пытаетесь цепляться к словам — вот вам:


                        Стандарт HTML5:
                        4.11 Scripting
                        6 Web application APIs


                        Конкретно про веб-сокеты — HTML Living Standard:
                        9.3 Web sockets

                        • –1
                          По первым двум ссылкам не нашел слово «socket».

                          Третья — это вообще что? Какое отношение имеет к W3C?
                      • +1
                        WebSocket не только протокол передачи данных, но и название JavaScript API, входящего в семейство HTML5 API. Да, HTML тоже не только язык разметки. Даже стандарт HTML 4 специфицировал отображение сущностей языка HTML на DOM API.
                  • 0
                    всего лишь один из возможных API для использования WebSocket и мне совершенно непонятно, какое отношение он имеет к HTML.

                    https://developer.mozilla.org/en/docs/Web/Guide/HTML/HTML5
                  • 0
                    что Веб-сокеты появились в HTML5

                    Есть такая штука как HTML5 API. Это просто группа стандартов. Стандарт самого HTML включен в него же. Как и API для работы с DOM например.

                    • 0
                      Ок, каюсь, был сбит с толку названием.
              • –2

                Я бы и про "поверх tcp" поспорил, т.к. ничего не мешает вебсокетам работать поверх udp или unix socket, т.е. "Веб-сокет — это протокол передачи данных."

                • +1

                  Реализацию веб-сокетов поверх UDP не подскажите?

      • +1
        Да, но пропаганда «пишем сайт на php используя MVC» не затрагивает тему вебсокетов.
        • 0
          Но в целом никак ей не противоречит. У нас «сайт» (приложение) на PHP c MVC и веб-сокетами. Просто ещё один тип событий веб-сокеты. На самом деле четвёртый: первый — http-запрос, второй — cli-команда, третий — amqp событие (пуллинг по хрону), а потом и веб-сокеты прикрутили, причём в двух вариантах — через прослойку на node.js и нативно. В ближайших планах честный пушинг amqp. Приложению как таковому (инфраструктуре и бизнес-логике) абсолютно всё равно откуда пришло событие «пользователь такой-то прислал данные о новом(ых) платеже(ах)», оно абстрагируется от канала поступления на самой ранней стадии обработки и дальше идёт по единому маршруту.
      • 0

        давайте подумаем что это меняет.


        1. простая модель — запрос/ответ.

        Ну то есть мы посылаем на сервер какой-то ивент и получаем ответ. Собственно все. Просто другой транспорт но модель выполнения абсолютно такая же как и в случае с http.


        1. Подписка на изменения данных.

        Вот тут уже интереснее. Мы получаем какое-то событие о том что мы хотим подписаться на изменения, ну например баланса. Сервер при операциях с балансом будет кидать ивент о том что "воу у нас стэйт поменялся" а какой-то объект будет отслеживать эти события и формировать представление для клиента. Тут уже похоже на MVC c вью которое постоянно обновляет представление стэйта модели.


        Но опять же, это вопрос не транспорта а того что нам нужно сделать.

    • 0

      Поэтой причине на бэкэнде хорошо себя показывает такой вариант как Model-View-Adapter. То есть есть некий адаптер между HTTP и приложением, который занимается обработкой "событи" и конвертирует их в какое-то действие в приложении. Так же результат работы приложения конвертируется в HTTP ответ. Ну и т.д.

      • +1
        Не расскажете поподробней о Model-View-Adapter?
        • 0

          https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93adapter


          То есть идея такая. У вас есть View и есть Model. И они друг о друге ничего не знают. То есть одно и то же View может работать с разными моделями просто за счет смены адаптеров. Ну и наоборот. Одна и та же модель может иметь несколько видов представлений в зависимости от адаптера между ними.


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

          • 0
            Мне немного напоминает MVP, или ошибаюсь?
          • 0
            Практический смысл это может иметь в случае, если объекты (скорее модели чем адаптеры) реализуют один интерфейс. И тогда у нас вью уже кое что знает о модели или адаптере. И тогда возникает вопрос — какая разница, где гвозди прибивать?
            • 0
              Практический смысл это может иметь в случае, если объекты (скорее модели чем адаптеры) реализуют один интерфейс.

              Можете пояснить? Ибо у них могут быть разные интерфейсы. Просто между каждой парой view — model будет свой адаптер или цепочка адаптеров.

  • 0
    Перечеркнутой линией обозначена необязательная связь Контроллера с Видом.

    Это как?
    Может V и M?
    • 0

      Вы картинку-то смотрели? Вариант "без связи между V и M" — он на отдельной схеме расположен. Слева же связь между V и M есть, а между контроллером и видом — опциональна.

      • 0
        Так я и смотрел. Поэтому и спросил. :)

        В вебе контроллер практически всегда вызывает рендеринг вида явно (я не говорю, что это правильно). :)
        А вот вид практически никогда не лезет в модель сам.
        • 0

          MVC — это не только веб.

        • 0
          Вид очень часто лезет в модель. Передает контроллер виду объект $user, а вид лезет в него запросами типа $user->getName()
          • 0
            необязательная связь Контроллера с Видом

            Передает контроллер виду
            • 0
              Необязательная в теории не значит не существующая на практике.
              • 0
                на практике пытаться фанатично трактовать MVC чревато, вы и сами думаю знаете.
    • 0
      Простите, не очень понятен вопрос. Там прямо под картинкой цитата Фаулера «на самом деле Вид и Контроллер могут быть связанными друг с другом непосредственно. Однако, разработчики в основном не используют эту связь»

      А если интерисует «физический смысл», то это когда во время работы приложения одни виды сменяют другие (открываются, закрываются) и считается что всем этим ансамблем управляет контроллер
    • 0
      Простите, не очень понятен вопрос. Там прямо под картинкой цитата Фаулера «на самом деле Вид и Контроллер могут быть связанными друг с другом непосредственно. Однако, разработчики в основном не используют эту связь»

      А если интерисует «физический смысл», то это когда во время работы приложения одни виды сменяют другие (открываются, закрываются) и считается что всем этим ансамблем управляет контроллер
  • –8
    Но обычно, под MVC все таки подразумевают вариант с Активной Моделью.

    Хм, а в вебе обычно пассивные модели. :) Страничка отдалась и все. Ничего в ней больше не меняется. :)

    Независимость Модели является главным в MVC.

    Независимость приветствуется везде… :)

    Вся бизнес логика приложения, то есть большая часть кода, сосредотачивается в Контроллере и это при том что как раз Контроллер является самой зависимой частью в MVC – в общем случае он зависит и от Модели и от Вида.

    Почему же?
    Есть API — используйте его.
    Хотите, поместите некоторую логику в модель — и так само используйте API.
    Зависимости от M нету, так как M — пустая.
    Как вообще может быть зависимость от V?

    Отсюда и появился термин ТТУК — толстый тупой уродливый контроллер

    Другой вариант — толстая тупая уродливая модель. :)

    в Контроллер помимо всей бизнес-логики приложения помещается также еще и логика управления пользовательским интерфейсом

    Что это вообще такое? :)

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

    Прекращайте дрочить на ООП.
    MVC возможно не только на ООП головного мозга.

    Данных нету. Вокруг сферические объекты. Буквы — это тоже объекты.

    Второй подход гораздо ближе к первоисточникам.

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

    Мартин Фаулер абсолютно прав, когда говорит что MVC это не паттерн

    Та это вам все адекватные люди говорят. Но вы же кастрюли на голову оденете и как носороги упираетесь.

    «1» Отделение модели предметной области (бизнес логики) приложения от пользовательского интерфейса

    В называемом вами классическом это тоже есть.

    «2» Независимость Модели и синхронизация пользовательских интерфейсов за счет шаблона Наблюдатель

    К вебу имеет слабое отношение…

    Очень часто (особенно когда дело касается простых виджетов) оно вообще не делается и используется «упрощенный MVC»

    И выходит черти что. Каша из php и html.

    То, что Модель реализует шаблон Наблюдатель явно указывает на то, что Модель это именно один объект.

    В один класс пихать методы для работы с БД и бизнес-логику? Перемога.

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

    если внесем какие угодно изменения в бизнес логику приложения, но при этом оставим неизменным интерфейс-фасад, то ни Вид, ни Контроллер это никак не затронет.


    Хм.
    Предположим, что у нас нет фасада.
    Глупо же было из-за изменения движка базы менять шаблоны? :)

    Причем шлюз этот «вместо того чтобы обеспечивать общий единый для всех API, предоставляет различные API для каждого клиента


    Это же так классно поддерживать несколько API :)

    Автор подчеркивает, что Модели это не данные, а исключительно интерфейсы/объекты-посредники/фильтры

    Вообще-то да.

    обеспечивающие удобный доступ к данным, которые могут находится где угодно – на разных машинах, в разных форматах

    Программисты на фреймворках понимают это так, что модели остаются ходилками в БД, поверх которых навешали мусора. :)

    Типичные ошибки: копирование доменных данных в модели GUI-компонент

    Хм.
    Но если мы имеем дело с объектами, то они передаются по ссылке.
    А как же как быть, когда нам нужны данные из 2 моделей?
    А нагружать этой логикой V не хочется. Проще эти данные объединить в С.

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

    +100500
    Но пропагандисты фреймворков ведут людей по быстрому пути :)

    Поэтому, если есть те, кому интересно и «не надоело», то пишите и я выложу вторую часть полностью посвященную именно этой теме.


    Конечно же, выкладывайте.

    В общем первая часть статьи (первая часть того, что выложено, а не вся статья) — ничего нового. Такие самые заблуждение, как и везде, в частности и на хабре.

    А вторая часть — грамотная.

    MVC — это всего лишь разделение кода на уровни.
    Разделять нужно с умом. А не делать так, как пишут идиоты в интернете.
    Есть необходимость — вынесли что-то в отдельный класс, нету — не вынесли.

    Дополню:
    Если логика примитивная и нужна только одному контроллеру, то ее все же можно оставить и в контроллере.
    Но не в виде ни под каким предлогом.
    • +1
      Программисты на фреймворках понимают это так, что модели остаются ходилками в БД, поверх которых навешали мусора. :)

      Бред. Мои модели ничего о БД вообще не знают. Ходилка в БД работает поверх них.
      Но пропагандисты фреймворков ведут людей по быстрому пути :)

      К фреймворкам это не имеет никакого отношения. Можно с фреймворком преобразовывать доменный объект в какой-то DTO или прятать его прокси/адаптером/фасадом, а можно без него не преобразовывать и вообще из шаблона в базу писать.
      Но не в виде ни под каким предлогом.

      А если логика нужна виду? Банальное: список каких-то значений пустой — выдать параграф «нет данніх», не пустой — відать список.
      • +1
        Бред. Мои модели ничего о БД вообще не знают.

        Вы молодец. :)
        Если бы все были такими, то и статьи не было бы. :)

        К фреймворкам это не имеет никакого отношения.

        Самое непосредственное.

        Почти вся разработка сейчас или на фреймворках, или на CMS.

        А если логика нужна виду? Банальное: список каких-то значений пустой — выдать параграф «нет данніх», не пустой — відать список.

        Та пишите.
        Получите то, от чего начали:
        Мешанина php и html. :)

        Но спасибо хоть ответили, а не как некоторые :)
        • 0
          Самое непосредственное.

          Почти вся разработка сейчас или на фреймворках, или на CMS.

          Да без разницы на чём она. не зависит от использования фреймворка отдавать во вью или контроллер объект модели или прятать его за прокси/адаптерами/фасадами или, как вариант, давать дто.

          Та пишите.
          Получите то, от чего начали:
          Мешанина php и html. :)

          Есть шаблонизаторы вообще. Так или иначе логика того что и как показывать (например одни сообщения красным, другие зеленым) должна быть в виде, а не в контроллере или модели.
          • +1
            Да без разницы на чём она

            Да, без разницы на чем.
            Только пропагандисты фреймворков предлагают быстрый путь вместо правильного. :)

            Есть шаблонизаторы вообще.

            Ну тогда в шаблонизаторе будете в базу лазить. :)
            Это уже будет не совсем шаблонизатор. :)

            Хотя я не против вызова из шаблона других виджетов / контроллеров / шаблонов.
            Только это только вызов, без логики обработки данных.

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

            Это ж другое.
            Такая логика уместна в шаблоне. :)
            • 0
              Ну так суть MVC в чём — каждой логике своё место, а не что в виде, например, не должно быть никакой логики.
            • 0

              Вы зря обобщаете «пропагандистов фреймворков». И вообще: кто они, єти пропагандисты?

            • +1

              Логика присутствует на всех уровнях. Просто она разная. А вы передёргиваете.

              • –1
                Вы троль?
              • +1
                Полностью согласен.

                К тому же логика должна присутствовать и в наших рассуждениях. Так, например, когда нужны данные из двух моделей, все обращения к другим моделям происходят из основной модели, соответствующей текущему контроллеру. Иначе опять происходит переползание логики предметной области в контроллеры. ИМХО.
                • +1

                  И эта "основная модель" будет являться корнем агрегата сущностей или сервисом.

    • 0
      Если логика примитивная и нужна только одному контроллеру, то ее все же можно оставить и в контроллере.
      Но не в виде ни под каким предлогом.

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

  • +3
    Спасибо, виден системный подход. Жду продолжения.

    Типичные ошибки: обращение к доменным объектам напрямую

    Часто использую в виде передачи в вид через контроллер доменных объектов (сущностей и объектов-значений), но не считаю это ошибкой в общем случае, а просто оптимизацией своего труда — в большинстве случаев создание отдельных фасадов будет заключаться в написании кучи геттеров типа FacadeObject::getSomeValue() {return $this->domainObject->getSomeValue();}. Да, оно изолирует доменный объект от вида и контроллера, не допускает даже в теории (без хаков типа рефлексии) изменение доменных объектов, но в большинстве случаев, имхо, эта изоляция не стоит потраченного времени и усложнения кода, если соблюдать дисциплину — не дергать в виде и контроллере методов объектов, изменяющих их состояние и только в контроллере дергать сервисы, изменяющие состояние домена. В каких-то языках, возможно, помог бы её соблюдать модификатор доступа типа friendly, но в PHP его нет, а в JS вообще модификаторов нет толком.

    Ну и фронт-контроллер отвечает у меня за инициализацию приложения (в PHP) и роутинг пользовательских событий в отдельные контроллеры, которые инициализируют доменную модель для реакции на событие UI, дергают сервисы, передают, если нужно часть данных доменной модели в вид для отображения (в PHP, в JS вид слушает события модели) и сохраняют изменения доменной модели. То есть контроллеры обеспечивают не только UI, но и инфраструктуру для доменной модели, в частности обеспечивают персистентность её данных.

    Сама же доменная модель зависит только от объявленных в ней же абстракций, которые контроллеры заполняют конкретными инфраструктурными реализациями. Иногда, конечно, абстракции текут (прежде всего из-за трудоемкости полной абстракции от инфраструктуры хранения данных), но в целом считаю, что у меня удачный компромисс между стремлением всё сделать по науке и практическими требованиям заказчика прежде всего к скорости разработки. Главное, соблюдать дисциплину и внимательно следить когда действительно пора вводить дополнительный слой абстракций и делить существующую на несколько для изоляции и уменьшения связанности.
    • 0
      внимательно следить когда действительно пора вводить дополнительный слой абстракций

      +1
      Тут преждевременная оптимизация не нужна. :)
  • +1
    Если не по теме, игнорируйте.
    Есть приложение, не веб, десктопное, которое общается с базой данных. Вся бизнес-логика вынесена в хранимые процедуры (или функции в терминах Postgre). Насколько я понимаю, это толстая модель данные+бизнес-логика. В приложении нет ни одного прямого select, insert, update, delete. Соответственно на каждое действие есть соответствующая процедура, с правами для каких-то групп пользователей. Вроде бы всё логично.

    Но попытка узнать, как части этого приложения перенести в веб интерфейс (интранет), натыкается на какое-то фундаментальное непонимание меня веб-программистами. Начиная с того, что авторизацию в таком веб-приложении нельзя делать на основе авторизации в базе данных (пустили в БД, пользователь вошёл, не пустили, не вошёл). Заканчивая тем, что у меня «неправильно» организованы данные, функциями никто не пользуется и права так раздавать нельзя. А разделением прав будет заниматься некая прокладка фреймворка, а все пользователи приложения, в БД будут логиниться под одним пользователей (условным web_user). Так как знаний у меня не достаточно, оценить полный спектр технологий/фреймворков и самое главное структуру такого веб интерфейса я не могу.
    Читая статью, мне показалось, что моя идея имеет права на существование. Я не прав?
    • 0
      А как в десктопном приложении аутентифицируются пользователи? Каждому заведена учётка в СУБД и её данные вводят? В вебе так же предлагается? Делать так можно, просто у многих разработчиков на фреймворках/cms нет знаний как это делать, прочитали когда-то в туториале как настроить соединение с базой с пользователем и паролем из конфига и всё.
      • 0
        Да, учётные данные в БД. Пользователи, которые распределены по ролям, так как на каждый чих (действие) есть процедура, то правами управлять просто. В вебе (конечно с учётом того, что это внутренняя сеть, и соединений будет до 1000) хотелось бы так же, чтобы не плодить сущности, и не заниматься раздачей прав с нуля.
        • 0
          Компромисс — пользователи авторизуются в фреймворке его средствами, там же им назначаются роли, а для каждой роли фреймворк ходит под отдельным пользователем БД, условные web_manager, web_accounter, web_admin, web_director, которым в базе назначено по одной роли. Фреймворк выбирает нужную пользователю роль и от её имени стучится в базу. Во многих фреймворках это делается с минимум разработки, в основном только конфиги написать под каждую роль. Минус — стандартными средствами СУБД не сделать бизнес-логирование, надо дописывать в функции параметр «пользователь» и использовать его (если пустой, то пользователя БД).
        • 0

          Зачем 1к конектов к бд, когда есть persistent connections?
          Что делать когда юзеров станет не 1к, а 10к, 100к. Столько одновременных коннектов уже субд не вытянет.
          Авторизачия через бд весьма узкий кейс, который фреймворками не предусмотрен. Кроме того, не дает каких-либо плюсов по сравнению с классической авторизацией через приложение.

          • 0
            Плюс — управление пользователями и логирование их действий стандартными средствами СУБД. На уровне СУБД исключается ситуация, что какие-то даные увидит, изменит или удалит тот, кто не должен с градацией вплоть до отдельных столбцов.
            • 0

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

              • +1
                Так я как раз и не думаю, о том, кто и что может увидеть или не может, я один раз добавляю пользователя в роль. Всё. Дальше всё по умолчанию нельзя (нет прав на исполнение процедуры). Дальше, самое страшное что может произойти, это пользователь не сможет что-то сделать, или увидеть.
                Вся логика в приложении это круто. Поменять условия выборки — поменяй код. Поменялись проверки — поменяй код. При этом надо заставить всех пользователей перезапустить приложение. Громоздкие SQL запросы в коде. Зачем? Если сейчас я чуть меняю хранимую процедуру (параметры передаются те же) и у всех всё работает по-новому. Не говоря уже о фантазиях сделать приложение под другую платформу (веб, macOS).
                • 0

                  Веб-приложения не надо перезапускать. И код обычно меняется проще, чем схема БД.


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

                  • 0
                    Перезапускать не надо, только если в клиентской (браузерной) части нет логики, так?

                    А про неограниченный доступ к БД с рабочих мест — а какая альтернатива в вебе? Если мы говорим про приложение, которое работает только с БД, и только после авторизации. Зачем какой-то дополнительный компонент авторизации, если уже всё есть – можно/нельзя войти проверяет сервер БД.
                    • 0

                      Клиентскую часть перезапускать не надо, если не менялся API.


                      Зачем какой-то дополнительный компонент авторизации, если уже всё есть – можно/нельзя войти проверяет сервер БД.

                      1. Потому что так проще (процедурные расширения SQL — не самые простые языки программирования). Возможно, для вас это не так. Но не стоит обобщать свой опыт на весь мир.


                      2. Потому что веб-сервер может держать больше соединений чем сервер БД.


                      3. Сервер БД не умеет идентифицировать пользователя через WS-Federation или OAuth/OpenID.


                      4. Если доступ пользователя к столбцам в БД настраивается довольно просто — то доступом к строкам управлять вам придется вручную, и никакие фреймворки тут не помогут.


                      5. Вам придется городить знатные велосипеды, чтобы передать из БД уведомление об изменении данных.

                      А про неограниченный доступ к БД с рабочих мест — а какая альтернатива в вебе?

                      Доступ к БД только от веб-сервера, конечно же. Пароль никому не сообщать, порт закрыть файерволом или биндить на loopback.

                      • 0
                        1. «Проще», это вот опять, сложный вопрос. Я до сих пор не понимаю какой комплект технологий (на сервере и клиенте) мне нужен, чтобы просто вытащить в веб-интерфейс справочник из двух полей. Так чтобы легко добавлять/изменять/удалять данные прямо в гриде.

                        2. Мне не актуально, правда.

                        3. Аргумент, но наверное не для внутреннего использования.

                        Я бы с удовольствием обменялся опытом, проектировал бы БД, за еду обучение веб-подходам в очень узкой области)
                        • 0
                          «Проще», это вот опять, сложный вопрос. Я до сих пор не понимаю какой комплект технологий (на сервере и клиенте) мне нужен, чтобы просто вытащить в веб-интерфейс справочник из двух полей. Так чтобы легко добавлять/изменять/удалять данные прямо в гриде.

                          На клиенте: HTML + CSS + jquery или какая-нибудь библиотека для двусторонней привязки данных (KnockoutJs или AngularLight).


                          На сервере: PHP или другой язык, пригодный для веб-программирования (C#, Java, Ruby, Python).


                          Самым сложным тут будет — избежать отправки на сервер справочника целиком (что чревато конфликтами при одновременном редактировании). Если справочник редактируется монопольно — то задача вообще простейшая, иначе надо будет отслеживать какие строки пользователь менял, а какие — нет.


                          Я бы с удовольствием обменялся опытом, проектировал бы БД, за еду обучение веб-подходам в очень узкой области)

                          Да я и "за так" вам про веб-подходы расскажу. Но лучше все-таки это делать на http://ru.stackoverflow.com/, а не в комментариях к случайному посту на хабре.


                          Аргумент, но наверное не для внутреннего использования.

                          Для внутреннего использования неплохо заходит авторизация через Active Directory (которая на самом деле Kerberos, не путать с авторизацией через LDAP!). И она, насколько я знаю, из всех СУБД работает только с MS SQL Server.

                  • 0
                    Хранить пароли не обязательно в открытом виде и вообще хранить не обязательно. Можно хранить зашифрованными (не путать с захешированными), можно передавать с каждым запросом и даже тоже зашифрованным.
                • +1

                  Ну так и с логикой в коде так же. Один раз назначили пользователю роль и все. С этой стороны разница только в том, что они хранятся в таблицах типа user и role, а не в системных.
                  С коннектом напрямую в БД проблема в том, что подключенный пользователь имеет доступ ко всем средствам SQL, поэтому надо по умолчанию ограничивать права на всё.
                  С доступом через веб-приложение немного попроще — если приложение не предоставляет возможность для отображения таблицы транзакций, то никто их и не прочитает, без всякой проверки прав. А если предоставляет, то можно например id пользователя добавлять в каждый запрос, чтобы он только свои видел.


                  Если сейчас я чуть меняю хранимую процедуру (параметры передаются те же) и у всех всё работает по-новому. Не говоря уже о фантазиях сделать приложение под другую платформу (веб, macOS).

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

          • +2
            1к соединений, это потолок в данном случае, в реальности речь про сотни. 10к и 100к не будет. В чём узость авторизации через БД, я не понял. Плюсы выше про раздачу прав один раз. Равно как, и например, удаление пользователя. В одном месте удалил и не думаешь, откуда и как он ещё мог зайти.
          • 0
            Я, честно говоря, давно не интересовался вэб-программированием, но «кейс фреймворками не предусмотрен» звучит странно. Почти как «стандартная библиотека моего любимого языка программирования не предусматривает умножения матриц». Неужели в мире вэба свет окончательно сошелся на фреймворках, и на чистом php уже никто не хочет даже просто «пообщаться с БД»?
            • 0
              Логично, что фрймворки пишуться так, чтобы покрыть самые частые способы использования. И решить самые частые проблемы. И да, я не знаю ни одного фреймворка, который бы авторизовал юзеров посредством бд. Но это не значит что этого нельзя сделать или это сложно сделать. Просто это нужно крейне редко.

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

                Symfony c Doctrine позволяют это делать, причём на уровне конфигов.
                • +1

                  Эм… это как? Ну то есть, там аутентификация на стороне php происходит, с хэшированием пароля через password_hash и т.д. Да и Doctrine тут не причем, просто есть дефолтный entity user provider.

                  • 0
                    Это без использования механизма аутентификации Симфони. При создании Doctrine подключения к базе данных, брать параметры не из parameters.yml, а из request. Тупо не аутенфицировался — ошибка подключения, запросил процедуру/вью без необходимых (на уровне БД) прав — ошибка исполнения запроса.
                    • 0

                      Это из коробки?

                      • 0
                        не представляю как. Ведь контейнер билдится один раз на проде и подменить уже ни чего нельзя… Разве что конструировать ентити менеджер самому
            • +2
              Неужели в мире вэба свет окончательно сошелся на фреймворках, и на чистом php уже никто не хочет даже просто «пообщаться с БД»?

              В целом да. Более того, это считается дурным тоном для большинства задач. Уж как минимум, соединение должен настроить фреймворк по конфигам. Справедливости ради, нормальные фреймворки позволяют и соединение устанавливать с динамическими параметрами, но большинство разработчиков на них, наверное, даже не знают как это делать, из голого ПХП знают как, а в воркфлоу фреймворка как заинжектить динамику не знают, привыкли к «магии».
            • –2
              Неужели в мире вэба свет окончательно сошелся на фреймворках

              Не везде, но фреймворки доминируют.
              Разработчики то ли обленились, то ли отупели, то ли тупыми и были, то ли не хотят брать на себя ответственность. :) Бла-бла-бла.
              Много свежей крови, которая кроме фреймворков ничего не умеет.
              Поколение программистов, не умеющих программировать на языке, на котором написан фреймворк :)

              а в воркфлоу фреймворка как заинжектить динамику не знают, привыкли к «магии»

              Но фреймворки тоже толком не умеют. :)

              Ну такое.

              Давайте, вахтеры, минусуйте. :)
              • 0
                Разработчики то ли обленились, то ли отупели, то ли тупыми и были, то ли не хотят брать на себя ответственность. :)

                Обленились, да. Хороший разработчик — ленивый разработчик. Он не будет писать сотни раз один и тот же код в разных проектах. И даже один раз писать и потом копипастить или подключать не будет, если знает, что есть готовое решение. Это только люди с синдром NIH пишут всё сами, начиная чуть ли не с BIOS.
                • +1
                  Хороший разработчик — ленивый разработчик

                  Согласен.

                  если знает, что есть готовое решение

                  Вот только пользоваться фреймворками люди не умеют.
                  Вы же сами это говорили. :)
                  Да и MVC унылый на фреймворках, как показала статья и комменты. :)

                  Это только люди с синдром NIH пишут всё сами, начиная чуть ли не с BIOS.

                  Есть понятие unix-way.
                  Фреймворк — это швейцарский нож, которым никто не умеет пользоваться :)

                  Это разве нормально, что программист на фреймворке языка не знает языка и не умеет программировать? :)

                  Хотя да, разные программисты нужны. :)
                  • +1
                    «Не хочет писать SQL-запросы вручную» не означает «не умеет программировать».
                    • 0
                      «Не хочет писать SQL-запросы вручную» не означает «не умеет программировать».

                      Карл, а где я такое говорил?.. :)
                      • 0
                        Вы так хотите, чтобы вас носом ткнули? Примерно вот здесь:
                        Дело в том, что в объектно-ориентированном приложении нет данных, а есть множество объектов и каждый из них содержит какие-то данные и методы работы с ними.

                        Прекращайте дрочить на ООП.

                        Если вы предлагаете не использовать объекты, по которым запросы к базе данных строятся автоматически, значит предлагаете использовать запросы вручную и массивы.
                        • –2
                          Это все ваши домыслы.
                          Вон из профессии.
                  • +5
                    Вот только пользоваться фреймворками люди не умеют.

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


                    Да и MVC унылый на фреймворках, как показала статья и комменты. :)

                    MVC это buzz-word. В целом например фэйсбук со своим flux подошел очень грамотно. Они просто переименовали вещи и отгородились от общей концепции. Что бы меньше конфликтов вызывало в понимании.


                    Фреймворк — это швейцарский нож, которым никто не умеет пользоваться :)

                    Посмотрите на современные фреймворки. Как правило они состоят из набора готовых самодостаточных компонентов. Обычно есть стандартная сборка этих компонентов которая и именуется фреймворком. Но никто не мешает вам брать и использовать другие компоненты.


                    Есть правда чуть другой вид фреймворков. Они ориентированы на то чтобы дать разработчику не конструктор, из которого он может собрать что ему надо и заменять детали, а скорее платформу. Тот же RoR, Yii и подобные монолитные фреймворки идут именно по этому пути. У этого подхода есть как свои минусы так и плюсы.


                    Есть понятие unix-way.

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


                    Это разве нормально, что программист на фреймворке языка не знает языка и не умеет программировать? :)

                    Нет, не нормально. Бизнес логика приложения по хорошему не должна быть завязана на язык. Так же есть такая проблема среди разработчиков что если они выбирают один конкретный инструмент, то пытаются потом задачи подгонять под него же. Например ORM. Это хороший инструмент когда нам надо сделать что-то с каким-то небольшим набором данных. Провести бизнес транзакцию. Но многие начинают впадать в крайности и пытаться тем же ORM решать вопросы репортов, сложных выборок и т.д. Это не означает что "ORM не нужны", это означает что люди любят зацикливаться и не особо хотят думать.

                    • 0
                      Если вы дадите разработчику голый PHP выйдет скорее всего хуже. Ну то есть тут проблема не в том что люди не умеют пользоваться фреймворками, а в целом не умеют или не хотят думать что они делают.

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

                      ЦА фреймворков — плохие программисты? :)

                      Культ карго, эффект Даннинга-Крюгера и т.п.

                      А, ну это да. Странно только, что он так сильно распространен среди программистов или «программистов» :)

                      Они просто переименовали вещи и отгородились от общей концепции.

                      Ерунда какая-то :)

                      Как правило они состоят из набора готовых самодостаточных компонентов. Обычно есть стандартная сборка этих компонентов которая и именуется фреймворком.

                      1. Только не все умеют эту сборку готовить :)
                      2. А что должно быть во фреймворке, если выбросить все компоненты?

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

                      Хм, но общение может быть организовано посредством какой-то шины :)

                      Очень часто когда люди кричат «фреймворки не нужны»

                      Правильней «фреймворки не всем нужны» :)

                      Но многие начинают впадать в крайности

                      Об этом и речь, что не нужно впадаться в крайности. :)

                      Что еще скажу: если человек понимает, что он делает, и знает где что лежит, то плевать, что кто-то считает, что он делает неправильно. :)

                      Хотя в крайности тут тоже впадать не нужно.
                      Я вот раньше писал плохо отформатированный код :) Но мне он был понятен :) А сейчас самому противно смотреть на такой код. :)
                      • +2
                        Выходит парадокс :)
                        Для того, чтобы нормально пользоваться фреймворком, нужно быть хорошим программистом.
                        Но хороший программист может обойтись и без фреймворка.
                        А плохие программисты не могут нормально пользоваться фреймворком.
                        Но без фреймворка будет еще хуже. :)

                        Нет парадокса.
                        Хороший программист может обойтись без фреймворка, но хорошо подходящий под задачу фреймворк (обычно значительно) ускорит её решение (а плохо подходящий он не выберет).
                        А плохому программисту фреймворк поможет (или, скорее, заставит) создавать не такой уж плохой код, с которым, в частности, хорошему будет проще разобраться или
                        ЦА.
                        В общем ЦА фреймворков — программисты вообще.
                      • +1
                        Для того, чтобы нормально пользоваться фреймворком, нужно быть хорошим программистом.
                        Но хороший программист может обойтись и без фреймворка.
                        А плохие программисты не могут нормально пользоваться фреймворком.
                        Но без фреймворка будет еще хуже. :)

                        Никакого парадокса. Есть такая штука — сюхари.


                        • не опытный программист если ему дать просто язык программирования напишет вам небезопасное и кривое решение. Причем оно будет плохим во всем.
                        • Чтобы уменьшить риск ему можно одеть смирительную рубашку в виде фреймворка, который декларирует "правильные" подходы. Далеко не факт что программист будет эти подходы правильно понимать. И да есть проблема что поскольку подходы принимаются на веру программисты становятся религиозны.
                        • Со временем и при нормальной команде разработчик начинает понимать подходы и использовать инструменты с умом.
                        • Сильный разработчик прошел все эти этапы, прекрасно ориентируется почему фреймворки такие какие они есть, понимает подходы и т.д. А зная разные подходы и трезво оценивая плюсы и минусы каждого, уже не важно на каком фреймворке (даже если вы решитесь делать все без них у вас выйдет свой фреймворк) будут делаться дела.

                        Странно только, что он так сильно распространен среди программистов или «программистов» :)

                        Это общечеловеческий феномен.


                        1. Только не все умеют эту сборку готовить :)
                        2. А что должно быть во фреймворке, если выбросить все компоненты?


                        1. Да, смотрите про "три стадии обучения".
                        2. Клей, мосты между компонентами, адаптеры, загрузка конфигураций и базовая структура. Это не много кода обычно.

                        Хм, но общение может быть организовано посредством какой-то шины :)

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


                        Правильней «фреймворки не всем нужны» :)

                        Фреймворки нужны всем. Это каркас. Хотите вы или нет но он у вас появится. Другое дело что есть те 0.1% разработчиков чьи задачи требуют создание своего уникального каркаса.


                        Что еще скажу: если человек понимает, что он делает, и знает где что лежит, то плевать, что кто-то считает, что он делает неправильно. :)

                        И тут мы приходим к эффекту Даннинга-Крюгера. Как понять что человек на самом деле понимает что делает а не игнорирует советы других? Проблема то в том что программисты частенько самоучки. И частенько они тусуются в кругу таких же вот самоучек. И невежество начинает укрепляться и распространяться. И в итоге люди исповедующие нормальные подходы остаются в меньшинстве. А поскольку они в меньшинстве то все надеятся на мудрость толпы и т.д.


                        Я вот раньше писал плохо отформатированный код :) Но мне он был понятен :) А сейчас самому противно смотреть на такой код. :)

                        Я раньше геттеры у классов делал и думал что это нормально. Как же я был не прав.

                        • –2
                          Никакого парадокса. Есть такая штука — сюхари.

                          Беда в том, что программист может застрять на первом уровне и иметь культ карго. :)
                          Ибо никакого обучения и осмысления нету. Обычное кодирование, как макака. :)
                          На предложение подумать своей головой, в ответ агрессия. :)

                          Процитирую:
                          До того, как вы начнете на практике применять паттерны ООП, и не поймете их минусы и плюсы, я советую не читать книг по паттернам, и не использовать фреймворки, иначе случится паттерн головного мозга, и паттерны будут применяться не по назначению, а просто потому, что вы их знаете, вы будете лепить их к месту и не к месту.


                          Вам не кажется, что те, кто начинал на голом языке, имеют больший профессионализм?

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

                          А на фреймворках компоненты как взаимодействуют друг с другом? :)
                          Service Container — это та самая единая шина. :)

                          У меня единая шина событий.
                          А компоненты одного пространства имен свободно вызывают зависимости, но их не много.

                          Фреймворки нужны всем.

                          Тогда так:
                          «Мейстримовые фреймворки не всем нужны» :)

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

                          Так я и говорю, что это не много. :)
                          Это можно и самому реализовать, как нужно. :)

                          И в итоге люди исповедующие нормальные подходы остаются в меньшинстве. А поскольку они в меньшинстве то все надеятся на мудрость толпы и т.д.

                          Но большинство пишет на фреймворках… :)
                          • +3
                            Беда в том, что программист может застрять на первом уровне и иметь культ карго. :)

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


                            На предложение подумать своей головой, в ответ агрессия. :)

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


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


                            Процитирую:

                            Кого?


                            Паттерны лишь словарь. Вы говорите кому-то "используй адаптер" и разработчик понимает что ему надо завернуть объект с одним интерфейсом в другой объект, с другим интерфейсом чтобы сделать совместимость (слово адаптер не просто так выбрано). То есть возможно в документации к фреймворку будут использоваться подобные слова, но в целом я не припомню ни одного где подобные вещи диктовались бы. Обычно вы будете натыкаться на предложение "заюзать паттерн" далеко не в начале документации.


                            Ну и опять же. Перед тем как учить паттерны стоит разобраться с такими понятиями как связанность, управление зависимостями, инкапсуляция, декомпозиция задачи и т.д. Структурное программирование можно вместо ООП поизучать. Но это поднимает уже вопрос процесса обучения — его нет. Я часто видел когда на вопрос "с чего начать" кидают книжку по паттернам, хотя человек еще не умеет алгоритмы строить.


                            Вам не кажется, что те, кто начинал на голом языке, имеют больший профессионализм?

                            тут вопрос в том что есть "начинал". Вот к примеру я начинал писать на PHP не потому что мне надо было заказ на фрилансе закрыть, а потому что нужен был простой консольный скриптик который бы сконвертил 3000 документов из одного формата в другой и я не хотел это делать руками. Пришлось разобраться с основами программирования, регулярками и подобным.


                            А многие под "начинать" подразумевают "ну я на выходных почитал про php и сейчас взял пару заказов на фрилансе и времени разбираться нат надо просто проблему решить".


                            Перед тем как брать фреймворк в руки разработчик уже должен:


                            • знать как информация представлена в памяти хотя бы на базовом уровне
                            • знать что есть алгоритмы и как их писать. Банально понимать как написать свой пузырек или алгоритм бинарного поиска.
                            • знать хотя бы основную часть синтаксиса языка.
                            • представлять как происходит процесс разработки ПО.

                            Если вы посмотрите на какой-нибудь Ruby-on-rails и какие-нибудь толковые курсы в духе "RoR за 3 месяца", то там еще до знакомства с самим фреймворком вас сначала научат на ruby писать, потом научат тесты писать и только потом фреймворк.


                            То есть знать язык надо, но писать свой фреймворк — плохая идея.


                            А на фреймворках компоненты как взаимодействуют друг с другом? :)
                            Service Container — это та самая единая шина. :)

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


                            У меня единая шина событий.

                            а вот это уже шина. И это та самая глобальная зависимость в ваших проектах. Если мы возьмем любой компонент вашей системы ему нужна будет эта самая шина.


                            В целом по поводу событий для снижения связанности… Это очень хороший способ снизить связанность между компонентами. Но помимо связанности есть еще такое понятие как "зацепление" (coheasion) и если связанность должна быть низкой, то зацепление должно быть высоким. Что это значит? Это значит что код который относится к одной области ответственности (все что связано с юзерами например) должно лежать рядом и общаться напрямую без всяких там шин.


                            «Мейстримовые фреймворки не всем нужны» :)

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


                            Это можно и самому реализовать, как нужно. :)

                            на готовых компонентах — да. Но только опять же зачем? в чем смысл? берем symfony/framework-standard-edition и он покрывает 90% всех проектов. А вот если мы хотим делать продукт свой например, и нам очень хочется что бы структура проекта отражало то как мы планируем работать с проектом, и мы хотим точно представлять что мы используем — то тут да. компонентики, контейнер зависимостей какой, и все будет хорошо. Вот только для этого на проекте должен быть синьер разработчик который будет следить за всем этим. Джунам — только стандартные сборки.


                            Но большинство пишет на фреймворках… :)

                            мне больше нравится интерпретация "большинство используют фреймворки". Если для вас "фреймворк" это структура проекта — ну ок. Для меня "фреймворк" это все что составляет инфраструктуру проекта. То есть если у меня нет фреймворка, он у меня будет.

                            • 0
                              Кого?

                              Чувака одного с форума :)

                              тут вопрос в том что есть «начинал»

                              Я тоже начинал по маленькому.
                              Захотел прикрутить динамику к своему статичному сайту. :)

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

                              Но они же знают, что они ищут. :)
                              Допустим кеш.
                              Или кеш на мемкеше наследует базовый кеш.

                              еще такое понятие как «зацепление» (coheasion) и если связанность должна быть низкой, то зацепление должно быть высоким.

                              Зацепление высокое :)

                              Они нужны 99.9% проектов.

                              Я обязан упомянуть статью

                              то все расходы на поддержку этого фреймворка ложатся на вас

                              Какие ж там расходы.
                              Там же не так и много кода по сравнению с самим приложением.
                              • +1
                                Но они же знают, что они ищут. :)

                                они явно объявляют свои зависимости. Например в такой штуке кака конструктор. И им без разницы есть там какой-то конструктор или клиентский код сам все разрулит.


                                Зацепление высокое :)

                                Опять же, когда зацепление высокое но связанность недостаточно низкая то это приводит к вещам вроде god object. Важен баланс. И я не склонен верить высказываниям что у вас все хорошо (только если в скажете что у вас 90+ покрытие юнит тестами кода, и это не 100 тест кейсов, и это настоящие юнит тесты не выходящие за пределы одного процесса).


                                Я обязан упомянуть статью

                                Я обязан дать ссылку на докладик: Greg Young — Stop over engineering. Там очень хорошо и про написание своих фреймворков, и про ложный нон конформизм, или за попытки обобщить специализированный функционал....


                                Там же не так и много кода по сравнению с самим приложением.

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

                                • 0
                                  Хм. :)
                                  Я тоже не приветствую оверинжиниринг. :)
                                  • 0

                                    собирать свой фреймворк даже из готовых компонентов в 99% случаев оверинженеринг. Например у меня специализация — апишки писать. Я взял стандартный симфони, накрутил туда пару своих решений, пару чужих, тупо своя сборка, и просто использую из проекта в проект. Большая часть "клея" — стандартная. Это значит что можно дать этот проект на суппорт и дальнешнее развитие любому разработчику который знаком с symfony. А особенности и отличия прописать в README.


                                    Делать же сборку под один проект можно только если вы прекрасно понимаете что делаете. А это уже не новички.

                        • 0
                          Другое дело что есть те 0.1% разработчиков чьи задачи требуют создание своего уникального каркаса.

                          Искал комменты, где говорится что только фреймворки наше все.
                          Нашел этот.

                          Ну ок, я тогда в 0,1% :)
                          Спасибо.
                          • +2
                            Ну ок, я тогда в 0,1% :)

                            у вас создание своего коркаса оправдывается не с экономической точки зрения а просто потому что вам так захотелось. Вы же сами отмечали что делаете так только на личных проектах.

                  • 0
                    Да и MVC унылый на фреймворках, как показала статья и комменты. :)

                    Нормальный MVC. Используют его многие ненормально. Например, руководствуются туториалами как пользоваться фреймворками
                    Есть понятие unix-way.
                    Фреймворк — это швейцарский нож, которым никто не умеет пользоваться :)

                    Хороший фреймворк состоит из изолированных, слабосвязанных, заменяемых на сторонние реализации или просто исключаемых модулей
                    • 0
                      Нормальный MVC. Используют его многие ненормально. Например, руководствуются туториалами как пользоваться фреймворками

                      Плевать.
                      Когда будут использовать нормально, тогда и поговорим. :)

                      Прекращайте троллинг.
                      • 0
                        Голый язык используют еще чаще ненормально, а уж про ненормальные самописный фреймворки и говорить не приходится. О чем еще говорить? )
                        • 0
                          Ну ок, все говно. :) Довольны? :)
                          • +2

                            кроме пчел

              • +1

                Открою для вас секрет: фреймворки для того и изобретают, чтобы написание программ было доступнее. Программисты не обленились, нас просто стало больше.

    • –2

      Если бы вы писали БД для веба с нуля — то авторизация средствами БД была бы ужасной архитектурной ошибкой, так же как и бизнес-логика в хранимках. Просто из-за скорости разработки.


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


      Возможно, веб-программисты просто не понимали зачем вам вообще они. По-хорошему, тут верстальщика достаточно, а PHP в требуемом объеме вы и сами изучить можете.


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


      Если использовать языки программирования, отличные от PHP, то там можно хранить в сессии не пароль к БД, а непосредственно открытое соединение. Да и на PHP так можно делать, если написать свой http-сервер или fastcgi-обработчик. Но это будет уже намного сложнее.




      Основное ограничение подобного подхода — принципиальная невозможность нормально передать из БД наружу событие об изменении данных. Это значит, что никаких веб-сокетов в подобном веб-сайте не появится никогда, да и AJAX при таком подходе будет не лучшим решением. С другой стороны, в интранете большего и не надо.

      • +1
        «Если бы вы писали БД для веба с нуля — то авторизация средствами БД была бы ужасной архитектурной ошибкой, так же как и бизнес-логика в хранимках. Просто из-за скорости разработки.»

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

        Т.е. вы хотите сказать, что весь вопрос только в готовности БД?
        Или
        Просто из-за скорости разработки.

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

        • –1
          Т.е. вы хотите сказать, что весь вопрос только в готовности БД?

          Да, весь вопрос в готовности БД. Веб-приложение с логикой внутри можно сделать быстрее чем БД с той же самой логикой внутри.

          • 0
            Веб-приложение с логикой внутри можно сделать быстрее чем БД с той же самой логикой внутри.

            Ничего себе у вас обобщения.
            Вы когда нибудь работали с банковскими приложениями?
            Когда бывает на обдумывание, как рассчитать какое нибудь говно со сложными процентами, которое придумали маркетологи, уходит времени на порядки больше, чем оформление расчета в процедуре?
            И данные вы будете вытаскивать себе в приложение, что бы там их покрутить?
            А БД при этом подождет с блокировками?
            Может быть стоит принять, что для разных задач существуют разные оптимальные подходы?
            • –2

              Вот именно "говно со сложными процентами" и делается намного проще на нормальных языках программирования, нежели на SQL.

              • –1
                Т.е. SQL это «не нормальный» язык программирования?
                Я же говорю, вопрос религии всплыл.
                • +1

                  SQL — это прежде всего язык написания запросов, а не программирования. Это уже накладывает некоторые ограничения.


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

              • 0
                Это же так приятно, написать красивый запрос, который быстро работает и не нагружает сервер. В том числе и вычисление сложных процентов. Сначала вы с кайфом проектируете структуру, которая устойчива к перерасчётам, ковыряниям ручками в данных, изменениям сальдо задним числом, и всему такому, а потом вычисление по всем вкладам/ссудам, и так чтобы одним запросом.
          • +1
            Вот извините, не соглашусь. Может быть если приложение простое это и верно. У меня только хранимых процедур 2к, если представить, что это переехало в код приложения, да ещё и с обёртками, становится страшно. А зачем это делать, если ровно тоже самое можно сделать не вылезая из сервера, не понятно.
            Мне нравится проектировать БД, стараюсь делать, чтобы результатом можно было пользоваться откуда угодно.

            Попробую привести пример. Есть прайс-лист, видеть его может почти кто угодно. Например в нём пять колонок. И изменения в одних колонках вызывает каскадные изменения в других, плюс запись лога изменений, плюс что-нибудь ещё.
            Изменять отдельную колонку может менять только определённая группа пользователей. Я бы написал 5 хранимых процедур, раздал права на каждую соответствующей группе и всё. Приложение понятия не имеет о том, что и кому можно, оно зовёт одну процедуру в зависимости от того, какую колонку меняют. И можно или нельзя менять проверяет сервер БД. Это же просто и быстро пишется что со стороны приложения, что со стороны сервера БД. Неужели перенеся эту логику в приложение станет проще? (Я осознаю, что почти всё, что я написал можно вообще сделать в триггере).
            • 0
              Триггера не очень люблю, отслеживать их сложно.
              Описанный вами пример можно сделать проще.
              Одна процедура входная.
              В зависимости от параметров вызывает другие процедуры, а приложение дергает всегда одну процедуру с разными значениями параметров. :))
            • 0
              У меня только хранимых процедур 2к, если представить, что это переехало в код приложения, да ещё и с обёртками, становится страшно

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


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


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




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


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


              В веб-приложении при хорошем фреймворке практически ничего не изменится. А в БД?

              • 0
                Лично я вижу проблему 2к хранимок в том, что там наверняка есть куча повторяемого кода, который нельзя куда-то вынести потому что язык не позволяет. Та же обработка ошибок...

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

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

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

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

                Да, это действительно проблема, но она обходится, например вспомогательными таблицами с признаками доступа по пользователю/группе, дальше можно просто присоединить к таблице с доступом данные.
                • 0
                  Вручную надо исправить ровно одну процедуру – выборку, где это поле нужно добавить. И написать ещё одну, для изменения этого поля (если нужно).

                  А если поле не добавляется, а выносится в отдельную таблицу? Тогда надо исправлять каждую выборку, где это поле присутствует.


                  Если у этого поля еще и "популярное" имя — то поиск такого поля по всем хранимкам станет тем еще приключением.


                  А если схема БД еще и не в виде файла хранится...

            • +1
              вас не понимают потому что так никто не делает
              так не делают потому что:
              1. pl\pgSQL — _очень_ плохой язык, который мало кто знает
              2. очень редко вся бизнес логика должна выполняться в транзакции, поэтому для масштабируемости её целесообразно выполнять на отдельном сервере
              3. авторизация и прочие дополнительные функции в БД слабо кастомизируются
              4. выше упомянутые проблемы с отслеживанием версий и параллельной разработкой
              5. БД коннект на пользователя это обычно очень расточительно
              6. не уверен насколько гибкие настройки пермишенов в pgsql, но по идее любой кулхацкер сможет заддосить вашу БД просто написав пару строк в консоли браузера
              даже если все эти проблемы не актуальны для тупого круда в интранете, вы надеюсь понимаете что никому не интересно применять абсолютно не применимое в 99% случаев решение

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

              PS это не про вас случайно http://thedailywtf.com/articles/table-driven-software?
              PPS просто интересно, а чем вы предлагаете дергать postgres из жаваскрипта?
  • +1

    логика в субд — это боль и страдания, имхо

    • 0
      Почему?
      При много большом количестве пользователей неизбежны коллизии. На сервере я всегда могу точно сказать в каком состоянии данные, а транзакции помогают эту целостность поддерживать. Или вы про что-то другое?
      • –1
        Лично я не нашёл удобного инструмента для её версионирования с разными ветками.
        • +2
          Код процедур хранится в файлах.
          Файлы в контроле версий.
          • 0
            В одной ветке процедуры 1, 2, 3, в другой 1,2, 4. При переключении ветки с первой на вторую процедура 3 должна удалиться, а 4 создаться, причём вторая ветка ничего о первой не знает, ветвление произошло когда были только 1 и 2. Как это легко сделать?
            • +1
              А как это легко сделать, если у вас логика лежит не в процедуре, а некоем другом файле с логикой?
              Или поясните, о чем вы?
              • +2
                Логика в файлах, файлы в системе контроля версий. Переключили ветку, поменялись файлы. Всё.
              • 0
                В случае логике на обычных ЯП мне нужно только сбилдить проект после переключения (а в случае интерпретируемых вообще ничего не нужно делать) В случае логики в СУБД, мне нужно после переключения удалить процедуру 3 и создать процедуру 4. Крайне желательно не путём удаления процедур 1, 2 и 3 и создания 1, 2 и 4.

                И это самый простой пример. Могут быть разные версии одной процедуры, например. Если не изменилась, то трогать ничего не надо в базе, если изменилась надо изменить и в базе.
        • +1
          Может быть я неправильно подхожу к разработке, но с такой проблемой не сталкивался. Версия приложения соответствует такой в БД. Изменение версии приложения и обновлённых процедур происходит синхронно.
          Меня больше беспокоит прямой доступ к данным, когда все кому не лень при наличии инструмента и некоторых знаний может выбрать что угодно. И такие случаи были, пытались запросы писать из excel.
          • –1
            Как добиться такого соответствия, если переключаешься между версиями по десятку раз на дню?
            • +2
              У вас редкая ситуация.
              Но вы можете хранить версии, например бекапа БД, раз у вас такая потребность.
              В бекапе таблицы и процедуры вместе.
              Или база с таблицами отдельно, код процедур отдельно.
              При необходимости можно заскриптовать создание версии БД и файл скрипта хранить там же в ветке.
              Туда же в ветку положить и файлы вашего приложения.
              Варианты есть.
              • –1

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

                • +1
                  О чем вы?
                  О каких подстановках?
                  Я говорю о бизнес-приложениях.
                  Бизнес-приложения, это работа с данными.
                  Процедуры сохраняют данные (с проверками, например), изменяют данные (по различным правилам), удаляют данные (по правилам), извлекают данные (по правилам).
                  Веб или десктоп приложения отображают данные.
                  Различные сервисы принимают-отправляют данные вызывая процедуры.
                  О какой проблеме вы говорите?
                  Я выше писал о решении проблемы версионности.
                  Если вы храните бизнес логику гдето, это где то, тоже файл.
                  И наплодили веток.
                  И думаете как между ними переключатся и не потерять изменения, при чем тут хранение бизнес логики в хранимых процедурах?
                  Это другие проблемы.
                  • –1
                    В чем смысл хранить правила в бд? Ведь ЯП позволит это сделать более выразительно и проще.
              • –1

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


                Тот же git flow.


                И с логикой в БД эти подходы не дружат.

                • +1
                  Я, признаюсь, так и не понял, в чем они не дружат, с логикой в БД?
                  • +1

                    Ну не умеет GIT переключать разные версии БД. И отслеживать обновления схемы БД не умеет! И нет инструментов, которые бы во всех случаях эти самые обновления умели отследить и объединить, в отличии от файлов.

                    • +1
                      А GIT это и не нужно.
                      Вопрос вероятно в компетенции или привычке.
                      Вся схема (структура) БД легко скриптуется и записывается в файл, или как вариант, сохраняется файл бекапа (но там данные место занимают, что вам нужно, не нужно).
                      Т.е. когда вы коммитите свои изменения вы добавляете в ветку файл со скриптом.
                      Взяли ветку, развернули скрипт с БД из ветки.
                      Работайте.
                      Или вы хотите сказать, что если логика хранится где то, не в процедурах (кстати, процедуры можно воспринимать как файлы с логикой), то никогда не происходит изменения структуры БД?
                      И вы можете использовать свое приложение с любой версией БД начиная с царя гороха?
                      Я такого идеального мира не встречал, признаюсь.
                      • 0
                        ну миграции в современных фреймворках как раз таки этот вопрос решают. Но они могут оперировать структурой и данными, а вот создавать юзеров/раздавать им права это както вне компетенции приложения
                        • 0
                          Миграции делаются автоматически?
                          Или программист делает их ручками?
                          Если второе, так это аналог скрипта для обновления БД, который вы можете положить себе в ветку.
                          И что то мне говорит, что тривиальные случаи изменения БД, проблем не вызывают при любой технологии.
                          А сложные, все равно приходится работать руками.
                          Мы пользовались сторонним инструментом для сравнения БД и составления скриптов, для приведения к единому состоянию.
                          • +1

                            Разумеется, миграции — это те же скрипты, которые можно положить в ветку (и они там лежат!).


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

                          • 0
                            ручками пишет в консоли чтото типа bin/console dcotrine:migrations:diff
                            а дальше оно уже само анализирует состояние кода и состояние бд. На основании разницы формирует миграцию.

                            зы. Всем поклонникам хранимок. Code First не глупые люди придумали
                            • –1
                              Посмотрел.
                              Повсеместно принято, что в «серьезных» CRUD приложениях база данных становится во главу угла. Ее проектируют самой первой, она обрастает хранимыми процедурами (stored procedures), с ней приходиться возиться больше всего. Но это не единственный путь! Для Entity Framework есть Code First подход, где главным становится код, а не база. Преимущества:

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

                              Господи, это же для тривиальные случаев.
                              Для таких случаев отличный инструмент.
                              А когда идет обновление сложнее, с взаимосвязанными элементами, с правильной последовательностью обновления, с обновлением справочников и данных, тогда ценность этой штуки резко уменьшается.
                              Это примерно как использовать мастера создания чего то.
                              Отличные инструменты и реально ускоряют.
                              В тривиальных случаях.
                              А дальше ручками.
                              И чем сложнее у вас логика, тем менее ценными становятся мастера.
                              • +1
                                Господи, это же для тривиальные случаев.
                                Для таких случаев отличный инструмент.
                                А когда идет обновление сложнее, с взаимосвязанными элементами, с правильной последовательностью обновления, с обновлением справочников и данных, тогда ценность этой штуки резко уменьшается.

                                Именно! В том-то и проблема, что нормальных инструментов для нелинейного версионирования схемы БД — не существует.


                                Существовали бы — писать хранимки было бы намного проще.


                                А пока — используется подход "схему БД меняем только после согласования со всеми коллегами"

                                • 0
                                  Я же говорю, вопрос в привычке или компетенции.
                                  Хранимки не равны схеме БД.
                                  Хранимки вы можете хранить в другой БД.
                                  Можете убить хранимки, схема БД от этого не изменится.
                                  А вы все время их смешиваете.
                                  И что такое
                                  нелинейного версионирования схемы БД
                                  вообще не понятно.
                                  У вас в один момент времени на сервере живет много версий БД?
                                  Ладно, не убедили в общем.
                                  Вижу тут вопрос религии.
                                  • 0

                                    https://habrahabr.ru/post/321050/#comment_10056898


                                    Зря вы в разных ветках отвечаете, раз сами жалуетесь, что вам это трудно.

                                  • +1
                                    Хранимки не равны схеме БД.

                                    Да, не равны. Они часть часть схемы.
                                    И что такое
                                    нелинейного версионирования схемы БД

                                    вообще не понятно.

                                    Когда база меняется не пошагово в одном потоке и одном направлении, максимум иногда откатывается, а шаг иди два, а идёт развитие параллельно в нескольких направлениях, возможно разными разработчиками, и эти направления потом сливаются.
                                    У вас в один момент времени на сервере живет много версий БД?

                                    Одновременно одна, но за день может менятся несколько раз и это не только «вперёд» и «назад», но и «влево-вправо».

                                    Простой пример:
                                    в продакшене база с таблицей contract c полем типа enum status. В рамках одной задачи нужно расширить количество значений, разбив существующее на два, в рамках другой перенести поле в отдельную таблицу для хранения истории изменений. Задачи разработчики делают в разных ветках гита/мерка/свн/… О задачах друг друга до поры до времени вообще не знают. Их лид должен сначала проверить изменения одного, потом другого, а потом слить их. Разработчики написали скрипты миграции (накатывания и отката) для своих задач. Сейчас у него копия продакшен базы (версия A). Сначала он должен быстро проверить задачу разбиения значения на два (версия B), потом создания отдельной таблицы (версия C). Для этого система версионирования должна позволять ему быстро (читай автоматически) переключаться с версии A на B (разбить значение), с B на A (объединить значения), с A на C (создать таблицу, скоипровать значения, удалить поле) с C на A (создать поле, скопировать последнее значение, удалить поле). Эта задача, в принципе решена существующими инструментами в виде скриптов миграции созданными разработчиками или даже автоматически (на пустой базе, без сохранения данных кроме самых тривиальных случаев типа переименования столбца/таблицы). Но вот задача переключения с B на C и обратно решена уже хуже. Система версионирования должна понять, что общий предок у них версия A, откатить изменения версии B, накатить изменения версии C и наоборот. Задача объединения версий B и С практически не решена, максимум по таймстампам пытается определить какой скрипт миграции ставит первым. И это лишь по схеме собственно данных, когда есть формальное описание схемы, как правило не на SQL. С хранимыми процедурами, функциями, триггерами всё ещё хуже. Собственно из рассмотренных мною решений никто и не пытается автоматически что-то делать.

                                    • –1
                                      Хранимые процедуры НЕ часть схемы БД.
                                      Хранимые процедуры это скомпилированный код с сохраненным планом запроса.
                                      Хранимые процедуры могут хранится в другой базе и даже на другом сервере.
                                      Тоже и функции.
                                      Схема БД от этого не меняется.
                                      К триггерам я отношусь не очень хорошо, часто триггерами прикрывают косяк проектированя БД, когда приходится обновлять где то данные. Хотя как инструмент они есть и вероятно кому то очень нужен. Я обходился без триггеров, хотя механизмо работы с ними владею, конечно. Но это мое частное мнение, отстаивать не готов. Так отступление.
                                      Так вот, когда вы примете, что процедуры и функции, это просто код, сохраненный где то, с ними и работать остается как с кодом.
                                      А ситуация описанная вами не разруливается легко и при хранении логики не в функциях. Приходится ручками работать.
                                      Подумайте об организационных решениях.
                                      Как вариант, может стоит подумать, что бы несколько разрабов не дербанили один модуль одновременно, раз такие издержки возникают.
                                      Или продумывайте схему данных более тщательно, возьмите базовика в команду, тогда меньше придется схему данных гонять туда сюда.
                                      • +2
                                        Или просто пишите код не в базе. Разница в том, сколько именно приходится работать ручками.
                              • 0
                                Вот вы не поверите, но нормальные орм в состоянии разрулить порядок апдейтов
                      • 0

                        Схема БД, записанная в 1 файл, хорошо смотрится только пока БД разворачивается с нуля.


                        Но вот у вас в БД уже полно данных, и вам надо выкатить новую версию. Что будете делать?

                        • +1
                          Выкатить новую версию чего?
                          Веб морды, дескопного прилоения или новую версию БД?
                          Или и того и другого?
                          И мы говорим про обновлении продакшена или про работу разработчика, который вынужден прыгать по веткам?
                          P\S: (У вас преимущество, я могу писать раз в 5 минут, это снижает мотивацию писать, особенно в разные ветки).
                          • 0

                            Мне странно ваше непонимание.


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


                            Развертывать нужно новую версию приложения, куда входит новая схема БД.

                            • 0
                              Если вы посмотрите дискуссию выше, вопрос был у человека, которому по роду разработки постоянно (десять раз на дню) приходится переключатся на разные ветки. Думаю это не продакшен все таки.
                              А вопрос разворачивания новых версий, он вообще отдельный.
                              Если смотреть в БД, то по любому, для создания новой схемы, там накатывается скрипт.
                              И как вы запустите этот скрипт, уже другой вопрос.
                              У нас было специальное приложение, которое накатывало скрипты и файлы обновления и следило за ошибками.
                              И создавая скрипты, мы обязаны были думать о последовательности обновлений и о возможности отката, если что то пошло не так.
                              Не вижу тут принципиальной невозможности использовать процедуры.
                              • +1
                                У нас было специальное приложение, которое накатывало скрипты и файлы обновления и следило за ошибками.

                                … и это приложение было написано для линейной истории версий. То есть для одной ветки. У меня в каждом проекте такое же есть, кстати.


                                А вот при разработке в разных ветках проблемы и начинаются.


                                1. Александр добавил в таблицу колонку X
                                2. Борис добавил в таблицу колонку X
                                3. Виктор добавил в таблицу колонку Y
                                4. Изменения Александра (1) были развернуты на сервере
                                5. Виктор смерджил себе изменения Бориса (2)
                                6. Александр смерджил себе изменения Виктора (5) и обнаружил конфликт
                                7. Александр переименовал свою колонку X, два ей имя Z.
                                8. Борис переименовал свою колонку X, два ей имя T.

                                Теперь все эти изменения надо развернуть на сервере. Не потеряв данные, которые уже накопились в колонке X.


                                Вы представляете себе, с какой стороны вообще подступать к этой задаче?


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

                                • 0
                                  Это Вам прямая дорожка к философии MDM. Не к частным решениям, а к детально прописанного подходу к манипулированию данными.К регламентам и процедурам. И git тут не помощник. Разные сферы.

                                  Разумеется, обычные СУБД не предоставляют соответствующих инструментов. Но для промышленных СУБД такой инструментарий за хорошие деньги стоит приобретать.
                                  • 0

                                    А-а-а! Нахер! Нахер MDM! Это чертово глюкалово, которое нихера не работает, только тормозит!


                                    Извините, не сдержался.

                                • 0
                                  Экая вакханалия у вас с базой творится.
                                  Тут нужно прописывать порядок работы, быть может.
                                  И ваш инструмент автоматически такую ситуацию разруливает?
                                  Как такой вариант:
                                  К таблице обращение только через процедуру.
                                  Изменилась таблица, изменилась процедура.
                                  Все кто берет процедуру из ветки, видят, что таблица изменилась.
                                  Далее разруливается, как обычно с кодом.
                                  • +2

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


                                    И ваш инструмент автоматически такую ситуацию разруливает?

                                    Такие — никак. Я намеренно привел ситуацию, которую не умеет разруливать ни один известный мне инструмент.


                                    Но заметьте: когда такое творится с базой — это "вакханалия". А когда такое творится с кодом — это нормальный рабочий процесс, разруливаемый гитом без всяких проблем.


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

                                    • –1
                                      Т.е. отстаивая свою нелюбовь к БД вы приводите пример, который не разруливается и вне БД.
                                      Такой аргумент нет смысла учитывать.
                                      То, что вам код нравится больше, чем БД, не отменяет того, что с БД нужно работать, просто вы, скорее всего, «не умеете их готовить».
                                      Это довольно распространенная ситуация.
                                      • 0

                                        Глаза разуйте уже.


                                        Но заметьте: когда такое творится с базой — это "вакханалия". А когда такое творится с кодом — это нормальный рабочий процесс, разруливаемый гитом без всяких проблем.
                                        • 0
                                          Нет, вакханалией я назвал ситуацию, когда Вася, Петя, Коля и т.д. меняют структуру БД в одном и том же месте, не связанно друг с другом, кому как бог на душу положил.
                                          Т.е. речи об некоей архитектуре общей не идет.
                                          И приходится потом разруливать всякие косяки.
                                          • 0

                                            Они меняют ее не в одном месте, а в разных. Колонки-то независимы друг от друга.

                      • 0
                        В приложении у меня хранится описание схемы данных (таблиц, индексов, ключей), при переключении ветки происходит сравнение текущей схемы базы с описанной в приложении и накатываются изменения приводящие её к описанной. Не всегда всё хорошо отрабатывает, но процентов 90, а то и больше потребностей разработки и тестирования покрывает с сохранением данных в базе при переключении без всяких бэкапов. С хранимками и прочими триггерами я не нашел удобного способа переключаться между ветками. Единственный рабочий вариант — дропать базу и создавать её с нуля.
                        • 0

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

                        • –1
                          Т.е. процентов 90 у вас работает, остальное нет?
                          Это же не вариант.
                          Вариант единственный, должно работать все.
                          Дропнуть базу и накатить скрипт, тривиальная операция.
                          А в вашем варианте наборы данных, хотя бы тестовых вы тоже храните в приложении?
                          • 0
                            Процентов 10 требует ручного вмешательства. Собственно как и при работе с кодом посредством популярных VCS.
            • 0
              Вот честно, не сталкивался, есть боевая база и приложение к ней. И есть несколько версий для разработчиков, где каждая версия БД соответствует версии приложения которое меняет разработчик, он не переключается никуда.
    • +1
      Хм.
      Вовсе нет.
      Логика в хранимых процедура это весьма удобно и часто используется.
      А отображать можно хоть вебом, хоть десктопом.
      • –2
        Логика в хранимых процедура это весьма удобно и часто используется.


        «Потом его в дурку забрали, конечно» (с)

        Извините, не удержался.
        • 0
          Очень информативный и аргументированный комментарий у вас.
        • 0
          У Вас жгучий сарказм, не понимаю почему минусуют.
          Логика в хранимых процедура это весьма удобно и часто используется.

          А здесь все зависит от типа приложения и характера сопровождения: у нас, например, 4 типа СУБД поддерживаются, а решение сопровождается самим клиентом. Поэтому все в хранимках делать — это та еще задачка.
          Но если рассматривать конкретных случае — решение вполне себе приемлимое.
          • 0
            Но если рассматривать конкретных случае — решение вполне себе приемлимое.

            Все верно.
            Это и пытаюсь донести.
            С чего началось обсуждение:
            логика в субд — это боль и страдания, имхо


            • +1
              Если вас отпустит, то я добавлю: боль и страдание в большинстве случаев, но допустимо в узких кейсах
              • 0
                Что такое «большинство случаев»?
                Большинство случаев в вашей личной практике?
                Большинство случаев создания сайтов визиток?
                Или даже скажем, что кроме веба жизни нет?
                • +1
                  Даже не в вебе почемуто есть «сервер приложений» и «сервер баз данных».
                  Если оглядется, то можно увидеть что все больше и больше десктопного софта сползает в веб.
                  И, вы наверно не поверите, но подавляющее большинство «веб-приложений» эту визитки, лендинги или простые cms-based решения, в которіх вообще нету смысла авторизировать юзеров посредством логина в бд
                  • 0
                    Хорошо.
                    Пример.
                    Двигается груз.
                    На складах скануют, десктопные приложения.
                    Пишут в БД посредством дерганья процедур.
                    При этом сразу создаются накладные и происходят проверки.
                    С веба клиенты отслеживают движение груза, веб интерфес обращается к БД, дергает процедуры, в процедурах правила описаны, что показывать клиенту, что не показывать.
                    Отдел расчетов, десктопное приложение, обращается в БД, дергает процедуры,
                    которые выбирают данные из БД (накладные, созданные на складах), на основе и по правилам обработки данных выставляются счета.
                    Счета клиент, через веб приложение просматривает и оплачивает.
                    Другие клиенты, на своих складах, через приложение, создают накладные на груз и через веб (а кто то по е-майл) заливают их в БД, через те же процедуры (в которых описаны проверки и правила).
                    Т.е. все источники и потребители дергают одни и те же процедуры для обработки данных.
                    Далее репликация разносит данные в десятки филиалов на локальные сервера баз данных, где работает все аналогчно (остановка на часы недопустима, каналы связи этого не позволяют гарантировать, поэтому репликация бегает).
                    Все это крутится с логикой в хранимых процедурах.
                    Проект не маленький, работает без сбоев и развивается.
                    Данные и логика обработки данных живут в одном месте и хорошо живут.
                    Ну просто как пример.
                    Теперь эту кухню, разместите у себя в коде и прикиньте возникающие при этом сложности.
                    Просто как вариант.
                    • +2
                      Все тоже самое, только через АПИ. При этом бд доступна только с локалхоста (сесурити), а не со всего мира.

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

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

                      При этом клиентские приложения не имеюют прямого доступа к бд и физически не могут ничего сделать с бд, только то что дает АПИ.

                      Теперь эту кухню, разместите у себя в коде и прикиньте возникающие при этом сложности.

                      Почему вы не учитываете сложность написание всей этой кухни в процедурах, без возможности переиспользования кода. Без возможности использовать готовые, оттестированные решения?
                      • 0
                        «Красивая, легкая админка».
                        Все через API.
                        А по поводу сложности написания всех этой кухни.
                        Апи ваше данными манипулирует на каком языке? Не SQL?
                        Но кроме сложности манипулированя данными вы добавляете обертку сверху в виде API, что еще усложняет.
                        В общем, если вы столкнетесь с приложениями такого уровня, вы откроете для себя много нового.

                        • 0
                          Уж поверьте, но писать приложение на высокоуровневом ЯП гораздо проще чем на языке предназначенном только для манипулирования данными.
                          Для всех выскоуровневых ЯП имеюются удобные абстракции для работы с СУБД. А так же возможность писать рав запросы для кейсов, когда средсв ОРМ недостаточно.
                          Тут как раз все наоборот.
                          Что вы будете делать, когда часть данных придется вынести из базы в редис/монгу/етц?
                          Что вы будете делать, когда бизнесс захочет искать по по гигабайтах текста? sql очень мощный и выразительный язык. Но у него своя ниша
                          • 0
                            удобные абстракции для работы с СУБД

                            Простите, друг.
                            Но, вероятно, Вы не работали в ситуации, когда не понятно, как вытянуть производительность БД используя все тонкости конкретной СУБД, в рамках выделенных ресурсов для этого.
                            Только на днях консультировал любителей абстракций и ОРМ, на предмет, почему не могут выполнить простенький, вроде, отчет, который работал отлично, когда данных было мало, и вдруг перестал работать, когда приложение отработало пару месяцев.
                            Ладно, удачи вам, пусть ваш путь будет легким.
                            • 0

                              Вы слышали что-нибудь про преждевременные оптимизации?


                              То, что вам пришлось консультировать коллег — это совершенно нормальный рабочий процесс. Поймите: у них уже два месяца как есть приложение, которое работает! У них не было проблем ни с занесением данных в БД, ни с отображением их для пользователя.


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


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

                              • 0
                                Не совсем так.
                                Через два месяца пришло осознание, что БД это не просто какая то лабуда, а отдельный раздел знаний, требующий навыков и времени на освоение.
                                Что когда демонстрировали заказчику на тестовых данных, все было отлично.
                                А когда контроллеры оборудования стали лить реальные данные, все встало колом, отчет это первая ласточка.
                                А теперь идет речь о перепроектировании приложения, о выбросе того, что сделано, потому, что БД это фундамент, образно говоря, и чешут репу, где взять на это деньги.
                                А проблем с занесение данных и с отображением, обычно не бывает.
                                Это тривиальные операции.
                                Как раз отчеты обычно и ставят раком плохо спроектированную БД.
                                Попробую еще раз, для вас специально.
                                Я ЗНАЮ, что существуют операции с данными, которые вы не сможете сделать с адекватной производительностью и обработкой, без использования процедур в БД. Возможно вам это не встречалось, но поверьте, я более 20 лет работаю с базами данных в разных организациях.
                                Т.е. ваше приложение будет вынуждено в такой ситуации дергать процедуру.
                                И вы начнете размазывать вашу логику. Часть на сервере приложений. Часть в процедурах.
                                Улавливаете мысль?
                                Следующих шаг, зачем делать обработку данных в разных местах?
                                Логичнее сосредоточить ее в одном месте.
                                И вот логика перелезла в процедуры.
                                А веб, десктоп, прочие сервисы, это просто интерфейсы для отображения и обмена данными.
                                Я не утверждаю, что нельзя делать по другому.
                                Да можно конечно.
                                Я утверждаю, что бизнес логика в процедурах это не боль, как вы утверждаете, а вполне себе рабочее решение (каким цветом рисовать строку, это не бизнес логика, простите, это тривиальная рюшечка интерфейса, хотя признак цвета строки может отработать процедура также).
                                • 0
                                  Следующих шаг, зачем делать обработку данных в разных местах?

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

                                  • 0
                                    Чтобы упростить код. Потому что когда логика в разных местах, код получается проще.

                                    Вы это серьезно пишете?
                                    • +1

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


                                      Все паттерны, библиотеки, фреймворки и технологии — это не просто страшные или модные слова, это средства, которые делают код проще. Они были созданы для этой цели.

                                • 0
                                  Вы гоняете отчёты прямо на том же сервере, в которые заливаете оперативные данные? Или всё же держите для этого реплику (или даже сервер отчётов, со специально денормализованной схемой), да на отдельной машине, выделенной специально для генерации тяжёлых запросов?
                                  • 0
                                    Реплика отдельная.
                            • +1

                              В PHP комьюнити есть такой ORM как Doctrine. И авторы оного когда выступают на конференциях с докладами вроде "Doctrine best practice" очень много говорят про то что ORM созданы для OLTP и для таких вещей как репорты придуман замечательный инструмент — SQL. Так что проблема не в инструментах а в головах.


                              Что до "абстракций". Абстракции разные бывают. DAO тоже абстракция и она не мешает вам использовать вашу СУБД на полную катушку. Но вот с точки зрения приложения вся работа с СУБД изолирована и детали работы с оной так же. В этом собственно и заключается суть абстракции.

                              • 0
                                Я работал с DAO.
                                Для любой задачи более, менее сложной обработки данных, кроме тривиальных селектов до апдейтов, делаются процедуры обработки данных и потом, удобно из интерфейса через DAO дергать процедуры :)
                        • +2
                          Но кроме сложности манипулированя данными вы добавляете обертку сверху в виде API, что еще усложняет.

                          Нет. Обертка над SELECT/INSERT/UPDATE/DELETE в виде API с бизнес-логикой добавляется вместо обертки над теми же SELECT/INSERT/UPDATE/DELETE в виде SQL-процедур.

                          Сталкивался с приложениями обоих видов. Поддерживал одно время программу на Delphi+Firebird с логином через БД, последнее время занимаюсь веб-программированием. Поэтому могу сказать по опыту — серверные приложения гораздо проще в поддержке. В свою очередь могу вам посоветовать познакомиться с такими приложениями. Откроете для себя много нового)
                          • 0
                            Хорошо.
                            Вам нужно выбрать из сотни миллионов записей о транзакциях, несколько десятков тысяч, сохранить их во временной таблице, наложить на нее индекс, другой.
                            Затем из других связанных таблиц выбрать еще пару тыс. записей.
                            Сохранить их во временной таблице.
                            Потом пробежаться курсором по результирующему множеству, полученному с помощью оконных функций и в соответствии с правилами обработать, произведя проверки на доступность операций для документов с данным статусом и для отсутствующих документов, сгенерировать их (для генерации есть свои процедуры.
                            При этом на время операции генерирования, будут блокироваться части таблиц, в которые пишут другие процессы, т.е. нужна максимальная производительность операций.
                            Вы будете данные операции делать в некоей обертке с бизнес логикой?
                            • 0

                              Это вы свое решение рассказали. А теперь расскажите условие задачи.

                              • 0
                                Задача?
                                Обработка документов в банке.
                                Начисление процентов, пени, комиссий за услуги, ежедневное.
                                • 0

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

                                • +1
                                  1. Никто не спорит, что для аналитических задач орм не годится. Но есть инструменты и поинтересней чем процедуры в субд. Теже кубы/вертика и еще пачках других решений, которые будут более гибкими и удобными.

                                  2. Я вот прямо сплю и вижу как придется менять процедуру начисляющую проценты по кредиту/депозиту каждый раз когда банк предлагает новый продукт для клиента, ага. Кроме того, эта задача работает явно в контексте клиента и легко паралелится на пачку воркеров со всеми удобствами высокоуровневого ЯП
                                  • –1
                                    1. Никто не спорит, что для аналитических задач орм не годится. Но есть инструменты и поинтересней чем процедуры в субд. Теже кубы/вертика и еще пачках других решений, которые будут более гибкими и удобными.

                                    Вы пробовали сопровождать кубы и пачки других решений? Очень интересная задача и весьма дорогая в обслуживании.
                                    2. Я вот прямо сплю и вижу как придется менять процедуру начисляющую проценты по кредиту/депозиту каждый раз когда банк предлагает новый продукт для клиента, ага. Кроме того, эта задача работает явно в контексте клиента и легко паралелится на пачку воркеров со всеми удобствами высокоуровневого ЯП

                                    Ну, то есть опыта такой работы у вас нет, но вы точно знаете как это делать лучше.
                                    Хорошо, пусть ваша дорога будет удобной для вас.
                                    • 0
                                      Вы пробовали сопровождать кубы и пачки других решений? Очень интересная задача и весьма дорогая в обслуживании.


                                      Ну так вы определитесь, что вам нужно? Перфоманс и гибкость или абы как, но чтобы хоть чтото? Мне ли вам рассказывать о возможностях кубов по сравнению с процедурами?

                                  • 0
                                    Кроме того, эта задача работает явно в контексте клиента

                                    Далеко не факт. Очень многое зависит от административных регламентов и политик.
                                    • +1
                                      Если вам не трудно, то расскажите как начисление процента по кредиту Васи Пупкина или ООО «Рога и Копыта» может зависить от чегото не связанного с самим кредитом и его получателем + какихто общих «справочников» со ставками и тому подобное? Мне просто интересно, что такого может быть в административных регламентах и политиках, что не позволит распаралелить эти рассчеты?
                                      • 0
                                        Часто результат начисления процентов по всем договорам должен быть оформлен в виде единого документа по всем операциям и клиенты в нём даже не упоминаются, от них результат расчёта никак не зависит.

                                        И я только про контекст, а не про параллельную обработку.
                            • 0
                              Действительно, вы бы подробнее задачу описали, с примером каким-нибудь.
                              Если задача именно в таком виде, то я бы так и сделал, с временными таблицами и процедурами. Пусть 3% логики будут в базе, но хотя бы остальными 97% будет проще управлять.
                              Но вообще есть вопросы. Зачем на время операции генерирования блокировать таблицы? Почему нельзя пару тысяч записей вытянуть в оперативную память? Курсор и оконные функции это типичные вычисления в цикле с накоплением результата. Почему нельзя использовать код вида while ($row = $query->fetchRow()) { do something }? Джойн двух временных таблиц, подозреваю, можно заменить на группировку вида $orders[$client_id][] = $order.

                              Вот тут хороший пример был. Куча SQL с временными таблицами заменяется на 3 вложенных цикла.
                              • 0
                                Зачем на время операции генерирования блокировать таблицы?

                                Чтобы во время начисления не прошла операция выдачи или погашения. Нужно, как минимум, блокировать вставку новых платежей по конкретному счёту по которому в данный момент производится начисление. Знаете способ как блокировать вставку записей в таблицу с конкретным значением поля?
                                • 0
                                  А, ну так какая разница, из SQL мы ее заблокируем, или из приложения.

                                  Способ есть, через блокировки. Блокируем строку счета на запись, и во всех операциях на изменение счета сначала читаем строку с этим счетом.
                                • +1
                                  Зачем блокировать клиентские операции? Начисление процентов делается на определённую дату/время, значит нужно лишь ограничить выборку транзакций этой временнОй меткой, после расчёта добавить транзакцию начисления процентов с информацией о времени расчёта. Если во время расчёта прошли какие-то операции — да и пусть их, они будут учтены при следующем расчёте. Так как в запросе указан диапазон, можно включать оптимизации (key-range lock например), чтобы не блокировать всю таблицу.
                                  • 0
                                    Если во время расчёта прошли какие-то операции — да и пусть их, они будут учтены при следующем расчёте.

                                    Грозит проблемами не только с конкретным клиентом, но и с регулятором. Банально, у клиента 100 000 тела кредита и 10 000 процентов, нужно начислить ещё 100 процентов в полночь. Начинаем считать. Тут же приходит платеж от клиента на 20 000. Если мы его пишем без блокировок, не дожидаясь окончания расчёта, то, с одной стороны, мы распределим платеж как 10 000 на тело и 10 000 на проценты и рассчитаем проценты на 100 000, хотя должны бы по идее либо 10 100 на проценты и 9 900 на тело, либо 10000 на тело и 10000 на проценты, но тогда расчёт процентов должен быть не на 100000, а на 90000, грубо не 100, а 90. Клиент заметит лишних начисленных 10 рублей или не погашенных 100 рублей процентов и побежит с жалобой в ЦБ РФ.
                                    • 0

                                      А проценты на тело и проценты на проценты как-то по-разному считаются?.. Надо просто записать платеж на 20 000 целиком, куда он там достался — можно определить позже, при следующем расчете процентов.

                                      • 0
                                        Проценты на проценты могут не считаться как раз. Нам надо не только записать платеж к себе, но и дать клиенту (а также сообщить регулятору, про онлайн кассы слышали?) чек или квитанцию, где четко расписано «тела уплачено 10000, процентов 10000» или «тела уплачено 9900, процентов 10100»
                                    • +1
                                      Если мы его пишем без блокировок, не дожидаясь окончания расчёта, то, с одной стороны, мы распределим платеж как 10 000 на тело и 10 000 на проценты

                                      Мы его пишем без блокировок, но отнюдь никуда не распределяем. Мы просто создаём запись в таблице транзакций, проставляя время (00:01) и сумму (20к). Так как отметка времени позже полуночи, то в расчёт процентов предыдущего дня этот платёж не попадает. Полночь — это момент отсечки, ровно так же, как если бы мы заблокировали БД.

                                      Как раскидать сумму платежа по телу и по процентам — это должно рассчитываться совершенно отдельно, где-то на этапе составления отчётов и расчёта процентов при закрытии следующего дня.
                                      • 0
                                        проставляя время (00:01)

                                        Грязный хак. Особенно быстро выплывет, если платеж принимается не самостоятельно, а через внешних посредников типа платежных систем — у клиента в чеке 00:00:00, а у вас 00.00.01 в выписке по счёту.

                                        это должно рассчитываться совершенно отдельно

                                        Это может рассчитываться отдельно, если у регуляторов нет требований выдавать клиенту в момент оплаты чек, квитанцию, корешок к ПКО с чётким разбиением уплаченной суммы на тело, проценты, пеню и т. п.
                                        • +1
                                          Почему хак? Время истинное, не искусственное, это я просто выбрал для примера время близкое к полуночи. Даже если время транзакции будет ровно полночь, наносекунда в наносекунду, работать это будет точно так же, потому что условие выборки будет timestamp < noon.

                                          Если регуляторы требуют выдать квитанцию с немедленной раскладкой, то надо принять платёж без блокирования таблиц, но временно приостановить выдачу квитанции. Клиенту так и так пришлось бы сидеть и ждать окончания расчёта, ну так пусть это будет сделано lock-free.
                                          • –1
                                            Как узнать, что следует приостановить выдачу квитанции? И до каких пор приостанавливать?
                                            • 0
                                              Разные варианты могут быть. Например, приостановить все виды отчётов пока день не закрыт полностью. Или пока не закончатся все задачи, способные ретроактивно повлиять на баланс. Или по-быстрому инициировать пересчёт процентов конкретно для этого счёта, что займёт совсем мало времени, после чего выдать актуальную квитанцию.
                                              • 0
                                                Квитанция не отчёт, она выдаётся не после закрытия дня. Она результат проведения платежа, её в реалтайме ждут клиент, её ждёт платежная система, не разрывая соединения.
                                                • +1
                                                  Если в квитанции есть информация, не содержащаяся в самом платеже — всякие итоги, раскладки, статистики и т.п., то это уже мини-отчёт. Кто его ждёт — не суть важно. Но это уже игра с терминологией.

                                                  Точно так же все будут ждать результатов платежа, если заблокировать таблицу. При этом конца расчёта будет ждать не один клиент, а несколько. Если делать без блокировки, то ждать будет только тот, у кого проценты за день ещё не подсчитаны. Если пересчёт делать индивидуально, маленькими кусками, а не одной большой задачей по всей базе, то время ожидания будет миллисекунды.
                                        • 0

                                          Это не хак, это упрощение. Надо просто милисекунды хранить. Их и показывать-то необязательно.


                                          Хуже с неодинаковостью времени на разных серверах.

                              • 0
                                Циклы в БД это зло, порой вынужденное.
                                Циклы обрабатывают данные построчно.
                                Циклы работают на порядки медленнее и сильно засаживают производительнось сервера БД.
                                Циклы в БД это крайний случай, когда без них не получается обойтись.
                                Это трудно понять, пока вы не работаете с большими массивами данных.
                                В приведенном вами примере адский геморрой в исходном примере, который вы причесали.
                                И часто, когда с таким обращаются, когда сервер БД начинает почему то адски тормозить, приходится собирать SQL запрос, или выцеплять его профайлером, потом анализировать его выполнение в инструментарии БД,
                                потому, что в приложении это сделать просто невозможно,
                                потом переписывать и отдавать заказчику, который собирает его строку из приложения и ждет очередной засады, потому, что не понимает как работает SQL сервер.
                                Ну ладно.
                                Удачи вам в работе ;)
                                • 0

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

                                  • 0
                                    Да, пробегите в цикле по миллиону записей.
                                    Посмотрите время выполнения.
                                    • –1

                                      Миллион записей — как раз ерунда. Если, конечно же, это раз в день делать, а не раз в секунду.


                                      Вот если записей десяток миллиардов — это уже проблема...

                                    • +1

                                      по миллиону? да хоть на мобильном телефоне, даже не подлагнет. Самое медленное что сейчас у меня есть в проектах это база банных (UPDATE\INSERT\SELECT -в порядке скорости). Горизонтальный шардинг пока решает проблемы.
                                      В отличии от комментаторов выше хранимки мы используем, но мало, и там где от них вреда нет. В текущем проекте они обновляют ровно одну таблицу и не требовательны к производительности

          • +1
            У Вас жгучий сарказм, не понимаю почему минусуют.


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

            Довелось мне как-то работать в проекте, которым руководил ДБАшник. Так вот там ВСЯ бизнес логика была в хранимках. На джаве была только тупая прослойка, которая дергала хранимки и отдавала данные наружу. Даже хуже: прямой доступ к таблицам и вьюшкам нам был запрещен.

            Не знаю, чем бы это всё закончилось, если бы остались бабки и проект не умер.
            • +1
              Вы прямо описали мой случай. Очень удобно. По мне так джава и должна была заниматься тем, что предоставлять интерфейс к данным. А хранимые процедуры в данном случае выглядят как API к данным. Всё ж логично.
              • +3
                Есть несколько разновидностей нарушения ответственности:
                1) Программист старается спихнуть с себя ответственность в соседние слои, которыми занимаются другие люди. Мол, проблема на вашей стороне.
                2) Программист тянет одеяло на себя, т.е. реализует сам максимум всего, не особо беспокоясь, насколько это разумно. Именно это произошло у нас с тем проектом: ДБАшники всем заправляли и сделали всё в базе.

                Что касается бизнес-логики в базе, то у меня есть несколько возражений/вопросов против такого подхода:
                1) На сервере приложений я могу использовать свой любимый (или наиболее подходящий) язык программирования, а не PL SQL с синтаксисом и прочими «прелестями» из 60-х или другой вариант из весьма ограниченного списка.
                2) Как обстоит дело с горизонтальной масштабируемостью БД? С серверами приложений всё просто: поднял еще пачку при необходимости, ничего не отключая, и всё.
                3) Как обстоит дело с обновлением хранимок, особенно когда у нас больше одного сервера?
                • 0
                  И вдогонку: как там дела с тестированием и т.д.?
                  • 0
                    Горизонтальная масштабируемость.
                    Классно звучит.
                    А данные вы в БД не храните?
                    Т.е. подняли пачку серверов для приложений и все отлично.
                    А серверы баз данных?
                    Или у вас на каждом сервере своя БД?
                    • +1
                      ну с бд то пробелм нет, на чтение можно выставить достаточное количество реплик, чтобы распределить нагрузку. А вот на запись то мастер один и его никак не смасштабируешь, и вся логика в нем
                      • –1
                        ну с бд то пробелм нет,

                        Отличная фраза.
                        И чего это люди парятся с этими самыми БД?
                        Придумали там Ораклы всякие да МС Сивелы, транзакции там, да блокировки.
                        Налепил реплик, и всего делов то, а?
                        А если вам нужно увидеть остаток по счету, а в это время в БД льются транзакции из разных мест и происходит движение денег по счетам? Тоже реплик наделаете?
                        • 0

                          И в чем же проблема посмотреть остаток по счету в реплике пока его меняют в мастере?

                          • 0
                            Посмотреть не проблема. Проблема посмотреть его так, чтобы к моменту когда после просмотра решили обновить, он не изменился. На мастере это относительно (так же как на единственном сервере) легко, заблокировать с реплики мастер вроде невозможно нигде и, кажется, стандартными средствами СУБД нельзя даже понять на реплике, что на мастере началась транзакция, чтобы подождать её окончания.
                        • 0
                          А если вам нужно увидеть остаток по счету, а в это время в БД льются транзакции из разных мест и происходит движение денег по счетам?

                          Деньги на этом конкретном счёту перемещаются каждую секунду, и отчёт по остатку должен быть актуален с точностью до секунды? Или всё же допускается увидеть в отчёте «Ваш баланс по состоянию на DD/MM/YYYY hh:mm:ss»?
                      • 0
                        Ну, если бизнес-логика требует, чтобы операции чтения ждали окончания операции записи, если та уже началась, то стандартные реплики не особо помогут вроде, операции блокировки по репликации вроде нигде из «большой четвёрки» не передаются, только закомиченные транзакции. На реплики обычно ложатся отчёты, для которых милисекунды мало что значат, а операционная деятельность, включая чтение типа SELECT FOR UPDATE, ведётся на мастере.
                    • +1
                      Если БД занимается только данными (для чего она и предназначена), а бизнес-логику молотят app servers, то база нагружена меньше, разве нет? И я гораздо позже упрусь в необходимость горизонтального масштабирования DB master, а может вообще не упрусь.
                      • 0
                        А что есть по вашему бизнес логика?
                        • 0
                          Как-то так: https://ru.wikipedia.org/wiki/%D0%91%D0%B8%D0%B7%D0%BD%D0%B5%D1%81-%D0%BB%D0%BE%D0%B3%D0%B8%D0%BA%D0%B0
                          • 0
                            Ясно.
                            Поколение интернета, все в Вики.
                            Последний пример из бизнеса реального.
                            Калькулятор стоимости отправки грузоперевозчика.
                            Клиенту нужно рассчитать стоимость отправки.
                            Стоимость зависит от маршрута.
                            От весогабаритных характеристик груза.
                            От скидки клиента.
                            Скидка зависит от объема перевезенного в текущем месяце и объема перевезено клиентом в прошлом месяце.
                            Скидка зависит от оплаченных счетов клиента.
                            Стоимость также может зависет от наличия других заказов по этому направлению, которые консолидируются и ожидают отправки.
                            Все это я могу сделать в рамках одной процедуры, подтягивая запросами нужные мне данные.
                            Т.е. веб приложение обращается к процедуре, внутри процедуры все рассчитывается и выдает на гора ответ.
                            Теперь вынесите эту логику в апп сервер.
                            Сколько запросов вам придется оформить и отправить, для получения данных?
                            И каждый запрос SQL сервер будет компилировать и строить план запроса,
                            в то время, как хранимая процедура уже откомпилирована и план запроса сохранен для нее.
                            А время тикает.
                            И при изменении расчета, например добавилась сезонная скидка, мне нужно изменить одну, единственную процедуру и все сервисы, которым нужно знать расчет тарифа, получат его.
                            При этом я буду манипулировать данными с помощью языка, предназначенного для манипулирования данными, а значит эффективно.
                            Ну ладно.
                            Тут всплывают вопросы религии, споры бесполезны на такой почве.
                            • +3
                              Ваше же пример. Скидка зависит условно от 100 параметров. Какая вермишель будет в вашей процедуре? сколько там будет ветвлений? Вы на 100% уверены что нигде не ошиблись? Ваша процедура покрыта тестами? Сколько времени вам понадобиться, чтобы спустя год чтото в этой процедуре поменять?

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

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

                              Я конечно не ДБА, но разве субд строит план запроса каждый раз? как же кеш планов?

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


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