69
Reactive Model-View-ViewModel 모바일 응용프로그램 아키텍쳐 이규원 https:// www.facebook.com/gyuwon.yi @ styletigger

Reactive Model-View-ViewModel Architecture

Embed Size (px)

Citation preview

Page 1: Reactive Model-View-ViewModel Architecture

Reactive Model-View-ViewModel모바일응용프로그램아키텍쳐

이규원

https://www.facebook.com/gyuwon.yi

@styletigger

Page 2: Reactive Model-View-ViewModel Architecture

MVVMModel-View-ViewModel

Page 3: Reactive Model-View-ViewModel Architecture

MVVM(Model-View-ViewModel)

• In 2005, John Gossman(Microsoft)

• Separation of Presentation and Presentation Logic

• Two-way Binding

• Properties and Commands

• Testability

• WPF, Silverlight, Xamarin Forms, AngularJS, EmberJS, KnockoutJS, RoboBinding

• Introduction to Model/View/ViewModel pattern for building WPF apps

• WPF Apps With The Model-View-ViewModel Design Pattern

Page 4: Reactive Model-View-ViewModel Architecture

ViewModel

Presentation Logic

View

User Interface

Model

Business Logic and Data

2-way Binding

MVVM 응용프로그램

Page 5: Reactive Model-View-ViewModel Architecture

ViewModel

Presentation Logic

View

User Interface

API

Service

2-way Binding

Model

Server Client

서비스클라이언트응용프로그램

Page 6: Reactive Model-View-ViewModel Architecture

상태동기화State Synchronization

Page 7: Reactive Model-View-ViewModel Architecture

Showcase …

Showcase 15

no envy

Showcase …

… …

Showcase 15

no envy

Profile

Showcase 15

no envy

Showcase …

New Feed Explore Notifications

단일컨텐트에대한다중뷰

Page 8: Reactive Model-View-ViewModel Architecture

Showcase …

Showcase 15

1 envy

Showcase …

… …

Showcase 15

1 envy

New Feed Explore Notifications

Profile

Showcase 15

1 envy

Showcase …

뷰상태동기화

Page 9: Reactive Model-View-ViewModel Architecture

동기화흐름Flow of Synchronization

Page 10: Reactive Model-View-ViewModel Architecture

Showcase …

Showcase 15

1 envy

Showcase …

… …

Showcase 15

1 envy

New Feed Explore Notifications

Profile

Showcase 15

1 envy

Showcase …

뷰모델사이의데이터흐름

Page 11: Reactive Model-View-ViewModel Architecture

VM

VM VM

VM VM

VM

뷰모델사이의데이터흐름

Page 12: Reactive Model-View-ViewModel Architecture
Page 13: Reactive Model-View-ViewModel Architecture
Page 14: Reactive Model-View-ViewModel Architecture

ViewModelRepository

One-way

Push

Publish

One-way

단방향데이터흐름

Page 15: Reactive Model-View-ViewModel Architecture

Scale

Complexity

상태동기화복잡도

Page 16: Reactive Model-View-ViewModel Architecture

불변모델개체Immutable Model Objects

Page 17: Reactive Model-View-ViewModel Architecture

ShowcaseViewModel

IsEnvied: bool

EnvyCount: int

뷰모델속성을통한데이터노출

Page 18: Reactive Model-View-ViewModel Architecture

<Button BackgroundColor="{Binding IsEnvied, Converter={...}}" />

<Label Text="{Binding EnvyCount, StringFormat='...'}" />

뷰모델속성바인딩

Page 19: Reactive Model-View-ViewModel Architecture

IsEnvied EnvyCount PropertyChanged Validity

False 0 Valid

True 0 "IsEnvied" Invalid

True 1 "EnvyCount" Valid

뷰모델속성상태변경

Page 20: Reactive Model-View-ViewModel Architecture

뷰에바인딩된속성에대한 PropertyChanged 이벤트는레이아웃계산과그리기작업을촉발한다

Page 21: Reactive Model-View-ViewModel Architecture

모델속성을통한데이터노출

ShowcaseViewModel ShowcaseModel

IsEnvied: bool

EnvyCount: int

Model

Page 22: Reactive Model-View-ViewModel Architecture

<Button BackgroundColor="{Binding Model.IsEnvied, Converter={...}}" />

<Label Text="{Binding Model.EnvyCount, StringFormat='...'}" />

모델속성바인딩

Page 23: Reactive Model-View-ViewModel Architecture

Model PropertyChanged Validity

{ IsEnvied: False, EnvyCount: 0 } Valid

{ IsEnvied: True, EnvyCount: 1 } "Model" Valid

모델상태변경

Page 24: Reactive Model-View-ViewModel Architecture

단, 모델개체는불변성을가져야한다

Page 25: Reactive Model-View-ViewModel Architecture

Immutable Objects

• Cannot be modified after initialization

• Thread-safe

• Readability

• Runtime efficiency

• Functional programming

Page 26: Reactive Model-View-ViewModel Architecture

모델속성을통한데이터노출

ShowcaseViewModel ShowcaseModel<< immutable >>

IsEnvied: bool

EnvyCount: int

Model

Page 27: Reactive Model-View-ViewModel Architecture

불변모델반응형스트림Reactive Streams of Immutable Model Objects

Page 28: Reactive Model-View-ViewModel Architecture

데이터흐름

•컨텐트상태는불변성을가지는모델개체로캡슐화

•뷰모델은모델개체를속성으로뷰에노출

•컨텐트상태가변경되면새로운모델인스턴스발행

Page 29: Reactive Model-View-ViewModel Architecture

‘불변성을가진모델개체의반응형스트림’

Page 30: Reactive Model-View-ViewModel Architecture
Page 31: Reactive Model-View-ViewModel Architecture

…Model

Revision n + 2Model

Revision n + 1Model

Revision n…

Page 32: Reactive Model-View-ViewModel Architecture

스트림저장소

Page 33: Reactive Model-View-ViewModel Architecture

Rx(Reactive Extensions)

• Observables + LINQ + Schedulers

• Asynchronous and event-based programming

• C#, JavaScript, C, C++, Ruby, Python, Java

• Microsoft Open Tech(*RxJava by Netflix)

• https://rx.codeplex.com/

Page 34: Reactive Model-View-ViewModel Architecture

반응형스트림

public interface IObservable<out T>

{

IDisposable Subscribe(IObserver<T> observer);

}

public interface IObserver<in T>

{

void OnCompleted();

void OnError(Exception error);

void OnNext(T value);

}

Page 35: Reactive Model-View-ViewModel Architecture

모델

public abstract class Model<TModel, TId>

where TModel : Model<TModel, TId>

where TId : IEquatable<TId>

{

private readonly TId _id;

public TId Id { get { return _id; } }

protected Model(TId id)

{

_id = id;

}

}

Page 36: Reactive Model-View-ViewModel Architecture

모델

public sealed class ShowcaseModel : Model<ShowcaseModel, long>

{

private readonly bool _isEnvied;

private readonly int _envyCount;

public ShowcaseModel(long id, bool isEnvied, int envyCount) : base(id)

{

_isEnvied = isEnvied;

_envyCount = envyCount;

}

public bool IsEnvied { get { return _isEnvied; } }

public int EnvyCount { get { return _envyCount; } }

}

Page 37: Reactive Model-View-ViewModel Architecture

스트림저장소

public static class StreamStore<TModel, TId>

where TModel : Model<TModel, TId>

where TId: IEquatable<TId>

{

public static IObservable<TModel> GetStream(TId id);

public static void Push(TModel model);

}

Page 38: Reactive Model-View-ViewModel Architecture

모델-뷰모델

public abstract class ModelViewModel<TModel, TId> : ViewModel

{

private TModel _model = null;

public TModel Model

{

get { return _model;}

set { SetProperty(ref _model, value); }

}

protected virtual void OnNext(TModel next)

{

Model = next;

}

}

Page 39: Reactive Model-View-ViewModel Architecture

스트림구독Stream Subscription

Page 40: Reactive Model-View-ViewModel Architecture
Page 41: Reactive Model-View-ViewModel Architecture

약한스트림구독

ModelViewModel

Observer WeakSubscription

Stream

Reference

Weak Reference

Page 42: Reactive Model-View-ViewModel Architecture

약한스트림구독

public abstract class ModelViewModel<TModel, TId> : ViewModel

{

private readonly TId _id;

private readonly IObserver<TModel> _observer;

private readonly IDisposable _subscription;

protected ModelViewModel(TId id)

{

_id = id;

var stream = StreamStore<TModel, TId>.GetStream(id);

_observer = Observer.Create<TModel>(onNext: OnNext);

_subscription = new WeakSubscription<TModel>(stream, _observer);

}

~ModelViewModel() { _subscription.Dispose(); }

}

Page 43: Reactive Model-View-ViewModel Architecture

스위치연산자Switch Operator

Page 44: Reactive Model-View-ViewModel Architecture

비동기데이터조회

•응용프로그램반응성향상

• Futures Pattern

Page 45: Reactive Model-View-ViewModel Architecture

중복된비동기데이터조회

•불필요한무효화(invalidation)

•시작과종료순서의불일치

Page 46: Reactive Model-View-ViewModel Architecture
Page 47: Reactive Model-View-ViewModel Architecture

Switch()

“Transforms an observable sequence of observable sequences into an observable sequence producing values only from the most recent observable sequence.”

- from MSDN

Page 48: Reactive Model-View-ViewModel Architecture

스위치

Page 49: Reactive Model-View-ViewModel Architecture

스위치

public abstract class ModelViewModel<TModel, TId> : ViewModel

{

private readonly Subject<IObservable<TModel>> _spout = new Subject<IObservable<TModel>>();

protected ModelViewModel(TId id)

{

_spout.Switch()

.Subscribe(next => StreamStore<TModel, TId>.Push(next));

}

protected virtual void Push(IObservable<TModel> next)

{

_spout.OnNext(next);

}

}

Page 50: Reactive Model-View-ViewModel Architecture

Task to Observable

public abstract class ModelViewModel<TModel, TId> : ViewModel

{

protected void Push(Task<TModel> next)

{

Push(next.ToObservable());

}

protected void Push(Func<Task<TModel>> next)

{

Push(next.Invoke().ToObservable());

}

}

Page 51: Reactive Model-View-ViewModel Architecture

Model to Observable

public abstract class ModelViewModel<TModel, TId> : ViewModel

{

protected void Push(TModel next)

{

Push(Task.FromResult(next).ToObservable());

}

}

Page 52: Reactive Model-View-ViewModel Architecture

병합연산자Coalescing Operator

Page 53: Reactive Model-View-ViewModel Architecture

UserModel

Id : "user1"

UserName

ProfilePhotoUri

UserModel

Id: "user1"

UserName

ProfilePhotoUri

FolloweeCount

FollowerCount

Followees: 10

Followers: 24

목록조회와상세정보조회

Page 54: Reactive Model-View-ViewModel Architecture

데이터유실

UserModel

Id : "user1"

UserName

ProfilePhotoUri

UserModel

Id: "user1"

UserName

ProfilePhotoUri

FolloweeCount

FollowerCount

Followees: 10

Followers: 24

UserModel

Id: "user1"

UserName

ProfilePhotoUri

FolloweeCount

FollowerCount

Followees: 10

Followers: 24

Push User Detail Page Push User List Page Pop

Page 55: Reactive Model-View-ViewModel Architecture
Page 56: Reactive Model-View-ViewModel Architecture

Id: "user1" UserName ProfilePhotoUri FolloweeCount FollowerCount

Id: "user1" UserName ProfilePhotoUri FolloweeCount FollowerCount

Id: "user1" UserName ProfilePhotoUri FolloweeCount FollowerCount

Coalesce

=

병합연산

Page 57: Reactive Model-View-ViewModel Architecture

병합연산

public static class ModelExtensions

{

public static UserModel Coalesce(this UserModel user, UserModel other)

{

if (user == null) throw new ArgumentNullException("user");

if (other == null) return user;

if (other.Id != user.Id) throw new ArgumentException();

if (user.Equals(other)) return user;

return new UserModel(user.Id,

user.UserName,

user.ProfilePhotoUri,

user.FolloweeCount ?? other.FolloweeCount,

user.FollowerCount ?? other.FollowerCount);

}

}

Page 58: Reactive Model-View-ViewModel Architecture

병합연산

public class UserViewModel : ModelViewModel<UserModel, string>

{

protected override void OnNext(UserModel next)

{

var current = Model;

base.OnNext(next.Coalesce(current));

}

}

Page 59: Reactive Model-View-ViewModel Architecture

같음확인Equality Comparisons

Page 60: Reactive Model-View-ViewModel Architecture

뷰모델속성설정

public class ViewModel : INotifyPropertyChanged

{

protected bool SetProperty<T>(ref T field,

T value,

[CallerMemberName] string propertyName = null)

{

if (EqualityComparer<T>.Default.Equals(field, value))

return false;

field = value;

NotifyPropertyChanged(propertyName);

return true;

}

}

Page 61: Reactive Model-View-ViewModel Architecture

Changed!Changed…?

ShowcaseId: 15

IsEnvied: trueEnvyCount: 10

ShowcaseId: 15

IsEnvied: trueEnvyCount: 10

ShowcaseId: 15

IsEnvied: falseEnvyCount: 9

Changed…?

개체참조비교

Page 62: Reactive Model-View-ViewModel Architecture

같음확인논리

public sealed class ShowcaseModel : Model<ShowcaseModel, long>, IEquatable<ShowcaseModel>

{

public bool Equals(ShowcaseModel other)

{

if (other == null)

return false;

if (object.ReferenceEquals(this, other))

return true;

return Id == other.Id &&

_isEnvied == other._isEnvied &&

_envyCount == other._envyCount;

}

}

Page 63: Reactive Model-View-ViewModel Architecture

Changed!Changed…?

ShowcaseId: 15

IsEnvied: trueEnvyCount: 10

ShowcaseId: 15

IsEnvied: trueEnvyCount: 10

ShowcaseId: 15

IsEnvied: falseEnvyCount: 9

Not Changed

모델데이터비교

Page 64: Reactive Model-View-ViewModel Architecture

정리

Page 65: Reactive Model-View-ViewModel Architecture

Reactive MVVM Architecture

•단방향데이터흐름

•불변모델

•반응형스트림

•약한스트림구독

•스위치연산

•병합연산

•같음확인

Page 66: Reactive Model-View-ViewModel Architecture

Reactive MVVM Architecture

ViewModel Model<< 1-way binding >>

Model<< push >>

Co

alescin

g

Equ

ality C

om

pariso

n

Stream Store

Switch

We

ak Su

bscrip

tion

View

Commands,Entry Fields

and UI States

Model<< publish >>

Page 67: Reactive Model-View-ViewModel Architecture
Page 68: Reactive Model-View-ViewModel Architecture

Reactive MVVM 아키텍쳐를적용한안드로이드앱을함께개발하실멋쟁이

프로그래머느님을애타게찾고있습니다.

public async Task<IEnvicase> CreateAndroidAsync(){

var team = await JoinUsAsync(new You());return team.CreateAndroidApp();

}

https://www.facebook.com/gyuwon.yi@styletigger

[email protected]