Pull to refresh

Через MVP к VIPER. Часть первая: MVP

Development for iOS *Development of mobile applications *Designing and refactoring *

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


Когда я начал работу над своим предыдущим проектом, в команде было ровно два целых ноль десятых мобильных разработчика: один писал версию под Андроид, второй – под iOS.


Естественно, iOS версия создавалась на классическом, рекомендуемом самим Apple, паттерне MVC.


У меня была View: "любимый" сториборд, в котором было over9000 довольно много экранов, и который был похож на это:



У меня была модель – классы, для хранения настроек, данных пользователя, некоторых данных, которые сохранялись во внутренней БД.


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


Networking.request(.POST, withURL: serverAddress, andParameters: parameters) { (dictResult, error) in
    if let dictResult = dictResult {

        // some actions with view

        if let rates = dictResult["rates"] as? [AnyObject] {
            for rate in rates {
                if let rateDictionary = rate as? JSONDictonary {
                    let result = Result(jsonDictionary: rateDictionary)
                    self.resultsArray.append(result)
                }
            }
        }

        // some actions with view

    } else {
        if let error = error {
            DispatchQueue.main.async(execute: {
                self.showError(error)
            })
        }
    }
}

В общем: я уверенно двигался от Model View Controller к Massive View Controller и с этим нужно было что-то делать.


Я начал изучать возможные архитектуры для мобильных приложений, и конечно, мне сразу же понравился паттерн Clean architecture (он же, по сути – VIPER):



картинка из The Book of VIPER


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



А что если я скажу тебе, что UIViewController — это View.

Именно поэтому я взялся за MVP. Самое сложное и в то же время – самое простое – понять, что UIViewController – относится к слою View. Он должен работать с UI и только с ним: принимать от пользователя действия связанные с UI (нажатия кнопок, ввод текста, etc.) и менять отображение самого UI. Сначала это казалось сложным, но я вывел для себя несколько простых правил, которые помогают положить во вью-контроллер все необходимое, и при этом не положить туда ничего лишнего:


  1. Все методы и алгоритмы вью-контроллера должны работать с UI. Если вы видите какой-то метод или кусок кода, который может работать без использования UIKit, знайте: этому методу/блоку кода здесь не место.


  2. Для презентера, все в точности наоборот: там не должно быть ни одного метода для выполнения которого нужен UIKit. Если такие методы обнаружены – нужно внимательно изучить эти участки кода и вынести их во вью-контроллер.


  3. У вью-контроллера и презентера есть протоколы на которые они подписаны, это их внешние интерфейсы. Там определены методы, которые можно вызывать для них извне. Поэтому, если вдруг, вы видите во вью-контроллере вызов метода из интерфейса (протокола) этого же вью-контроллера – этот метод должен находиться не во вью-контроллере, а в презентере.

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


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

Tags:
Hubs:
Total votes 16: ↑14 and ↓2 +12
Views 14K
Comments Comments 12