Как стать автором
Обновить

Комментарии 18

НЛО прилетело и опубликовало эту надпись здесь

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

Я правильно понимаю что этой картинкой вы хотите сказать что если вам поставили задачу дополнить интерфейс вы будете дорабатывать вьюху? А что есть вариант не дорабатывать?

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

Добро пожаловать в асинхронный мир.

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

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

Проблема разрыва логики

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

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

Вместо этого скажу, что архитектура не то, чтобы должна решать все перечисленные 3 проблемы. Для их решения есть свои собственные инструменты. А архитектура немножко для другого. (И, кстати, про цели архитектуры тоже неплохо бы подтянуть матчасть.) Вот например, из документации MVC имеет своей целью максимальную переиспользуемость кода. Цитата: "A goal of a well-designed MVC application should be to use as many objects as possible that are (theoretically, at least) reusable."

Но мы прям с нетерпением ждем, что же такое Вы нам покажете.

Без конкретных примеров абстракции (ещё и на ночь) довольно трудно воспринимать. (Может быть, утром?)

Если представить просто некий абстрактный (то есть — отвлечённый от всякой конкретики) пример, то при необходимости каких-либо дополнений захочется не пытаться наращивать слои. Слои трогать не хочется, они уже созданы. Более удачно, менее удачно. Не суть важно. Созданы. Из всей этой конструкции наружу торчит только Контроллер. Вот и возникает желание навесить сверху новый контроллер, который будет распределять запросы к различным подсистемам, одна из которых соответствует старому компоненты, а другая — новому. При этом Модель (данных) будет содержать метаданные, описывающие различные варианты или типологию компонентов нижестоящего уровня, а Представление будет выдавать результат работы выбранного Контроллером нижестоящего компонента.

Учитывая, что и Модель, и Представление также могут быть развёрнуты в тройки (M,V,C), то послойные правки могут упорядоченным образом распределены по этим тройкам. Это уже другой подход. Наверное, возможный.

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

Зачем требуется определённый порядок? (Похоже, без примеров не обойтись.)

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

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

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

Расскажу как решались подобные проблемы в десктопных UI(думаю и в вебе можно смастерить плюс-минус тоже самое).

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

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

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

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

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

PS: классический MVC паттерн как по мне, вообще не сильно полезная штука

Собственно, хорошо построенная архитектура в вебе, примерно этому и соответствует: бэкенд(модель данных)/фронтенд(UI для ее отображения). Поэтому если у вас есть проблемы с состоянием(в частности глобальном) в UI, то изначальный вопрос, зачем оно там взялось. (нет состояния - нет "разрывов" логики, что есть то и отобразили)

Да, тут конечно возникает часто необходимость локальности данных, так как ходить на каждый чих в бэкенд может быть дорого, но это вполне решается в рамках той же парадигмы: Глобальная модель данных <-синхронизация-> Локальная модель данных <-> Отображение UI.

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

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

Часто видел в проектах на Qt проблему. Стандартные qt модели работают хорошо ровно до тех пор пока у вас тривиальная логика.

А по хорошему модель в qt должна выступать исключительно в качестве прокси над реальными данными (к примеру sql база) и вообще не реализовывать никакой логики. Должно получаться что-то типа business data -> qt model -> view/delegate. То есть модель проксирует бизнес данные во вьюху для отображения и в обратную сторону - события от делегатов для редактирования. С таким подходом даже при навороченной логике всё достаточно гармонично работает. Но надо внимательно следить за чистотой кода, чем часто пренебрегают, особенно когда много миддлов (программистов не понимающих важность архитектурного планирования) и когда горят сроки.

Под моделью данных я как раз имел ввиду, нормализованное хранилище состояния/данных приложения, а не стандартные model/view из qt. Слой данных реализует доступ к данным, обновление состояния и набор событий связанных с его обновлением, и по сути полностью изолирован от UI. Так что тут я с вами полностью согласен, чем меньше состояния внутри компонентов UI тем лучше.

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

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

Мой довольно скромный опыт в этой области приводит к простому, но не совсем очевидному выводу. MVC, MVP, MVVM и прочее -- это не то, что я делаю, это то, что делает GUI библиотека типа Qt или WxWidgets. Соответственно, мы либо принимаем архитектурные решения авторов, либо бодаемся с ними. Бодаться накладно, а чтобы принять, надо, получается, не выбирать самый подходящий паттерн из книжки или из головы, а смотреть, как предполагается по авторской логике решать ту или иную задачу именно в рамках их системы. И это, видимо, в большинстве случаев лучшее из того, на что можно рассчитывать.

Так и не понял, что такое "фича" в вашем понимании, и зачем вы разбиваете её на слои. Обычно под фичей понимают единицу функциональности. Но слои функциональности и архитектурные слои - ортогональные друг другу иерархии. Например, фича "синхронизации данных" может вообще не иметь View. А фича "рендеринг через Vulcan" - ничего не знать про Domain Model.

Соглашусь, что архитектурных слоёв порой должно быть больше, чем 3. Вот даже у вас на картинках их уже 4. Но обоснование у вас слишком абстрактное, чтобы можно было понять, что с ним так или не так.

Какая-то каша в голове у тс.

1) mvx - это единая неразрывная сущность, а не 3 класса.

2) unit-тестами никто не покрывает mvx, это тупо.

3) да, существует проблема толстого контроллера, именно поэтому используют только mvvm.

4) Проблемы появляются когда появляется иерархия mvx. Тогда придется определять какая компонента главная. И придется дублировать иерархия и для view и для vm.

5) Разрыва никакого нет. Слой данных и слой логики единны и самодостаточны.

6) Логика всегда синхронна. А VM гарантирует актуальность данных.

@Lynnfieldспасибо за статью. Лично мне в ней не хватает решений проблем. Ты описал разные проблемы, но нет никаких решений. То есть я прочитал статью о том, как всё плохо, но так и не узнал, а как же хорошо. Либо прийти к выводу о том, что это и не проблемы вовсе, и это не дело MVx их решать.

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

А так, молодец!

Крутая статья. Очень жду продолжения)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории