52
from MVC to VIPER Krzysztof Profic @kprofic

From mvc to viper

Embed Size (px)

Citation preview

Page 1: From mvc to viper

from MVC to VIPER

Krzysztof Profic @kprofic

Page 2: From mvc to viper

Legacy codebaseBetter codebase

Page 3: From mvc to viper

Pragmatic approachwhat hurts my eyes?

Page 4: From mvc to viper

Pragmatic approachwhat hurts my eyes?

UIViewController

Page 5: From mvc to viper

Massive UIViewController

Page 6: From mvc to viper

4 Steps

• MVC on diet

• MVVM

• Intentions

• VIPER

Page 7: From mvc to viper

4 Steps

• MVC on diet

• MVVM

• Intentions

• VIPER

Page 8: From mvc to viper

Massive View Controller

Light View Controller

MVC on diet

Page 9: From mvc to viper

ReducingMassive ViewController

• extract datasource

• move domain logic into the model

• move view code into the view layer

objc.io #1

Page 10: From mvc to viper

ReducingMassive ViewController

• extract datasource

• move domain logic into the model

• move view code into the view layer

objc.io #1

Page 11: From mvc to viper

ReducingMassive ViewController

• extract datasource

• move domain logic into the model

• move view code into the view layer

objc.io #1

Page 12: From mvc to viper

ReducingMassive ViewController

• Separation of concerns

• Single responsibility principle

objc.io #1

Page 13: From mvc to viper

Reanimate your MVCreduce MVC principles violation

put ViewController on a diet

Page 14: From mvc to viper

What is the Rule?

Page 15: From mvc to viper

“Keep the code where it belongs”

Page 16: From mvc to viper

Layer

Page 17: From mvc to viper
Page 18: From mvc to viper
Page 19: From mvc to viper

Entities

Use Cases

Controllers

Presen

ters

GatewaysUI

DB

ExternalInterfaces

Device

s

The Clean Architecture

Enterprise Business Rules

Application Business Rules

Interface Adapters

Frameworks & Drivers

Web

Controller

Use CaseInteractor

Presenter Use CaseOutput Port

Use CaseInput Port

Flow of control

<I>

<I>

http://blog.8thlight.com

Page 20: From mvc to viper

Layersseparation of concerns = dividing software into …

Page 21: From mvc to viper

“Keep the code on the right layer”

Page 22: From mvc to viper

The Dependency Rule

Page 23: From mvc to viper

Entities

Use Cases

Controllers

Presen

ters

GatewaysUI

DB

ExternalInterfaces

Device

s

The Clean Architecture

Enterprise Business Rules

Application Business Rules

Interface Adapters

Frameworks & Drivers

Web

Controller

Use CaseInteractor

Presenter Use CaseOutput Port

Use CaseInput Port

Flow of control

<I>

<I>

http://blog.8thlight.com

Page 24: From mvc to viper

MVC variation

Page 25: From mvc to viper

MVC variation

Page 26: From mvc to viper

MVVM

Page 27: From mvc to viper

4 Steps

• MVC on diet

• MVVM

• Intentions

• VIPER

Page 28: From mvc to viper

Let’s talk code

Page 29: From mvc to viper

- (void)viewDidLoad { [super viewDidLoad]; if (self.model.salutation.length > 0) { self.nameLabel.text = [NSString stringWithFormat:@"%@ %@ %@“, self.model.salutation, self.model.firstName, self.model.lastName]; } else { self.nameLabel.text = [NSString stringWithFormat:@"%@ %@“, self.model.firstName, self.model.lastName]; } NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"EEEE MMMM d, yyyy"]; self.birthdateLabel.text = [dateFormatter stringFromDate:model.birthdate]; }

PersonViewController.m

Page 30: From mvc to viper

@implementation PersonViewModel

- (instancetype)initWithPerson:(Person *)person { self = [super init]; if (!self) return nil; _person = person; if (person.salutation.length > 0) { _nameText = [NSString stringWithFormat:@"%@ %@ %@“, self.person.salutation, self.person.firstName, self.person.lastName]; } else { _nameText = [NSString stringWithFormat:@"%@ %@", self.person.firstName, self.person.lastName]; } NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"EEEE MMMM d, yyyy"]; _birthdateText = [dateFormatter stringFromDate:person.birthdate]; return self; }

@end PersonViewModel.m

Page 31: From mvc to viper

- (void)viewDidLoad { [super viewDidLoad]; self.nameLabel.text = self.viewModel.nameText; self.birthdateLabel.text = self.viewModel.birthdateText; }

PersonViewController.m

Page 32: From mvc to viper

4 Steps

• MVC on diet

• MVVM

• Intentions

• VIPER

Page 33: From mvc to viper

Motivation

• ViewController implements only viewWill* viewDid*

Page 34: From mvc to viper

• encapsulate small pieces of business logic

• use case approach (form validation, login user)

• hookable via &

• reusable

IntentionsArchitecture is about Intent “Uncle Bob”

IBOutlet IBAction

Page 35: From mvc to viper
Page 36: From mvc to viper

@interface ViewController ()

@property (strong) IBOutlet ModelContainer* modelContainer;

@end

@implementation ViewController

- (void)viewDidLoad { [super viewDidLoad]; PersonViewModel * pvm = [[PersonViewModel alloc] initWithModel:self.person]; self.modelContainer.viewModel = pvm; } @end

ViewController.m

Page 37: From mvc to viper

Observing ViewModel

Page 38: From mvc to viper

@interface ObserveIntention ()

@property (strong, nonatomic) IBOutlet id sourceObject; @property (strong, nonatomic) IBOutlet id target; @property (copy, nonatomic) IBOutlet NSString *sourceKeyPath; @property (copy, nonatomic) IBOutlet NSString *targetKeyPath;

@end

Page 39: From mvc to viper

@implementation ObserveIntention

- (void)awakeFromNib { [super awakeFromNib]; [self updateValue]; [self.sourceObject addObserver:self forKeyPath:self.sourceKeyPath options:0 context:nil]; }

- (void)updateValue { id value = [self.sourceObject valueForKeyPath: self.sourceKeyPath]; if (self.targetKeyPath) { [self.target setValue:value forKeyPath:self.targetKeyPath]; } }

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)obj change:(NSDictionary *)change context:(void *)context {

if ([keyPath isEqualToString:self.sourceKeyPath]) { [self updateValue]; } }

@end

Page 40: From mvc to viper
Page 41: From mvc to viper

BehavioursUIControl

objc.io #13

Page 42: From mvc to viper

Login

Page 43: From mvc to viper

User Story #90.10 - Login

• A. When I as a user open the app the first time I enter the “main login” page, where I need to login with my username (email address) and password.

• B. When I tap the “login button” while online and no errors occur I’m moved to initial page with users profile.

Page 44: From mvc to viper

User Story #90.10 - Login

• A. When I as a user open the app the first time I enter the “main login” page, where I need to login with my username (email address) and password.

• B. When I tap the “login button” while online and no errors occur I’m moved to initial page with users profile.

Page 45: From mvc to viper
Page 46: From mvc to viper

@interface LoginIntention() @property (strong) IBOutlet UITextField * usernameTextField; @property (strong) IBOutlet UITextField * passwordTextField; @property (strong, nonatomic) IBOutlet UILabel * statusLabel; @end

@implementation LoginIntention

- (IBAction)login:(id)sender { self.statusLabel.text = @"connecting..."; [self sendActionsForControlEvents:UIControlEventValueChanged]; self.statusLabel.text = [NSString stringWithFormat:@"Authenticating %@“, self.usernameTextField.text]; [self sendActionsForControlEvents:UIControlEventValueChanged]; self.statusLabel.text = @"done"; [self sendActionsForControlEvents:UIControlEventValueChanged]; }

@end

LoginIntention.m

Page 47: From mvc to viper

@implementation LoginViewController

- (IBAction)loginIntentionStateChanged:(LoginIntention *)sender { if ([sender.statusLabel.text isEqualToString:@"done"]){ [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; } }

@end

LoginViewController.m

Page 48: From mvc to viper

4 Steps

• MVC on diet

• MVVM

• Intentions

• VIPER

Page 49: From mvc to viper

If you want more, checkout VIPER

• View

• Interactor

• Presenter

• Entity

• Routing

Page 50: From mvc to viper

Summary:

MVC on diet MVVM

Intentions / Behaviours VIPER

Page 51: From mvc to viper

Thank you!

Krzysztof Profic @kprofic

Page 52: From mvc to viper

• http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

• http://www.scottlogic.com/blog/2014/05/11/reactivecocoa-tableview-binding.html

• http://chris.eidhof.nl/posts/intentions.html

• http://www.objc.io/issue-13/behaviors.html

• http://www.objc.io/issue-13/viper.html