Как приручить реактивное программирование

64
Как приручить реактивное программирование Денис Цветцих Ice Rock Dev icerockdev.com 12-я конференция .NET разработчиков 15 мая 2016 dotnetconf.ru

Upload: denis-tsvettsih

Post on 21-Mar-2017

88 views

Category:

Software


3 download

TRANSCRIPT

Page 1: Как приручить реактивное программирование

Как приручить реактивное программирование

Денис ЦветцихIce Rock Dev

icerockdev.com

12-я конференция .NET разработчиков15 мая 2016dotnetconf.ru

Page 2: Как приручить реактивное программирование

2

Кто я?• 7+ лет .NET• Разработка корпоративных

приложений• Люблю хипстерские библиотеки

Page 3: Как приручить реактивное программирование

3

Почему я здесь?• 6 лет назад приручил Rx• 3 года назад приручил ReactiveUI• С тех пор активно использую в

XAML проектах

Page 4: Как приручить реактивное программирование

4

Многие не используют• Не знают о Rx и ReactiveUI• Находятся под влиянием «мифов»

о реактивном программировании

Page 5: Как приручить реактивное программирование

5

О чем мы поговорим?• Что такое реактивное

программирование?• Для каких задач его использовать?• Развеем мифы, которые мешают его

использовать

Page 6: Как приручить реактивное программирование

6

Опрос• Кто не знает, что такое реактивное

программирование?• Кто знаком с Rx и ReactiveUI, но не

решился использовать в своих проектах?

• Кто использовал Rx или ReactiveUI на продакшене?

Page 7: Как приручить реактивное программирование

ЧТО ТАКОЕ РЕАКТИВНОЕ ПРОГРАММИРОВАНИЕ

Page 8: Как приручить реактивное программирование

8

Что такое реактивное программирование?

Реактивное программирование – это парадигма программирования, ориентированная на потоки данных и распространение изменений. (Википедия)

Page 9: Как приручить реактивное программирование

9

Парадигма программирования

Парадигма программирования – это система идей и понятий, определяющих стиль написания компьютерных программ.

Page 10: Как приручить реактивное программирование

10

Императивная программа

var A = 10;var B = A + 1;

// Чему равно В?11

A = A + 1;

// А теперь чему равно В?11

Page 11: Как приручить реактивное программирование

11

Реактивная программаvar A = 10;var B <- A + 1; <- оператор «судьбы»

// Чему равно В?11

A = A + 1;

// А теперь чему равно В?12

Page 12: Как приручить реактивное программирование

12

Реактивное программирование

Реактивное программирование – это парадигма программирования, ориентированная на потоки данных и распространение изменений.

Потоки данных – последовательность значений каждой переменной или свойства класса.

Распространение изменений – уведомления «заинтересованных» об изменениях.

Page 13: Как приручить реактивное программирование

13

PullPull – класс A взаимодействует с классом B и вытягивает из него необходимые данные

Class A Class B

GetData()

Interacts with

Page 14: Как приручить реактивное программирование

14

PushPush – класс B самостоятельно выталкивает данные, как только они становятся доступны.

Class A

ProcessData()

Class BReacts on

Page 15: Как приручить реактивное программирование

15

Примеры из жизни• Вычислимые ячейки Excel

• Принцип Голливуда – «Не звоните нам, мы сами вам позвоним»

• Push - уведомления

Page 16: Как приручить реактивное программирование

РЕАКТИВНОЕ ПРОГРАММИРОВАНИЕ НА C#

Page 17: Как приручить реактивное программирование

17

Прошлое реактивного программирования на C#

• Bindable Linq• https://bindablelinq.codeplex.com• 1.0 beta 1• Последний коммит 5 окт 2008

• Continuous LINQ• http://clinq.codeplex.com/• 2.2.0.1• Последний коммит 23 июня 2010

• Obtics• https://obtics.codeplex.com/• 1.0.13.0• Последний коммит 11 июня 2011

Page 18: Как приручить реактивное программирование

18

Настоящее• Reactive Extensions (Rx)• Эрик Мейер из MS Research

• ReactiveUI• библиотека на базе Rx для создания

элегантных UI для всех XAML платформ

Page 19: Как приручить реактивное программирование

19

Внутри .NETpublic interface IObservable<T>{

IDisposable Subscribe(IObserver<T> observer);}

public interface IObserver<T>{

void OnNext(T value);void OnCompleted();void OnError(Exception error);

}

Page 20: Как приручить реактивное программирование

20

Внутри .NETpublic interface IObservable<T>{

IDisposable Subscribe(IObserver<T> observer);}

public interface IObserver<T>{

void OnNext(T value);void OnCompleted();void OnError(Exception error);

}

Page 21: Как приручить реактивное программирование

21

Внутри .NETpublic interface IObservable<T>{

IDisposable Subscribe(IObserver<T> observer);}

public interface IObserver<T>{

void OnNext(T value);void OnCompleted();void OnError(Exception error);

}

Page 22: Как приручить реактивное программирование

22

Внутри .NETpublic interface IObservable<T>{

IDisposable Subscribe(IObserver<T> observer);}

public interface IObserver<T>{

void OnNext(T value);void OnCompleted();void OnError(Exception error);

}

Page 23: Как приручить реактивное программирование

23

Внутри .NETpublic interface IObservable<T>{

IDisposable Subscribe(IObserver<T> observer);}

public interface IObserver<T>{

void OnNext(T value);void OnCompleted();void OnError(Exception error);

}

Page 24: Как приручить реактивное программирование

24

Оператор судьбы через Rx

var A = new Subject<int>();

// B <- A + 3var B = A.Select(a => a + 3);

// C <- A * Bvar С = A.Zip(B, (a, b) => a * b);

A.OnNext(1);

Page 25: Как приручить реактивное программирование

25

Оператор судьбы через Rx

var A = new Subject<int>();

// B <- A + 3var B = A.Select(a => a + 3);

// C <- A * Bvar С = A.Zip(B, (a, b) => a * b);

A.OnNext(1);

Page 26: Как приручить реактивное программирование

26

Оператор судьбы через Rx

var A = new Subject<int>();

// B <- A + 3var B = A.Select(a => a + 3);

// C <- A * Bvar С = A.Zip(B, (a, b) => a * b);

A.OnNext(1);

Page 27: Как приручить реактивное программирование

27

Observable.Select – проекция

Page 28: Как приручить реактивное программирование

28

Observable.Merge – слияние

Page 29: Как приручить реактивное программирование

29

Observable.Zip - объединение

Page 30: Как приручить реактивное программирование

КАКИЕ ЗАДАЧИ МОЖНО РЕШАТЬ

Page 31: Как приручить реактивное программирование

31

Пример - LoginViewModel

public class LoginViewModel //: INotifyPropertyChanged{ public string Login { get; set; } // PropertyChanged

public string Password { get; set; } // PropertyChanged

public ICommand LoginCommand { get; private set; }

private Task OnLogin() { }}

Page 32: Как приручить реактивное программирование

32

1. Подписка на изменение свойства

// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);

// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }

// Отписка_subscription.Dispose();

Page 33: Как приручить реактивное программирование

33

1. Подписка на изменение свойства

// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);

// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }

// Отписка_subscription.Dispose();

Page 34: Как приручить реактивное программирование

34

1. Подписка на изменение свойства

// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);

// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }

// Отписка_subscription.Dispose();

Page 35: Как приручить реактивное программирование

35

1. Подписка на изменение свойства

// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);

// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }

// Отписка_subscription.Dispose();

Page 36: Как приручить реактивное программирование

36

2. Подписка на изменение нескольких свойств

IDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);

Page 37: Как приручить реактивное программирование

37

2. Подписка на изменение нескольких свойств

IDisposable _subscription = this.WhenAny( vm => vm.Login, vm => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);

Page 38: Как приручить реактивное программирование

38

2. Подписка на изменение нескольких свойств

IDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);

Page 39: Как приручить реактивное программирование

39

3. Реактивная асинхронная команда

CanExecute – false, когда1) Не выполняется условие отправки

запроса2) Выполняется асинхронный запрос

Page 40: Как приручить реактивное программирование

40

3. Реактивная асинхронная команда

public LoginViewModel(ILoginService loginService){ _loginService = loginService;

var canExecute = this.WhenAny(vm => vm.Login, vm => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value));

Page 41: Как приручить реактивное программирование

41

3. Реактивная асинхронная команда

public LoginViewModel(ILoginService loginService){ _loginService = loginService;

// Task<bool> Login(login, password)

var canExecute = this.WhenAny(vm => vm.Login, vm => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value));

Page 42: Как приручить реактивное программирование

42

3. Реактивная асинхронная команда

public LoginViewModel(ILoginService loginService){ _loginService = loginService;

var canExecute = this.WhenAny(vm => vm.Login, vm => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value));

Page 43: Как приручить реактивное программирование

43

3. Реактивная асинхронная команда

LoginCommand = ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password));

LoginCommand.Subscribe(OnLoginCompleted);} // of ctor

private void OnLoginCompleted(bool loginSuccessed){ }

Page 44: Как приручить реактивное программирование

44

3. Реактивная асинхронная команда

LoginCommand = ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password));

LoginCommand.Subscribe(OnLoginCompleted);} // of ctor

private void OnLoginCompleted(bool loginSuccessed){ }

Page 45: Как приручить реактивное программирование

45

3. Реактивная асинхронная команда

LoginCommand = ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password));

LoginCommand.Subscribe(OnLoginCompleted);} // of ctor

private void OnLoginCompleted(bool loginSuccessed){ }

Page 46: Как приручить реактивное программирование

46

Достоинства ReactiveCommand

• Не нужно мониторить значения свойств Login и Password

• Не нужно мониторить начало и конец асинхронной операции логина

Page 47: Как приручить реактивное программирование

47

Что ещё умеет ReactiveUI

• Навигация ViewModel First• Маппинг View и ViewModel ручной• IoC на основе Splat • Валидация (не в фреймворке, в сэмплах)• Есть плагин для Fody, который генерит INPC

Но все равно как MVVM фреймворк ReactiveUI слабоват

Поэтому используем из него только команды и привязки

Page 48: Как приручить реактивное программирование

48

Книга мифов о ReactiveUI

Page 49: Как приручить реактивное программирование

49

1. Rx – это экзотическая функциональщина (F#, Scala, Haskel)

F#

Scala

Page 50: Как приручить реактивное программирование

50

На самом деле• Интерфейсы IObservable и

IObserver входят в состав .NET• Для C# существует несколько

библиотек от BindableLinq до ReactiveUI

Page 51: Как приручить реактивное программирование

51

2. Реактивное программирование – это backend

Akka.NET Orleans

ReactiveUI

Page 52: Как приручить реактивное программирование

52

Rx для UI маленький, да удаленький

Что ещё ReactiveUI:• ReactiveCommand• ObservableForProperty• WhenAny

Page 53: Как приручить реактивное программирование

53

3. Боюсь использовать ReactiveUI, слишком экзотично

Page 54: Как приручить реактивное программирование

54

Недостатки ReactiveUI• IoC привязан к Splat• Есть MessageBus, без которого

можно обойтись• Неудобная для WinRT и UWP

навигация ViewModelFirst

Page 55: Как приручить реактивное программирование

55

Используем совместно с другим MVVM

Используем сильные стороны:• ReactiveCommand• Привязки на уровне ViewModel

(ObservableForProperty и WhenAny)

Не используем слабые стороны:• Навигация• IoC

Page 56: Как приручить реактивное программирование

56

4. Использовать несколько MVVM на одном проекте нельзя!

Page 57: Как приручить реактивное программирование

57

Можно, только осторожно

• Каждому MVVM – своя область ответственности

• Контроль, чтобы эта область не расползалась (регулярные ревью)

Page 58: Как приручить реактивное программирование

58

Наш опытReactiveUI Mugen PrismReactiveCommandObservableForPropertyWhenAny

XAML BindingsComposite UI

Page 59: Как приручить реактивное программирование

59

Подведем итоги• ReactiveUI можно (и нужно )

использовать:• Реактивные команды• Привязки на уровне ViewModel вместо

MessageBus• ReactiveUI используем как

дополнение к любимому MVVM фреймворку

Page 60: Как приручить реактивное программирование

60

Реактивное программирование – не страшный и загадочный зверь

Page 61: Как приручить реактивное программирование

61

А верный друг на ваших проектах!

Page 62: Как приручить реактивное программирование

62

Что дальше делать?• Познакомиться: скачать Rx или

ReactiveUI, посмотреть сэмплы• Отладить приложение для

Codefest, сообщество будет вам благодарно

• Попробовать Rx и ReactiveUI на продакшене

Page 63: Как приручить реактивное программирование

63

Полезные ссылкиКлассное видео для начинающихhttps://vimeo.com/43172610

Про Rx для разных языков программированияhttp://reactivex.io/

Официальная страницаhttp://reactiveui.net/Код, примерыhttps://github.com/reactiveuiAutofac https://github.com/alexeyzimarev/RxUI6WithAutofac

Page 64: Как приручить реактивное программирование

64

Спасибо за внимание

Денис Цветцих[email protected]