0,8
рейтинг
7 сентября 2012 в 03:56

Разработка → MVC умер, пришло время MOVE перевод

MVC феноменальная идея. У вас есть модели, которые самостоятельные кусочки состояний, представления которые самостоятельные кусочки UI, и контроллеры которые самостоятельные кусочки…

Что?


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

Чтобы исправить это, я использую новый паттерн: MOVE. Models, Operations, Views и Events.

Обзор


Диаграмма MOVE паттерна
Я опишу детали чуть позже, но эта диаграмма показывает базовую структуру MOVE приложения.
  • Модели (Models) представляют собой все что должно знать ваше приложение.
  • Операции (Operations) представляют собой все что ваше приложение делает.
  • Представления (Views) посредник между вашим приложением и пользователем.
  • События (Events) используются чтобы безопасно соединять все эти компоненты.

Чтобы избежать спагетти кода, стоит отметить, что есть рекомендации, какие объекты какого типа, что имеют право делать. Я показал их стрелками на диаграмме. Например, представлению разрешено слушать события, запускаемые моделью. Операциям разрешено изменять модели, но модели не должны указывать на представления или операции.

Модели


Архетипическая модель, объект «user». Он по крайней мере имеет email, и возможно, имя и телефон.

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

Операции


Обычная операция для приложения: авторизация пользователя. Это фактически две суб-операции объединенные вместе, первая: взять email и пароль от пользователя, вторая: загрузить модель «user» из базы данных и проверить соответствие паролей.

Операции, это исполнители в мире MOVE. Они несут ответственность за изменения в вашей модели, показывают правильные представления в нужное время, и реагируют на события запускаемые взаимодействием пользователя. В хорошо построенном приложении, каждая суб-операция может быть запущена независимо от ее родителя; именно поэтому на диаграмме выше события идут по исходящей, а изменения по нисходящей.

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

Представления


Экран входа — это представление, которое отвечает за показ нескольких текстовых полей для пользователя. Когда пользователь кликает по кнопке входа, представление «loginAttempt» событие, которое содержит введенные пользователем имя пользователя и пароль.

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

События


Событие «loginAttempt» запускает представление, когда пользователь кликает на кнопку вход. Кроме того, когда операция логина завершилась, модель «currentUser» запускает события, чтобы сообщить вашему приложению, что она изменилась.

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

Почему сейчас?


Я не хочу быть неправильно понятым, подразумевая, что MVC это плохо; Последнее десятилетие он был невероятно успешным способом структурирования больших приложений. Тем не менее, когда он был придуман, стали популярны новые техники программирования. Без замыканий (или анонимных блоков) назначение событий может быть утомительным; и без deferrables (так же известных как deferreds или promises) идея понимания индивидуальных операций как объектов, сама по себе не имела бы особого смысла.

Подчеркиваю: MVC крут, но он спроектирован с технологиями десятилетней давности. MOVE это просто обновление для более эффективного использования инструментов которые сейчас у нас есть.
Перевод: Conrad Irwin
Николай Костюрин @JiLiZART
карма
33,0
рейтинг 0,8
Fullstack Web Developer
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

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

  • +36
    > проблема с MVC как данность, в том что вы пихаете слишком много кода в контроллеры.

    А вы? (это не к переводчику)

    По сути — человек взял и наложил шаблон MVC на n-Layer структуру приложения. Bussines Logic обозвал Operations и радуется что новое (для себя) открыл. <сарказм>Хорошо хоть не запатентовал :)</сарказм>

    > MVC крут, но он спроектирован с технологиями десятилетней давности.

    Болтовня. Шаблоны GoF были описаны еще до MVC, что не мешает ими эффективно пользоваться по сей день. Разумеется любой шаблон это как молоток — инструмент. А как и что, гвозди или шурупы, будут им забивать — уже зависит от квалификации программиста.

    В общем, IMHO многие используют несколько модифицированные шаблоны MVC. Только никто при этом не кричит «MVC умер». Вывод — самопиар.
    • 0
      Разница в том, что:
      1) В MVC контроллер, как правило, что-то императивное: то есть шаг за шагом что-то «делающее». А в MOVE взаимодействие описывается декларативным образом.
      2) В MVC вы в общем случае не можете добавить дополнительную обработку события от пользователя не меняя контроллер. В MOVE же это делается легко.
      Это основные пункты отличия MVC от MOVE, по крайней мере, для меня.

      Я смотрю Apache Wicket в тренде с этим подходом:)
      • +5
        MVC только объявляет Controller связующим звеном между Model и View. Поэтому события для организации взаимоотношений с Bussines Logic IMHO вполне вписываются в исходный шаблон.

        Я не в коем случае не говорю что подход с событиями плох. Просто не надо выдавать реализацию MVC+n-Layer за что-то новое.
      • 0
        В MVC не предлагается конкретного однозначного способа реализации, чтобы делать подобные сравнения.
      • +7
        MVC — более общее понятие, а, судя по описанию, MOVE — это один из вариантов.

        И даже не вижу ничего сверх-хорошего. Вью напрямую слушает модель. Это ладно. Операции разделены с данными — не ощущается подвох? Всё время от этого уходили, ООП, функциональные языки. А теперь опять назад.

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


        Хотелось бы пример. Это каким образом декларативно? Операции почему-то отделены от данных. Это имело бы смысл, если бы операции не зависели от данных, а были темплейтами (женериками) и т.д. Как-то тяжело представить, кроме работы с контейнерами, которые реализованы. А вот для бизнес-логики, не представляю. Чтобы операцию авторизации применили не только к юзеру, а к заказу, например.
        Либо операции так же пишутся методами — императивно, либо нужно создавать свой язык поверх языка. Что не есть хорошо. Я знаю таких любителей, которые в гонке за гибкостью, не видят цели и выгоды. И в конечном счете делают монстра, который крайне ненадежный, не типизированный и который настроить дороже, чем если бы просто править код при изменении требований.
        • 0
          Чтобы операцию авторизации применили не только к юзеру, а к заказу, например.


          Попробуйте подняться на один уровень абстракции. s/authorization/validation/g.

          Что-то типа этого:

            a = current_object(); # got a user, an order, the whatever
            if Magestic.valid?
                puts Magestic.output(a)
            else
                Magestic.error
            end
          
          • 0
            Как вообще применять темлейты, я догадываюсь.

            Смысл написанного кода от меня ускользает. Что-то с кодом не то.

            Т.е. что написано, как-то понятно, но цель не понятна.
          • 0
            возможно, потому что я не на этом языке пишу. Пишу на шарпе. Если там current_object() — что-то определенное в языке, а Magestic из стандартной библиотеки, то вот поэтому и не понял.

            Если же нет, то код очень странный. Не выражает смысла. Набор слов, а предложение не складывается
            • 0
              Magestic может быть, например, интерпретатором lua. Дело не в языке.

              Скажем, у вас есть набор RSS-потоков, и вы из каждого хотите вытянуть HTML и показать пользователю. При этом каждый сайт показывает свой HTML, один шаблон не прикрутить. Тогда вы храните DOM-пути к тексту и Magestic вытаскивает из каждой страницы по этому пути — текст. Основной код при этом вообще не знает ничего о посторонних страницах, чтобы распарсить новый источник — необходимо просто указать путь к диву с контентом.

              Как-то так.
              • 0
                Ок. Я привык к эксепшинам и шарпу. Поэтому код кажется избыточным и даже не нужно писать такой метод.

                a = current_object();


                Здесь не нравится — сайд-эффект. Методу лучше передать объект. Но, ладно, это может быть местами и оправдано.

                if Magestic.valid?
                puts Magestic.output(a)
                else
                Magestic.error
                end


                если с эксепшинами, то что-то вроде этого:
                Magestic GetMagestic()
                {
                     if (Magestic.Valid)
                    {
                          return Magestic;
                    }
                    
                    throw new Exception("Magestic is not valid");
                
                }
                
                //.... Где-то в методе
                
                puts GetMagestic().output(a)
                


                Можно так же написать метод, и вызывать так:
                Magestic.CheckValid().output(a);

                Ну и как-то мне тяжело сообразить, где здесь требования и бизнес-логика. Конечно, можно применять темплейты, если они позволяют добиться выгоды. Представим себе, что current object — является каким-то объектом, тип которого допускает проверять валидность. Тогда, видимо, должен поддерживать интерфейс IValid. Если у вас ООП язык со строгой типизацией. Так тогда и метод валидации принимает интерфейс, ему не нужно быть теплейтом.

                Вообще, тяжело рассуждать, когда цель кода слабо обозначена и какой-то частный случай.
                причем здесь абстракция s/authorization/validation/g — не понятно.

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

                • 0
                  Все дело в строгой типизации. Для языков со строгой типизацией такой подход вряд ли оправдан.

                  Абстракция «validation» вместо «authorization» — я имел в виду, что авторизация обычно касается объекта «пользователь», и только «пользователь»; валидация же может быть обобщена для применения к любому объекту.
    • НЛО прилетело и опубликовало эту надпись здесь
    • +7
      Стоит только уточнить, что MVC был придуман как раз задолго до патернов GoF, еще при работе над smalltalk'ом. Впрочем, это не отменяет факта, что сама концепция ни разу не устарела, именно потому что она концепция, а не паттерн, т.е. не привязана к ООП напрямую.
      • 0
        Вообще, mvc составной паттерн, если уж на то пошло.

        И да, как и любой паттерн, он гибок- например в веб-приложениях вьюшка и модель не реализуют Observer, как в каноничной реализации mvc.
        • +2
          Если уж на то пошло, то mvc — это концептуальная схема для реализации которой применяют несколько паттернов :)
    • 0
      1-10 строк в действии контроллера для них много уже? (Больше — крайне редко)
      Хотелось бы посмотреть на их проект, чтобы сравнить. Кажется, что это очередная исключительно теоретическая беллетристика
      • 0
        Прошу прощения, мне показалось, что речь про веб.
    • +2
      Если мне не изменяет память, MVC был впервые описан в спецификации Smalltalk-80, то бишь лет за 10 до GoF.
  • +20
    Я использовал подобную технологию в своём фреймворке до того, как это стало мейнстримом
  • +2
    Давайте нарисуем единорога на капоте машины и назовем это машиной будущего: модификации предложенные в MOVE столь малы, что назвать получившийся продукт «не MVC» просто некорректно.

    А вообще, события уже очень давно используются в любом мало-мальски нормальном фреймфорке.
  • 0
    Qt уже очень давно использует свою систему сигналов и слотов.
    При попытке использовать MVC в JavaScript, сам язык вынуждает использовать события.
    • 0
      Да что Qt, Windows испокон веков использовал Messages.
      • 0
        Но MVС там меньше… намного.
      • 0
        Там слишком брутально же, а тут (как вообще везде в последние 10 лет) — речь про syntactic sugar.
        Я до сих пор с ужасом вспоминаю подписку на PostMessage vs. SendMessage.
  • +2
    Всегда думал, что вся логика приложения должна находится в моделях.
    То что модели != данным в БД проецированным на экземпляры классов.
    Всегда думал, что много кода в контроллерах == не понимание паттерна MVC.

    И нате MOVE.
    • 0
      Вся суть MVC в названии, ничего больше. То что вы понимаете под MVC — одна из реализаций проявляющаяся себя в лучших и худших сторонах в зависимости от задачи. Предложенная в статье реализация также имеет свои плюсы и минусы. Автор намудрил с терминами, сравнивая свою реализацию с некой другой часто употребляемой.
      • 0
        Думаю, вы не правы.
        Тогда бы не существовало MVP и MVVM.
        MVC подразумевает, что бизнес-логика находится в моделях.

        Начинающие программисты (особенно в веб-программировании, где аббревиатура MVC стала популярна) очень часто трактуют архитектурную модель MVC как пассивную модель MVC. В этом случае модель выступает исключительно совокупностью функций для доступа к данным, а контроллер содержит бизнес-логику. В результате код моделей по факту является средством получения данных из СУБД, а контроллер представляет собой типичный модуль, наполненный бизнес-логикой, или скрипт в терминологии веб-программирования. В результате такого понимания MVC разработчики стали писать код, который Pádraic Brady, известный в кругах сообщества Zend Framework, охарактеризовал как ТТУК — «Толстые тупые уродливые контроллеры» (Fat Stupid Ugly Controllers)
        • +3
          ТТУК — «Толстые тупые уродливые контроллеры» (Fat Stupid Ugly Controllers)
          Хулительное наименование можно придумать для чего угодно, при наличии хотя бы минимального интеллекта.
        • 0
          Жалко, не догадался подогнать под аббревиатуру «FUCK»…
          • 0
            Ага. «Большие Легкомысленные И Ярковыраженные Дебилообработчики».
        • 0
          Концепция дома подразумевает наличие двери стены, крыши. MVC декомпозирует приложение на три компонента, подразумевая для них обобщенное назначение. Стена дома может быть кирпичной, бетонной, иметь окна. Окна могут быть панорамными, выполнять функцию стены. Модель может быть пассивной, может активной, содержать бизнес логику. Контроллер «толстым» или «тонким». Вариаций множество, суть остается та же. Зарекомендовавшие себя реализации закрепили за собой названия. Коттедж, замок, хрущевка)) HMVC, MVVM, MVP… Теперь мы спорим, какими должны быть стены, двери у дома, считая что дом это нечто конкретное.
          • 0
            Нет, просто у таких вещей как Model, View и Controller есть определения.
            И если вы переносите всю логику в Controller то Model перестает быть Model, а Controller перестает быть Controller.

            Если этого не понимать, то MVC, MVP и MVVM превращаются, как сейчас в пустой звук.
            • –1
              Логика есть у каждого из трех элементов MVC, о полном переносе бессмысленно говорить. Явной границы между элементами сложно достичь, приходиться идти на компромиссы. Вы цитируете википедию, обратите внимание, в ней написано о двух вариантах реализации MVC — пассивном и активном, как результат компромиссов. MVC — это концепция без конкретики реализации. Всё остальное — это варианты реализации MVC, пытающиеся претендовать на звания концепций с конкретной реализацией. Не приписывайте к MVC одного способа реализации.
              • 0
                MVC — это концепция без конкретики реализации

                Вы вообще понимаете что говорите?
                Вы бросаетесь терминами, как будто они ничего не значит.

                Вы понимаете что такое «концепция», «реализация»?
                Может поэтому для вас MVC это набор звуков «Model, View, Controller» за которыми ничего не стоит?

                Буду использовать терминологию Wiki. Как более-менее компромиссную (хотя я не полностью с ней согласен)
                MVC — это концепция без конкретики реализации

                Конце́пция — генеральный замысел, руководящая идея. Концепция определяет стратегию действий.

                1. Да, MVC можно признать концепцией.
                2. Далее, концепция MVC утвеждает, что
                Модель — Модель предоставляет знания: данные и методы работы с этими данными, реагирует на запросы, изменяя своё состояние. Не содержит информации, как эти знания можно визуализировать.

                Представление — Отвечает за отображение информации (визуализацию). Часто в качестве представления выступает форма (окно) с графическими элементами.

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

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

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

                Повторюсь, я использовал Wiki-терминологию, которую можно считать общепринятой. Но я не совсем с ней согласен, но это уже мои личные проблемы.
                • 0
                  Соответствено бизнес-логика находится в модели.
                  Зачем тогда контроллер? Мапить события от вида на методы модели?
                  • 0
                    Там же написано:
                    > Контроллер — Обеспечивает связь между пользователем и системой: контролирует ввод данных пользователем и использует модель и представление для реализации необходимой реакции.

                    Контроль данных и выбор необходимого представления.
                    • 0
                      Ну предположим что выбор необходимого представления не является функцией контроллера при реализации MVC с активной моделью. Что тогда остается? Контроль данных это что? Весьма абстрактный термин.
                • 0
                  От предметной области зависит, где будет преобладать бизнес логика. Может в модели, как вы всегда думали, может в контроллере, может в представлении, хотя, с ней всё расплывчато. Всё зависит от решаемой задачи.
                  • –2
                    «Я ему про Фому, он мне про Ерёму»
                    Извините, но вы вообще не понимаете, и без того скудную, теорию по программированию. До тех пор, пока вы этого не поймете что термин это не пустое содрогание воздуха, для вас пустым звуком останутся такие понятия как:
                    — шаблон
                    — принцип
                    — способ
                    — модель
                    — система
                    — уровень абстракции и т.д.

                    И соответственно не придет понимание работы MVC, MVP и прочих шаблонов.
                    И тут не зависит все от решаемой задачи, т.к. весь принцип MVC описан в определении.
                    То что вы пытаетесь подсунуть под видом MVC им уже не является.
                    Это тоже самое, что заявить, указав на синие стены, что они красные. И что все зависит от того, в каком настроении вы на них посмотрите.

                    • 0
                      Извиняю) Вы перегружены теорией. Прочли, что пассивная модель плохо, всё, нигде её нельзя. Поделитесь своим опытом, почему вся логика приложения должна находится в моделях? Я вам расскажу, почему не всегда должна, при этом принцип MVC сохранится.
                      • 0
                        По определению.
                        Если вы используете бизнес-логику в контроллерах — это уже не MVC.
                        Строго по определению.
                        • 0
                          А где в MVC нужно писать бизнес логику?
                          • 0
                            Уже прочитал всю ветку.

                            Не согласен с вашим трактованием википедии.

                            Медель:
                            >данные и методы работы с этими данными — аксессоры,
                            > реагирует на запросы, изменяя своё состояние — императивно, посредством акссесоров.

                            Контроллер:
                            >контролирует ввод данных пользователем и использует модель и представление для реализации необходимой реакции.
                            Реализация необходимой реакции включает в себя реализацию бизнес логики, которая, следовательно должна быть реализована в контроллерах.
                            • 0
                              Почитал вики дальше — странно все это, нужно к истокам за инфой ходить.
                            • 0
                              Контроллер —… и представление для реализации необходимой реакции.

                              Контроллер не реализует, он предоставляет выбор реализации. Т.е. он обращается к необходимой модели.
                              • 0
                                Угу, понял, логично. Спасибо. Я только в начале августа начал писать на php CI, и вот это ошибку допустил. Раньше мне казалось, что в MVC — мусор, теперь тоже так кажется). Ума не приложу, почему бизнес логика не отделяется от хранилища.
                                • 0
                                  Почему то, многие воспринимают Model лишь как проекцию данных из хранилища на объекты.
                                  Model — это классы, которые реализуют логику работы над данными.
                                  Как вы храните данные Model не интересует.
                                  Способы реализации Model я знаю двух типов, с помощью:
                                  — Active Record
                                  — Data Mapping

                                  В первом случае, данные хранятся вместе с бизнесс-логикой и публичные методы Model отвечают на вопрос «Что можно сделать с данным типом данных?

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

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

                                  Другими словами, мне кажется, что концепция MVC с пассивной моделью — лучше, а те, кто считают иначе, имхо, сами начинающие веб-программисты. Лучше потому, что:
                                  1. Данные отделены от модели, и изменения типа хранения данных не повлияют на логику работы программы, т.к. обработка данных — инкапсулирована в подсистему данных, и вне зависимости от внутренностей — прототип функций доступа не изменится.
                                  2. Нет смеси двух разных сущностей.

                                  Хотя, если в модели еще 2 разных подсистемы:
                                  * Первая — подсистема доступам к данным, на уровне функций доступа высокого уровня, с высоким уровнем абстракции (не getDataFromTable, а checkUserPassword).
                                  * Вторая — подсистема бизнес-логики, которая инкапсулирует первую и предоставляет API для контроллера.
                                  То жить можно, но тогда почему бы не вынести вторую в первую. Для ясности, уточню, что бизнес-логика тут разделена на 2 уровня: низкой абстракции работы с данными и высокой. В низкой, в императивной форме описывается «как», а в высокой «что».
                                  • 0
                                    Ага, понял, вот Data Mapping — то о чем я говорил. А по Active Record — ушел читать вики.
                                  • 0
                                    > бы не вынести вторую в первую
                                    бы не вынести вторую подсистему в контроллер, где ей и место, как мне кажется.
                                  • 0
                                    Я не понимаю как вы в Data Mapping(DM) уйдете от проблемы изменения логики, при изменении структуры данных?
                                    К тому же, появляется новая проблема, вы не знаете что можно делать с данными.
                                    Т.е. вы инкапсулируете логику но не публикуете интерфейсы.

                                    Поэтому я все же в вебе склоняюсь к Active Record(AR), т.к. при смене члена команды, ему не придется читать руководство разработчика по работе с данными и запоминать. У него есть интерфейс. Да и писать это самое руководство не придется.
                                    К тому же, я руководствуюсь все время правилом: «Лучшая документация — это код». А в DM оно не соблюдается.

                                    Хотя у DM есть одна интересная особенность. Если вам интересны данные в каком либо разрезе(например конкретный момент времени в прошлом), то у него тут большое преимущество перед Моделями в AR. Т.к. вы все время работаете со срезом данных и бизнес-логика к этому готова.
                                    А в AR придется критерий среза передавать все время в методы.
                                    • 0
                                      Прикол при DM в том, что есть разделение между логикой работы с данными и бизнес логикой приложения.
                                      Все что напрямую взаимодействует с данными — вынесено в отдельную подсистему. Если изменился тип хранения данных, изменения будут только в логике работе с данными, и никак не затронут бизнес логику.

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

                                      А вот внешне модель уже будет иметь интерфейс, который описывает данные никак. Он будет архивысокого уровня, вида createNewUser(login, mail, other), getTopMenuItems()… А для контроллера больше ничего и не нужно. Ну вот зачем ему знать, какие операции можно проводить с данными? Ему только нужно знать, что вообще он может делать с моделью.

                                      Лучшая документация — это код. Это не зависит от AR / DM.
                                      • 0
                                        Но с другой стороны, ужесточение правил разделения уровней абстракции в DM, вероятно весомо усложнит процессор разработки логики работы с данными, либо создаст серьезный ущерб производительности:

                                        function createNewUser($userName, ...) 
                                        {
                                          if (userExists($userName))
                                            return false;
                                        
                                          //проверка валидности имени и прочих параметров
                                        
                                          appendUser(...)
                                        }
                                        

                                        где createNewUser — функция уровня бизнес логики, а userExists и appendUser — функции логики работы с данными. И хотя они обе оперируют абстракцией User, первая и в реализации оперирует этой абстракцией, а вторая только в интерфейсе и состоит из атомарных операций, которые знаю о логике работы программы практически ничего.

                                        Беда в этом примере в том, что тут будет 2 запроса к БД, а при AR мог был бы быть только 1, и тогда, с точки зрения производительности активная модель, AR — лучше пассивной либо DM. Чтобы убрать этот абстракции до чего-то типа createIfnotExists, либо врубать хитрату в реализации с отложенными вызовами.

                                        P. S. абстракции можно было и иначе делать, суть лишь в том, что атомарные операции с БД — выделены в одном месте.
                                        • 0
                                          >которые знаю о логике
                                          которые знают о логике

                                          > Чтобы убрать этот абстракции до чего-то типа
                                          Чтобы убрать этот недостаток, нужно усложнить до чего-то типа

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


                                        Как бы в данном случае AR и DM идентичны, т.к. используют для работы с данными getters и setters.
                                        class User {
                                             protected $name;
                                             public function getName() {
                                                  return $this->name;
                                             }
                                             public function setName($value) {
                                                 $this->name = $value;
                                             }
                                        }
                                        


                                        Различая будут в реализации доступа к бизнес-модели:
                                        /* DM */
                                        $builder = new UserBuilder();
                                        $user $builder->buildNewUser();
                                        
                                        /* AR */
                                        $user  = User::buildNewUser();
                                        
                                        • 0
                                          В DM не будет тоже самое, что и в AR в этом контексте вашего примера. Не нужно тому, кто использует слой бизнес логики, $user из слоя работы с данными.

                                          Правильно ли я понимаю различие:

                                          //AR
                                          class User {
                                             public function checkUserPass($login, $pass)
                                             {
                                          	return count(query("select count(*) from users where login=$login and pass=$pass;").result()) > 0;
                                             }
                                          }
                                          
                                          //DM
                                          class DtUser {
                                             public function loginExists($...) {}
                                          
                                             public function getPassByLogin($..) {}
                                          }
                                          
                                          class User {
                                             public function checkUserPass($login, $pass)
                                             {
                                                if (!DtUser::loginExists($login))
                                                   return false;
                                          
                                                return DtUser::getPassByLogin($login) == $pass;
                                             }  
                                          }
                                          
                                          
                                          • 0
                                            В DM не должно быть обращений к хранилищу, в крайнем случае будет что-то вроде
                                            class User {
                                              public function checkPass($pass) {
                                                return $this->pass === $pass;
                                              }
                                            }
                                            

                                            а лучше в контроллере
                                            $success = 1 == $repo->countByLoginAndPass($login, $pass);
                                            • 0
                                              Хорошо. А где-же должно быть обращение к хранилищу?
                                              • 0
                                                class UserRepository {
                                                  public function countByLoginAndPass($login, $pass) {
                                                    return $this->db->query("select count(*) from users where login=$login and pass=$pass;").result();
                                                  }
                                                }
                                                

                                                • 0
                                                  Ну так. Я это и написал… другими словами просто. Или тут какие-то неявные отличия есть?
                                                  • 0
                                                    У вас в User есть ссылка на DtUser.
                                          • 0
                                            Лучше перепишу пример, что бы стало понятно:
                                            /* 
                                             * AR
                                             * Важный момент в AR то, что вы получаете экземпляр, прежде чем с ним работать.
                                             * Прямые запросы в статике - как раз и есть тот плохой подход, который вы ругаете
                                             */
                                            class User {
                                            
                                               public function getPassword() { ... }
                                            
                                               public static function findUserByLogin($dbProvider, $login) { ...  }
                                            
                                               public function checkUserPass($pass)
                                               {
                                                  return $this->getPassword() === $pass;
                                               }  
                                            }
                                            
                                            class Controller 
                                            {
                                              protected $dbProvider;
                                            
                                              public function action($login, $pass) {
                                                 $user = User::findUserByLogin($this->dbProvider, $login);
                                                 $result = $user->checkUserPass($pass);
                                                 ...
                                              }
                                            }
                                            
                                            /*
                                             * DM
                                             */
                                            class DtUser {
                                                public function getPassword() { ... }
                                            }
                                            
                                            class UserService {
                                               public function checkUserPass(DtUser $user, $pass)
                                               {
                                                  return $user->getPassword() == $pass;
                                               }  
                                            }
                                            
                                            class Controller 
                                            {
                                              protected $dbProvider;
                                            
                                              public function action($login, $pass) {
                                                 $user = $this->dbProvider->getDtUser($login);
                                                 $bissnessLogic = new UserService();
                                                 $result = $bissnessLogic->checkUserPass($user, $pass);
                                                 ...
                                              }
                                            }
                                            


                                            Как то так, вот 2 концепции.
                                      • 0
                                        А для контроллера больше ничего и не нужно. Ну вот зачем ему знать, какие операции можно проводить с данными? Ему только нужно знать, что вообще он может делать с моделью.

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

                                        public function action()
                                        {
                                            $specificUser = User::<все подскажет autocomplete IDE>;
                                        }
                                        


                                        В DM это сделать проблематично.
          • 0
            А мансарда? А дом, полностью представляющий собой мансарду?

            Граница между View и остальным — довольно чёткая, между Model и Controller — довольно зыбкая и расплывчатая, обычно есть несколько переходных ступеней.
            • 0
              Мансарда это ведь чердак? :) Человечество постоянно что-то изобретает и придумывает именования изобретению, как первичный классификатор. Получается вполне конкретное определение по названию. Так было и с MVC, когда его придумали для настольных программ с графическим интерфейсом. Но пытливые умы, двигающие прогресс, придумывают новое, применяют новые технологии, улучшая, расширяя возможности, сферы применения и первичный классификатор (именование изобретения) становится всё более абстрактным.

              Граница четкая между Views и Model, если ею является Controller как связующий элемент. Где граница контроллера с моделью и представлением не стоит даже пытаться выявлять)) Дополнительные слои в MVC как раз и образуются в попытках её выявления. Например, граница между головой и телом человека — шея, а где граница между шеей и головой? какие клетки уже принадлежат шеи… может на атомном уровне есть граница? ))
              • 0
                В мансарде крыша играет роль стены. На чердаке, в общем, тоже.

                Граница четкая между Views и Model, если ею является Controller как связующий элемент
                Это называется Model–view–adapter. В классическом MVC они вляют друг на друга по кругу.
              • 0
                Да, есличо, в применении к вебу это MVA мне больше нравится, чем классическое MVC.
    • +1
      Можно еще добавить слой Сервисов. В Моделях остаются только описания сущностей, работа с БД уходит в Сервисы, в Контролерах реализуется логика работы путем вызова сервисных методов. Еще добавляют четвертый слой — DAO для реализации атомарных операций с данными. Получается следующая цепочка из более-менее изолированных сущностей — Модель > DAO > Сервис > Контроллер.
      • 0
        Ну да, «вид, строго отделённый от контроллера, плавно перетекающего в модель»…
    • +3
      Всегда думал, что вся логика приложения должна находится в моделях.
      То что модели != данным в БД проецированным на экземпляры классов.
      Всегда думал, что много кода в контроллерах == не понимание паттерна MVC


      Куда помещать business logic — это больное место MVC. Ряд веб фреймворков (не буду тыкать пальцем) пихают в контроллер и авторы утверждают, что так и надо. Более того, напрямую заданый вопрос на stackoverflow по поводу основного фреймворка Apple (http://stackoverflow.com/questions/8386614/cocoa-mvc-where-is-application-work-logic-intended-to-be-placed) получил ответ от автора книги по этому фреймворку (!!) что «логику пихать в контроллер».
      • 0
        Кашмар.
      • 0
        Долго не понимал, зачем нужны контроллеры (сам в 2003 сделал бесконтроллерный мини-фреймворк), пока на одном собеседовании полтора года назад не объяснили: чтоб вешать на них транзакционность (в 2003 для транзакционности служили серверные процедуры ORACLE или DB2).
        • 0
          Есть много вариантов. Один из популярных — ответ на вопрос «пользователь выбрал „help/about“ — где расположен код, который покажет вид „About“? :).
          • 0
            г
            де расположен код, который покажет вид „About“? :).
            В движке.
  • +1
    Автор немного не понимает значение слова авторизация. Очень раздражает когда ее путают с аутентификацией.
    • +2
      Возможно проблема перевода.
      • 0
        Скорее всего. В английском путаницы почти нет с этими терминами.
  • +2
    Хм, я разве для построения серьезного проекта достаточно использовать только один паттерн? В вашем случае MVC или MOVE. Думаю в этом основная проблема того что "… вы пихаете слишком много кода в контроллеры.".

    Взять «Архетипическая модель, объект «user»» — конечно что же, используя только MVC, можно засунуть все методы юзера в один файл и получить 5-10 тысяч строчек кода. Особенно если используется несколько типов учетных записей и в каждой функции проверяются возможности пользователя.
    Вы же не хотите писать многочисленные проверки? Примените паттерн Strategy, вынести его в отдельную библиотеку и получите модели которые "… не содержат функции, которые сохраняют данные в базу ..." и красивую библиотеку классов с поведениями юзеров.
  • 0
    Моделька не революционная, но интересная. Насколько я ее понял, она очень похожа на то, что использую я: HMVC + Observer.

    Заголовок, конечно кричащий до безобразия (аля «TV is dead», если кто не в курсе), однако думаю, что для многих принять и понять MOVE как нечто обособленное и начать с ним работать может оказаться проще, чем наращивать архитектурные плюшки в рамках MVC. Пусть будет.
  • +4
    ЭЭЭЭ…
    Вы знаете, кроме веб приложений и веб технологий есть огромный мир всего другого. И паттерн MVC не «спроектирован с технологиями десятилетней давности.» а использовали и описали задолго до появления веба.
    И MVC не крут. Это просто инструмент для решения типичной задачи.
    Всеравно что сказать «Вау, смотри, этот молоток крут». Не молоток крут, а человек, который круто забивает гвозди.
    И если для ваших задач лучше подходит молоток-гвоздодер (MOVE) не делает его решением всех проблем.

    И кроме ваших 2х есть еще десятки описаных паттернов и наверняка еще куча неописаных.
    Я понимаю, что это перевод. И наверняка атор авторитетен, но это какой-то десткий сад.
    • 0
      Последнее слово поначалу прочитал как «дейкстрский сад»…
  • 0
    Было бы отлично, если бы еще к таким статьям прилагали данные типа: насколько в числовом выражении это ускорило разработку проекта X в сравнении со старой моделью? Сколько денег это позволило сохранить? И т.п.
  • 0
    Рекомендую также ознакомиться с CQRS/Event Sourcing
  • +3
    Не надо относиться к паттернам как канонам, которые нельзя переступить. Описанный вами MOVE тот же MVC, как уже было замечено, лишь немного преобразившийся. Споры на счет: шаблон крут/не крут не считаю рациональными. Если мне надо (и это хорошо впишется в архитектуру) я наделю модель возможностью иметь не только геттеры и сеттеры, но и методы, которые меняют ее комплексно. Если надо сделаю из нее POJO. Если я вижу что можно объединить модель и контроллер в один модуль и это улучшит положение я это сделаю. Задача не бывает всегда одинаково штампована, так чтобы паттерн «прокатывал» одинаково каждый раз. Паттерн — это рекомендация, ей нужно следовать, но не слепо.
    • 0
      Про паттерны следует побольше читать Грэма и Норвига…
  • +2
    С MVC все ок. Единственная (и главная) проблема в том, что некоторым разработчикам паттерны заменяют мозг
  • +2
    Отвратительное качество перевода. Автор либо стоит выспаться, либо переосмыслить свое понимание паттерна MVC.
  • +1
    В MOVE приложении, модели только обертки знаний. Это означает что, помимо геттеров и сеттеров они могут содержать функции, позволяющие проверять «это пароль пользователя?», но не содержат функции, которые сохраняют данные в базу или загружают их в стороннее API. Это работа «операций».

    В хорошем MVC приложении модели тоже не содержат функций, которые сохраняют данные в базу данных или в стороннее API.

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

    В MVC это контроллеры.

    По сути предлагается то же MVC лишь с зафиксированным способом обмена информацией между компонентами приложения — событиями, другие способы (прежде всего прямые вызовы) объявляются «вне закона». Подход интересный, но на качественно отличный от MVC имхо не тянет.
    • 0
      События хороши своеё потенциальной асинхронностью, легковесностью (в плане тредов) и акторизуемостью. Чем они тут существенно отличаются от шаблона Command — вопрос…
  • 0
    Можно посмотреть на один из референсов МС — Project Silk. Там «Операции», вызываются из контроллера. Для каждой написан свой хэндлер:
    var vehicles = Using<GetVehicleListForUser>().Execute(CurrentUserId);
  • 0
    Использую что-то похожее:
    Model содержит данные и операции с ними (в примере с авторизацией — поиск пользователя по логину\паролю, создание нового). Здесь основная концентрация кода.
    View, как обычно, предоставляет интерфейс пользователю (поля и кнопочки), на основе модели, но события отправляет Контроллеру.
    Controller же содержит обработчики событий, поступающих от Вида, дергает Модель на действия и решает, какой из Видов показать. Причем сложной логики здесь нет.

    Вроде бы классическая MVC модель с толстой моделью и тонким контроллером, однако, слои не знают друг друга, а слушают и генерируют события (т.е. ссылок друг на друга нет, кроме получение информации Видом в виде Модели), чем обеспечивается минимальная связанность (если чего-то не хватает, то остальные будут жить).
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      и кто оказался прав )
      • –1
        Учитывая то, что второе предложение приписали несуществующему Богу существующие или уже не существующие неизвестные авторы, то прав оказался таки Ницше. Или Вы утверждаете, что вышестоящая фраза pablobablo является доказательством существования бога?
        • 0
          Существование или не существование бога (как творца всего сущего) недоказуемо в рамках современного научного подхода. Бог вне системы, которая формирует наше (научное) представление о мире. Нельзя исключить, например, что законы физики являются лишь проявлением его воли: «Да будет сила гравитационного взаимодействия двух тел прямо пропорционально их массе и обратно пропорционально квадрату расстояния между ними. И стало так».
    • +1
      «Ха-ха» -Смерть
  • +3
    И чем это отличается от MVVM с биндингами на событиях?

    Велосипед, причем с квадратными колесами.
    • 0
      О, нашёл наконец-то MVVM, в самом последнем комментарии. Позвольте с вами согласиться, коллега.
  • 0
    дежавю
  • 0
    Собираюсь переписывать(оптимизировать) EpisodeCMS, используя этот подход.
    Проект опен-сорс. Набираю команду.
    • 0
      только не говорите, что именно этот пост вас сподвиг всё взять и переписать
      • 0
        Именно этот пост стал поворотным моментом. Я связался с автором оригинальной статьи, но он сказал, что занят, но с радостью проконсультирует.
  • 0
    >но проблема с MVC как данность, в том что вы пихаете слишком много кода в контроллеры.

    Для кого проблема? У меня такой проблемы нет.

    В моем подходе (ASP.NET MVC/Linq2Sql) контроллер содержит собственно логику REST-вызова, т.е. что должно происходить, когда клиент вызывает данный метод, а так же обеспечивает правильное заполнение модели, ее передачу DAL-у и получение из него.

    Модель представляет собой легковесный DTO (data transfer object) с вспомогательными маппинг-конструкторами, функциями форматирования, аттрибутами валидации, и тому подобными плюшками.

    DAL — построен по паттерну Repository и содержит вызовы Linq2Sql, с некоторой вспомогательный логикой — кеширование, подстановка данных не из вызываемых таблиц, а из таблицы архива (при этом для клиента, вызывающего данный метод, это выглядит одинаково), и т.д. Методы DAL возвращают IQueryable<...>, поэтому возникает полное ощущение, что работаешь напрямую с Linq2Sql. Разумеется используются интерфейсы, поэтому все отлично mock-ается и тестируется.

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

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

    P.S. С ужасом вспоминаю MVP для WebForms — там был просто ад!
  • 0
    Что при практическом применении MVC всегда было нечётко — так это граница между моделью и контроллером…
  • +1
    По-моему MOVE нарушает принцип KISS. MVC эталонная модель и в реальных проектах могут быть отклонения специфичные для некоторого функционала, но не вижу смысла разделять трехзвенную логику позволяющую делать тоже самое на четырехзвенную. Чем больше компонентов — тем больше кода и файлов, а значит выше сложность. Зачем плодить сложность на пустом месте? ИМХО.
  • 0
    Выбирали фреймворки для флекса, видели и puremvc в том числе. Может быть он и хорош, но количество классов(даже вроде есть генераторы кода под puremvc) и необходимость наследования — показались неправильным что ли. Хотелось избавиться от необходимости плодить события и иметь возможность явно видеть, кто и что вызывает, а не бегать по листенерам и строковым константам, ну и без кастов. Все фреймворки внутри себя использовали события, а точнее какой-нибудь один синглтон, через который все идет. RobotLegs предлагает еще сигналы и ioc, но все равно проблему избыточности не решает. Со spring actionscript даже желания разбираться не было).

  • 0
    я только сейчас прочитав понял что я так и делаю :) но не знал что это MOVE
  • +1
    «посоны, MVC — это прошлый век, сейчас я покажу вам настоящу, уличную магию!» и показывает всё тот же mvc-треугольник, но с разноцветными стрелочками, который с гордостью называет MOVE

    операции, модели, представления… это же функции, структуры и шаблоны знакомые нам с доисторических времён

    а вообще, треугольник этот в клиент-серверную архитектуру не вписывается совершенно — отсюда и столько версий «истинного mvc»

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

    если тебуется менять одну субд на другую — выдели код общения с ней в отдельный слой и назови его «драйвер базы данных» или даже «объектно-реляционный преобразователь»
    если требуется поддержка разных клиентов — выдели код общения с ними в отдельный слой и назови «фронтальный контроллер». для всяких soap-ов и json-rpc большего и не надо.
    если требуется менять формат ответа для одних и тех же возвращаемых данных — выдели код, формирующий ответ в отдельный слой и назови его «представление».
    если нужно менять правила работы с данными — выдели их в отдельный код и назови его «бизнес логика».
    а если всего этого не надо — фигачь всё вместе, но не забывай, что для разных задач есть разные языки более соответствующие языки: языки программирования, языки шаблонов, языки запросов, языки стилизации, языки настройки, языки сопоставления с образом и многие другие.

    и не надо спорить о том сколько слоёв должно быть в приложении — 3 или 4. их может потребоваться гораздо больше. и совершенно не важно как их называть, лишь бы было понятно их предназначение.
    • +1
      > а вообще, треугольник этот в клиент-серверную архитектуру не вписывается совершенно

      С чего бы это?
      • 0
        Потому что нужно два таких треугольника.
      • 0
        Потому, что клиент-серверная архитектура — это слои, и сообщение между моделью и видом мимо контроллера-адаптера не предусмотрено и обычно вообще невозможно.
        • +1
          А кто сказал что Модель это только один слой?
          • 0
            Какая разница, всё равно сообщение между несоседними слоями мимо промежуточных слоёв не предусмотрено и обычно вообще невозможно.
            • 0
              В вырожденных случаях треугольник нарисовать вполне можно — никто не утверждает что модель, контроллер и вид должны общаться прямыми вызовами в рамках одного процесса. Сложнее когда часть логики одного вида на клиенте, а часть на сервере.
              • 0
                Если часть кода модели будет в браузере, то можно сделать и классический MVC-треугольник...;-)
                • 0
                  Рано или поздно станет сложно поддерживать (ессно для задач посложнее «валидировать форму коммента на стороне клиента»). Проще, имхо, сразу реализовать два треугольника, или связанных контроллерами, или чтобы браузерный являлся серверным видом.
  • 0
    Омг, я с Django, оказывается, паттерн MOVE использую.
  • 0
    Для меня MOVE — это как раз то от чего предостерегает автор в начале — MVC с толстым контролером. Видимо автору настолько противила называть толстые контролеры, которые он писал, контролерами что он решил назвать им Операциями. Видимо изменение термина успокоило его и теперь он может с легким сердцем писать бизнес-логику там где писал раньше, оправдываясь тем, что это же мол не контролер, а операция. Тут это можно))))

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

    Лично я как разработчик «тонких» клиентских приложений (фронтэнд) в свое время вообще отказался от понятия контроллера и использую подписки моделей на события представлений, а представления на изменения моделей. Естественно и модель и представление это часто не однослойная конструкция. Как называть мой подход даже не думал, главное что работает.
  • 0
    К слову, автор MVC уже давно понял его проблемы и придумал новую парадигму – Data, Context and Interaction (DCI).

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