Migrating to VIPER from inherited UI+business-logic/etc superclass

213 Views Asked by At

I've decided to try migrating my existing project architecture to VIPER. VIPER seems popular due to the way it separates modules. However, I have 2 similar view controllers that inherit from CustomVC. These 2 view controllers call for super methods to setup UI and run some business logic. If I leave the UI functionality in CustomVC, should I move the business logic to an analogous CustomPresenter superclass? Should I move common navigation behavior to an analogous CustomInteractor class? Okay, I do that, then what: do the 2 view controller modules inherit from the CustomPresenter and/or CustomInteractor classes? In the answers, please guide me toward what is acceptable in this situation, considering VIPER architecture goals. Thank you.

1

There are 1 best solutions below

0
On BEST ANSWER
  • As described in https://TheSwiftDev.com/the-ultimate-viper-architecture-tutorial that teaches VIPER in its purest/original form (without some of the tangents that have appeared in recent years), VIPER is all about zones (or layers) of quarantined/divorced-apart functionality that speak to each other interzone via an app-domain data structs (many of which are the simpler E entities in the VIPER acronym) and the app-domain messages that each zone publish as their interzone API. In effect, each V I P R zone of VIPER presents a sort of façade to the other zones:
  1. while keeping UI/Apple-think/Android-think quarantined within V view zone, because such UI matters are not purely app-domain;
  2. while keeping sensor/datastore/networking/Apple-think/Android-think quarantined/divorced within I interactor zone, because such data-acquisition/data-exchange matters are not purely app-domain;
  3. while keeping navigation/Apple-think/Android-think/iOS-think/MacOS-think quarantined/divorced within R router zone, because such navigation matters are not purely app-domain (e.g., is the error presented by a pop-up modal dialog box or by a nonmetal dialog box or appending to the end of a scrolling log window-pane? as depending on which OS/platform) With all that in mind:
  • The UI-centric CustomVC and its UI-centric subclasses go into V view zone in VIPER. A façade at the perimeter of V view zone translates interzone app-domain entity-based messages to intrazone UI concepts, constructs, and method invocations of Apple-think frameworks or Android-think frameworks.
  • The business logic (which is obviously purely app-domain by definition) goes in the P presenter zone in VIPER. Whether there is a CustomPresenter superclass direct analogue in P presenter zone or whether P presenter zone models it differently due P presenter zone's own needs is a designer's choice, taking into account local taste. My point is that there is no strict rule to obey zealously there; not every way of organizing code in V view zone is the way to organizing code in P presenter zone.
  • The navigation goes in the R router zone in VIPER. A façade at the perimeter of R router zone translates interzone app-domain entity-based messages to intrazone navigation concepts, constructs, and method invocations of Apple-think frameworks or Android-think frameworks. For example, the navigation might be different on iOS than on MacOS than on an Android port of the same app, because a pop-up modal dialog box versus a semipermanent nonmodal dialog box versus a window-pane might exist in your app's designed UI on certain platform(s) but not on other platform(s). Especially for navigation, ponder just a moment while working on, say, a currently iOS-only app, whether that might be done differently on, say, a desktop MacOS app or on an Android port of the app. If your current architecture of the app is anything like Massive View Controller, you might have navigation quite comingled with UI (which is one symptom of the massive of Massive View Controller antipattern); you will need then need to meticulously tease navigation apart from UI so that navigation & UI get quarantined/divorced separate from each other. Whether there is a CustomRouter superclass direct analogue in R router zone or whether R router zone models it differently due R router zone's own needs is a designer's choice, taking into account local taste. My point is that there is no strict rule to obey zealously there; not every way of organizing code in V view zone is the way to organizing code in R router zone.
  • The sensor, datastore, and networking goes in the I interactor zone of VIPER. A façade at the perimeter of I interactor zone translates interzone app-domain entity-based messages to intrazone sensor/datastore/networking concepts, constructs, and method invocations of Apple-think frameworks or Android-think frameworks or 3rd-party libraries/frameworks. In this zone especially, ponder a little bit whether the quarantine/divorce is so clean & perfect that you can swap out non-app-domain infrastructure X for a different non-app-domain infrastructure Y, such as swap out a database instead of Apple Core Data that perhaps your app outgrew. Whether there is a CustomInteractor superclass direct analogue in I interactor zone or whether I interactor zone models it differently due I interactor zone's own needs is a designer's choice, taking into account local taste. My point is that there is no strict rule to obey zealously there; not every way of organizing code in V view zone is the way to organizing code in I interactor zone.
  • The purely app-domain lingua franca interzone is partially simple entities in E entity zone, but more & more nowadays it is also reactive functional-programming-lite effect-event subscriptions & flows, such as RxSwift or Realm. RxSwift if the lingua-franca interzone programming language is Swift (or its Android analogues RxKotlin or RxJava or ZIO+CatsEffect if in Scala if the lingua-franca interzone programming language is one of those 3 languages) can be chosen by the designer as the official app-domain purity. Realm is messier because it does much of what RxSwift does, but when Realm is in interzone lingua franca, now Realm in the datastore interactor zone has not been kept quarantined within its proper datastore-interactor compartment, so now Realm cannot be swapped out as easily for some even better datastore technology in the future. The main moral of the story is: wisely overtly design & choose what comprises the pure app-domain lingua franca entities, messaging, philosophy, dependencies, etc interzone because that is the portion you need to live with unchanged as the app evolves to new OSes, new platforms, new infrastructure.

So no, once all the UI, business logic, and sensor/datastore/networking data-acquisition/exchange has been entirely separated from each other, the view controllers would no longer have anything directly to do with CustomPresenter or with CustomInteractor or CustomRouter, most especially no inheritance from them. All interactions among CustomUI & its subclasses versus CustomPresenter & its subclasses (if any) versus CustomInteractor & its subclasses (if any) versus CustomRouter & its subclasses (if any) would be via pure app-domain messaging (or effect-event subscription) interzone via app-domain lightweight entities—i.e., indirect interaction through V view zone's façade and/or I interactor zone's façade with P presenter zone.