Как приручить реактивное программирование
TRANSCRIPT
Как приручить реактивное программирование
Денис ЦветцихIce Rock Dev
icerockdev.com
12-я конференция .NET разработчиков15 мая 2016dotnetconf.ru
2
Кто я?• 7+ лет .NET• Разработка корпоративных
приложений• Люблю хипстерские библиотеки
3
Почему я здесь?• 6 лет назад приручил Rx• 3 года назад приручил ReactiveUI• С тех пор активно использую в
XAML проектах
4
Многие не используют• Не знают о Rx и ReactiveUI• Находятся под влиянием «мифов»
о реактивном программировании
5
О чем мы поговорим?• Что такое реактивное
программирование?• Для каких задач его использовать?• Развеем мифы, которые мешают его
использовать
6
Опрос• Кто не знает, что такое реактивное
программирование?• Кто знаком с Rx и ReactiveUI, но не
решился использовать в своих проектах?
• Кто использовал Rx или ReactiveUI на продакшене?
ЧТО ТАКОЕ РЕАКТИВНОЕ ПРОГРАММИРОВАНИЕ
8
Что такое реактивное программирование?
Реактивное программирование – это парадигма программирования, ориентированная на потоки данных и распространение изменений. (Википедия)
9
Парадигма программирования
Парадигма программирования – это система идей и понятий, определяющих стиль написания компьютерных программ.
10
Императивная программа
var A = 10;var B = A + 1;
// Чему равно В?11
A = A + 1;
// А теперь чему равно В?11
11
Реактивная программаvar A = 10;var B <- A + 1; <- оператор «судьбы»
// Чему равно В?11
A = A + 1;
// А теперь чему равно В?12
12
Реактивное программирование
Реактивное программирование – это парадигма программирования, ориентированная на потоки данных и распространение изменений.
Потоки данных – последовательность значений каждой переменной или свойства класса.
Распространение изменений – уведомления «заинтересованных» об изменениях.
13
PullPull – класс A взаимодействует с классом B и вытягивает из него необходимые данные
Class A Class B
GetData()
Interacts with
14
PushPush – класс B самостоятельно выталкивает данные, как только они становятся доступны.
Class A
ProcessData()
Class BReacts on
15
Примеры из жизни• Вычислимые ячейки Excel
• Принцип Голливуда – «Не звоните нам, мы сами вам позвоним»
• Push - уведомления
РЕАКТИВНОЕ ПРОГРАММИРОВАНИЕ НА C#
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
18
Настоящее• Reactive Extensions (Rx)• Эрик Мейер из MS Research
• ReactiveUI• библиотека на базе Rx для создания
элегантных UI для всех XAML платформ
19
Внутри .NETpublic interface IObservable<T>{
IDisposable Subscribe(IObserver<T> observer);}
public interface IObserver<T>{
void OnNext(T value);void OnCompleted();void OnError(Exception error);
}
20
Внутри .NETpublic interface IObservable<T>{
IDisposable Subscribe(IObserver<T> observer);}
public interface IObserver<T>{
void OnNext(T value);void OnCompleted();void OnError(Exception error);
}
21
Внутри .NETpublic interface IObservable<T>{
IDisposable Subscribe(IObserver<T> observer);}
public interface IObserver<T>{
void OnNext(T value);void OnCompleted();void OnError(Exception error);
}
22
Внутри .NETpublic interface IObservable<T>{
IDisposable Subscribe(IObserver<T> observer);}
public interface IObserver<T>{
void OnNext(T value);void OnCompleted();void OnError(Exception error);
}
23
Внутри .NETpublic interface IObservable<T>{
IDisposable Subscribe(IObserver<T> observer);}
public interface IObserver<T>{
void OnNext(T value);void OnCompleted();void OnError(Exception error);
}
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);
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);
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);
27
Observable.Select – проекция
28
Observable.Merge – слияние
29
Observable.Zip - объединение
КАКИЕ ЗАДАЧИ МОЖНО РЕШАТЬ
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() { }}
32
1. Подписка на изменение свойства
// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);
// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }
// Отписка_subscription.Dispose();
33
1. Подписка на изменение свойства
// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);
// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }
// Отписка_subscription.Dispose();
34
1. Подписка на изменение свойства
// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);
// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }
// Отписка_subscription.Dispose();
35
1. Подписка на изменение свойства
// ПодпискаIDisposable _subscription = this.ObservableForProperty(vm => vm.Login) .Subscribe(OnLoginChanged);
// Реакция на событиеprivate void OnLoginChanged (IObservedChange<LoginViewModel, String> change){ }
// Отписка_subscription.Dispose();
36
2. Подписка на изменение нескольких свойств
IDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);
37
2. Подписка на изменение нескольких свойств
IDisposable _subscription = this.WhenAny( vm => vm.Login, vm => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);
38
2. Подписка на изменение нескольких свойств
IDisposable _subscription = this.WhenAny( vm => vm.Login, vn => vm.Password, (login, password) => !string.IsNullOrEmpty(login.Value) && !string.IsNullOrEmpty(password.Value)) .Subscribe(OnCredentialsChanged);
39
3. Реактивная асинхронная команда
CanExecute – false, когда1) Не выполняется условие отправки
запроса2) Выполняется асинхронный запрос
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));
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));
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));
43
3. Реактивная асинхронная команда
LoginCommand = ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password));
LoginCommand.Subscribe(OnLoginCompleted);} // of ctor
private void OnLoginCompleted(bool loginSuccessed){ }
44
3. Реактивная асинхронная команда
LoginCommand = ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password));
LoginCommand.Subscribe(OnLoginCompleted);} // of ctor
private void OnLoginCompleted(bool loginSuccessed){ }
45
3. Реактивная асинхронная команда
LoginCommand = ReactiveCommand.CreateAsyncTask (canExecute, async _ => await _loginService.Login(Login, Password));
LoginCommand.Subscribe(OnLoginCompleted);} // of ctor
private void OnLoginCompleted(bool loginSuccessed){ }
46
Достоинства ReactiveCommand
• Не нужно мониторить значения свойств Login и Password
• Не нужно мониторить начало и конец асинхронной операции логина
47
Что ещё умеет ReactiveUI
• Навигация ViewModel First• Маппинг View и ViewModel ручной• IoC на основе Splat • Валидация (не в фреймворке, в сэмплах)• Есть плагин для Fody, который генерит INPC
Но все равно как MVVM фреймворк ReactiveUI слабоват
Поэтому используем из него только команды и привязки
48
Книга мифов о ReactiveUI
49
1. Rx – это экзотическая функциональщина (F#, Scala, Haskel)
F#
Scala
50
На самом деле• Интерфейсы IObservable и
IObserver входят в состав .NET• Для C# существует несколько
библиотек от BindableLinq до ReactiveUI
51
2. Реактивное программирование – это backend
Akka.NET Orleans
ReactiveUI
52
Rx для UI маленький, да удаленький
Что ещё ReactiveUI:• ReactiveCommand• ObservableForProperty• WhenAny
53
3. Боюсь использовать ReactiveUI, слишком экзотично
54
Недостатки ReactiveUI• IoC привязан к Splat• Есть MessageBus, без которого
можно обойтись• Неудобная для WinRT и UWP
навигация ViewModelFirst
55
Используем совместно с другим MVVM
Используем сильные стороны:• ReactiveCommand• Привязки на уровне ViewModel
(ObservableForProperty и WhenAny)
Не используем слабые стороны:• Навигация• IoC
56
4. Использовать несколько MVVM на одном проекте нельзя!
57
Можно, только осторожно
• Каждому MVVM – своя область ответственности
• Контроль, чтобы эта область не расползалась (регулярные ревью)
58
Наш опытReactiveUI Mugen PrismReactiveCommandObservableForPropertyWhenAny
XAML BindingsComposite UI
59
Подведем итоги• ReactiveUI можно (и нужно )
использовать:• Реактивные команды• Привязки на уровне ViewModel вместо
MessageBus• ReactiveUI используем как
дополнение к любимому MVVM фреймворку
60
Реактивное программирование – не страшный и загадочный зверь
61
А верный друг на ваших проектах!
62
Что дальше делать?• Познакомиться: скачать Rx или
ReactiveUI, посмотреть сэмплы• Отладить приложение для
Codefest, сообщество будет вам благодарно
• Попробовать Rx и ReactiveUI на продакшене
63
Полезные ссылкиКлассное видео для начинающихhttps://vimeo.com/43172610
Про Rx для разных языков программированияhttp://reactivex.io/
Официальная страницаhttp://reactiveui.net/Код, примерыhttps://github.com/reactiveuiAutofac https://github.com/alexeyzimarev/RxUI6WithAutofac