Donnerstag, 5. Juni 2014

Referenz: Architektur eines Cloud-basierten Cross-Plattform-Backend-Systems für mobile Anwendungen

Liebe Leser,

heute wurde ein Blogpost von mir auf dem adesso Unternehmensblog mit dem Titel "Architektur eines Cloud-basierten Cross-Plattform-Backend-Systems für mobile Anwendungen" veröffentlicht. Darin beschreibe ich eine mögliche Architektur für die Anbindung einer mobilen Unternehmens-App an ein entsprechend skalierbares und ausfallsicheres Backend samt Einbindung eines Unternehmens-Services.

Link zum Beitrag: http://blog.adesso.de/architektur-eines-cloud-basierten-cross-plattform-backend-systems-fuer-mobile-anwendungen/

Euer,
JL

Dienstag, 22. Oktober 2013

Fixing the JSF error "ViewRoot is null" occuring exactly after 60 minutes when using MyFaces CODI although session timeout in web.xml is higher

Dear Readers!

I will do this post in English since this problem bugged me for a long long time and I couldn't find the solution on the web by searching for "ViewRoot is null".

Given:

You have JSF 2 web application using MyFaces CODI and you have a session timeout longer than 60 minutes defined in your web.xml (Why? Because the customer wants it!).

<session-config>
    <session-timeout>120</session-timeout> 
</session-config>

The problem:

After more than 60 minutes of inactivity - when you klick somewhere on your page - you get an ugly error stating "ViewRoot is null".

The solution:

It turns out that MyFaces CODI is the source of the problem - it defines a HARDCODED session timeout of 60 minutes.

How did I find out?

I started to download the source code of each library used in my web application and searched for the string "60" - strange, isn't it? But I was successful.

So how to fix this?

We need two classes to circumvent the problem using adavanced features of CDI. The first class uses the CDI Alternative and Specialization feature. It defines a customized WindowContextConfiguration returning a customized session timeout.

package at.coopxarch.bluprint.presentation.controller.cdi;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Alternative;
import javax.enterprise.inject.Specializes;
import org.apache.myfaces.extensions.cdi.core.api.config.ConfigEntry;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.config.WindowContextConfig;
import at.coopxarch.bluprint.common.util.BluPrintConstants;

@SuppressWarnings("serial")
@ApplicationScoped
@Alternative
@Specializes

public class BluPrintWindowContextConfig extends WindowContextConfig {

    /**
     * Specifies the time for the timeout for a window. After a timeout is detected all beans 
     * which are only linked to the window will be destroyed.
     *
     * @return the time for the timeout for a window
     */
    @ConfigEntry
    public int getWindowContextTimeoutInMinutes()
    {
        return BluPrintConstants.SESSION_TIMEOUT_IN_MINUTES;
    }
}

The second class is a CDI producer to instantiate and inject our special WindowContextConfig.

package at.coopxarch.bluprint.presentation.controller.cdi;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;

public class BluPrintWindowContextProducer {

    @ApplicationScoped
    @Produces
    public BluPrintWindowContextConfig produceBluPrintWindowContextConfig() {

       return new BluPrintWindowContextConfig();
    }
}

The downside of the solution:

The downside of this solution is the fact that you have to define the session timeout in two places: in the web.xml and as a constant somewhere in the code. It is advisable to comment the web.xml "session-timout" section so in case of a change of the session timeout a coder can also change the second session timeout definition. But that - of course - is optional ;-)

Let's see if anybody replies back to me who has had the same problem...

Yours
JWR@coopXarch

Freitag, 30. März 2012

Die Lizenz zum Entwerfen: JWR@coopXarch ist nun "Certified Professional for Software Architecture - Foundation Level"

Liebe Leser!

Nachdem ich nun erfolgreich die Prüfung zum CPSA-F abgelegt habe (Certified Professional for Software Architecture - Foundation Level), will ich hier ein wenig darüber berichten.

Das Zertifizierungsprogramm zum "CPSA" ist eine Initiative der iSAQB, einer Organisation bestehend aus Experten zum Thema "Software Architektur". Laut Homepage ist die iSAQB ein "unabhängiges, neutrales Gremium, das die fachliche Qualität des Certified-Professional for Software Architecture Schemas und das zugehörige Prüfungswesen überwacht."

Ich habe in Wien den 3-tägigen Kurs "Certified Mastering Software Architectures - Seminar mit Zertifikat CPSA nach ISAQB" besucht und im Anschluss die Zertifizierungsprüfung abgelegt. Der Vortragende war Dipl. Math. Manfred Ferken, den ich als sympathischen und kompetenten Seminarleiter wärmstens weiterempfehlen kann. Das Seminar besteht aus einem Theorievortrag auf Basis von Folien und praktischen Übungen. Das Seminar orientiert sich am "arc42 Framework" von Peter Hruschka (Atlantic Systems Guild) und Gernot Starke (unabhängiger Berater) - beide keine Unbekannten und sehr umtriebig auf dem Gebiet der Software Architektur. Ich hatte als praktischer Anwender des arc42 Templates für Architektur-Dokumentation einen kleinen Vorsprung vor den anderen Teilnehmern - trotzdem hat mir das Seminar neue Sichtweisen und viele Fallbeispiele aus der Praxis vermittelt. Vor allem die Diskussionen mit dem Seminarleiter und den Teilnehmern waren sehr lebhaft und lehrreich - ab und zu muss man einfach über den Tellerrand schauen.

Die Prüfung ist ein Multiple Choice Test und doch ziemlich anspruchsvoll - interessanterweise unterschreibt man ein NDA und daher kann ich über den Inhalt natürlich nichts erzählen. Für den engagierten Software Architekten ist die erfolgreiche Ablegung der Prüfung aber sicher kein Problem.

Übrigens: Durch die Ablegung des CPSA-F bin ich als Ziviltechniker für Informatik nun Österreichs einziger staatlich befugter, beeideter und unabhängig zertifizierter Software Architekt (CPSA-F) und Senior Projektmanager (IPMA-Level B). Ich hoffe, damit meine Kompetenz auf meinen Kernarbeitsgebieten dementsprechend fundiert untermauern zu können.

Euer
JWR@coopXarch.

Donnerstag, 22. Dezember 2011

coopXarch wünscht Frohe Weihnachten!

Liebe Leser!

Ein spannendes und arbeitsreiches Jahr liegt hinter uns - angesichts des unmittelbar bevorstehenden Weihnachtsfestes ist es an der Zeit, 2011 Revue passieren zu lassen.

Das Thema im Jahr 2011 aus Sicht der coopXarch war "Cloud Computing". Und wir nahmen und nehmen uns dieses Themas mit viel Engagement und Enthusiasmus an. Nach einer Zeit der Informationsrecherche, Veranstaltungsbesuche und Diskussionen war es im Frühjahr an der Zeit, selbst aktiv zu werden.

Mit joinMe! haben wir im Oktober eine Referenzarchitektur und -implementierung für ein elastisch skalierbares location-based social service vorgelegt, das auf einer Platform-as-a-Service (PaaS) läuft. Dabei ist es irrelevant, ob ein public PaaS Angebot (wie z.B. VMware CloudFoundry) gewählt wird, oder eine private PaaS (z.B. VMware vFabric) aufgebaut wird, um das Service zu betreiben. Die Softwarekomponenten sind so beschaffen, dass sie ohne eine einzige Code-Änderung in einem lokalen Tomcat, dem vFabric tc Server oder in der CloudFoundry Laufzeitumgebung betrieben werden können! Das zeigt die unglaubliche Deployment-Flexibilität und Umgebungs-Agnostik heutiger Enterprise Frameworks (in diesem Falle Spring).

joinMe! zeigt auch, wie "application-level modularization" erreicht werden kann, die eine Grundlage für elastische Skalierbarkeit ist, aber auch andere Vorteile wie Fehlerlokalisation und "always-on" Deployments bietet. Insofern bietet Cloud Computing für die Software Engineering Praxis die Möglichkeit, auch im Business Software Bereich ein Umdenken weg von monolithischem Applikationsdesign hin zu "loosely coupled" Systemen herbei zu führen.

Schade finden wir es, dass es keinen österreichischen Platform-as-a-Service Anbieter gibt - egal ob für public hosting oder als Anbieter für private PaaS Clouds für Unternehmen. Das würde unseres Erachtens Software-as-a-Service Anbietern die Möglichkeit geben, zu österreichischen Qualitätskriterien und unter österreichischer Gesetzgebung SaaS Angebote zu lancieren. Ob wir uns darum kümmern sollten?

Schlussendlich haben wir - durch die Entwicklung von Apps für Smart Devices für drei unterschiedliche Betriebssysteme (Android, iOS und Windows Phone 7) - einiges an Know How in diesem Bereich hinzu gewonnen. Zentral ist nach wie vor die Frage: "Soll ich nativ für jedes OS entwickeln oder auf 'one-serves-all' Frameworks wie PhoneGap setzen?". Hier haben wir unsere Antwort gefunden.

Unbedingt muss auch der große Erfolg erwähnt werden, den unser coopXarch Architekt Jürgen und unser erfahrener WP7 Entwickler Robert mit der "Spritpreise AT" App für Windows Phone 7 eingefahren haben. Diese App war lange unter den Top 3 Apps im österreichischen Windows Phone Marketplace. Das macht uns stolz und wir freuen uns mit Euch!

Die coopXarch Architekten wünschen ein frohes und besinnliches Weihnachtsfest: Zeit, um inne zu halten und zu reflektieren, Ruhe, um Kraft und Zuversicht zu schöpfen und viel Motivation und Mut, um im neuen Jahr neue Herausforderungen anzugehen und innovative Ideen Realität werden zu lassen.

Euer
JWR@coopXarch.

Montag, 17. Oktober 2011

joinMe! - ein Cloud2Mobile Showcase von coopXarch und Xion IT Systems AG

Liebe Leser!


Unser Cloud- und Mobile-Computing Showcase "joinMe!" ist fertig! joinMe! präsentiert sich für den Benutzer als App für Android, iOS oder Windows Phone 7 Smartphones und Tablets, die es ermöglicht, Personen in der Nähe mit dem gleichen Interesse zu finden. Das Datenhandling, der Geo-Location und Interessens-Match und die Notifikationen an die mobilen Geräte werden dabei von einem losen Applikationsverbund in der Cloud - in unserem Fall CloudFoundry von SpringSource/VMWare - durchgeführt. Durch die lose Kopplung ist eine elastische Skalierbarkeit der Services - so wie man es von den großen Anbietern Facebook, Twitter und Co. gewohnt ist - ermöglicht.

Die Homepage zu joinMe! findet sich hier. Wir haben auch einen Produktflyer mit QR Codes zu den einzelnen Apps erstellt.

In Kürze werden wir in einer Reihe von Blogbeiträgen die technischen Grundlagen, Architekturentscheidungen und den Umsetzungsweg vorstellen und auf Fallstricke und Lessons Learned eingehen.

Cloud- und Mobile-Computing ermöglichen innovative und elastisch skalierbare Services. Unternehmen werden in Zukunft durch die Nutzung von Plattform-as-a-Service Clouds weitere Homogenisierung und Konsolidierung zusammen mit den entsprechenden Einsparungspotentialen erzielen können.

Unser Ziel ist es, durch die frühest mögliche technologische und strategische Erschließung der Grundlagentechnologien als Berater und Umsetzer auf diesem spannenden und innovativen Gebiet erfolgreich tätig zu sein.

Euer
JWR@coopXarch.

Dienstag, 11. Oktober 2011

"Sehnsucht nach Scrum"

Liebe Leser!

Ich halte am Donnerstag, 03. November 2011, 09:00 einen Vortrag zum Thema "Agile Softwareentwicklung" mit dem Titel "Sehnsucht nach Scrum" im Rahmen der Vortragsveranstaltung des IT-Clusters Wien "Agile Software-Entwicklung trifft auf agiles Qualitätsmanagement".

Hier der Link mit näheren Information und der Anmeldung!

Wenn auch Ihr von einer Sehnsucht nach agilen Vorgehensmodellen beschlichen seid (oder die Existenz derjenigen bezweifelt), würde ich mich freuen, Euch zu sehen!

Euer
JWR@coopXarch.

Mittwoch, 17. August 2011

"Elastische Skalierbarkeit in der Cloud" - spritpreisrechner.at zeigt, wie man es nicht macht...

Liebe Leser!

Zugegeben - es ist immer ungleich viel schwerer, Leistung zu erbringen, als Fehlleistung zu kritisieren (als Beispiel sei die österreichische Fußball-Nationalmannschaft angeführt) - aber "die Initiative des BMWFJ für mehr Preistransparenz und Wettbewerb" hat nicht gerade einen Blitzstart hingelegt. Siehe hierfür z.B. http://diepresse.com/home/meinung/marginalien/685968/BenzinpreisRechner-stuerzt-ab_Die-Roboter-sind-schuld, wo es - sehr sarkastisch - heißt:
"Die lange erwartete 'Spritpreis-Datenbank' hätte am Dienstag online gehen sollen. Doch die Homepage kollabierte. Mit so einem Ansturm konnte ja wirklich niemand rechnen."
Seit nunmehr ca. 2 Jahren ist "Cloud Computing" in aller Munde - und die Vorteile, die das neue Paradigma ins Rennen führt, und hier interessiert uns insbesonder das Modell "Platform as a Service (PaaS)" gemeinsam mit elastischer Skalierbarkeit, auch "Auto-Scaling" genannt. Der Anwendungsfall "Spritpreis-Datenbank" - ein paar Clients melden Daten ein (Anforderung 1), viele viele (ev. auch extrem viele - Entschuldigung, wieder sarkastisch) Clients holen Daten ab (Anforderung 2), und die Daten müssen nicht transaktional-aktuell sein (Anforderung 3: soll heißen - es ist ok, wenn ein Client noch kurz den alten Preis bekommt, auch wenn der neue Preis gerade eingemeldet wurde), man verzeihe den Terminus - schreit gerade nach dem Lösungsmuster "PaaS-Cloud mit Auto-Scaling".

Wie hätte coopXarch nun die Architektur ausgelegt:

  1. Web Role spritpreis-meldung@cloudanbieter.com
    1. Eine "Web Role" (wir folgen hier der Microsoft Windows Azure Nomenklatur) ist das Eingangstor für Web Requests und läuft normalerweise auf einer Cloud Instanz (i.e. früher "ein Server"). Diese Web Role ist für die Melder, egal ob es Menschen über ein Web Formular sind, oder ein Automatismus, der die Preise updated (wieder über ein HTTP-basiertes Protokoll, z.B. REST).
    2. Da es eine bekannte Anzahl an Meldern gibt, ist es leicht die Anzahl der Knoten zu dimensionieren - z.B. ein Knoten pro 150 potentielle Benutzer (Warum 150? weil z.B. der Apache Web Server Konfigurations-Wert "maxClients" auf 150 eingestellt ist oder der Tomcat maximal 150 worker threads bietet).
  2. Web Role spritpreis-auskunft@cloudanbieter.com
    1. Das ist nun die Web Role für die Auskunftsapplikation - wieder können hier Menschen vor einen Web Browser oder einer "mobilen App" sitzen bzw. Robots / Crawler, welche die Web Role für Preisauskünfte ansteuern. Hier ist die elastische Skalierbarkeit unumgänglich, da zum Design-Zeitpunkt nicht gesagt werden kann, wie viele Clients auf das Auskunftsservice zugreifen werden. Noch dazu ist mit Spitzen zu rechnen - eben (sic!) bei der Inbetriebnahme. Die Skalierung in Form des Hochstarts neuer Serverinstanzen, um die Last der Anfragen bewältigen zu können, übernimmt nun der Cloud Controller des PaaS Anbieters. Das Starten dieser zusätzlichen Instanzen muss dabei nicht länger als 10-30 Sekunden dauern - daher die Bezeichnung "elastisch", i.e. "quasi in Echtzeit je nach aktuellem Bedarf".
  3. NoSQL Datenbank
    1. Nachdem Konsistenz hier eine untergeordnete Rolle spielt (siehe Anforderung 3), wird eine NoSQL Datenbank verwendet, die hoch skalierbar ist und z.B. dokumentenorientiert arbeitet (Dokument "Tankstelle", Embedded Dokument "Produkt", Embedded Dokument "Preis") - ich würde hier die MongoDB als geeignet vorschlagen, da sie auch (Index-basierte) Geo-Abfragen bietet (z.B. für den Anwendungsfall "Zeige mir den billigsten Diesel im Umkreis von 5km"). Die VMWare CloudFoundry PaaS Cloud bietet etwa die MongoDB als persistenten Storage an.
  4. Worker Roles "Datenbank Cleanup", "Report Generator" etc.
    1. Eine "Worker Role" arbeitet "im Hintergrund" auf einer Datenbasis, um gewisse Aufgaben auszuführen. In diesem Falle könnten alle Spritpreise, die älter als die gehaltene Historie von 14 Tagen (Anforderung 4) sind, aus der Datenbank gelöscht werden. Oder es könnten Preisverlaufskurven generiert und als Bilder abgelegt werden, um Abfragen möglichst effizient mit den Verlaufskurven ausliefern zu können (Anforderung 5).
Zugegeben - viele PaaS Anbieter sind noch im Beta-Stadium bzw. bieten eventuell nur unzureichende Service Levels - ich als staatlich befugter und beeideter Ziviltechniker für Informatik finde es jedoch besonders schade, dass der Staat (in Gestalt des BMWFJ) diese unsere Kompetenz nicht zu Rate gezogen hat, um ein innovatives Service mittels innovativer Technik umzusetzen (und dieser somit ein Stückchen mehr zum Durchbruch zu verhelfen) und verbleibe, mit besten Grüßen,

Euer,
JWR@coopXarch.

Donnerstag, 30. Juni 2011

Architektur vs. Agile Software-Entwicklung

Liebe Leser,

angespornt durch einige Aussagen von Kollegen und Branchengrößen möchte ich meine Gedanken zur vermeintlichen Kontroverse von Software-Architektur und agiler Software-Entwicklung zum Besten geben.

Architektur
Mein generelles Verständnis zur Definition von Software Architektur habe ich bereits in einem früheren Blogpost beschrieben.

Agile Software-Entwicklung
Unter agiler Software-Entwicklung verstehe ich kein konkretes Vorgehensmodell. Ich bin der Überzeugung, dass man Agilität auf unterschiedlichste Art und Weise in der Praxis ausleben kann. Sei dies in Form von XP, Scrum, Kanban, einem weniger verbreiteten Modell oder einfach nur der individuellen Mixtur aus mehreren davon. Persönlich kann ich jedem der namentlich genannten Vorgehensmodelle etwas abgewinnen. Wie schon oft zitiert ist das Agile Manifesto die Wurzel all dieser Ausprägungen.

Die beiden Extreme
Zwei extreme Einstellungen sind in Bezug auf diese Kontroverse durchaus verbreitet:

1) Wir arbeiten agil und können daher keine Architektur vorhab festlegen.
2) Wir legen unsere Architektur vorab fest und können daher nicht agil arbeiten.

Diese Extreme sind meiner Ansicht nach schlicht weg falsch! Natürlich sind beide Themen unter einen Hut zu bringen. Eine einfach klingende Regel, die allerdings nicht so leicht in die Praxis umzusetzen ist, sollte lauten: So wenig Architektur wie möglich und so viel wie nötig.

Wie kommt es zu diesen Extremen?
Warum glauben dennoch viele Agilisten, dass Architektur nicht zur Agilen Software-Entwicklung passt? Ich denke, dies ist fälschlichen Interpretationen geschuldet. Kent Beck hat in seinem Buch "Extreme Programming Explained: Embrace Change" den Begriff "YAGNI" geprägt. YAGNI steht für "You aren't / ain't gonna need it" und bedeutet, dass man nicht alle Möglichkeiten und Varianten vorab berücksichten, sondern lediglich die vorhanden Anforderungen umsetzen soll. Dies vor dem Hintergrund, da nicht bekannt ist wie sich ein System - basierend auf ändernden Anforderungen - in Zukunft entwickeln wird. So wie auch viele das agile Manifest fälschlich interpretieren (aber das ist eine andere Geschichte), so wird auch dieser Begriff meiner Meinung nach oft zu hart ausgelegt. Das YAGNI-Prinzip hat in der Feature-Entwicklung seine Berechtigung, darf aber nicht auf den gesamten Software-Entwicklungsprozess umgelegt werden.

Meiner Ansicht nach sind die grundlegende System-Architektur und die notwendigen Design-Entscheidungen vorab festzulegen und können nicht laufend anhand von Anforderungen angepasst werden. Die Betonung liegt hier auf dem Wort "grundlegend". Ein gewisses Maß an Flexibilität ist durchaus wünschenswert und gerade durch eine vorab durchdachte Architektur gewährleistet. Ein einfaches Beispiel soll die Notwendigkeit von Architektur und Design-Entscheidungen veranschaulichen:

Bei der Umsetzung einer konkreten Anforderung wird festgestellt, dass gewisse Daten persistiert werden müssen. Ohne zuvor festgelegte Architektur bzw. grundlegende Design-Entscheidungen kann es nun sehr schnell passieren, dass ein momentan passend wirkender Datenspeicher - nehmen wir eine relationale Datenbank an - eingeführt wird. Die Persistenz wird, weil es gerade zur Anforderung passt, als Active Record Pattern umgesetzt. Im Zuge der späteren Entwicklung stellt das Team fest, dass die aktuellen Persistenzobjekte besser als Domain Entities konzipiert gewesen wären und für die Datenpersistenz ein Repository Pattern Ansatz auch brauchbarer wäre. Ich wage zu behaupten, dass man in diesem Fall vor einem nicht unwesentlichen und aufwändigen Refactoring stünde, welches die Grundfesten des gesamten Systems erschüttern würde.

Warum glauben Architektur Hardliner, dass agile Vorgehen nicht anwendbar sind? Einerseits vermute ich, dass dies einem Umkehrschluss aus der agilen Extremeinstellung zuzuschreiben ist (Architektur passt nicht zu einem agilen Vorgehen - s.o.). Andererseits kann am Beispiel von Scrum auch wieder eine Misinterpretation oder zu strikte Auslegung des Vorgehensmodells zu dieser Ansicht führen. Scrum gibt einen Rahmen vor, welcher natürlich absichtlich sehr offen gehalten ist. Es gibt defacto keine Design-Phase. Warum sollte man dennoch nicht in der ersten Iteration auch die Architektur gestalten? Auch wenn es in der Scrum-Community eine Diskussion zu "Sprint Zero" gibt, ist es in meinen Augen alternativ durchaus legitim eine Initialisierung vorab der Featureimplementierung in einer eigenen Iteration auf Basis des bekannten Product Backlogs durchzuführen. Man sollte ausserdem nicht vergessen, dass Scrum-Projekte mit Planning Meetings beginnen in denen nicht ausschließlich die Anforderungen besprochen werden, sondern auch die gesamte Vision im Mittelpunkt steht. Auf Basis der Anforderungen und der Produktvision kann man auch eine Architektur(vision) ableiten.

Mein Fazit
Die Ära der voll durchgeplanten und bis ins letzte Detail designten Software-Systeme ist vorbei. BDUF (Bug Design Up Front) sollte vermieden werden. Software-Architektur darf allerdings auch in einer zunehmend agilen Software-Entwicklungswelt dennoch nicht zu locker gesehen oder gar gänzlich vernachlässigt werden, da einem sonst die vermeintlich günstig erkaufte Flexibilität schnell sehr teuer kommen kann. Der Weg liegt wie so oft in der Mitte und diesen zu finden ist mitunter Aufgabe von agil denkenden Software-Architekten. Ob die Rolle des Architekten nun im Team gemeinschaftlich wahrgenommen wird, ein Teammitglied dazu auserkoren wird oder ein konsultierender Architekt dem Team zu Beginn zur Verfügung gestellt wird soll an dieser Stelle nicht weiter behandelt werden. Software-Architektur ist auf jeden Fall weiterhin ein wichtiger Bestandteil in der Software-Entwicklung, auch wenn sich die Umwelt durch agile Vorgehensmodelle geändert hat.

Euer,
JL@coopXarch

Montag, 6. Juni 2011

These zur mangelnden Investitionsbereitschaft in Software Qualität betrieblicher Informationssysteme

Liebe Leser!

Sperriger Titel, aber folgender Gedanke beschlich mich beim morgendlichen Zähneputzen:

These:

Investitionsbereitschaft in Software Qualität ist reziprok proportional zum zeitlichen Abstand des Eintritts eines - kausal auf ein Qualitätsproblem folgendes - negativen Ereignisses, dessen Eintrittswahrscheinlichkeit und dessen Auswirkung.

Argumentation anhand von Beispielen (die angeführten Zahlen sind meine persönlichen Annahmen):

Softwareversagen im Bereich Avionik:

Zeitlicher Abstand -> wenige Minuten
Negatives Ereignis -> Absturz
Eintrittswahrscheinlichkeit -> nahezu 100%
Auswirkung -> Multiple Todesfälle nahezu 100%

Softwareversagen im Bereich Automotive:

Zeitlicher Abstand -> wenige Sekunden
Negatives Ereignis -> Unfall
Eintrittswahrscheinlichkeit -> ca. 50%
Auswirkung -> Tod zu 40%, Verletzung zu 60%

Softwareversagen im Bereich betrieblicher Informationssysteme:

Zeitlicher Abstand -> Stunden, Tage, Monate, Jahre
Negatives Ereignis -> Fehler, verletzte Datenintegrität und Konsistenz, Datenverlust, Finanzieller Verlust, überproportional steigende Wartungskosten
Eintrittswahrscheinlichkeit -> ca. 99%
Auswirkung -> Imageschaden, finanzieller Schaden, Kundenunzufriedenheit, Haftungen (bis hin zur Haftstrafe)

Interpretation:

Trotz hoher Eintrittswahrscheinlichkeit eines negativen Ereignisses ist der zeitliche Abstand in vielen Fällen derart groß, dass eine Investitionsbereitschaft stark gebremst wird, noch dazu, wo die Auswirkungen nicht als lebensbedrohlich gewertet werden und Folgen wie mögliche Haftungen oft nicht transparent sind.

Ergo: 

Um die Investitionsbereitschaft zu steigern, müssen die möglichen Auswirkungen transparenter dargestellt werden, um Entscheidungsträger nach dem Kosten-Nutzen Prinzip geeignet aufzuklären. Eine Darstellung des Ablaufs im Zeitraffer ist anzuraten, um dem Gefühl der „Sicherheit aufgrund eines ausreichenden zeitlichen Puffers“ entgegen zu wirken. Geeignete Simulationsmodelle sind auszuarbeiten.

Einen sonnigen Juni wünscht
Euer 
JWR@coopXarch.

Montag, 9. Mai 2011

Der Fluxkompensator und seine Bedeutung für den Software Test

Liebe Leser!

Jeder, der den Film "Zurück in die Zukunft" mit einem großartigen Michael J. Fox in der Hauptrolle gesehen hat, kennt auch die Basiserfindung für die Durchführung jeglicher Zeitreise, den
Fluxkompensator.

Aus [wikipedia], 08.05.2011:


"Der Fluxkompensator ist das Kernstück der 
Zeitmaschine, der nach Browns Aussage „Reisen durch die Zeit erst möglich macht“. Er besteht aus einem grauen, rechteckigen Kasten mit drei länglichen, blinkenden Glasröhrchen, die hinter einer Glasscheibe eben im 120°-Winkel zueinander angeordnet sind. Der Fluxkompensator ist an der Rückwand zwischen den beiden Sitzen im Fahrzeuginneren angebracht. Brown hat ihn am 5. November 1955 erfunden, als er beim Aufhängen einer Uhr in seinem Badezimmer von der Schüssel seiner Toilette abrutschte und unsanft mit dem Kopf aufschlug."



Nun - obwohl der ein oder andere von uns sicher auch schon mal unsanft mit dem Kopf auf diverse Nassraumeinrichtungsbestandteile geprallt ist (nein?), hat das - wie ich vermute - keine revolutionären Ideen zum Thema Zeitreisen ausgelöst (bei mir jedenfalls nicht).

Das Problem

Als ich jedoch ein "Mehrrunden-Mehrgüter" Auktionssystem als Scrummaster und Backend Architekt verantworten durfte, kam ich in die Verlegenheit, folgendes Problem zu lösen:
  • Eine Auktion startet mit der Katalogphase, in dieser werden zu versteigernde Güter im Katalog von den Eigentümern registriert - diese Phase dauert 2 Tage.
  • Nach der Katalogphase beginnt die Auktion, wobei diese in maximal 20 Runden zu je 2 Minuten 40 Sekunden Bietzeit und 20 Sekunden Berechnungszeit gegliedert ist.
  • Gibt es in einer Runde kein neues Gebot auf zumindest ein Gut in der Versteigerung, ist die Auktion beendet und die Höchstbieter erwerben jeweils die Güter.

Die Entscheidung


Ich traf nun - entgegen einigen Widerstands aus dem Team (was ich nicht gerne mache, aber manchmal muss man sich eben durchsetzen) - folgende weitreichende Designentscheidung:

Die einzelnen Auktionsstati (Katalogphase, Rundenphase, Berechnungsphase) werden aufgrund der aktuellen Uhrzeit in Bezug auf den Start der Katalogphase bestimmt (z.B. Start Katalogphase + 2 Tage = Start Auktionsphase). Der Vorteil hierbei ist, dass der Status nicht persistent gespeichert werden muss. Somit kann der aktuelle Auktionsstatus - aufgrund fehlerhafter bzw. vergessener Statusübergänge (z.B. Systemabsturz während eines Übergangs) - nie falsch sein und man spart sich einen Scheduler, der zum richtigen Zeitpunkt den Status "eins weiter" setzt (z.B. auf die nächste Runde). Dieser Scheduler könnte auch nur schwer auf die Millisekunde genau arbeiten und damit könnte ein Bieter auch kurz nach Beendigung der Runde bieten - für einen Architektur-Ästheten eine unerträgliche Einschränkung.

Soweit - so gut. Wie testet man so eine Applikation aber in der Praxis? Wenn ich Güter registriere, will ich nicht zwei Tage warten, bis ich darauf bieten kann. Selbst wenn ich die Zeitdauer der Katalogphase per Konfiguration für den manuellen Test auf 20 Sekunden setze, muss ich mich beeilen, um alle Güter rechtzeitig zu registrieren, ganz zu schweigen davon, dass z.B. ein Telefonat mit dem Chef einen Neustart des Tests bedingt (außer man kann nebenbei Güter erfassen, was sicher auch auf die Stimmung des Chefs ankommt). Beim Unit Test stellt sich dasselbe Problem - wie kann ich deterministisch testen? Wenn z.B. der Build Server während eines Tests mit 100% CPU Load gesegnet ist, könnte es sein, dass in Runde x gar kein Gebot einlangt, und somit die Auktion beendet ist. Non-Determinismus ist aber hier ein absolutes No-Go.

Aufgrund dieser Problematik dachte das Team wohl, dass ich die Design-Entscheidung zurücknehmen würde. Ich aber habe meine grauen Zellen angestrengt und kam zu folgender Idee: Wir brauchen einen Fluxkompensator! (Team: staunende Augen, Kopfschütteln). Sowohl im manuellen als auch automatischen Test will ich - gleich nach der Durchführung einer Aktion wie z.B. einer Gebotsabgabe - in die Zukunft reisen können, um zur richtigen Zeit meine nächste Aktion zu setzen und ohne unnütz Zeit mit Warten verbringen zu müssen. Die explizite Kontrolle der Zeit bringt den gewünschten Determinismus! Soviel zur Idee - fehlt nur noch die Umsetzung.

Der Lösungsansatz

Wie sieht der Lösungsansatz nun konkret aus? Software-technisch beginnt alles (wie meistens) mit einem Interface:

package at.coopXarch.flux;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * This service simply provides timestamps.
 * @author jwr
 */
public interface ITimestampProvider {
    /**
     * This formatter is required to achieve the same representation as java.lang.String of java.util.Date and
     * java.sql.Timestamp
     */
    final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    /**
     * Gets a notion of "now".
     * @return Timestamp that represents "now".
     */
    Date getTimestamp();
    /**
     * Notion of a time increment. In real time we would <code>sleep()</code>, but note that in a test bed we can control the sampling of time.
     * @return Timestamp after increasing "current" time with sample value.
     */
    Date sample();
    /**
     * Set the time increment we desire when calling <code>sample()</code>.
     * @param sampleIncrement Increment of time we desire.
     */
    void setSampleIncrement(long sampleIncrement);
    /**
     * Set a specific time as a notion of "now". We cannot do this with real time but in a test bed we can control it.
     * @param sampleValue Value of time representing "now".
     */
    void setSampleValue(long sampleValue);
    /**
     * Reset "now" timestamp to a specific absolute "begin" value. We cannot do this with real time but in a test bed we can control it.
     */
    void reset();
}

Die Implementierung - Variante 1 "Echtzeit"

Die folgende Implementierung liefert Echtzeit - die Zeit wird also, wie üblich, mittels new Date() bestimmt. In der Applikation muss man nun dafür sorgen, dass überall statt new Date() nun getTimestamp() aufgerufen wird. In der Produktion ist also folgende Implementierung des Interfaces zu verwenden:

package at.coopXarch.flux;

import java.util.Date;

/**
 * This service simply provides timestamps.
 * @author jwr
 */
public class TimestampProviderImpl implements ITimestampProvider {
    @Override
    public Date getTimestamp() {
        return new Date();
    }
    @Override
    public Date sample() {
        throw new UnsupportedOperationException("You cannot do this in real time!");
    }
    @Override
    public void setSampleIncrement(long sampleIncrement) {
        throw new UnsupportedOperationException("You cannot do this in real time!");
    }
    @Override
    public void setSampleValue(long sampleValue) {
        throw new UnsupportedOperationException("You cannot do this in real time!");
    }
    @Override
    public void reset() {
        throw new UnsupportedOperationException("You cannot do this in real time!");
    }
}

Die Implementierung - Variante 2 "Fluxzeit"

Die folgende Implementierung des Interfaces steuert jetzt den Fluxkompensator bei - sie wird also im manuellen und automatisierten Test verwendet:

package at.coopXarch.flux;

import java.util.Calendar;
import java.util.Date;

/**
 * This class acts as a FluxKompensator. Do not tell Albert Einstein!
 * @author jwr
 */
public class FluxKompensator implements ITimestampProvider {
    private final Calendar cal;
    private Date initialTimestamp;
    private static final long DEFAULT_SAMPLE_INCREMENT = 500;
    private long sampleIncrement = DEFAULT_SAMPLE_INCREMENT;
    private Date dateHolder = null;

    public FluxKompensator() {
     synchronized (this.getClass()) {
      cal = Calendar.getInstance();
         // D-Day: e.g. 31.03.11 10:10
         cal.clear();
         cal.set(2011, 2, 31, 10, 10, 0);
         initialTimestamp = cal.getTime();
     }
    }
    @Override
    public synchronized Date getTimestamp() {
        if (dateHolder == null) {
            sample();
        }
        System.out.println("getSampledTimestamp()=" + dateFormat.format(dateHolder));
        return new Date(dateHolder.getTime());
    }
    @Override
    public synchronized  Date sample() {
        final Date previous = dateHolder;
        final Date now = (previous != null) ? new Date(previous.getTime() + sampleIncrement) : initialTimestamp;
        dateHolder = now;
        System.out.println("sample()=" + dateFormat.format(now));
        return new Date(now.getTime());
    }
    @Override
    public void setSampleIncrement(long sampleIncrement) {
        this.sampleIncrement = sampleIncrement;
        System.out.println("setSampleIncrement() to " + (sampleIncrement / 1000) + "s");
    }
    @Override
    public synchronized void setSampleValue(long sampleValue) {
        final Date now = new Date(sampleValue);
        System.out.println("setSampleValue()=" + dateFormat.format(now));
        dateHolder = now;
    }
    @Override
    public synchronized void reset() {
        cal.clear();
        cal.set(2011, 2, 31, 10, 10, 0);
        initialTimestamp = cal.getTime();
        sampleIncrement = DEFAULT_SAMPLE_INCREMENT;
        dateHolder = null;
    }
}

Voila! Nun kann man in der Testumgebung mittels setSampleValue() jeden beliebigen Zeitpunkt setzen - während des manuellen Tests sogar im User Interface (siehe unten)! Und beliebig lange auf einem konkreten Zeitpunkt verweilen (ist schön im Log zu sehen, alle Aktionen haben auf die Millisekunde denselben Timestamp). Auch im Unit Test haben wir die Zeit vollkommen unter Kontrolle und man kann sie beliebig vorwärts und auch rückwärts setzen (Achtung: rückwärts fließende Zeit kommt im realen Zeitfluss nur sehr SELTEN vor und kann zu Risiken und Nebenwirkungen führen!).

Im GUI sieht das folgendermaßen aus:


Besonders die Option "Zeit vergehen lassen" finde ich besonders nett - dahinter steht natürlich ein Aufruf von sample().

Fazit

Mit diesem Ansatz haben wir alle Tests im gegenständlichen Projekt ohne Probleme durchgeführt und das Produkt erfolgreich ausgeliefert. Ich finde den Lösungsansatz kreativ und leistungsfähig, bin aber natürlich auf Eure Meinung gespannt.

Und zum Schluss der Dialog zwischen Marty McFly und Dr. Emmett L. „dem Doc“ Brown nach meiner absoluten Lieblingsszene zu Beginn des Films:
Marty: "Hören sie, Doc. Die Geräte waren die ganze Woche eingeschaltet."
Doc:
"Meine Geräte? Da fällt mir ein Marty. Schalte lieber nicht den Verstärker ein. Es könnte die Möglichkeit bestehen, daß er zuviel Spannung kriegt."
Insider wissen um die Vorgeschichte (Gitarre, Box, Explosion) und schicken mir bitte einen YouTube Link dazu. Ich habe nur den, wo Marty "Johnny B. Goode" spielt (auch nicht zu verachten: http://www.youtube.com/watch?v=d4Cr7kxjSBs)

Mit diesen Ausführungen verbleibe ich
Euer
JWR@coopXarch.

Montag, 7. Februar 2011

Standard Software ist nicht gleich Standardisierung!

Liebe Leser!

Im Jänner besuchte ich ein Cloud Computing Event eines namhaften Beraters - eine durchaus interessante Mischung von Vorträgen zu diesem interessanten Hype-Thema. Ein Punkt hat mich dann aber doch sehr gestört. Ein Berater hat die Top 5 Punkte präsentiert, die in Zusammenhang mit einer Migration in die Cloud wichtig sind.

Der erste Punkt der Aufzählung war "Standardisierung". Und als Maßnahme, um diese zu erreichen, fand sich auf der Folie der Vorschlag, Standard Software einzusetzen, und der Berater riet ergo dazu, keine Eigenentwicklungen mehr durchzuführen.

"Schön!" denkt man sich nun reflexartig als IT Verantwortlicher - viele dieser Projekte sind ohnehin nicht reibungslos gelaufen, sparen wir uns das in Zukunft und geben Standardprodukten "aus der Schachtel" den Vorzug.

"Halt!" sage ich als Hersteller von Individualsoftware. Warum?

  1. Was bitte, hat Standard Software mit Standardisierung zu tun, außer vorerst einmal das gemeinsam benutzte Wort "Standard". Gerade große, monolithische Standard-Software-Produkte können es sich leisten, Standards eben nicht oder nicht sofort umzusetzen, und wenn, dann mit herstellerspezifischen, proprietären Ausnahmen, die der verbesserten Effizienz dienen sollen. Als Entwickler einer individuellen Lösung kann ich es mir oft gar nicht leisten, nicht konform zu den letzten Standards zu sein.
  2. Die Integration von Standardprodukten treibt vielen IT Verantwortlichen die Schweißperlen auf die Stirn - wo es bei vielen Eigenentwicklungen eine Sache von Stunden bzw. Tagen ist, eine neue Schnittstelle umzusetzen und in Produktion zu bringen, kann es bei einem Standardprodukt lauten "Kommt mit Release x.y Mitte nächsten Jahres".
  3. Wie kann ich mich, als Unternehmen, mit innovativen Prozessen und Produkten vom Markt unterscheiden, wenn ich nur Standardprodukte einsetze? Natürlich erlauben es moderne Prozesssteuerungs-Tools, individuelle Prozesse umzusetzen, jedoch liegt die Unterscheidung zum Mitbewerb immer auch in innovativer fachlicher Logik. Diese Innovation bedingt aber zu einem gewissen Grad, Business Logik in Technologie zu gießen - und zwar als "Eigenentwicklung".
Diese Punkte führe ich im Kampf um das Alleinstellungsmerkmal "Eigenentwicklung" an (und habe noch mehr in der Hinterhand). 

Scheinbar entbrennt ein Kampf Standardisierung versus Flexibilität. Am vorjährigen Oracle Day hat ein Top Berater eines anderen großen Beratungsunternehmens den anwesenden Entscheidern in selber Manier geraten, nur mehr Srandardprodukte einzusetzen und diese nicht einmal mehr zu groß anzupassen. Warum? Damit man Versionsupgrades reibungsfrei durchführen kann. Viele Kunden zahlen nämlich jährlich hohe Supportkosten, können dann aber nicht auf die neueste Produktversion umsteigen, weil die vielen individuellen Anpassungen genau das verhindern.

Standard Software ist ohne Zweifel Bestandteil jeder funktionierenden und kosteneffizienten IT. Aber Standardisierung bedeutet meines Erachtens, die Voraussetzungen für Integration und Flexibilität zu schaffen, um die innovativsten und produktivsten Prozesse unterstützen zu können, die zum Wohl des Unternehmens umsetzbar sind. Und in diesem Kontinuum hat Eigenentwicklung aus meiner Sicht nach wie vor seinen Platz.

Ob der - von anderer Seite vorgeschlagene - Verzicht auf jegliche Eigenentwicklung uns den entscheidenden Schritt in Richtung Service Orientierung und Prozessketten Chaining, Cloud, IT als Commodity und IT Industrialisierung voranschreiten lässt, überlasse ich, geschätzte Leser, Eurer werten Einschätzung. 

Ich habe meinen Standpunkt klar gemacht.

Euer 
JWR@coopXarch.

Montag, 31. Januar 2011

Asynchrone eventbasierte Programme mit Rx

Liebe Leser,

am 12. Oktober 2010 hatte ich das Vergnügen mich beim Mittagessen mit Bart de Smet (Microsoft) über Rx für .NET [1] zu unterhalten. Zuvor konnte ich seiner amüsant inszenierten hoch professionellen Keynote beim DevCamp 2010 [2] beiwohnen. Rx steht für Reactive Extensions for .NET und kann mit einem Satz folgender Maßen beschrieben werden:

Rx ist eine Bibliothek zur Erstellung von asynchronen und event-basierten Programmen, welche "observable collections" verwenden.

Das mag auf den ersten Blick nicht sonderlich spannend klingen. Denkt man allerdings ein wenig weiter, dann offenbaren sich tolle Möglichkeiten um kostengünstigere, wartungsfreundlichere und für den Benutzer bedienungsfreundlichere Software zu erstellen.

Viele sind vermutlich schon mindestens einmal vor dem Szenario gestanden, dass auf Grund einer Eingabe von Daten oder einer sonstigen Benutzeraktion eine Liste von Ergebnissen angefordert wird, welche dann in Form eines Listen- oder Gridsteuerelementes angezeigt werden soll. In der Regel muss man als Entwickler die Entscheidung treffen, ob man das Laden der Daten synchron oder asynchron umsetzt. Der einfachere Weg ist sicher die synchrone Verarbeitung, welche sich in einem nicht reaktionsfähigen GUI auswirkt, dafür aber viel einfacher und übersichtlicher programmierbar ist. Für kleine Datenmengen und schnelle Zugriffsmöglichkeiten auf Daten ist dies sicher ein gültiger Ansatz. Jedoch stößt man in der Praxis leider oft auf andere Gegebenheiten, wo man evtl. ein Service konsumieren muss, welches die Daten liefert. Für viele Applikationen ist es ein No-go, wenn das GUI in einen blockierenden Zustand gerät. Bleibt also noch die asynchrone Variante. Wer sich schon einmal dafür entschieden hat, dem ist bewusst, dass hierfür zwar Methoden in .NET zur Verfügung stehen, jedoch einiges an Mehraufwand notwendig ist und der produzierte Sourcecode auch nicht sonderlich wartungsfreundlich wirkt. Ich wage auch zu behaupten, dass manche Konstellationen sehr schwer damit umsetzbar sind.

Hier kommt Rx ins Spiel. Rx bietet elegante und einfach anzuwendende Möglichkeiten um eine asynchrone Verarbeitung von event-gesteuerten Aktionen zu realisieren. Es ermöglicht weitergehend die Kombination von asynchronen Verarbeitungen ohne unnötigen Verbindungscode an verteilten Stellen im Sourcecode schreiben zu müssen (Stichwort Wartbarkeit!). Die asynchronen Verarbeitungen werden als Datenquellen betrachtet, wodurch das LINQ Programmiermodell zur Anwendung kommt. Man kann sich beispielsweise Mausbewegungen einfach als Datenbank von Punkten vorstellen. Rx bietet ein ein push-based Modell im Gegensatz zu dem pull-based Ansatz, der bis dato häufig vorherrscht.


Wie verwendet man nun Rx und was ist als Voraussetzung notwendig? Die beiden wichtigsten Interfaces wurden bereits mit der .NET 4 Base Class Library (BCL) mitgeliefert. Dabei handelt es sich um IObservable<T> und IObserver<T>. Damit ist lediglich die Basis gelegt. Für den effizienten Einsatz muss man eine der Rx Bibliotheken herunterladen und einbinden. Rx steht aktuell für .NET 4, .NET 3.5 SP1, Silverlight 3, Silverlight 4 und JavaScript zur Verfügung. Des Weiteren ist Rx integraler Bestandteil von Windows Phone 7. Alle Ausprägungen sind auf der Rx Downloadseite verfügbar.

Die folgenden Codefragmente sollen den Unterschied zwischen synchroner und asynchroner Verarbeitung von Collections verdeutlichen.

Gewohnte Verarbeitung von Collections:

IEnumerable<BlogItem> items = _service.GetBlogItems();
foreach (BlogItem item in items)
{
    // Verarbeitung der BlogItem Objekte...
}

// Erst wenn alle BlogItems geliefert wurden, kommt man an diese Stelle.

Mittels Rx und den ObservableCollections würde der Code wie folgt aussehen:

IObservable<BlogItem> items = _service.GetBlogItems();
items.Subscribe(item =>
{
    // Verarbeitung der BlogItem Objekte...
});

// Sofort hier. Sobald Daten ankommen -> Lambda Expression aufgerufen.

Rx baut auf der LINQ Infrastruktur auf und erlaubt uns daher einen sehr komfortablen Umgang mit den asynchron zu liefernden Daten. Zum Beispiel können Einschränkungen sehr einfach mittels „where“ eingebaut werden.

Die bereits erwähnte Überlegung mit den Mousekoordinaten soll für ein weiteres Beispiel noch einmal aufgegriffen werden. Der MouseMove Event wird einer Form zugefügt und gleichzeitig mittels "observable collection" abgefragt. Folglich wird die Mouse lediglich als Datenquelle von Punkten betrachtet:

var form = new Form();
var mouseMoves = from mme in Observable.FromEvent<MouseEventArgs>(form, "MouseMove")
                 let point = mme.EventArgs.Location
                 where point.X == point.Y
                 select point;

using (mouseMoves.Subscribe(pt =>
       {
          Console.WriteLine(“Mouse Cursor bei {0}”, pt);
       })
{
   Application.Run(form);
}

Im obigen Beispiel wird mittels LINQ Query die Eventsequenz zu einer Sequenz aus Punkten (Point Objekt) projiziert und gleichzeitig nach Gleichheit von X- und Y-Koordinate gefiltert.

Rx soll nicht als Ersatz für bestehende Möglichkeiten der eventgesteuerten (asynchronen) Programmierung dienen. Durch die Verwendung von observable Collections entstehen jedoch einfacher und übersichtlicher zu entwickelnde Anwendungsszenarien, die bisher nur mit Mühe zu bewerkstelligen waren. Um die vielfältigen Möglichkeiten von Rx kennenzulernen empfiehlt sich ein Blick auf die Rx Beispielsammlung [3].

Euer
JL@coopXarch

[1] Rx Webseite (DevLabs) http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx
[2] DevCamp http://www.devcamp.at
[3] 101 Rx Samples http://rxwiki.wikidot.com/101samples

Donnerstag, 16. Dezember 2010

Was ist eine Referenzarchitektur? Wie wird sie bewertet?

Liebe Leser!

Man hört oft von Referenzarchitekturen und deren Vorteile. Was ist nun eine Referenzarchitektur?

Laut wikipedia ist eine Referenzarchitektur ein Modellmuster – also ein idealtypisches Modell – für eine Klasse  zu modellierender Architekturen. Typischerweise wird eine Klasse von Softwarearchitekturen mit einem bestimmten Anwendungsbereich mittels einer Referenzarchitektur beschrieben. Neben fachlichen gibt es aber auch technische Referenzarchitekturen.

Produkte aus konkreten, aus einer Referenzarchitektur abgeleiteten Architekturen, können auch Teil einer „Produktfamilie“ sein. In diesem Fall kann die Referenzarchitektur die der Produktfamilie gemeinsamen Aspekte beschreiben.

Hauptvorteile bei der Verwendung von Referenzarchitekturen ist die Zeitersparnis durch die erzielte Wiederverwendung – hierbei reicht das Spektrum der Wiederverwendung von den architektonischen Blaupausen bis hin zu konkreten Software Komponenten, da diese ja alle der Referenzarchitektur inhärenten Anforderungen erfüllen. Ein System, welches einer Referenzarchitektur folgt, muss also nicht „von Null weg“ auf dem Reißbrett geplant werden, sondern fußt auf – im besten Fall – vielfach bewährten Konzepten, Entscheidungen und Lösungsmustern. Damit ist die Verwendung von Referenzarchitekturen auch angewandtes Wissensmanagement, da sich viele evolutorisch gewonnene Erfahrungen in einer Referenzarchitektur manifestieren.

Nachteile der Verwendung einer Referenzarchitektur sind der Aufwand der Erstellung und Pflege (technologische und konzeptuelle Neuerungen im Technologie- und Anwendungsbereich der Referenzarchitektur müssen ja nachgezogen werden), die Vererbung von Fehlern der Referenzarchitektur in konkrete, von dieser Referenz abgeleiteten, Architekturen und die Einschränkung des kreativen Freiraumes der Beteiligten, da viele Rahmenbedingungen und Entscheidungen bereits vorweg genommen sind [vgl. auch http://www.imn.htwk-leipzig.de/~weicker/pmwiki/pmwiki.php/Main/Referenzarchitektur]. Ein weiteres Problem ist das „Konsistent-Halten“ von konkreten abgeleiteten Architekturen und Referenzarchitektur – ohne Konsistenz entwickeln sich beide Architekturen unabhängig voneinander weiter und Fortschritte in der Referenzarchitektur müssen – möglicherweise manuell – in jede einzelne instanziierte Architektur eingearbeitet werden.

Für Produktfamilien ist es wichtig, die Gemeinsamkeiten der Produkte zu beschreiben und den Spielraum für erlaubte Abweichungen festzulegen. Dabei ist eine Referenzarchitektur umso wertvoller, je größer der gemeinsame Kern ist und je formeller die erlaubten Abweichungen – die Generik – beschrieben und validiert werden können.

Euer
JWR@coopXarch.

Sonntag, 28. November 2010

Architektur in der Cloud

Liebe Leser,

ich war vor kurzem auf einem abendlichen Microsoft Architect Forum Event in Wien. Die Themen lauteten „Windows Azure Update“ und „Der Architekt im Zeitalter von Cloud Computing“. Zu Beginn wurden einige neue – durchaus sehr interessant wirkende – Features von Windows Azure vorgestellt. Darüber hinaus fand eine sehr spannende Podiumsdiskussion von ehemaligen und aktuellen Microsoft Architekt-Evangelisten statt. Im Rahmen der Diskussion wurden einige sehr spannende Ansichten kundgetan, welche mich durchaus zum Nachdenken angeregt haben. Im Folgenden möchte ich einige Quintessenzen wiedergeben, welche ich aufgenommen bzw. für mich gebildet habe.

Kostenbetrachtung
Im Gegensatz zu Architekturen der vergangenen Jahre ist gerade in Verbindung mit Cloud Computing ein KPI (Key Performance Indicator) besonders wichtig geworden. Dabei handelt es sich um den sogenannten TCO (Total Cost of Ownership). Dieser Wert beschreibt im konkreten Kontext die Kosten, welche gesamtheitlich betrachtet in Verbindung mit einer vorliegenden Architektur entstehen. Bei herkömmlichen Lösungen lässt sich dieser sehr schwer fassen bzw. beziffern. Durch Cloud Computing und der damit einhergehenden pay-per-use Philosophie entsteht eine Kostentransparenz, welche die Kosten wieder in einen zentralen Blickwinkel rückt und uns Architekten dadurch zur Konzeption einer kosteneffizienten Gesamtlösung zwingt. Schöne Architektur über alles und um jeden Preis ist damit passé.

Business Value
Der oberste Wert, an dem sich ein Architekt orentieren sollte, ist der Business Value, der hinter einer umzusetzenden Lösung steckt. Architekten sind heutzutage mehr denn je dazu angehalten, dass das Systemdesign und die Systemarchitektur nach den Grundsätzen des BCM (Business Capability Management) ausgerichtet und dem konkreten Geschäftszweck und –wert angepasst sind. Die IT als Selbstzweck war seit jeher eine schlechte Idee. Im Hinblick auf Business Value und Kostentransparenz muss die IT an das vorliegende Geschäft angepasst werden und sollte darüber hinaus sogar in vielen Fällen als Business Enabler dienen. Dies bedeutet natürlich auch, dass nicht immer die perfekte Lösung gefragt ist, sondern vielmehr die auf das jeweilige Geschäft (und die damit verbundenen Anforderungen) am besten passende. Die Rolle des Architekten in diesen Zeiten beinhaltet deshalb noch stärker denn je die Aufgabe der Brückenbildung zwischen Fachbereich(en) und IT um gerade die Kundenbedürfnisse genau zu erfassen und danach zu handeln. 

Systemgrenzen / Systemdesign

Die Architektur von zukünftigen nachhaltigen Cloud-Lösungen kann mehrere grundsätzliche Ausprägungen annehmen. Die aktuell am erfolgversprechendste und auch mit der geringsten Einstiegshürde für Kunden verbundene ist vermutlich jene einer Hybrid-Cloud. Dabei werden Teile der Services bzw. Daten in der Cloud und andere on-premise gehostet. Die beiden Ufer werden durch die Cloudanbieter-Infrastruktur wie beispielsweise den Windows Azure AppFabric ServiceBus miteinander verbunden. Daraus resultiert natürlich eine essenzielle und entscheidende Herausforderung für den Architekten: er muss eine intelligente Serviceisolierung und die dazugehörigen Servicegranularitäten festlegen. Diese Aufgabe ist unter anderem stark von den jeweils vorherrschenden Governance- und Compliencebestimmungen eines Unternehmens oder gar eines Landes abhängig.

Versionierung
Ein nicht zu vernachlässigendes Thema in Bezug auf Serviceorientierung – und nichts anderes ist eine cloudbasierte Lösung in der Regel – ist Serviceversionierung. Überlegungen hierzu existieren bereits seit längerem und besonders durch das Aufkommen von SOA (Service Oriented Architecture) wurden diese vakant. Ein möglicher Ansatz, welcher mir ganz gut gefällt, ist die Lösung der Versionierungsproblematik auf organisatorischer Ebene. Hierbei werden für alle Servicebetreiber und Servicekonsumenten geltende Policies in Bezug auf Lebensdauer und Servicegenerationen festgelegt. Der Einsatz von Servicefassaden für alle in Betrieb befindlichen Generationen ist ebenfalls verpflichtend. Solche Policies findet man nicht nur unternehmensintern, sondern auch bei großen Anbietern von unternehmensübergreifenden oder öffentlichen Services, wie diese zum Beispiel von Amazon angeboten werden.

Stateless Behaviour
Ein weiteres Faktum bei der Erstellung einer Architektur unter der Verwendung von Cloud-Technologie ist, dass Services in der Cloud stateless sein müssen! Mit Hilfe von Queues und persistenten Storagemöglichkeiten (wie SQL Azure, Table Storage oder Blob Storage) können Services natürlich (laufend) Informationen über deren State ablegen, welche dann im Falle eines Serviceausfalles bzw. Neustart des Services (auf irgendeiner virtuellen Instanz) wieder ausgelesen werden können. Diese Logik ist jedoch ebenfalls von Anfang an vorzusehen und aktuell auch selbst zu implementieren. 

Fazit
Im Hinblick auf oben genannte Punkte und natürlich darüber hinaus bin ich mir sicher, dass Architekten aktuell und in unmittelbar bevorstehender Zukunft vor neuen spannenden Herausforderungen gestellt sind. So wie sich die IT in einem ständigen Wandel befindet, so trifft dies auch auf die Handlungsweisen und Aufgaben eines Architekten zu. Wir befinden uns in einer spannenden Zeit und es ist an uns, diese mitzugestalten.

Euer
JL@coopXarch

Mittwoch, 24. November 2010

JWR@coopXarch spricht auf den Software Quality Days 2011

Liebe Leser!

Ich spreche in meinem Vortrag im Rahmen der Konferenz "Software Quality Days 2011" über die Schaffung eines Ökosystems für agile, nachhaltig-effektive Software-Entwicklung.

Ein Ökosystem für agil-effektive Software-Entwicklung

Die erste B2B-Automobil-Auktion auf www.papa.at wurde am 3. März 2009 nach nur vier Monaten Entwicklungszeit des Online Portals erfolgreich durchgeführt. Dieser Beitrag stellt das Projekt vor, das auf agiles Vorgehen (Scrum), innovative Methoden und Technologien (Kontinuierliches Integrieren, Automatisiertes Testen, Spring Framework, GWT) und die vom Vortragenden entwickelte Plattform für agile Projektzusammenarbeit "Openspace" gesetzt hat und erfolgreich liefern konnte. Der Vortragende gibt als Projektleiter, Scrum Master und Backend-Architekt des Projekts Einblicke in die Erfolgsgeheimnisse und "Lessons Learned" und zeichnet ein Bild eines "Ökosystems“ für agile, nachhaltig-effektive Software-Entwicklung.

Mittwoch, 19. Jänner 2011 von 15:15 bis 16:00 Uhr (Die Gesamt-Veranstaltung "Software Quality Days 2011" findet vom 18. bis 20.01.2011 statt - siehe Konferenzprogramm).

Austria Trend Hotel Savoyen Vienna, A-1030 Wien, Rennweg 16

Ich freue mich natürlich über Euren Besuch auf den Software Quality Days 2011! DI Johannes Bergsmann ist ein Ziviltechniker Kollege - er und sein Software Quality Lab veranstalten die Software Quality Days.

Euer
JWR@coopXarch.

Dienstag, 23. November 2010

Software Architektur im Großen - wie überzeuge ich nur die Mannschaft?

Liebe Leser!

Zur Zeit darf ich eine große Organisation bei Ihren Bemühungen um eine unternehmensweite Architekturinitiative unterstützen. Hier wird versucht, eine Enterprise Architektur aus der gegebenen Landschaft zu extrahieren und zu kartographieren. Neben der Ist-Darstellung gibt es auch bereits eine Soll-Darstellung. Gleichzeitig wird die Software Architektur der bestehenden Applikationen (und das sind nicht 2 oder 3 oder 30, sondern viel mehr) rekonstruiert ("Architektur-Rekonstruktion" - mein Part) und mit dem Gesamtbild in Einklang gebracht - alles in allem also eine vorbildliche Initiative.

In der Diskussion entstand dann die interessante Frage, wie wohl die Unterstützung der Mannschaft dafür gewonnen werden kann, da bei der Einbeziehung von Mitarbeitern auf Produktebene vornehme Zurückhaltung bis leichter Widerstand ("na wenn wir das jetzt auch noch tun sollen, verschieben sich aber A, B und C...") zu spüren war.

Jetzt ist es zweifelsfrei so, dass man alles verkaufen muss, auch Architektur (vgl.etwa [Peter Hruschka]), jedoch möchte ich doch meine Meinung zu diesem Punkt in den folgenden Bullets anführen:

  • Architekturmanagement ist keine Schönheitsdisziplin als Antithese zu "Wir sind auch bisher ohne Architektur ausgekommen" (Architektur-Agnostik)
    • Stadtplanung ohne Architektur führt zum selben Ergebnis wie Softwareentwicklung ohne Architektur: zu beliebiger, heterogener, emergenter und teilweise stark suboptimaler Anordnung von Bauelementen mit Problemen in der Pflege und Weiterentwicklung bzw. Skalierung.
    • Skalierung ohne Architektur ist jedenfalls ein Abenteuer, wie man an vielen Ghettos rund um Großstädte sehen kann - oder eben auch in stark gewachsenen Softwareapplikationen bzw. Applikationslandschaften. Jedoch muss man auch sehen, dass das Gegenteil von vollständiger Abwesenheit, also z.B. künstliche Städte vom Reißbrett, noch keinen Ästheten vom Hocker gehauen hat...
    • Wer also glaubt, man könne ganz ohne Architektur-Fokus auskommen, sollte sich nicht wundern, wenn die Organisation bald ohne ihn auszukommen versucht...
  • Der CIO ist für das "Herunterbrechen der Architektur-Ziele auf die Mitarbeiterebene" verantwortlich als Analogon zu "Umsatzziele werden ja auch auf den einzelnen Verkäufer herunter gebrochen"
    • Jedem ist ungefähr klar, wie Umsatzziele aufgeteilt werden, um sie schlussendlich hoffentlich zu erreichen. Bei Architekturzielen fragt man sich jedoch, wie die Mannschaft davon zu überzeugen wäre.
    • Ich meine, wir haben es hier mit einem Analogon zu tun und muss es auch so behandeln. Ein Kompetenzcenter Architektur unterstützt den CIO (oder auch CTO) bei der Definition und Kommunikation der Maßnahmen, auf die Reise in die Linie schicken muss diese Maßnahmen aber der CIO - das ist sein Job!
  • Die Wertschöpfung aus Architekturmaßnahmen muss und darf nicht nur langfristig erkennbar sein als Gegenpol zu "Wer macht die schönere Kosten/Nutzen Aufstellung"
    • Die Gefahr ist nicht, dass Investitionen in Architektur möglicherweise nicht ganz die erhofften Erwartungen treffen, sondern, dass Budget investiert wird und nach 2-3 Jahren gar nichts dabei heraus schaut. Das passiert, wenn etwa das Budget für die Quersubventionierung von anderen Schmerzbereichen verwendet wird, oder nur tote Dokumentation ohne Chance auf Wartung erstellt wird.
    • Man kann auch kurzfristige Benefits ins Rennen schicken, dafür eignet sich z.B. der Ist/Soll Vergleich sehr gut, da er den Ausgangspunkt und das Ziel visuell darstellt. Für viele Mitarbeiter offenbart sich hier erstmals das Gesamtbild der Applikationslandschaft und schafft die Basis für die Motivation, den Status Quo zu verändern.
  • Eine Kultur der Architektur als Gegenbewegung zu "Ich muss mich immer für Architekturmaßnahmen rechtfertigen!"
    • Meiner Meinung nach ist die Migration in eine Kultur des Architekturverständnisses dann erreicht, wenn nicht der, der sich Zeit für Architektur nimmt, eine Ausrede suchen muss ("ja hast du denn nichts Besseres zu tun?"), sondern der, der Architekturmaßnahmen unterlässt. Für eine Unterlassung gibt es auch immer Gründe, wie das allseits bekannte "Es muss aber unbedingt nächsten Ersten ausgeliefert werden!". Realität schafft Fakten. Punkt. Dann muss man es auf das "Schulden in der Zukunft" Konto laden und später behandeln. Nur vergessen sollte man es nicht.
Zusammenschau:

Im klassischen Umfeld:
Es bedarf meines Erachtens sowohl des Verständnisses als auch des sanften Drucks - oder positiv formuliert - der Motivation, um Bemühungen zu fokussieren und das Vorhaben auf die Reise zu schicken. Wer an Architektur als Freifach oder Kür glaubt, ist meines Erachtens blauäugig und wird auf Dauer zur Gefahr für den nachhaltigen Erfolg.

Und im agilen Umfeld?
Hier kommt der Druck aus dem Team selbst, sofern es die Wichtigkeit verstanden hat und die Relation zum geschaffenen Wert hergestellt ist. Agile Vorgehensweisen sind Wertmaximierer, und wenn ein Wert zu erkennen ist, müssen die Aktionen diesen auch berücksichtigen - ihn also "schöpfen".

Ich hoffe, das Thema ist für Euch genauso spannend wie für mich!

Euer
JWR@coopXarch.

Montag, 1. November 2010

Automatisierte Validierung der Software Architektur mit dem Tool "SonarJ"

Liebe Leser!

Zur Modellierung und Validierung von Softwarearchitektur verwenden wir das Tool "SonarJ". Im Anschluss lest ihr eine Mail an mein Team aus dem "42" Projekt, das auf Architekturverletzungen und damit verbundene, von mir bereits teilweise durchgeführte Refactorings verweist und aufzeigt, welche zusätzlichen Schritte zu setzen sind, um die bestehenden Architekturverletzungen zu beheben. Sehr schön sieht man wieder einmal, dass das schönste Architekturmodell ohne automatische Validierung nicht eingehalten werden kann und sich im Prozess der Entwicklung sub-optimale Designentscheidungen und daraus folgende Implementierungen nicht "up-front" vermeiden lassen. Aber lest selbst...

---- mail snippet ----

Hallo 42-Team!

Nachdem ich gerade mit SonarJ für ein anderes Projekt arbeite, hab ich auch gleich die 42-Software einem Architektur-Review unterzogen und ein paar unschöne Abhängigkeiten entfernt:

Das ist die definierte Architektur (horizontale Box = Layer; vertikale Box = Domain-Bereich) mit den in grün eingezeichneten erlaubten Abhängigkeitsbeziehungen – links von oben nach unten, rechts von unten nach oben (eine Abhängigkeit vom Backend auf den Layer „view“ ist z.B. verboten):


Ein frappantes Ergebnis des SonarJ Durchlaufs war eine Abhängigkeit vom Backend auf den Layer „view“ - das ist natürlich immer strengstens verboten, ist aber 3x im Code vorgekommen! Ich habe das klarerweise sofort behoben.

Nachdem es nun keine Abhängigkeiten auf den layer „view“ mehr gibt, könnte man das Projekt gänzlich ohne den View Layer "at.*****.client" im Klassenpfad kompilieren und die Backend Tests fahren – wer will, kann’s ja ausprobieren.

Folgende Architekturverletzungen gibt es noch (in rot auf der rechten Seite der Layer eingezeichnet):


Die Layer „model“ und „service“ greifen auf „remoting“ zu, was natürlich auch zu vermeiden wäre – der Grund sind die DTOs (i.e. die „*Info“ Klassen), die wir in den 3(!) Layern "remoting", "service" und "model" definiert haben:


AuctionServiceImpl.java befüllt ein AuctionInfo und das referenziert auf VehicleInfo(s).


Die Verstreuung der *Info Klassen sollte man natürlich auch in den Griff bekommen, allerdings gibt es im Backend sehr viele weitere zyklische Abhängigkeiten, sodass nach Beseitigung der Abhängigkeiten nur die Layer „remote" und "controller“ unabhängig würden, das Backend mit "data-access", "model" und "service" bliebe aber nur monolithisch verwendbar.

Hier nochmal alle nicht erlaubten Abhängigkeiten:



Diese Architekturverletzungen müssen noch systematisch durch Refactoring behoben werden. 

mfg
Hannes.

---- mail snippet ----

Euer
JWR@coopxarch.

Mittwoch, 27. Oktober 2010

Logging in dot.net

Einführung
Aktuell bin ich als Entwicklungsleiter in einem C# Umfeld eingesetzt. Bei einer Client/ServerApplikation galt es, UseCases zu monitoren und die Laufzeit zu messen. Dabei interessiert besonders
  • Anzahl und Dauer der Netzwerkrequests vom Client zum Server
  • Art, Anzahl und Dauer der abgesetzten SQL-Statements am Server
  • Dauer des Netzwerkresponses vom Server zum Client
und natürlich das selektive Einschalten von Logging für zu überwachende Teilbereiche, wie ich es von Java (sprich von log4j [1]) gewohnt bin.

Der Client loggte bereits mittels der Logging-Implementierung von dot.net, nämlich Systems.Diagnostic.TraceSource. Der Server hatte kein explizites Logging, intern wurden jedoch einige Bibliotheken verwendet, die auf unterschiedliche Arten loggen. Verwendet wurden
  • als Job Scheduler Quartz.net, verwendet Common.Logging [3]
  • als ORM NHibernate, verwendet log4net [2], die dot.net Variante von log4j [1]
  • zur Netzwerkkommunikation WCF, verwendet die Systems.Diagnostic.TraceSource
Die Aufgabenstellung lautet daher:
  • Einführen von Logging auf Client und Serverseite
  • Harmonisierung der bestehenden Frameworks
  • Zusammenfassung der Logs von Client und Server, um die gewünschten Fakten zu ermitteln

Common.Logging
Common.Logging ist kein eigenes Logging Framework, sondern eine Abstraktion (eine "Bridge") von unterschiedlichen Frameworks. Common.Logging erlaubt die konfigurierbare Wahl des Logging-Frameworks, welches die Ausgabe schlussendlich wahrnimmt. Geschaffen wurde die Bibliothek nach dem Vorbild von Commons.Logging (man beachte das "s"), welches dieselbe Aufgabe in der Java-Welt wahrnimmt.

Eine Bibliothek sollte mich durch ihre Verwendung nicht  nötigen, andere Frameworks einzusetzen, die gänzlich andere Aspekte  abdecken, in diesem Falle Logging. Daher sollten Bibliotheken immer Common.Logging benutzen. D.h. an dieser Stelle ist Kritik an NHibernate angebracht, dass log4net verwendet wird. Ein entsprechender Issue, der die Umstellung auf Common.Logging fordert, existiert bereits in Jira, bitte fleissig voten [4].

Der eigene Code hingegen kann sehr wohl direkt ein spezifisches Logging-Framework verwenden, allerdings wird damit ein späterer, möglicher Wechsel auf ein alternatives Logging-Framework unnötig erschwert. Daher macht es Sinn, dass auch innerhalb des eigenen Codes Common.Logging verwendet wird.

Common.Logging bringt zusätzlich noch Adaptoren mit, die die Logausgabe von Logging-Frameworks "einfangen" und nach Common.Logging überführen. Somit kann man sehr leicht die Logging-Ausgaben unterschiedlicher Frameworks "harmonisieren".

Im Folgenden schauen wir uns an, wie wir die oben genannten Anforderungen über log4net und TraceSource abwickeln können.

Variante 1: Loggen über log4net
Die beteiligten Komponenten werden wie folgt verdrahtet:
Sowohl Client als auch Server verwenden Common.Logging, damit muss der rote Teil der Grafik konfiguriert werden. An dieser Stelle soll nicht angeführt werden, wie Common.Logging oder Log4Net zu konfigurieren ist. Dazu sei auf die entsprechenden Homepages verwiesen. Anmerken möchte ich jedoch, dass die Konfiguration von Log4Net sowohl in einem eigenen config-File als auch in der app.config passieren kann. Am Server ist auf jeden Fall das eigene config-File anzustreben, da Log4Net dieses überwachen kann, bei einer Änderung die Datei neu einliest und man damit die Konfiguration zur Laufzeit ändern kann. So kann im Bedarfsfall eine Komponente näher untersucht werden, ohne dass der Server restartet werden muss.

Anbei die Teile der app.config, die notwendig sind, um TraceSource nach Common.Logging über zu führen:
<!-- ************ System.Diagnostics Konfiguration ************ -->
<system.diagnostics>

  <!-- Listener für Weiterleitung der Ausgaben von Trace und TraceSource nach Common.Logging registrieren -->
  <!-- Der Wert für initializeData gibt an, welche Levels von Trace und TraceSource weiter gegeben werden, -->
  <!-- siehe System.Diagnostics.TraceEventType -->
  <sharedListeners>
    <add name="Diagnostics"
         type="Common.Logging.Simple.CommonLoggingTraceListener, Common.Logging"
         initializeData="DefaultTraceEventType=Information; LoggerNameFormat={listenerName}.{sourceName}">
    </add>
  </sharedListeners>

  <!-- Bestehende Behandlung von Trace (mit clear) deaktivieren und Listener für Weiterleitung der Ausgaben -->
  <!-- von Trace in Common.Logging aktivieren. Damit wird Trace ausschließlich in Common.Logging überführt. -->
  <trace>
    <listeners>
      <clear />
      <add name="Diagnostics" />
    </listeners>
  </trace>

  <!-- Bestehende Behandlung von TraceSource (mit clear) deaktivieren und Listener für Weiterleitung der Ausgaben -->
  <!-- von TraceSource in Common.Logging aktivieren. Damit wird TraceSource ausschließlich in Common.Logging überführt. -->
  <!-- Eine Eigenheit von TraceSource ist, dass alle Sources (= Logger in der Log4Net-Sprache) -->
  <!-- einzeln zu Listenern (= Appendern in der Log4Net-Sprache) zugewiesen werden müssen.-->
  <sources>
    <source name="System.ServiceModel" switchValue="All" propagateActivity="true">
      <listeners>
        <clear />
        <add name="Diagnostics" />
      </listeners>
    </source>
  </sources>
</system.diagnostics>

Der erste Block definiert einen Listener (=Appender in der Log4x-Sprache), der das Logging von TraceSource entgegen nimmt und nach Common.Logging überführt. Der zweite Block sorgt dafür, dass System.Trace-Aufrufe nach Common.Logging umgeleitet werden. Hier ist zu beachten, dass ein Default-Listener registriert ist (Log-Window in Visual Studio), welcher mit clear entfernt werden kann. Der dritte Block definiert, dass genau eine Source (= Logger in der Log4x-Sprache), nämlich "System.ServiceModel" mit dem oben definierten Listener verdrahtet wird. Diese Source nimmt die Protokollierung der WCF-Kommunikation vor. Alternativ kann Beginn und Ende der Kommunikation über Aspekte geloggt werden, was zu weniger und sinnvolleren Logging-Outputs führt.

Die Harmonisierung der unterschiedlichen Log-Quellen funktionierte auf diese Art und Weise, wie sieht's nun mit dem Zusammenführen der Outputs von Client und Server aus? Dies kann sehr einfach mit einem Tool wie NetLogClient [5] erfolgen, welches sowohl vom Client als auch vom Server den Output von definierten Loggern über UDP entgegen nimmt und diese zeitlich geordnet visualisiert (NetLogClient ist der C#-Counterpart zu chainsaw).

Variante 2: Loggen über TraceSource
Die beteiligten Komponenten werden wie folgt verdrahtet:

Client als auch Server verwenden System.Diagnostic.TraceSource, der rote Teil der Grafik muss konfiguriert werden. Auch hier schauen wir uns nur die relevanten Teile an.

Zuerst muss Log4Net nach TraceSource übergeführt werden, in der Konfiguration von Log4Net ist folgendes vorzusehen.
<!-- A1 is a TraceAppender and uses PatternLayout -->
<!-- Siehe http://logging.apache.org/log4net/release/sdk/log4net.Layout.PatternLayout.html -->
<!-- # %date Zeitpunkt in ISO8601DateFormat {ISO8601} oder absolut=ohne Date-Info {ABSOLUTE} -->
<!-- # %thread Thread name -->
<!-- # %level   Used to output the level of the logging event. -->
<!-- # %logger  Used to output the logger of the logging event. -->
<!-- # %ndc  NDC (nested diagnostic context) associated with the thread that generated the logging event -->
<!-- # %message message -->
<!-- # %newline platform dependent line separator character or characters -->
<appender name="A1" type="log4net.Appender.TraceAppender">
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date{ABSOLUTE} [%thread] %-5level %logger %ndc - %message%newline"/>
  </layout>
</appender>

Zweitens ist Common.Logging zu konfigurieren:
<!-- ************ Common.Logging Konfiguration ************ -->
<common>
  <logging>
    <!-- Common.Logging nach Diagnostic.Trace überführen. -->
    <factoryAdapter type="Common.Logging.Simple.TraceLoggerFactoryAdapter, Common.Logging">
      <arg key="level" value="DEBUG"/>
      <arg key="showLogName" value="true"/>
      <arg key="showDataTime" value="true"/>
      <arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:fff"/>
    </factoryAdapter>
  </logging>
</common>

Diese Lösung hat den Nachteil, dass drei unterschiedliche Layouts vorhanden sind, die an jeweils unterschiedlichen stellen anzupassen sind, um über die gesamte Architektur einheitliche Layouts zu erhalten. Die Harmonisierung ist damit abgehandelt, die Zusammenführung funktioniert über den Microsoft Service Trace Viewer. Für diesen sind sowohl auf der Client- als auch auf der Serverseite XML-Logs zu erstellen, die dann importiert werden müssen. Zusammengehörige Requests werden in beiden Varianten durch dieselbe Activity-ID identifiziert.

Bewertung
Wenn man sich die Konfiguration der beiden Varianten ansieht (und mit Reflector ein bisschen in TraceSource rumschnüffelt), dann merkt man, dass Log4Net und TraceSource unterschiedliche Konzepte verfolgen.

Bei der Implementierung von Log4Net wurde das Observer- und das Mediator-Pattern verwendet. Jeder Logger kennt nur seinen Mediator, was zu leichtgewichtigen Logger-Objekten führt. Deshalb wird beim Einsatz von Log4Net auch fast immer das logger-per-class pattern [6] angewandt.

TraceSource verwendet zwar auch das Observer-, nicht aber das Mediator-Pattern. Deshalb muss für jede Source angegeben werden, welcher Listener den Output erhält. Auch werden Log-Levels nicht vererbt. Dies ist ein Grund, warum Log4Net-Jünger jammern, wenn sie mit TraceSource in Berührung kommen. Tatsächlich steht dahinter ein ganz anderes Konzept: die Logger - Entschuldigung, die Sources sind schwergewichtig, daher wird ein source-per-componente pattern angewandt (Sorry, dazu kenne ich keinen externen Link). Dies erklärt auch, warum die Source nicht über ihren Klassennamen inkl. Namespace von einem zentralen Buffer (Factory) geholt wird, sondern einfach mit new() erzeugt wird. Innerhalb der Komponente müssen die entsprechenden Klassen sehen wie die Source geteilt wird.

Die korrelierende Auswertung mit Microsoft Service Trace Viewer gefällt, schnell war der Wunsch da, auch SQL-Statements in diesem vorzufinden. Gewählt und umgesetzt wurde daher eine Mischvariante aus den obigen zwei Varianten:
Für den Menschen bestimmte Log-Dateien werden über Log4Net erstellt (Variante 1). WCF wird aber nicht integriert, sondern bleibt eigenständig. Für die SQL-Statements aus NHibernate wird ein weiterer, nicht additiver Logger eingerichtet (Variante 2), der nach TraceSource loggt. Die korrelierten Auswertungen inkl. SQL können mit Microsoft Service Trace Viewer betrachtet werden. Auch der UDP-Logger kann weiterhin eingesetzt werden. Anbei noch ein Bild des Service Trace Viewers.



Das Thema Logging ist damit aber noch nicht erschöpft, diesen Beitrag möchte ich aber an dieser Stelle beenden. Bitten möchte ich um Voting/Comments von drei Fehlern, die wir im Rahmen der Einführung gefunden haben, nämlich den obig erwähnten Punkt [4], dann noch unnötige Referenzen bei Log4Net [7] und einen Fehler bei der Codeausgabe von Common.Logging [8].

Euer
CL@coopXarch

Links