Montag, 31. August 2009

„Ich suche einen Arzt“

Was für einen Arzt? Für was? Wieso? Werden sie fragen, wenn sie das lesen. Suchen Sie einen Kieferorthopäden oder einen Chirurg, einen Allgemeinmediziner oder einen HNO-Spezialisten? Einen Gynäkologen oder Kinderarzt? Vielleicht doch einen Onkologen oder eher einen Kardiologe.
Fragen über Fragen. Fragen die sich in der Softwareentwicklung keiner stellt:

„Software-Entwickler gesucht“

Hoppla – da sucht einer jemanden der Software schreiben kann. Gut so, recht so. Andere suchen Tischler, Innenarchitekten, Zimmermänner. Ist doch dasselbe.
Wo bleiben die Fragen? Suchen Sie einen Spezialisten für .NET oder vielleicht doch für Java? Und handelt es sich um einen Packaging Spezialisten? Vielleicht eher um Architektur? Oder die verteilte Kommunikation?

Irgendwie dachte ich ja diese Fragen stellt man sich heutzutage. Die Stellenbeschreibungen scheinen immerhin nicht mehr ganz so undifferenziert wie einst. Ja, vielleicht haben sogar die Betriebe angefangen etwas zu verstehen.
Aber bei den Studiengängen ist das noch nicht so wirklich angekommen. Das erinnert mich immer wieder an mein Bewerbungsgespräch mit einem frisch gebackenen Master in Informatik. Auf meine Frage: „Was ist Ihr Steckenpferd, worin sind sie stark?“, die Antwort: „Ich habe alles gelernt – ich habe den Master gemacht“. Da stehen mir die Haare zu Berge, da wird mir übel. Tut mir leid, aber das kann ich nicht anders umschreiben.
„Wir haben hier einen Notfall von einem Motorradunfall.“ – da springt ja bekanntlich auch der Zahnarzt auf und sagt, „kein Problem ab auf den OP mit ihm ich mach das.“.

Mehr Spezialisierung muss her und das schon viel früher in der Ausbildung. Wenn ich von einigen Studiengängen sehe wie die Auszubildenden noch Turbo Pascal lernen und erfahren wie der erste Otto Computer funktioniert hat, dann finde ich das nicht Zeitgemäss. Wir bauen uns Abstraktionen um uns nicht mehr mit allem befassen zu müssen und untergraben die wieder. Das verstehe ich nicht.

Hier sollte man ansetzen, die Qualitätsprobleme sind nur die logische Konsequenz von dem, was schon bei der Ausbildung anfängt und über die Entwicklersuche weiter geht.

Sonntag, 12. Juli 2009

Disaster Entity Framework

Der Titel sagt schon das meiste aus. Ich hatte vor kurzem die Ehre in einem Projekt das Entity Framework kurz kennen zu lernen. Die Betonung liegt auf kurz. Wir haben uns nämlich in Kürze dafür entschieden das Entitiy Framework wieder auszubauen. Ich habe das Entity Framework nie wirklich für einen Enterprise-tauglichen O/R Mapper gehalten, ebenso linq-to-sql nicht. Aber so eine Art verbessertes DataSet, für schnelle, überschaubare Applikationen habe ich schon erwartet. Ja, vielleicht habe ich sogar erwartet, dass ich ein kleines, leichtgewichtiges Domain Model damit bauen kann.
Leider egal was, aus meiner Sicht kann das Entity Framework nicht für viel mehr gebraucht werden als ein Drag & Drop sample. Zumindest beim jetzigen Stand der Entwicklung.

Hier einige Punkte die uns ganz besonders gestört haben:

  • Change Tracking wird zwar geführt, allerdings ist es unglaublich schwierig an die veränderten Objekte zu kommen. Der Object Context gibt nämlich per Default immer nur das zurück was in der Datenbank ist. Simple OK/Cancel Szenarien oder Offline Caching werden also im Nu zu einem Workaround.
  • Kein Forward Engineering der Datenbank. Alles muss zuerst in der Datenbank erstellt werden und anschliessend kann das Modell aktualisiert werden.
  • Keine Update-Scripts für bestehende Datenbanken. Nicht so wie ich das z.B. von einem Telerik Open Access kenne. Update-Scripts für bestehende Kundendatenbanken bei Schemaänderungen müssen manuell vorgenommen werden.
Das ist nur ein Ausschnitt der Unannehmlichkeiten mit dem Entity Framework, aber es sind wohl die grössten, zumindest für mein letztes Projekt. Klar man kann das meiste umgehen, vor allem mit einigen Workarounds. Aber das ist nicht das was ich von einer neuen O/R Mapping Technologie erwarte. O/R Mapping Tools gibts seit geraumer Zeit einige und man könnte doch erwarten, dass man da zumindest etwas abguckt.
Übrigens sind die Unterschiede zwischen Linq-To-SQL und EF erschreckend klein - zumindest für den Praxisgebrauch. Linq-To-SQL unterstützt aber immerhin Forward Engineering.

Meine Empfehlung für Enterprise-Projekte und Datenzugriff: Lasst die Finger von EF und Linq-To-SQL. Jetzt verwenden wir für diese Projekt wieder gute alte DataSets.

Mittwoch, 13. Mai 2009

Erweiterungen für das CCD Wertesystem


Schon vor einiger Zeit habe ich im CCD Forum zwei Ergänzungen zum Wertesystem zur Diskussion gestellt ([1], [2]). Ich möchte diese hier ausformuliert nochmals präsentieren und werde, sobald ich das der OK Initiatoren habe, diese auch in das Wertesystem einpflegen.

Favouring Composition over Inheritance (FCoI)

Für die Wiederverwendung von Funktionalität bietet die OOP zwei allseits bekannte Möglichkeiten: Vererbung (whitebox-reuse) und Komposition (blackbox - reuse). Bei der Vererbung erbt eine Subklasse von einer Elternklasse und kann diese um Funktionalität erweitern und Verhalten ändern - die Internas der Elternklasse sind sichtbar. Bei der Komposition verwendet eine Klasse eine andere. Sie verwendet also einen externen Dienstleister um etwas zu tun. Dabei müssen die Schnittstellen zu der verwendeten Klasse gut definiert sein, da die Internas nicht sichtbar sind sondern die Komponente als BlackBox verwendet wird.

Beide Varianten bieten ihre Vor- und Nachteile. Vererbung ist sehr einfach einzusetzen und ein effizientes, gut verbreitetes Mittel zur Wiederverwendung von Funktionalität. Vererbung hat also durchaus seine Berechtigung. Leider wird sie aber oft viel zu viel eingesetzt. In vielen Fällen sollte man der Komposition Vorschub gewähren, denn Sie ist flexibler. Bei der Vererbung wird die Subklasse von der Elternklasse abhängig. Oft entstehen schleichend grosse Klassenhierarchien welche bei genaueren Betrachtung häufig LOD (Law of Demeter) und LSP (Liskov Substitution Principle) verletzen. Auch ist es schwierig bei der Vererbung die Funktionalität zur Laufzeit auszutauschen, was bei der Komposition kein Problem ist. Selbst das Anpassen der Funktionalität in grossen Klassenhierarchien wird schnell zum unangenehmen Problem.


"Because inheritance exposes a subclass to details of its parent's
implementation, it's often said that 'inheritance breaks encapsulation".
(
Gang of Four 1995:19)

Bei der Komposition ist das gesamte system weniger gekoppelt. Die Komposition kann allerdings auf den ersten Blick schwerer zu verstehen sein.

Deshalb gilt: Vererbung ist keine schlechte Sache. Sie sollte aber mit Bedacht eingesetzt werden und oft sollte die Komposition favorisiert werden.


Information Hiding Principle (IHP)

Eines der effizientesten Mittel zur Bekämpfung von Komplexität ist das reduzieren von Abhängigkeiten auf ein absolutes Minimum. Deshalb halte ich das alte, aber stets aktuelle, Prinzip für sehr wichtig. Gerade zu Zeiten des Contract-First-Designs sollte man sich überlegen, was eine Schnittstelle auch wirklich alles preis geben muss. Es gilt also nicht nur das ISP (Interface Segreation Principle) zu beachten, sondern auch das IHP.

Um die beiden also klar abzutrennen:

ISP besagt: Wenn du nicht immer alle Methoden brauchst, dann verteile sie auf mehrere Interfaces.

IHP besagt: Mache dein Interface nicht unnötig von weiteren Typen abhängig.

So einfach und klar wie das auch sein mag - so gerne hätte ich es explizit im CCD Wertesystem!

Freitag, 8. Mai 2009

Echte Komponentenorientierung - Toolgestützt

Programmieren Sie wirklich Komponentenorientiert?

Echte Komponentenorientierung bedeutet mehr als einfach ein Interface für eine Klassenimplementierung zu haben.
Angenommen Ihre Komponentenklassen implementieren alle ein Interface. Dann haben Sie einen Kontrakt der die Schnittstelle der Komponente klar definiert. Gut, dass ist schon viel, vielleicht mehr als einige Software bisher je hatten. Nur wenn diese Schnittstelle dann in der selben Assembly wie die Implementation liegt, dann haben Sie noch nicht viel gewonnen.
Skalierbar sind Sie damit nicht. Und auch nicht wirklich flexibel. Was wenn Sie nur die Implementierung austauschen möchten, einem Freelancer nur einen Teil des Projekts zugänglich machen wollen oder die Kontrakte unabhängig von der Implementation zentral erstellen wollen?
Vielleicht kann man für diese Probleme sogar noch irgendwie eine umständliche Lösung finden. Die Praxis hat mir aber gezeigt, dass die richtige Komponentenorientierung, wie Ralf Westphal sie schon einige Zeit im Zusammenhang mit der Systemorientierten Programmierung (SOP) predigt, ganz andere Stärken hat.

The power of real component oriented architecture I - Verträge nur bewusst ändern

Kam Ihr Chef schon mal zu Ihnen und hat in Ihrem Arbeitsvertrag mal eben kurz was geändert, weil ihn etwas störte oder er gerne etwas anderes im Vertrag hätte?

Ich hoffe nicht. Dann hätte er nämlich mit dem Obligationenrecht und vermutlich mit Ihnen ein Problem bekommen.
Genau das passiert aber oft in der Softwareentwicklung. Kontrakte werden im Affekt, nur kurz mal eben, geändert. Das hat aber gravierende Folgen. Verträge sind die zentralen Schnittstellen und sollen nur bewusst und überlegt geändert werden. In meinem Team gehen wir sogar so weit, dass Verträge nur gemeinsam und im Konsens geändert werden.
Solange die Verträge aber gerade neben der Implementierung hängen ist die Änderung nicht weit. Und die sind mir noch zu nah aufeinander wenn Sie in der gleichen Solution in verschiedenen Projekten hängen. Klick, klick und eine neue Methode ist drin – vermutlich aber nur kurz zu Testzwecken oder weil es schnell gehen muss, richtig?


The power of real component oriented architecture II - Fokus

Was hilft mehr als den Fokus bei einer Problemlösung zu wahren? Wie angenehm wäre es, wenn Sie einfach nur die Quelltextdateien sehen die zu Ihrem aktuellen Problem gehören? Und nur die Unit Tests die sich darauf beziehen?
Das ist das selbe wie Eric Evans uns mit Domain Driven Design nahe legt. Den Fokus auf die Domäne bewahren. Aber wie soll das gehen wenn das offene Projekt alles mixt?
Bei der echten Komponentenorientierung haben Sie genau dieses Problem nicht. Sie sehen was sie brauchen, nicht mehr, aber auch nicht weniger. Bei meiner täglichen Arbeit ist das ein Vorteil geworden, den ich nicht mehr missen möchte.

Physische Grenzen müssen her!

Was also ist zu tun um all die unbestrittenen Stärken der Komponentenorientierung zu nutzen (einige so bekannte Vorteile wie z.B. die Testbarkeit, Skalierbarkeit, Evolvierbarkeit, usw. muss ich wohl kaum noch zusätzlich benennen, dass haben andere schon zu genüge getan)? Dafür müssen physische Grenzen her. Der Quellcode muss anders organisiert werden. Nur so werden Kontrakte nicht mal eben geändert und man hat nicht monolithische Solutions mit hunderten Projekten und tausenden Quelltextdateien.
Microsoft verwendet dazu die Solution folders (rot markiert). Das ist aber meiner Meinung nach das falsche Strukturierungs-Mittel. Kontrakte, Implementierungen und verschiedene Komponenten mit verschiedenen Belangen sitzen immer noch zu nahe aufeinander. Entschuldigt das Bild aber ich möchte den Schmerz etwas vermitteln.

Wie also kann man diese physischen Grenzen ziehen?
Ganz einfach: Jede Komponentenimplementierung erhält eine einzelne Solution und jeder Kontrakt auch. Die Kontrakte kann man, wenn man möchte auch zusammenfassen. So sieht das dann in einer Ordnerstruktur aus:

Und in den einzelnen Solutions, als Kontrast zu vorher:


Das ist nenn ich überschaubar. Ich sehe was ich brauche. Ich kann ganz einfach meinen Fokus halten. Öffne ich diese Solution habe ich genau eine Implementierung für ein abgestecktes Problemgebiet vor mir. Und die Tests gleich dazu. So fällt mir das arbeiten viel einfacher.

Kein IDE Support

Leider erhält man von Visual Studio keine Unterstützung bei einem solchen Vorgehen. Bis zu einem gewissen Grad ist das auch in Ordnung. Schliesslich ist die „Hürde“ ja gewollt. Nur ist da im Vergleich zu vorher doch erheblich mehr Aufwand zu betreiben um ein neues Projekt zu initialisieren. Ist das mal getan hat man nur noch Mehraufwand zu bewältigen, wenn man neue Komponenten einführt.
Trotzdem beim Anlegen einer neuen Komponente sind immer folgende Schritte zu tun:

· Kontrakt-Projekt in der Kontrakt-Solution anlegen
· Umbiegen des Build-Verzeichnisses auf das gemeinsame Build-Verzeichnis
· Solution für die Komponentenimplementierung anlegen
· Umbiegen des Build-Verzeichnisses auf das gemeinsame Build-Verzeichnis

Das ist beinahe noch verschmerzbar. Viel mehr Aufwand kommt dann noch dazu, wenn man einen Schreibfehler in einem Komponentennamen gemacht macht und eine Komponente umbenennen möchte. Überall so viele Referenzen. Das kann durch ein Tool automatisiert werden. Dadurch wird vielleicht die Einstiegshürde herabgesetzt wirklich Komponentenorientiert zu arbeiten und keine monolithischen Riesen-Solutions mehr zu bauen.

Rettung naht – CAF

Mit der Unterstützung von Ralf Westphal mache ich mich auf zu einer Lösung des Problems. Wir starten das Projekt Component Architecture Factory (CAF). Der Gedanke dahinter ist simpel. In einer XML Datei beschreibe ich deklarativ meine Komponenten und ihre Abhängigkeiten. Der Rest kann CAF dann übernehmen.



Die Vision ist also, dass CAF direkt den Verzeichnisbaum aufbaut, die Solutions für die Kontrakte und Implementierungen baut, den Build Prozess zusammensteckt und das ganze auch gleich noch in ein Source Control Repository verpackt. Deklarativ die Architektur beschreiben und gleich ein Resultat in den Händen – klingt das nicht gut?
Ich werde hier weiter berichten, dranbleiben ;-)

Sonntag, 26. April 2009

Blogging - here we go again!

Nach einer langen und sehr arbeitsintensiven Blogging-Pause möchte ich mich nun wieder vermehrt dem Bloggen widmen. Und möchte hier in kürze über einige Themen berichten die mich im Moment bewegen und beschäftigen:
  • Domain Driven Design
  • Clean Code (Developer)
  • CAF
  • Application Space
Ich freue mich darauf. Bis bald.

Sonntag, 9. Dezember 2007

Mehr Paralellität mit PLINQ und TPL

Mit der nächsten Generation für die Parallelverarbeitung mit dem .NET Framework PFX unterstützt Microsoft den Trend der Paralellverarbeitung. Da aktuelle Prozessoren mit immer mehr Kernen ausgestattet sind muss, um die Performancevorteile mehrerer Prozessorkernen auszunutzen, mehr parallel verarbeitet werden.
Das .NET Framework hat das mit dem Threading-Model und dem ThreadPool schon angenehm einfach gemacht. Aber nicht einfach genug! Mehr Abstraktion muss her. Bestechende Ansätze Microsofts sind dabei PLINQ und die Task Paralell Library. So einfach war Paralellverarbeitung noch nie:

Ein kleines Beispiel eines ersten experiments mit der TPL:
Parallel.For(0, 100, delegate(int i) { a[i] = a[i]*a[i]; });

Das ist nicht nur unglaublich einfach, sondern auch noch schneller als mit der ThreadPool-Klasse. Die TPL optimiert und steuert die Arbeitthreads nämlich besser. Ein empfehlenswerter Artikel dazu ist Optimieren von verwaltetem Code für Mehrkerncomputer. Anschauen lohnt sich!

Gleiches gilt für PLINQ:

Abstraktion vom feinsten - PLINQ's AsParallel:
IEnumerable data = ...;var q = data.AsParallel().Where(x => p(x)).Orderby(x => k(x)).Select(x => f(x));foreach (var e in q) a(e);

So gehört sich paralelle Verarbeitung und die Zukunft gehört ihr. Und hier auch noch ein Artikel über das Ausführen von Abfragen auf Mehrkernprozessoren.

Anschauen lohnt sich auf jedenfall. Endlich kann ich mich auf die Problemlösung - die Logik - konzentrieren und muss mich nicht mit technischen Infrastukturdetails herumschlagen. Übrigens lohnt sich im Zusammenhang mit Multithreading auch einen Blick auf Ralfs NSTM Implementation.

Blog des PFX Teams: http://blogs.msdn.com/pfxteam/

Montag, 26. November 2007

Visual Studio 08 und .NET 2.0

Letzte Woche habe ich das Release von Visual Studio 2008 installiert.
Es war jetzt nicht super neu, da ich die Betas schon kannte. Trotzdem - irgendwie cool, die IDE hat definitiv nochmals einen Schritt nach vorne gemacht.
Neben den ganzen neuen Features in der CLR gefallen mir am neuen VS08 vorallem die neuen Compiler, welche es ermöglichen die neuen Sprachfeatures von C# und VB.NET auch für eine .NET 2.0 Anwendung zu verwenden.
D.h. ich kann:
  • Auto-Implemented Properties
  • Lambda Expresssions
  • Collection Intializiers
  • Object Initializers
  • Anonymous Types
  • Implicit Typed Variables
  • Extension Methods
  • Partial Methods
  • Query Words
trotzdem verwenden! Das ist doch echt mal ein Fortschritt: Ein neues Visual Studio das mit alten Framework Versionen arbeitet und aber einen tollen neuen Compiler mitbringt. Wenn man jetzt die grossen technologischen Brocken wie WF,WPF und WCF aussen vor lässt kann man abgesehen von ein, zwei Dingen wie Suite-B Support, ADO.NET Entity Framework oder der neuen Klassen HashSet, ObservableCollection, Package, NamedPipe und dem Namespace System.AddIn viele Neuerungen auch unter .NET 2.0 verwenden. So soll es sein. Und achja - Unit Testing kann ich jetzt auch ohne zusätzliche Software betreiben.

Übrigens habe ich bis heute noch nicht herausgefunden wie ich in diesem Blog ein syntax highlight aktiviere - komisch das google das nicht von haus aus drin hat.