Mit reaktiver Programmierung über den Acker

31
© Zühlke 2014 Mit reaktiver Programmierung über den Acker Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 1

Transcript of Mit reaktiver Programmierung über den Acker

Page 1: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Mit reaktiver Programmierung über den AckerMit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 1

Page 2: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Who_Am_I?

• Informationstechnik im Maschinenwesen

• Road behind:– Chemical Engineering– Walzwerke– Hotelbuchungssysteme– Brauereien und Abfüllanlagen

• Seit 2010 Software Engineer bei der Zühlke GmbH in Eschborn

• Schwerpunkte:– M2M– Innovation

Stefan RothMarburg Berlin Grenoble Erlangen Nürnberg München Regensburg, Darmstadt

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

[email protected]@googlemail.com@halfwit_twit

2. Dezember 2014 Folie 2

Page 3: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Reaktive Programmierung: Warum?

• Eventaggregatoren gezielt einsetzen

• Schöner Testen mir Rx

• Push vs. Pull

Oder besser: Warum eigentlich nicht?

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 3

Page 4: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Das Projekt

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 4

Page 5: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Systemsicht

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

ECU

- Fährt- Regelt

- Navigiert- Kalibriert

GPS - Positions-daten

Navigations-rechner

-Verfahrwege- Spuren

Feld-Daten

- Feldkonturen- gesp. Tracks- Fahrzeugdaten- Peripherie

Panel- UI- Karte- Fahrzeugdaten- Steuerung

??

?

2. Dezember 2014 Folie 5

Page 6: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Projekt-Charakteristika

Regelung Ablaufsteuerung•Workflows mit

„Stateless“

Viele unfertige Umsysteme•Notwendigkeit der

Simulation

AsynchronitätUnklare/Unfertige Requirements

States und Ereignisse•Kleinster gemeinsamer

Nenner

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 6

Page 7: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Klassische Kommunikation

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

• Interfaces müssen untereinander bekannt sein

• Player müssen sich gegenseitig „kennen“ oder Polling

2. Dezember 2014 Folie 7

Page 8: Mit reaktiver Programmierung über den Acker

© Zühlke 2014Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

Weitere Abhängigkeiten beim Testen

ComponentA

ComponentB

DoSomething(X, Y)

ComponentB’

DoSomethingElse(X, Q, Z)?

Unit tests

?

2. Dezember 2014 Folie 8

Page 9: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Entkopplung durch Events

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

„Tell don‘t ask“

ComponentA

ComponentB

User triggeredaction X

Subscribed toevents of type X

ComponentB’

Just produced: result Y

Subscribed to resultevents of type Y

Just produced: result Y

Just produced: result Z

Just produced: result Q

2. Dezember 2014 Folie 9

Page 10: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Statusübergänge durch Events

Umsysteme/ Simulation erzeugen

Events

States lösen wiederum Events aus

•ErsatzgrößeZeitvariant

•Nebenläufige Threads und Timer

Spezielles Setup oder

Alltag?

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 10

Page 11: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Weitere Eventquellen

2. Dezember 2014

Verknüpfung mit Reactive Extensions

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth Folie 11

PositionECU

Page 12: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Reactive Extensions für jedermann

.NET

JavaScript (RxJS)

Java (RxJava)+ Scala, Groovy, Clojure

Objective-C (ReactiveCocoa)

C++ (RxCpp)

Python Ruby

PHP

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

Rx = Observables + LINQ + Schedulers.

2. Dezember 2014 Folie 12

Page 13: Mit reaktiver Programmierung über den Acker

© Zühlke 20142. Dezember 2014

IEnumerable IObservable

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth Folie 13

1 Rückgabewert n RückgabewerteT IEnumerable<T>

Pull:

1 Rückgabewert n RückgabewerteTask<T> IObservable<T>

Push:

public interface IObservable<out T>{

IDisposable Subscribe(IObserver<T> observer);}

Page 14: Mit reaktiver Programmierung über den Acker

© Zühlke 20142. Dezember 2014

Eigenschaften eines IObservers

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth Folie 14

public interface IObserver<in T>{

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

}

Page 15: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

EventAggregatoren mit Rx

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

public class EventAggregator : IEventAggregator{

private readonly ISubject<object> messageSubject = new Subject<object>();

public IObservable<object> EventStream{

get{

return this.messageSubject;}

}

public void Send<T>(T message){

this.messageSubject.OnNext(message);}

public void Send<T>(T message, IScheduler scheduler){

if (scheduler == null) { this.Send(message); }else { scheduler.Schedule(() => Send(message)); }

}

public IObservable<T> GetEventStream<T>(){

return this.messageSubject.OfType<T>();}

}

2. Dezember 2014 Folie 15

Page 16: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Grobe Systemarchitektur

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

ECU

CAN-Bus

Business-Logik/Workflows

UI

Services

ECU Message translator

Event Aggregator

2. Dezember 2014 Folie 16

Page 17: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Klassisches Testen 1/2Warten auf das „hoffentlich bald“-Event

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

bool status = false;while (!status){

status = m_target.Status == expectedStatus;}

Target pollen

target.SelectedEcuOrientation = ExpectedEcuOrientation;

this.ContainingViewModel.NextStepCommand.Execute(null);

var completion = new ManualResetEvent(false);

machineCalibrationService.GetECUOrientation(

ecu =>

{

readEcuOrientation = ecu;

completion.Set();

});

completion.WaitOne();

2. Dezember 2014 Folie 17

Mit Synchronisierungsartefakten

Page 18: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Klassisches Testen 2/2Warten auf das „hoffentlich bald“-Event

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

• Synchronisierungs-Artefakten

• Asynchrone Tests Boilerplate code

• Ausweg: Async/Await. Sonst:

• Warten heißt Thread blockieren

• Timings unterschiedlich in Dev-und Build-Umgebung

• Tests ungeeignet für continuousintegration

2. Dezember 2014 Folie 18

Page 19: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Eventgetriebenes Testen

Gegeben:

• Man kann mit EventAggregator Events erzeugen und sich auf Events subscriben.

• EventAggregator als Singleton überall injectbar

Gesucht:

• Wie warte ich auf Events?– Muss ich das wirklich tun?

• UI-Tests

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 19

Voraussetzungen und Fragen

Page 20: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Testen von UI über Events 1/2

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

ViewM

odelWorkflows

Unit-Test

View

2. Dezember 2014 Folie 20

Page 21: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Testen von UI über Events 2/2

Page 22: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

ISchedulerProvider und TestScheduler 1/2

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

m_eventAggregator.GetEventStream<FineWheelAngleSensorCalibrationResult>()

.ObserveOnDispatcher()

.Subscribe((result) =>

{Status = result.Status;if (result.Status == CalibrationFineWheelAngleSensorStatus.Completed){

Parent.NextStepAvailable = true;}

});

/// <summary>/// Gets the <see cref="IScheduler"/> instance representing the current app's thread/// </summary>public IScheduler CurrentThread{get{return Scheduler.CurrentThread;

}}

/// <summary>/// Gets the <see cref="IScheduler"/> instance representing dispatching thread./// </summary>public IScheduler Dispatcher{get{return DispatcherScheduler.Instance;

}}

class SchedulerProv ider

«interface»

ISchedulerProv ider

«Property»

- CurrentThread :IScheduler

- Dispatcher :IScheduler

- Immediate :IScheduler

- NewThread :IScheduler

- ThreadPool :IScheduler

TestSchedulers

{leaf}

- m_currentThread :TestScheduler = new TestScheduler() {readOnly}

- m_dispatcher :TestScheduler = new TestScheduler() {readOnly}

- m_immediate :TestScheduler = new TestScheduler() {readOnly}

- m_newThread :TestScheduler = new TestScheduler() {readOnly}

- m_threadPool :TestScheduler = new TestScheduler() {readOnly}

«property»

+ CurrentThread() :TestScheduler

+ Dispatcher() :TestScheduler

+ Immediate() :TestScheduler

+ NewThread() :TestScheduler

+ ThreadPool() :TestScheduler

SchedulerProv ider

«property»

+ CurrentThread() :IScheduler

+ Dispatcher() :IScheduler

+ Immediate() :IScheduler

+ NewThread() :IScheduler

+ ThreadPool() :IScheduler

Default-SchedulerProvider:

2. Dezember 2014 Folie 22

Page 23: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

ISchedulerProvider und TestScheduler 2/2

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

m_eventAggregator.GetEventStream<FineWheelAngleSensorCalibrationResult>()

.Subscribe((result) =>

{Status = result.Status;if (result.Status == CalibrationFineWheelAngleSensorStatus.Completed){

Parent.NextStepAvailable = true;}

});

/// <summary>/// Gets the <see cref="IScheduler"/> instance representing the current app's thread/// </summary>public IScheduler CurrentThread{get{return Scheduler.CurrentThread;

}}

/// <summary>/// Gets the <see cref="IScheduler"/> instance representing dispatching thread./// </summary>public IScheduler Dispatcher{get{return DispatcherScheduler.Instance;

}}

class SchedulerProv ider

«interface»

ISchedulerProv ider

«Property»

- CurrentThread :IScheduler

- Dispatcher :IScheduler

- Immediate :IScheduler

- NewThread :IScheduler

- ThreadPool :IScheduler

TestSchedulers

{leaf}

- m_currentThread :TestScheduler = new TestScheduler() {readOnly}

- m_dispatcher :TestScheduler = new TestScheduler() {readOnly}

- m_immediate :TestScheduler = new TestScheduler() {readOnly}

- m_newThread :TestScheduler = new TestScheduler() {readOnly}

- m_threadPool :TestScheduler = new TestScheduler() {readOnly}

«property»

+ CurrentThread() :TestScheduler

+ Dispatcher() :TestScheduler

+ Immediate() :TestScheduler

+ NewThread() :TestScheduler

+ ThreadPool() :TestScheduler

SchedulerProv ider

«property»

+ CurrentThread() :IScheduler

+ Dispatcher() :IScheduler

+ Immediate() :IScheduler

+ NewThread() :IScheduler

+ ThreadPool() :IScheduler

Default-SchedulerProvider:

.ObserveOn(schedulerProvider.Dispatcher)

2. Dezember 2014 Folie 23

Page 24: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Nutzen von Rx TestSchedulern

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

• Simulation von Ereignissen durch Scheduling zu vordefinierten Zeiten

• Scheduler vor und nach Event “spulen”

• Verschiedene Threads verschiedene Scheduler

• Zeit = weiterer Freiheitsgrad

• Zeitvarianter Test der dennoch in wenigen msausgeführt wird

// advance schdeuler to one tick before PCU event:

this.TestScheduler.Dispatcher.AdvanceBy(1999);Assert.AreEqual(YYY.PointBIsSet, this.m_target.Status);

Assert.IsFalse(this.m_target.AutopilotActivatedCommand.CanExecute(nu

ll));

// advance two ticks further to simulate the PCU firing the

// automatic steering possible event:

this.TestScheduler.Dispatcher.AdvanceBy(2);Assert.AreEqual(YYY.AutomaticSteeringPossible,this.m_target.Status);

Assert.IsTrue(this.m_target.AutopilotActivatedCommand.CanExecute(null));

// schedule that after 2000 ticks the PCU will signal the ”automatic

// steering possible” signal:

this.TestScheduler.Dispatcher.Schedule(

TimeSpan.FromTicks(2000),

() =>

this.m_eventAggregator.Send(XXX.AutomaticSteeringPossible));

2. Dezember 2014 Folie 24

Page 25: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Die vierte Dimension: Zeit

• Viewmodel: Events werden auf dispatcherthread observed

• Viewmodels nutzen ISchedulerProvider

• Rx TestScheduler machen Zeit „programmierbar“– Virtuelle Zeit– Zeitmaschine– Unit tests

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 25

Page 26: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Eventgetrieben im Vergleich zu SOA

• Request/response vs. Observable-Pattern

• EventAggregator als ServiceBus?

• Nur noch event aggregator?

• Ist das noch punk „reaktiv“?

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 26

Page 27: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Ausflug ins Reactive Manifesto

ReactiveMani-festo

Respon-sive

Resilient

Elastic

Message Driven

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

http://www.reactivemanifesto.org/

• Flexible

• Looselycoupled

• Scalable

2. Dezember 2014 Folie 27

Page 28: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Vor- und Nachteile reaktiver Programme

• Voraussetzung in mobile OS‘s

• Push-Notifications bei Apps

• Mobile Apps und Taskwechsel

• Daher Push vs. Pull fast schon Dogma

• Reactive Extensions: Ansatz Eventverarbeitung und Asynchronität über Programmiersprachen hinaus gleich zu behandeln

• Kein Silver Bullet– Verständnis von Asynchronität weiter unabdingbar– Verklemmung und Verhungern weiter möglich

• Preis:– Verlust des Contracts und der Signatur– Debugging-Hell

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 28

Page 29: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Events als festen Bestandteil im Projekt

Logging

Tracing

Events

•Debug-Info•Fehlersuche

•Performance-Counter

•Info über Zustandsänderungen

•Testbarkeit erhöhen•In Ergänzung zu Services

2. Dezember 2014Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth Folie 29

Page 30: Mit reaktiver Programmierung über den Acker

© Zühlke 2014

Take-Aways

Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

Dauerbrenner

Lightweight Architecture

Lose gekoppelte Systeme

Dependency Injection

YAGNI,KISS

Services mit definierter

Verantwort-lichkeit

Evolutionäre Architektur

Vermeiden von unnötigen

Schichten

Zeitabhängig-keit durch

Events lösen

2. Dezember 2014 Folie 30

Page 31: Mit reaktiver Programmierung über den Acker

© Zühlke 2014Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth

Haben Sie [email protected]@halfwit_twit

2. Dezember 2014 Folie 31