Zukunftssichere Architektur. Ralf Westphal
Чтение книги онлайн.
Читать онлайн книгу Zukunftssichere Architektur - Ralf Westphal страница 4
[Abb. 8] Echte Abstraktion von den Details einer Entität durch Schachtelung.
Das bedeutet, je umfangreicher oder komplizierter ein System wird, desto schwieriger wird die Modellierung mit den auf ein Abstraktionsniveau festgenagelten Strukturelementen. Mit einem Wort: Ska-lierbarkeit ist keine Sache der Objektorientierung.
Geschachtelte Komponenten
Software muss auf beliebig vielenAbstraktionsebenen darstellbar sein. Die Modellierungselemente müssen daher schachtelbar sein. Modelle laufen immer Gefahr, von der Realität überholt zu werden. Das führt zu Pflegeaufwand beim Modell, weil es immer wieder der Implementierung nachgeführt werden muss. Wenn allerdings die Modellierungselemente gleichzeitig auch Implementierungsartefakte sind, ist dieser Gefahr zu begegnen. Denn dann kann das Modell aus der Coderealität bei Bedarf generiert werden. Die Klassendiagramme in Visual Studio sind dafür ein Beweis.
Um die Anforderung nach Schachtelbar-keit und Modell-Codeartefakt-Dualität zu erfüllen, schlage ich vor, die Konventionenlücke von unten mit Komponentenorientierung zu füllen. Komponente definiert sich für diesen Zweck minimal als:
Binäre Codeeinheit- denken Sie "Assembly" -
mit einem separaten Kontrakt - denken Sie wieder "Assembly" -,
deren Leistung beschrieben wird durch eine Spezifikation bestehend aus der Summe des exportierten Kontrakts und der importierten Kontrakte
und die sich beliebig schachteln lässt.
Das sind die unverbrüchlichen Eigenschaften von Komponenten. Abbildung 9 stellt die ersten drei dar. An dieser Stelle nur stichpunktartig die Argumente für eine Trennung von Kontrakt und Implementierung:
Ein separater Kontrakt ermöglicht den einfachen Austausch von Implementierungen. Das kann zu Testzwecken geschehen - Stichworte: Testattrappe, Mockup - oder um Alternativen bereitzustellen - Stichwort: Plug-ins.
Ein separater Kontrakt, der auch noch vor einer ersten Implementierung festgelegt ist - Stichwort: Contract-first-Design -, erlaubt die parallele Implementierung vieler Komponenten. Das steigert die Produktivität oder erleichtert das Outsourcing von Teilen.
Jeden Kontrakt in einer eigenenAssembly zu beschreiben, verringert die kognitive Belastung während der Entwicklung an einer Implementierung. Derjenige, der eine Komponente implementiert, sieht durch die Kontrakte und ihrer Spezifika-tiondenkleinstmöglichenAusschnittaus der Gesamtanwendung. Er kann sich dadurch bei der Arbeit auf das unmittelbar relevante Arbeitsfeld konzentrieren.
[Abb. 9] Komponenten bestehen aus zwei Assemblies - eine für ihren Kontrakt und eine für die Implementierung des Kontrakts.
Die Realisierung solcher Komponenten erfolgt getrennt nach Kontrakt und Implementierung. Für jeden Kontrakt legen Sie ein eigenes Visual-Studio-Projekt an, für jede Implementierung eine eigene Visual-Studio-Projektmappe. Diese Trennung ist wichtig, um einer schleichenden Zunahme der Entropie in einer Anwendung Widerstand entgegenzusetzen. Denn die Entropie, also die Unordnung nimmt immer dann zu, wenn Beziehungen zwischen Codeteilen hergestellt werden. Jede Beziehung - von der Assemblyreferenz über die Instanzierung einer Klasse bis zum Zugriff auf eine statische globale Variable - macht es nämlich schwieriger, Code zu verstehen. Beziehungen, die nicht im Architekturmodell vorgesehen sind, gilt es daher zu vermeiden. Solange große Teile des Codes aber in einer Projektmappe liegen, wie es in vielen Projekten noch der Fall ist, steht dem jedoch nichts im Wege. Deshalb ist es so wichtig, die Trennung von Kontrakt und Implementierung auch in der Codeorganisation zu spiegeln.
Die Schachtelung von Komponenten ist wichtig, um die logischen Abstraktionsebenen eins zu eins in Codeartefakte überführen zu können. Prinzipiell sieht dann die Architektur jeder Anwendung wie in Abbildung 10 aus. Auf drei grundsätzlich verschiedenen Ebenen beschreiben Sie die Struktur Ihrer Software:
Die grobe Applikationsarchitektur beschreibt, welche Betriebssystemprozesse grundsätzlich zur Software gehören. Das kann ein Clientprozess sein, ein Reportserver, ein Applikationsserver, ein Datenbankserver. Je nach Anwendungsart (Desktop/Web), Skalierbarkeitsanforde-rungen und Kommunikation mit sonstiger Infrastruktur lassen Sie den Code unter einem oder mehreren Hosts laufen. Hosts sind die Programme, die Assemblies mit Ihrer Logik laden. Eine selbstgeschriebene Konsolenanwendung gehört ebenso dazu wie Outlook oder die Enterprise Services, bekannt als COM+.
Wenn Sie die Betriebssystemprozesse kennen, die zusammen Ihre Applikation bilden sollen, zerlegen Sie den Code, der in jedem der Prozesse laufen soll, in Komponenten. Die Zahl der Prozesse ist gemeinhin nicht groß, daher ist es nicht schlimm, dass Prozesse sich nicht schachteln lassen. Bei den Prozessen können Sie mit einer logischen, auf das Modell beschränkten Schachtelung der sogenannten Softwarezellen leben. Aber die Zahl der Komponenten in Ihren Anwendungen kann schon sehr groß werden. Deshalb ist eine Schachtelung angezeigt, um den Code auf unterschiedlichen Abstraktionsebenen beschreiben zu können. Egal, ob Sie beim Entwurf top-down oder bottom-up vorgehen: Sie wollen jederzeit die Möglichkeit haben, Funktionalität in einen "Sack“ zu stecken, um sie zu verbergen.
Die Blattkomponenten im Komponentenbaum, das heißt, die Komponenten auf der untersten Ebene, zerlegen Sie in Klassen. Oder genauer: Nicht der Architekt tut das, sondern diejenigen, welche die Komponenten implementieren. Für den Architekten wären das zu viele Details. Hier bekommen deshalb die Kom-ponentenimplementierer Spielraum für eigene Kreativität. Indem Sie als Architekt ihnen vertrauen, reduzieren Sie die Komplexität, mit der Sie im Modell umgehen müssen. Ein Diagramm aller Klassen wird nicht nötig sein.
[Abb. 10] Softwareentwurf findet auf drei grundsätzlich verschiedenen Abstraktionsebenen statt.
Wenn nun aber eine Komponente aus zwei Assemblies besteht - je eine für Kontrakt und Implementierung - wie soll sie in einer umfassenderen Komponente enthalten sein können? Oder wie soll sie selbst andere Komponenten enthalten, die ja ebenfalls Assemblies sind?
Abbildung 11 zeigt eine simple Komponentenarchitektur auf zwei Abstraktionsebenen. Auf hohem Abstraktionsniveau gibt es nur zwei Komponenten: KL und M. KL ist Client von Service-Komponente M. Beim Hineinzoomen zerfällt KL jedoch in zwei Komponenten: K und L, die wiederum füreinander Client und Service sind.
[Abb. 11] Zusammengesetzte Komponenten verbergen Beziehungsdetails.
Konsequent komponentenorientiert gedacht gibt es damit auf dem hohen Abstraktionsniveau vier Assemblies und auf dem niedrigeren sechs. Der Code würde aus den Projektmappen für die Implementierung von K, L und M bestehen (Ki, Li, Mi) sowie Projekte für die Kontrakte von K, L und M enthalten (Kk, Lk, Mk). Wie können dann K und L physisch zu KL werden, damit das Modell sich in den Artefakten widerspiegelt?
Abbildung 12 verrät den Trick: Die Assemblies mit den Implementierungen und der Kontrakt