|
Software: Projektmanagement, Architektur, Methoden. |
||
|
home blog 04. nov 04. okt 20. sep 25. aug 08. jun 30. mai 03. mai 02. feb 06. jan 2008 |
Weblog Archiv 2009Theda, 4.11.2009Am 30.10.2009 ist unsere Tochter Theda Johanna Riemenschneider um 21:04 Uhr zur Welt gekommen. Sie wog 3535g und ist 55cm lang. Wer Kinder hat und bei einer Geburt dabei war, dem brauche ich nichts zu sagen. Es ist von den Erlebnissen, die wir in unserer Gesellschaft so haben, das wohl wichtigste und um Längen beeindruckendste.Meine Frau und ich sind kurz vor der Geburt in dem Bonner Gemeinschaftskrankenhaus St. Elisabeth angekommen, keine zwei Stunden später war unsere Tochter da. Das Familienzimmer, das wir auf der Neugeborenenstation bezogen haben, hat uns in den ersten Tagen sehr viel Sicherheit gegeben. Alles was man braucht inkl. medizinischer Betreuung, sehr freundlichem Rat durch die Schwestern und Anmeldungsservice fürs Standesamt ist dort zusammen. Betreut wurden wir vorher, während der Geburt und jetzt durch den Bonner Hebammenladen, die mit dem Krankenhaus zusammenarbeiten. Sowohl bei den Hebammen als auch im Krankenhaus haben wir uns sehr wohl gefühlt! Jetzt genießen wir die neue Zeit zu dritt...
Oostende, 4.10.2009Da die Geburt unserer Tochter für Ende dieses Monats vorhergesagt ist, wollten wir die letzten Tage zu zweit noch mal für einen Ausflug nach Belgien nutzen. Diesmal hatte meine Frau Judith Oostende angepeilt, das ehrwürdige Seebad an Flanderns Küste.
Nach einem Stopp in Antwerpen zwecks Einkauf bei Stephan Schneider fanden wir Oostende in dem typisch belgischen Flair vor. Die Innenstadt war mit Fahrgeschäften förmlich ausgestopft und die Küste in gewohnter Manier verbaut. Was uns jedoch nicht davon abhielt, zwei noch sehr erholsame Tage dort zu verbringen. Selbst ein Minigolfplatz tauchte in De Haan aan Zee unverhofft auf, übrigens einer der wenigen Orte, an dem die Bauten am Strand weniger als fünf Stockwerke haben...
Performance Tipps zu Web Services, 20.9.2009Kommunikation über SOAP ist große Mode geworden, nicht zuletzt, da jede bedeutende Technologieplattform einen mehr oder minder ausgereiften SOAP-Stack bereithält. Nun ist SOAP fix auf XML gebunden, besser gesagt: auf das XML Infoset. Und auch REST, mit dem wegen seines einfachen Grundprinzips so mancher liebäugelt, kommt praktisch nicht ohne XML aus, obwohl beliebige Formate zulässig sind.Das Verarbeiten von XML ist teuer, Remote Kommunikation ist sowieso teuer, aber wir nehmen das in Kauf. Es ist für betriebliche Informationssysteme üblich, sparsamen Umgang mit Rechenzeit und Speicher zugunsten von Interoperabilität, Portabilität und Wartbarkeit entweder zu opfern oder mit mehr "Blech" zu ersetzen. Auch wenn Techniker gerne das Gesicht verziehen, angesichts anhaltend hoher Personalkosten und stetig fallender Preise pro Taktzyklus und Speichereinheit macht das Sinn. Manch ein Projektteam treibt das sorglose Spiel aber zu weit. Es entsteht Software, von der maßgeblich der Eindruck bleibt, dass sie nicht lasttauglich oder zu langsam ist und schlecht skaliert. Die ersten beiden Fragen, die ich stelle, wenn ich mir eine Meinung in einem solchen Fall bilden will, sind:
Zur ersten Frage treibt mich immer das folgende Bild, das die Aufrufzeiten für verschiedene Technologien vergleicht:
Man erkennt, dass ein Nachrichtenversand über das Netzwerk verglichen mit lokalen Methodenaufrufen extrem teuer ist, und solange wir in einem System davon unnötig viele haben, brauchen wir nicht weiter nach Optimierungsmöglichkeiten zu suchen. Durch Reduktion der Anzahl können wir ein gewaltiges Potential ausschöpfen. Abgesehen davon, dass diese Maßnahme meist aufwändig ist, weil sie verlangt, die beteiligte Software stark zu verändern, ist die Idee trivial, und hat insbesondere mit Web Services und XML nicht viel zu tun. Wo können wir aber speziell bei Web Services ansetzen, wenn diese erste Maßnahme noch nicht reicht? Hier meine zweitbesten Ideen:
HTTP 1.1 und Keep-Alive verwenden
Schemavalidierung in Produktion abschalten Kompression bei Kapazitätsproblemen Ist Netzwerkkapazität ein Flaschenhals, dann können sich die beteiligten Teilsysteme auf GZip Kompression und/oder Fast Infoset einigen, was sich vor allem bei großen Nachrichten deutlich auswirkt. Die Kompression benötigt natürlich mehr Rechenzeit, das muss man dann abwägen.
Teildekodierung von Nachrichten
MTOM für umfangreiche Binärdaten
Einsatz von WS-Security überdenken
Einsatz von Reliable Messaging überdenken Ganz gleich, was wir am Ende umsetzen, es ist entscheidend, Performanceprobleme früh zu entdecken, denn gerade eine Restrukturierung von Teilsystemen, so dass weniger Aufrufe stattfinden, will man nicht erst nach einem Integrationstest beginnen. Frühes Entdecken gelingt, wenn man
Verteilung auf Teufel komm' raus?, 25.8.2009Die Idee ist verführerisch: ein Service, einmal implementiert und in Betrieb genommen, bleibt als kleiner, autonomer Funktionsbaustein der Unternehmens-IT stets zur Verfügung. Er ist durch WSDL (fast) selbstbeschreibend und man kann ihn aus jedem Consumer heraus ansprechen. Künftige Anwendungen bedienen sich dieses Dienstes einfach, und schon verkürzt sich der Zeitraum, mit dem ein Unternehmen seine IT an geänderte Bedürfnisse anpassen kann.Nicht wenige Anwendungen werden heute mit Begeisterung nach SOA Prinzipien gebaut. Es findet eine Zerlegung in funktionale Komponenten statt, und -- schwupps -- jede Komponente ist ein eigenständiger Service mit einem entsprechenden Kontrakt. Dieses Vorgehen führt zu hochgradig verteilten Systemen. Doch Verteilung erzeugt immer Mehrkosten in Form von Komplexität, Laufzeiteinbußen und wahrscheinlich zusätzlichen Betriebskosten, z.B. durch erforderliche Sicherheitsmaßnahmen, aufwändigere Installation, zusätzliches Monitoring und Application Management (vgl. hierzu Eight Fallacies und Eight Fallacies explained).
Mit SOA scheinen diese realen Probleme wieder in den Hintergrund zu treten, doch sie sind weiterhin vorhanden. Es ist also gefährlich, ohne klare Kriterien, wie Komponenten verteilt werden sollten, nur nach funktionalen Gesichtspunkten zu entscheiden. Aber wie können solche Kriterien aussehen? Die mir bekannte Literatur zu Software Design und SOA gibt mir keinen ausreichenden Aufschluss, also unternehme ich hier mal einen eigenen Versuch: Wenn wir in einem groben Design eines neuen Systems nach Prinzipien wie Separation of Concerns mehrere funktionale Komponenten identifiziert haben, wie können wir dann entscheiden, wie wir diese auf verschiedene Teilsysteme verteilen wollen?
Schritt 1:
Schritt 2:
Schritt 3:
a) und b) "ziehen" Komponenten also in verschiedene Teilsysteme, c) bis e) "drängen" sie wieder zusammen oder veranlassen uns zumindest, über Workarounds nachzudenken. Ich plädiere also dafür, solche Komponenten in einem Teilsystem zusammenzufassen, denen Fachlichkeit, Lebenszyklus und nicht-funktionale Anforderungen gemeinsam sind. Ein solches funktional und nicht-funktional kohäsives Stück Software kann dann natürlich nach außen verschiedene Servicekontrakte anbieten, d.h. wie verschiedene Services wirken. Innerhalb dieses Teilsystem gelten weiterhin die üblichen Regeln modularen Software Designs.
Das Design eines verteilten Systems ist also schwieriger, da mehr Gesichtspunkte zu berücksichtigen sind als in nicht verteilten Systemen. Man sollte sich allein deshalb gut überlegen, ob SOA mit allen Konsequenzen das richtige Paradigma für eine neu zu bauende Anwendung ist. Wer glaubt, Verteilung würde die verabscheuungswürdigen "Monolithen" und "Silos" der "alten Welt" in Zukunft verhindern, der wird sich in einer noch unangenehmeren Softwarewelt wiederfinden, in der sich die Probleme unwartbaren Programmcodes mit den Schwierigkeiten verteilter Systeme verbündet haben.
Ötztal, 8.6.2009Die Schwangerschaft meiner Frau hielt uns nicht von einer Woche Wandern im östereichischen Ötztal ab. Wir ließen es aber deutlich ruhiger angehen als in unserem letzten Tirolurlaub, zumal Anfang Juni noch nicht viele Bergbahnen im Sommerbetrieb sind. Statt also viele hundert Höhenmeter zu laufen, verlegten wir uns mehr auf ausgedehnte Spaziergänge und nutzten meist nachmittags die in Längenfeld gelegende Therme zum Schwimmen und Entspannen.
Zürich, 30.5.2009Auf unserem Weg ins Ötztal haben wir uns für einen Besuch von Freunden und deren Wahlheimat Zürich entschieden. Die Stadt ist wirklich ein hübscher Flecken Erde, wobei die Sonne an diesem Tag sich mächtig ins Zeug legte, um auch die letzte Ecke zum Strahlen zu bringen.
Antwerpen, 3.5.2009In diesem Mai haben wir Judiths Onkel, der für uns im September 2008 ein sehr schönes Wanderwochenende in der Luxemburger Schweiz organisiert hatte, sowie seine Frau und meinen Schwiegervater nach Antwerpen eingeladen. Zwecks Übernachtung hatte meine Frau die Zimmer in Aan de Keizer BnB gebucht, um von dort aus ein kleines Touristenpflichtprogramm zu absolvieren: Plantin-Moretus-Museum, Rubenshuis, Onze-Lieve-Vrouwekathedraal und einige Verkaufshäuser für Mode sowie der Besuch guter Restaurants.
Meine erste selbstgebaute Sprache, 2.3.2009Während der Feiertage des Jahreswechsels 08/09 wollte ich Xtext ausprobieren, denn aufgrund der Arbeiten unserer Kollegen in Kiel und Stuttgart sowie meiner Lektüre der Veröffentlichungen von Martin Fowler und Martin Ward hielt ich es für dringend erforderlich, mir selbst ein praktisches Gefühl für LOP, also den Bau von domänenspezifischen Sprachen zu verschaffen.Wie aufwändig ist sowas? Welche "besonderen Fähigkeiten" werden verlangt? Und wie gut funktionieren die Werkzeuge dazu, allen voran natürlich oAW und Xtext? Meine persönlichen Voraussetzungen halte ich für durchschnittlich. Sehr gute OO Programmierkenntnisse, aber kaum theoretisches Wissen zum Compilerbau. Praktischer Generatorbau auf Basis von oAW hatte ich auch erst im Rahmen eines itemis internen Powerworkshops besser kennengelernt, Xtext war mir jedoch völlig neu. Dafür kannte ich die von mir gewählte Domäne ganz gut.
Domäne: User Interface
Durchaus Popularität findet dieses Rich Client Muster lustigerweise im Web Frontend Bereich, nämlich bei JavaServer Faces. Hier heißt das PresentationModel dann BackingBean, aber die Rollenverteilung bleibt wie bei Fowler beschrieben. Die Anwendung dieses Musters führt dazu, dass man je fachlichem "Formular" zwei Klassen schreiben muss: die eine enthält Daten und Logik, die andere die Widgets und das Layout. Zusätzlich braucht's noch ein Stückchen konfigurierenden Code, der die Instanzen der beiden zusammenführt. Die folgenden Kästen zeigen das Model und die View. Presentation Model:
public class EmployeeDetailsModel extends SingleViewPresentationModel {
public EmployeeDetailsModel (Employee employee) {
super();
this.employee = employee;
initialize();
}
public void initialize () {
registerField(new DefaultField(TITLE,
String.class,
ManagedField.GET,ManagedField.SET));
registerField(new DefaultField(EMPLOYEE_FIRSTNAME,
String.class,
ManagedField.GET,ManagedField.SET));
registerField(new DefaultField(EMPLOYEE_LASTNAME,
String.class,
ManagedField.GET,ManagedField.SET));
registerField(new DefaultField(EMPLOYEE_POSITION,
String.class,
ManagedField.GET,ManagedField.SET));
registerField(new DefaultField(OKBUTTONTEXT,
String.class,
ManagedField.GET,ManagedField.SET));
}
protected Employee employee;
public Employee getEmployee () {
return employee;
}
public void setEmployee (Employee employee) {
this.employee = employee;
}
protected String title;
public String getTitle () {
return title;
}
public void setTitle (String title) {
this.title = title;
}
protected String okButtonText;
public String getOkButtonText () {
return okButtonText;
}
public void setOkButtonText (String okButtonText) {
this.okButtonText = okButtonText;
}
Java Swing View:
public class EmployeeDetailsView extends JDialog implements ManagedView {
public EmployeeDetailsView () {
super();
initialize();
}
public void initialize () {
JPanel contentPane = new JPanel();
double sizes[][]={
{10,80,layout.TableLayout.FILL,10},
{10,22,22,22,layout.TableLayout.FILL,32,10}
};
contentPane.setLayout(new layout.TableLayout(sizes));
contentPane.add(getFirstnameLabel(), "1,1");
contentPane.add(getEmployeeFirstnameTextfield(), "2,1");
contentPane.add(getLastnameLabel(), "1,2");
contentPane.add(getEmployeeLastnameTextfield(), "2,2");
contentPane.add(getPositionLabel(), "1,3");
contentPane.add(getEmployeePositionTextfield(), "2,3");
contentPane.add(getPanel3Panel(), "1,5,2,5");
setContentPane(contentPane);
setTitle("");
setMinimumSize(new Dimension(300,150));
setModal(true);
pack();
}
private ViewSupport viewSupport;
public void setup(ViewSupport vs) {
viewSupport = vs;
viewSupport.register(EmployeeDetailsModel.EMPLOYEE_FIRSTNAME,
new TextfieldSynchronizer(getEmployeeFirstnameTextfield()));
viewSupport.register(EmployeeDetailsModel.EMPLOYEE_LASTNAME,
new TextfieldSynchronizer(getEmployeeLastnameTextfield()));
viewSupport.register(EmployeeDetailsModel.EMPLOYEE_POSITION,
new TextfieldSynchronizer(getEmployeePositionTextfield()));
viewSupport.register(EmployeeDetailsModel.OKBUTTONTEXT,
new ButtonTextSynchronizer(getOkButton()));
viewSupport.register("ok",
new SwingManagedAction(getOkButton(),""));
viewSupport.register("cancel",
new SwingManagedAction(getCancelButton(),"Cancel"));
viewSupport.register(EmployeeDetailsModel.TITLE,
new WindowTitleSynchronizer(this));
viewSupport.registerComponents(this);
}
public Object getComponent () {
return this;
}
private JLabel firstnameLabel;
public JLabel getFirstnameLabel () {
if (firstnameLabel == null) {
firstnameLabel = new JLabel();
firstnameLabel.setText("First name");
}
return firstnameLabel;
}
private JTextField employeeFirstnameTextfield;
public JTextField getEmployeeFirstnameTextfield () {
if (employeeFirstnameTextfield == null) {
employeeFirstnameTextfield = new JTextField();
employeeFirstnameTextfield.setName("employeeFirstname");
}
return employeeFirstnameTextfield;
}
. . .
}
Gedanklich bleiben die Klassen natürlich eine Einheit, und es wäre praktisch, ein Formular fachlich kompakt spezifieren zu können, so dass die architekturgemäße saubere Trennung in zwei Artefakte von einem Generator übernommen wird. Meine User Interface Language sollte z.B. folgende Ausdrücke erlauben, die ich für UIs immer noch als ausreichend intuitiv erachte, also z.B. für obiges Beispiel dann so:
form EmployeeDetails (
binding(employee:de.itemis.hoa.cleanmvc.samples.bo.Employee)
dialog(title:String size[300 150])
layout(table columns[gap label fill gap] rows[gap input input input fill button gap])
elements(
c("1,1 ") label "First name"
c("2,1 ") textfield binding(employee.firstname:String)
c("1,2 ") label "Last name"
c("2,2 ") textfield binding(employee.lastname:String)
c("1,3 ") label "Position"
c("2,3 ") textfield binding(employee.position:String)
c("1,5,2,5") panel flow right (
button binding(okButtonText:String) >ok
button "Cancel" >cancel
)
)
)
Vom Wunsch zur Wirklichkeit1. Hello World Ich habe erstmal ohne lange zu überlegen den New Xtext Project Wizard verwendet. Und siehe da: das Eclipse Projekt Grundgerüst hatte ich nach gefühlten drei Mausklicks zusammen. Ich habe in der Xtext Grammatikdefinition zwei, drei Ausdrücke hingeschrieben, über Rechtsklick Generate Xtext Artifacts ausgelöst, der Grammatik entsprechend ein "Programm" formuliert und im Generator in einem Template zur Verifikation durch das Programm definierte Elemente ausgegeben. Nach Starten des oAW Workflow hatte ich meine "Hello World" Testausgabe. Das alles hat nicht länger als 30 Minuten gedauert.
2. Struktur
3. Vorbild
4. Viele Iterationen
Fazit Magische Fähigkeiten musste ich nicht entwickeln, die Xtext Grammatik ist schnell gelernt, und sowohl Extend als auch Xpand erweisen sich bei intensiver Arbeit wie eine gut bestückte und sich selbst erweiternde Werkzeugkiste. Es gilt hier noch viel stärker als bei sonstiger Programmierung, dass man redundanzfrei codieren muss, denn nur dann ergibt sich eine elegante Sammlung von Extensions für die Transformation und Generierung. Es hat sich als unumgänglich erwiesen, eine glasklare Architektur in einem sauberen Prototypen zu haben, sonst wird man zum Kapitän ohne Kompass. Zudem muss man bewusste Entscheidungen treffen, wo man Komplexität unterbringen will:
Abschliessend kann ich sagen, dass da ein fantastischer Werkzeugkasten verfügbar ist, um Projekten in Sachen Produktivität und Durchsetzung von Architekturen ohne Monate dauernde "Forschungsarbeit" zu einem echten Quantensprung zu verhelfen.
Code Reviews, 6.1.2009Seit ich Software entwickle, hat sich nichts daran geändert, dass der Code das langlebigste maßgebliche Resultat von Softwareprojekten ist. Dokumentation ist wichtig, nutzt aber wenig, wenn die Codebasis faulig oder zerbrochen ist, denn die Mühe bei der Fehlersuche oder Erweiterung wächst und oder schrumpft mit dem Grad der Verrottung des Codes und nicht mit der Menge Prosa, mit dem das (traurige) Werk beschrieben ist.Toolgestützte, statische Codeanalyse z.B. bzgl. Paketabhängigkeiten oder CCN hilft, manche Auffälligkeiten sehr schnell zu finden. Aber eben nicht alle. So Dinge wie chaotisches Logging mit mißverständlichen Meldungen, löchriges Exception-Handling, mögliche Race Conditions, subtile Formen von Codeduplikation, Algorithmen mit hoher Laufzeitkomplexität, Overengineering oder schlicht aussageloses Javadoc sind auch 2009 kaum durch Maschinen aufdeckbar. Und die genannten Probleme sind meist nicht im Handstreich zu beseitigen, sondern können eine teure Überarbeitung erfordern. Es gibt leider manche Programmierer, die diese Fehler haarsträubend konsequent einbauen. Das sind meist diejenigen Kollegen, die noch lernen. Solche Programmierer sind nicht in Ihrem Team? Sicher? Na, dann führen Sie wohl öfter Code Reviews durch, denn die Erfahrung ist im Code ablesbar, so einfach ist das. Nie Reviews durchzuführen heißt dagegen, auf Glück zu bauen, was in der Softwareentwicklung selten gut geht. In den Code Reviews, die ich durchführe, finde ich die folgenden Punkte besonders häufig:
Was ist mit der Prüfgrundlage, bspw. ein Code Styleguide, oder eine projektspezifische Beschreibung, worauf zu achten ist? Hm, schwierig. Schon sinnvoll, wenn es Eigenheiten des Projekts gibt, die sich niemand selbst herleiten kann, z.B. dass alle Instanzvariablen mit einem Unterstrich beginnen sollen, oder man immer Spaces statt Tabs zu verwenden hat. Aber dieser Styleguide kann nur ein Add-on auf den gesunden Verstand sein, sonst müsste man statt den Code zu prüfen erstmal eine dreibändige Abhandlung über das Programmierhandwerk verfassen. Vielmehr Sinn macht dagegen der Verweis auf einige Bücher, z.B.:
|
||