Applikationsarchitektur modularer Rich Client-Anwendungen am Beispiel der Windows Presentation Foundation Jörg Jooss MTC Architect OOP 2009
2 Das Szenario Rich Client-Anwendung (WPF, C#) von geringer Software-Qualität Design Patterns, Composite Application Library (CAL) Modulare Anwendung mit deutlicher höherer Software-Qualität überführen
3 Hintergrund: Qualitätsmerkmale Maintainability: A set of attributes that bear on the effort needed to make specified modifications (ISO 9126) StabilityAnalyzabilityChangeabilityTestability
Iteration 0: Die Applikation
5 Iteration 0: Bestandsaufnahme Autonomous View (Anti-)Pattern: Applikationslogik und Präsentationslogik sind vermischt Fehlende Abstraktionen 95% der Applikationslogik liegen in einer Methode Unit Testing sehr schwierig Code bietet kaum Möglichkeiten zur Aufteilung zwischen Teams Erweiterungen nach dem gleichen Entwicklungsansatz führen unweigerlich zum Big Ball of Mud BeobachtungenSoftware-Qualität
6 Iteration 1: Separate Presentation Um den Big Ball of Mud zu verhindern, müssen wir die Präsentation vom Rest der Anwendung trennen Konkrete Design Patterns: Model-View-Controller Model-View-Presenter Presentation Model WPF und CAL geben jeweils keinen Ansatz vor – aber in WPF ist Presentation Model sehr einfach zu realisieren
7 Hintergrund: Presentation Model Benutzerinteraktion ViewView Presentation Model Business Logic Businessness Logic API Events Commands Data Binding
8 Hintergrund: Commands Receiver+Action<T> +Func +Func Receiver+Action<T> ICommand+Execute+CanExecute+CanExecuteChangedICommand+Execute+CanExecute+CanExecuteChangedDelegateCommand+Execute+CanExecute+CanExecuteChangedDelegateCommand+Execute+CanExecute+CanExecuteChanged InvokerInvoker In CAL In WPF
Iteration 1: Shell und Presentation Model
10 Iteration 1 – The Story So Far… Commands definiert: O PEN, C LOSE und E XIT Presentation Model (PM) implementiert E XIT implementiert Datenbindung zwischen Views und PM Neu MainWindow zur Shell reduziert Utility-Klassen entfernt Geändert oder entfernt
11 Iteration 1: Bestandsaufnahme View enthält keine Anwendungslogik und ist vom Presentation Model entkoppelt Unit Testing des PM möglich (Unit Test als alternativer View) Applikationslogik kann nach Belieben realisiert werden Die Features von WPF (Datenbindung, Commands etc.) werden genutzt Mehr als ein leeres Fenster haben wir jetzt aber nicht… BeobachtungenSoftware-Qualität
12 Iteration 2: File Open …? Wie zeigen wir ein Dialogfenster an, ohne das Presentation Model ad absurdum zu führen? Einfachste Lösung: Indirektion – Auslagern in eine andere Komponente Service = Interface + Implementierung(en)
13 Iteration 2: File Open …? (contd) Vermeide Abhängigkeiten zwischen Shell und Applikationskomponenten – wie aber werden Informationen aus der Shell propagiert? C#-Events helfen nicht – der Subscriber kennt den Publisher bereits zur Buildtime CAL stellt den Event Aggregator als Publish/Subscribe-Mechanismus bereit
14 Hintergrund: Event Aggregator PublisherPublisherSubscriberSubscriber PublisherPublisher SubscriberSubscriber SubscriberSubscriber Event Aggregator CompositeWpfEvent<T>CompositeWpfEvent<T> CompositeWpfEvent<U>CompositeWpfEvent<U>
Iteration 2: Events und Services
16 Iteration 2 – The Story So Far… Funktionalität zum Öffnen von Dateien als Service gekapselt (IF ILE P ROVIDER und D IALOG F ILE P ROVIDER ) Das Ereignis F ILE C HANGED E VENT in neuer Assembly X ML E XPLORER S HARED definiert Property C URRENT F ILE zur Verwaltung der aktuell geöffneten Datei ergänzt löst F ILE C HANGED E VENT aus Presentation Model erfordert nun IE VENT A GGREGATOR und IF ILE P ROVIDER Neu O PEN und C LOSE implementiert Setzen C URRENT F ILE Geändert oder entfernt
17 Iteration 2: Bestandsaufnahme Konsumenten von Ereignissen in der Shell bleiben durch Publish/Subscribe lose gekoppelt Bereitstellung technischer Funktionen als Services erhöht Testbarkeit F ILE C HANGED E VENT ist momentan die einzige Gemeinsamkeit zwischen Provider (Shell) und potentiellen Konsumenten Es fehlt jedoch die Integration der Services BeobachtungenSoftware-Qualität
18 Iteration 3: Connecting the Dots Wir wollen die losen Teile (Shell, Presentation Model, Services) verbinden, zugleich aber die Verbindungen leicht ändern können Dependency Injection-Container erlauben die Konstruktion von Objekten und deren Abhängigkeiten CAL bietet Dependency Injection-Container (Unity) Bootstrapper
19 Kern eines Depedency Injection Containers Hintergrund: Dependency Injection BuilderBuilderIServiceIService ServiceImplServiceImpl ClientClient <<creates>> <<injects>>
Iteration 3: Bootstrapper und Dependency Injection
21 Iteration 3 – The Story So Far… Bootstrapper implementiert Dependency Injection-Container für Shell konfiguriert Neu Presentation Model und Shell nun DI friendly Startvorgang nun Application Boostrapper Container Shell, vorher Application Shell Geändert oder entfernt
22 Iteration 3: Bestandsaufnahme Abhängigkeiten zwischen den Komponenten sind nicht hart codiert, sondern über Dependency Injection flexibel änderbar Testkonfigurationen können so das System entsprechend rekonfigurieren und Stubs, Fakes etc. verwenden Wir haben immer noch nur ein leeres Fenster… BeobachtungenSoftware-Qualität
23 Iteration 4: Module für die Massen Wir wollen ein Konstrukt bereitstellen, das die eigentliche Anwendungslogik über alle Schichten kapselt – Module Solche Module können auf verschiedene Weise geschnitten werden: Infrastrukturkomponenten Anwendungsfeatures Subsysteme CAL bietet die Infrastruktur zur Bereitstellung von Assemblies als Module
Iteration 4: Views und Services in einem Modul
25 Iteration 4 – The Story So Far… Neue Assembly X ML E XPLORER M ODULE XML-Verarbeitung in Service gekapselt Ursprüngliche XML-UI samt Ressourcen und Utility-Klassen in UserControl E XPLORER V IEW verlagert E XPLORER V IEW P RESENTATION M ODEL implementiert und für F ILE C HANGED E VENT registriert NeuGeändert oder entfernt
26 Iteration 4: Bestandsaufnahme Ein Modul ist ein mehrschichtiger, in sich abgeschlossener Applikationsbaustein Wie die Shell verwendet es PM, Commands, Pub/Sub und User Controls als Views Hohe Kohäsion, niedrige Kopplung Event Aggregator erleichtert Thread Marshalling Die Implementierung verschiedener Module kann auf mehrere Teams aufgeteilt werden Aber was macht eine Assembly eigentlich zum Modul? BeobachtungenSoftware-Qualität
27 Iteration 5: I, Module Uns fehlt eine Möglichkeit das Modul zu initialisieren (Bootstrapper?) Kennzeichnung von Modulkomponenten Attribute Interfaces Basisklassen Konvention CAL sucht in einer Assembly nach Typen, die IM ODULE implementieren
Iteration 5: Das IModule
29 Iteration 5: The Story So Far… IM ODULE implementiert IU NITY C ONTAINER als modul-interner Service Container für Modul konfiguriert NeuGeändert oder entfernt
30 Iteration 5: Bestandsaufnahme Ein IM ODULE agiert wie ein modulspezifischer Bootstrapper Wie in der Shell können so Abhängigkeiten im Modul per DI konfiguriert werden Abhängigkeiten des Moduls werden von CAL injiziert Wie aber bringen wir Module zur Ausführung? BeobachtungenSoftware-Qualität
31 Iteration 6: How to Be Found and Seen Die Shell benötigt Mechanismen zum Finden von Modulen und Platzhalter zur Anzeige von Views Direkte Referenzen zwischen Shell und Modulen führen zu enger Kopplung CAL bietet Module Enumerators Regions
32 Hintergrund: Regions Name der Region Tipp: Binden statt hart codieren Name der Region Tipp: Binden statt hart codieren ContentControls, Selectors, und ItemControls können mit Regionen dekoriert werden
Iteration 6: Die modulare Anwendung
34 Iteration 6: Abschluss IR EGION M ANAGER wird von CAL bereitgestellt R EGION N AMES IN X ML E XPLORER S HARED zur Verwaltung von Region-Ids C ONTENT C ONTROL zur Anzeige von Views in der Region M AIN R EGION in der Shell Neu IR EGION M ANAGER im Modul als Abhängigkeit ergänzt View in der Region M AIN R EGION angezeigt IM ODULE E NUMERATOR in der Shell zum Laden des Moduls Geändert oder entfernt
35 Iteration 6: Bestandsaufnahme Die Shell muss Regionen zur Anzeige von Views vorsehen und benennen Shell und Module/Views sind komplett entkoppelt, kennen jeweils nur Regionenbezeichner und Ereignisse Die Strategie zum Finden von Modulen ist austauschbar BeobachtungenSoftware-Qualität
36 Zusammenfassung Modulare WPF-Anwendungen mit der Composite Application Library Commands/ Events Services/ Container BootstrapperModule Regions/ Views
37 Ressourcen Composite Application Guidance und CAL patterns & practices Developer Center MTC München Team Blog (Code zur Session)