Training - Beratung - Projektarbeiten

www.David-Tielke.de

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!

dotnetpro: Artikel “Besser mit Plan” in der Reihe “Pragmatische .NET Architektur” erschienen.

Heute ist die aktuelle dotnetpro 2/2015 erschienen. Mit dabei auch der erste Artikel von mir in einer dreiteiligen Serie zum Thema “Pragmatische .NET Architektur”. Im ersten Teil “Besser mit Plan”, geht es um die eigentliche Notwendigkeit einer Architektur und was das alles mit Softwarequalität zu tun hat. Dabei wird gezeigt, was ein Qualitätsmodell ist und was es genau auszeichnet. Am Beispiel des ISO/IEC 9126-Modells werden bestimmte qualitative Aspekte ermittelt, welche über verschiedene Projekte konstant sein sollten. Diese Aspekte werden in der anschließend (über die weiteren Teile der Serie) vorgestellten Architektur adressiert. Als erster Schritt wird dazu das zu entwickelnde Softwaresystem schrittweise Modularisiert um so zu einer mehrschichtigen Architektur mit Softwarekomponenten zu kommen. Der von mir auf Fachkonferenzen und UserGroups vorgestellt Ansatz der “Composite Components” ist das Ziel, was am Ende dieser Artikelserie erreicht werden soll.

Videotraining “Generics mit C#” bei video2brain erschienen

Generics mit C#_kleinHeute ist das Videotraining “Generics mit C#” bei video2brain von mir erschienen. Die mit C# 2.0 eingeführten Spracherweiterungen werden dabei sowohl grundlegend erklärt, als auch deren interna beleuchtet. Dabei ist der Fokus auf Fortgeschrittene und Profis gerichtet. Das Videotraining gibt es im Abo oder als Einzeltraining für 39,59€ bei video2brain .