Training - Beratung - Projektarbeiten

www.David-Tielke.de

C# Beispielprojekt zur CoCo Architektur jetzt auf GitHub

In den letzten drei Ausgaben der dotnetpro durfte ich in der Artikelserie zur "Pragmatischen .NET-Architektur" eine pragmatische Architektur vorstellen, die nicht nur in fast allen Projekten einsetzbar ist, sondern für Entwickler auch besonders einfach zu verstehen und kinderleicht umzusetzen ist. Das im letzten Teil entwickelte Beispielprojekt "KontaktManager" steht jetzt als Projekt auf GitHub zur Verfügung.

Zu dem Thema CoCo wird auf diesem Blog in Kürze eine Webcastreihe erscheinen, die Grundlagen und Praxiseinsatz beleuchten werden.

Links
CoCo KontaktManager C# auf GitHub

Welches Feature ich mir in C# 7.0 wünschen würde

Heute habe ich ein Webinar zu Thema “C# 6.0” bei developer-media durchgeführt, welches in 90 Minuten alle wesentlichen Neuerungen in der sechsten Version, von Microsofts Entwicklungssprache Nr. 1, beleuchtete. Dabei stellte einer der Teilnehmer am Ende eine sehr interessante Frage:

Welches Feature fehlt Dir in C# noch?

Eine interessante Frage wie ich finde, über die ich mir bisher noch nicht so wirklich Gedanken gemacht habe. Aber eigentlich musste ich nicht lange überlegen, denn mit der neuen Sprachversion hat Microsoft fast alles erfüllt, was ich mir gewünscht habe, bis auf einen wichtigen Punkt: Das validieren von Methodenparametern!

Wenn wirklich robuster und qualitativ hochwertiger Code geschrieben werden soll, sollten zu Beginn jeder Methode die Eingangsparameter auf Validität geprüft werden, d.h. Ist er null? Ist der String leer? Ist der Wert in einem gültigen Zahlenbereich?

public Person(string firstname, string lastname, int age)
{
    if (String.IsNullOrWhiteSpace(firstname))
        throw new ArgumentException(nameof(firstname));

    if (String.IsNullOrWhiteSpace(lastname))
        throw new ArgumentException(nameof(lastname));

    if(age < 1 || age > 120)
        throw new ArgumentException(nameof(age));

    // Eigentliche Aufgabe...
}

Ich versuche in allen meinen Projekten peinlichst genau darauf zu achten, dass diese Regel auch eingehalten wird. Dadurch treten Fehler direkt auf und nicht erst einige Module später, bei denen mit dem invaliden Wert gearbeitet wird. Dieser Luxus wird jedoch sehr teuer erkauft, durch sehr sehr komplexen Code. Eine Metrik für einfach zu verstehenden Code ist die zyklomatische Komplexität, welche die Anzahl der Ausführungspfade durch eine Methode angibt. Betrachtet man eine Methode mit 4 Parametern und prüft jeden Parameter nur auf ungleich null, ergibt sich bereits eine Komplexität von 4, ohne das eine Zeile Produktivcode geschrieben wurde. Hat eine Methode einen höheren Wert als 8, so gilt diese als sehr schwierig zu verstehen. Dadurch ergeben sich zahlreiche Nachteile wie schwierige Wartbarkeit, schlechte Verständlichkeit usw.

Darüber hinaus stellt sich mir die Frage, nach Sinn und Zweck, so etwas zu machen. Im Anweisungsblock der Methode sollte die eigentliche Aufgabe der Methode durchgeführt werden und dazu zählt es nicht, ob die Eingangswerte valide sind oder nicht. Genau genommen ist es sogar eine Verletzung des Single-Responsibility-Principles. Was ist also die logische Konsequenz? Das Ganze prüfen, bevor die Methode ausgeführt wird:

public Person(string firstname, string lastname, int age)
	ensure !String.IsNullOrWhiteSpace(firstname) 
			else throw new ArgumentException(nameof(firstname))
	ensure !String.IsNullOrWhiteSpace(lastname) 
			else throw new ArgumentException(nameof(lastname))
	ensure !(age < 1 || age > 120)
			else throw new ArgumentException(nameof(age))
{
	// Eigentliche Aufgabe...
}

Dadurch wird der Code nicht unbedingt lesbarer, aber die Aktivität der Parameterprüfung hat einen fest definierten Ort und der Methodenbody bleibt für die tatsächliche Aufgabe reserviert.

Das Konzept mag etwas an CodeContracts erinnern, in der Tat geht es auch in diese Richtung. Allerdings benötige ich für CodeContracts mindesten das .NET Framework 4.0, da sie nicht Bestandteil der Sprache, sondern des Frameworks sind. Die reine Parameterüberprüfung könnte durch Compiler-Magic in ganz normalem IL-Code resultieren, der sogar abwärtskompatibel wäre. Darüber hinaus werden in C# die CodeContracts in der Methode definiert:

public Rational(int numerator, int denominator) 
{ 
    Contract.Requires( denominator ! = 0 );

    this .numerator = numerator;
    this .denominator = denominator;
}

Eine viel bessere Lösung kommt von Microsoft selbst, in der Forschungssprache Spec# (Die aus C# entstanden ist), wurden die CodeContracts ähnlich umgesetzt, wie ich es mir für C# wünsche. Die Sprache wurde jedoch nur für die Umsetzung des Betriebssystem Singularity erstellt, welches komplett in Managed Code geschrieben wurde:

int ISqrt(int x) 
	requires 0 <= x; 
	ensures result*result <= x && x < (result+1)*(result+1); 
{ 
	int r = 0; 
	while ((r+1)*(r+1) <= x) invariant r*r <= x; 
	{ 
		r++; 
	} 
	return r; 
}

Leider wurde Spec# zusammen mit Singularity eingestellt und die Erkenntnisse davon offensichtlich nicht in C# übernommen.

Auch wenn C#  mit der Version 6.0 fast perfekt wird, würde ich mir eine Kombination aus den CodeContracts aus Spec# und abwärtskompatibler Compiler-Magic für C# 7.0 wünschen!

Videotraining "Visual Studio 2013 Grundlagen" bei video2brain erschienen

Am 19. September ist nach langer Zeit wieder ein Videotraining von mir bei Video2brain erschienen. Dieses Mal zeige ich in knapp 4 Stunden die wohl mächtigste IDE die es derzeit auf dem Markt gibt: Visual Studio 2013 von Microsoft. In sechs Kapiteln zeige ich u.a. wie man mit den Fenstern arbeitet, wie effektiv mit dem Codeeditor umgegangen wird und welche Tipps und Kniffe es beim Debuggen gibt. Für jeden der neu mit Visual Studio 2013 startet oder gerne einen schnellen Überblick über die Hauptfunktionen bekommen will, stellt das Training den idealen Einstieg dar.

In Zeiten von Tablets, Smartphones und Ultrabooks gibt es das Videotraining leider bei diesem Mal nicht als DVD, sondern nur als Download bei video2brain für 39,99€ oder im Trainingsabo.