© Zühlke 2014
Mit reaktiver Programmierung über den AckerMit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 1
© 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
© 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
© Zühlke 2014
Das Projekt
Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth 2. Dezember 2014 Folie 4
© 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
© 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
© 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
© 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
© 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
© 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
© 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
© 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
© 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);}
© 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();
}
© 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
© 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
© 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
© 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
© 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
© 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
© Zühlke 2014
Testen von UI über Events 2/2
© 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
© 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
© 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
© 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
© 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
© 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
© 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
© 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
© 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
© Zühlke 2014Mit reaktiver Programmierung über den Acker | Dr. Stefan Roth
Haben Sie [email protected]@halfwit_twit
2. Dezember 2014 Folie 31
Top Related