Комментарии 12
Честно говоря, всегда удивляла эта архитектура. Несмотря на формальную слабую связанность, фактически в большинстве случаев все элементы связаны сильно, потому что протоколы не переиспользуются для других экранов. Вообще ни один компонент не переиспользуется.
То есть вместо того, чтобы делегировать составляющие контроллера его компонентам и потом их переиспользовать (повторяющиеся анимации, действия, стили, логику работы и отображения), происходит не разделение, а расслоение контроллера, где каждый слой все равно уникален.
При этом такой подход и такое количество файлов убивает желание заниматься настоящей, разделяющей, декомпозицией.
Здесь же наблюдаем именно такую ситуацию. В SwiftUI реактивность является одной из основных идей фреймворка. Абстрагирование реактивности в пользу ручного управления состоянием должно иметь веские причины. Здесь же основная причина – противоречие канонам спорной, по моему мнению, архитектуры.
Протоколы переиспользуются, например, для тестов и моков. Всё там хорошо, кроме большого объема кода, но это лечится генерацией. У реактивщины есть свои минусы - когда ее много, она становится плохо управляемой.
У нее действительно слабая связанность. Просто ее часто неправильно готовят. Представим что у вас в приложении есть несколько UITableView, для тейбл вью у вас один вайпер на всех, у каждой ячейки в таблице свой собственный вайпер — позволяет вам переиспользовать ячейку в разных таблицах — ей не нужно знать где она. Допустим одна и таже ячейка может иметь или не иметь кнопку "Like" — извлекаем ее из ячейки и делаем ей собственный вайпер. Вот вам и слабая связанность и полное переиспользование кода и Р. Мартин счастлив. Впрочем это относится не только к вайперу, но и ко всяким вью моделям и тд.
А Вам не кажется, что вайпер на одну кнопку – это слишком много? Разве не логичнее делить кнопку не на шаблонные компоненты, а на аспекты кнопки – стиль там, способ нажатия, состояния?
Я хотел бы вам написать "Вы не понимаете — это другое" :) Но напишу так. Все должно быть сбалансировано конечно. И то что вы пишете имеет смысл если это какая то уникальная кнопка. Понятия слишком много не существует если того требует задача. Но если мы вернемся к кнопке лайк и посмотрим на ее бизнес задачу, допустим что бы поставить лайк пользователь должен быть авторизован, то есть только кликнув на кнопку пользователю может быть показан логин экран, после успешного прохождения авторизации (а может и процесса создания аккаунта) нужно будет потом отправить состояние лайк на бэкэнд и обновить состояние кнопки. Вы же не будете разруливать это в каждой вью модели (или бог знает что там экраном управляет) экрана который поддерживает лайки? Понятно что вы как то вычлените это. Но зачем вью модели экрана в целом знать о том что что то на экране может быть лайкнуто? А я часто вижу код что каждая вью модель знает про то что есть кнопка/ки лайк и редиректит в эту вычлененую чать -то есть фактически бессмысленный копи паст? При этом копка лайк допустим разная если это лист сущностей или экран деталей сущности. А еще с текстом без текста, а еще отправляет разную аналитику но выглядит при этом одинаково? А еще возможно за кнопку лайк отвечает вообще другая команда? Вот вам тут и пригодится и слабая связанность и отдельный вайпер для кнопки. Отделяем мух от котлет и властвуем.
Я не считаю, что все эти задачи типа проверки авторизации и прочего должны быть частью кнопки лайк. Все эти задачи вообще не обязаны быть частью интерфейсного элемента. Они могут быть нужны когда-угодно, и как их достать из этого вайпера кнопки потом?
А экраном никто не должен управлять целиком, особенно если экран сложный. Надо разделять экран на несколько VC, делать делегаты-обработчики, которые не знают про существование экрана, а просто описывают логику, и так далее. В данном случае просто назначьте обработчик делегатом кнопки, но обработчик будет не классом, а тайпалиасом, который будет можно применить и к другим кнопкам с другими дженерик-параметрами.
Вы фактически сказали тоже самое что и я только назвав тоже самое другими словами. Все должно быть составным. И на этом можно остановиться потому что мыслим мы одинаково. Просто забудьте слово вайпер. И мы тут же окажемся в согласии о том что автор понимает вайпер слишком буквально — как 5 сущностей…
ЗЫ: я нигде не сказал что авторизация является частью конпки лайк.
Если VIPER не понимать буквально, он просто перестанет существовать :).
Кстати т.н. Clean Architecture - по сути всего лишь про абстракции и создание границ между слоями, что есть ни что иное как DI из SOLID. То есть про возможность менять части системы по отдельности. Ни о каком фреймворке там речи не шло.
VIPER же похож на какой-то карго культ, особенно в попытке натянуть его на SwiftUI.
А собственно никто и не сказал что вайпер это фреймворк. Фреймворк это что то что можно загрузить как библиотеку. Вайпер всего лишь позволяет не ломать голову над названиями разных сущностей из разных слоев. Остальное от лукавого.
"Фреймворк" не в смысле подключаемой библиотеки, а в смысле организации кода.
Вайпер всего лишь позволяет не ломать голову над названиями разных сущностей из разных слоев.
Тут вообще спорно, что VIPER про разные слои. По идее так должно быть, но по факту, все, кроме Entity относиться к UI слою (из тех примеров что я видел), так как Interactor обычно тесно связан с логикой UI.
Кстати, почему-то авторы VIPER совершенно забыли про Controller, в CA именно он должен вызывать Interactor, Presenter работает в другую сторону. И Presenter и Controller являются адаптерами между UI и Interactor.
VIPER есть ни что иное, как криво преподнесенный MVP, который Боб Мартин прямо приводит в качестве примера, внезапно, Clean Architecture. А что такое MVC в iOS? Да то же самое! Так как там View так же ничего не знает о Model. Model в MVP - делает то же самое, что и Interactor в Viper.
Все что добавляет VIPER - интерфейсы, которые и так должны быть, если вы следуете DI принципу. Clean Architecture, чистая в первую очередь от фреймворков.
Примерно так и есть. Никто не сказал что каждая часть вайпера это одна сущность. И его просто стоит держать в голове что бы задумываться о тех же протоколах которые как вы тоже верно отметили тоже должны быть.
Я не являюсь адептом вайпера если кому то показалось. Но практически любой код который я видел и который мне нравится будет условно разделен на подобные слои. А мой собственный уж точно.
VIPER и SwiftUI: Model layer