Die erste See# Party ist für dieses Jahr vorbei und die Leser dieses Beitrages – welche die wunderbare Session von Rainer Stropek nicht gesehen haben – werden sich vielleicht wundern was das für ein blöder Titel ist ;-)
(“LINQ ist wie eine Taube…” und Extension Methods sind die “Kuckuckseier” die anderen Klassen untergejubelt werden können)
Wie habe ich die See# Party erlebt?
Es waren für uns drei Tage pure Action :-) Insgesamt gesehen hat es – trotz aller Pannen, die es aus meiner Sicht gab – dennoch irgendwie Spaß gemacht. Aber ich werde mich nicht nochmal überreden lassen eine eigene Session zu machen, wenn ich eine solche Veranstaltung organisiere. Mit dem Kopf bei der Veranstaltung, aber nicht bei der Session zu sein, ist sowohl anstrengend für die Besucher der Session, als auch für den Speaker…
Die Erfahrung war es allerdings absolut wert diese Veranstaltung zu machen. Den Spaß an der Sache hatte ich aber bei den Gesprächen mit den Teilnehmern und Speakern. Spaß macht es auch wenn hochkarätige Speaker wie Laurend Bugnion tatsächlich den Weg auf sich nehmen um auf der See# Party zu sprechen. Wenn Speaker aus der deutschsprachigen Community kommen um Vorträge zu halten. Und auch wenn neue Speaker die Möglichkeit nutzen, ihre erste Session auf einer Konferenz zu halten.
Spaß macht es auch, wenn man gerade zur rechten Zeit in eine Session kommt, in der Reiner Stropek LINQ zu einer Taube mit Kuckuckseiern macht. (@Rainer: ich finde den Vergleich sowohl absolut passend als lustig) Spass macht es auch, wenn Golo Roden die KeyNote zu ALT.NET genau so hält, wie man sie sich vorgestellt hat. (Es gab keine Absprache über das WIE, nur das Thema selber)
Bestätigt wird man auch, wenn Thomas Scheuermann trotz Sintflut in Nürnberg und überschwemmten Keller, die Reise auf sich nimmt um seine Session zu halten und anschließend wieder nach Hause fährt um den Keller wieder in Ordnung zu bringen. (@Thomas: vielen, vielen, vielen Dank dafür. Mehr weiß ich einfach nicht zu sagen *sprachlos*)
Leider habe ich nicht alle Sessions besuchen können... Aber dem Feedback nach, hätten sehr viele Leute gerne mehr als nur vier Sessions besucht. Auch das ist eine Bestätigung dass die Auswahl der Themen und der Sprecher tatsächlich gelungen ist. Auch das wurde mir immer wieder gesagt. Leider konnte ich auch keine der Sessions komplett besuchen, sondern bin mit meiner kleinen Kamera von einer Session zu anderen um noch ein paar Erinnerungen aufzufangen (Die Bilder werde ich in einer Wochen auf der Website publizieren)
#ssp2011?
Wie man aus dem obigen Text vielleicht lesen mag, geht der Trent zu einer See# Party 2011: Einer .NET Community Konferenz für den südlichen Raum der deutschsprachigen .NET Community (Süddeutschland, die Schweiz, Vorarlberg und Liechtenstein)
Darüber werde ich in den nächsten Tagen ausführlich nachdenken. Diese See# Party war durch die viel zu kurze Planungszeit enorm schwierig und chaotisch. Auch wurden unsere Erwartungen dadurch an manchen Stellen nicht komplett erfüllt. (Vor allem durch die viel kleiner Teilnehmerzahl wird es enorm schwierig sein die Kosten zu decken)
Es gibt auf jeden Fall eine große Liste mit Dingen die beim nächsten Mal besser gemacht werden können und müssen.
In acht Tagen werden wir uns wieder zusammensetzen und darüber reden, wie diese allererste See# Party war und wie es mit weiteren See# Partys weiter gehen könnte. Bis dahin bin ich auf einer Berghütte in der Schweiz, ohne Strom, ohne Internet und ohne Telefon. :-)
In der Vergangenheit habe ich in vielen Projekten, vielen Anwendungen und auch hier im Forum immer wieder die gleichen Fehler bei der Fehlerbehandlung gesehen, was mich dazu veranlasst diesen Beitrag hier zu schreiben.
Im Grunde ist es immer folgender Fehler der beim Try&Catch gemacht wird:
try
{
[do some errors]
}
Catch (Exception ex)
{
log.Error(“Meine super duper Fehlermeldung”);
throw ex;
}
Das ist dann keine Fehlerbehandlung, sondern eher Fehler verstecken!
Oftmals wird dieses Konstrukt (“Fehlerbehandlung” mochte ich es nicht nennen) in jeder Methode genutzt die aufgerufen wird. Das hat dann den Effekt, dass dieses Konstrukt logisch wie folgt verschachtelt wird:
try
{
try
{
try
{
try
{
[do some errors]
}
Catch (Exception ex)
{
log.Error(“Meine erste super duper Fehlermeldung”);
throw ex;
}
}
Catch (Exception ex)
{
log.Error(“Meine zweite super duper Fehlermeldung”);
throw ex;
}
}
Catch (Exception ex)
{
log.Error(“Meine dritte super duper Fehlermeldung”);
throw ex;
}
}
Catch (Exception ex)
{
log.Error(“Meine vierte super duper Fehlermeldung”);
throw ex;
}
Oftmals wird wenigstens die aktuelle Exception dem Logger übergeben:
Catch (Exception ex)
{
log.Error(“Meine vierte super duper Fehlermeldung”, ex);
throw ex;
}
Aber auch das ist nur die halbe Miete.
Was soll da falsch sein ?
Schauen wir uns nochmal das erst Stück Code an. Angenommen es passiert ein Fehler und das Programm, springt in den Catch-Teil. Jetzt geht der Unsinn los:
- Es wird eine Unsinnige Fehlermeldung ausgegeben!
Warum?
Falls die Meldung noch relevant sein sollte, enthält sie keine weiteren Informationen zu der eigentlichen Exception. Im Normalfall wurde der Code allerdings im Laufe der projektphase immer wieder geändert, was zur Folge hat, das die Nachricht längst nicht mehr stimmt oder es gibt inzwischen mehrere mögliche Fehlerquellen.
- throw ex ist der nächste grobe Fehler: es wird zwar die selbe Exception noch einmal geworfen, mit der selben Fehlermeldung, allerdings wird der immens Wichtige StackTrace abgeschnitten (“breaking the stack”). Der StackTrace beginnt ab der Methode in der throw ex aufgerufen wird. Sollte der Fehler in einer aufgerufenen Komponente auftauchen, kann das nicht mehr ermittelt werden. Es wird immer so aussehen, als wäre der Fehler in der aktuelle Methode aufgetreten, und zwar genau dort, wo thro ex aufgerufen worden ist. Genauso wie der StackTrace geht auch die InnerEception verloren (Danke an Peter für den Hinweis.)
- Selbst wenn die Exception an den Logger übergeben wird ist die Fehlerbehandlung unvollständig, denn es wird nur ein unvollständiger StackTrace gelogt.
Im Falle der verschachtelten Try&Catches sieht das so aus, dass 1. keine relevanten Fehlerinformationen geloggt werden und 2. jedes Mal der StackTrace bei jedem Catch von neuem beginnt.
Diese Fehlerbehandlung ist somit keine, sondern eine Selbsttäuschung.
Das wird man spätestens dann merken, wenn man als Entwickler vom Support die Meldung über einen Fehler bekommt und dann das Log-File analysieren muss. Ich wette das viele Fehler nicht per Log-File gefunden werden können.
Was ist zu tun?
Im ersten Schritt sollten alle throw ex Aufrufe durch ein einfaches throw ersetzt werden. Das führt dazu, dass die aufgetretene Exception genau so wie sie ist, nach “oben” weitergeleitet wird. Dann sollte das Logging angepasst werden: Bei einem einfachen Try&Catch sollte das Logging – wenn möglich – so geändert werden, dass die Exception an den Logger übergeben wird (Die meisten Logger sollten das Unterstützen):
try
{
[do some errors]
}
Catch (Exception ex)
{
log.Error(ex);
throw;
}
Im Fall der Verschachtelten Try&Catches wird nun noch an jeder Stelle in das Log geschrieben. Das ist nicht sinnvoll, das dadurch das Log sehr groß werden kann und die Informationen mehrfach im Log vorhanden sind. Es sollte also nur an einer Stelle geloggt werden und zwar am besten ganz oben, beim letzten Try&Catch.
In ASP.NET kann das sogar in der global.asax bei Application_Error gemacht werden.
Die verschachtelten TryCatches sehen dann logisch wie folgt aus:
try
{
try
{
try
{
try
{
[do some errors]
}
Catch (Exception ex)
{
throw;
}
}
Catch (Exception ex)
{
throw;
}
}
Catch (Exception ex)
{
throw;
}
}
Catch (Exception ex)
{
log.Error(ex);
HandleTheException();
}
Im letzten Catch wird dann die eigentliche Fehlerbehandlung gemacht: Es wird dem Benutzer eine sinnvolle Meldung ausgegeben (Nicht die Fehlermeldung, mit der kann der Benutzer nichts anfangen!)
Nach diesem Refactoring, sollte man sich fragen welche Try&Catches dann noch Sinn machen, wen nichts anderes Passiert, als die Exceptions durchzureichen. Ich bin ganz sicher, dass man einige nun Entfernen könnte.
Generell sollte man nicht grundlos alle möglichen Fehler abfangen, sondern in erster Linie Fehler vermeiden. Natürlich gibt es Stellen, bei denen man Fehler nicht Verhindern kann, das ist immer dann der Fall, wenn man aus seiner Anwendung raus auf etwas zugreift: Datenbank und Dateizugriffe, Web- und Webservice-Zugriffe, COM, etc.
Auf diese Art hat man nun schon mal eine relativ saubere Fehlerbehandlung.
Aber es geht immer noch besser:
An Stellen, an denen mögliche Fehler nicht verhindert werden können, können diese abgefangen und mit einer eigenen Exception nach “oben” weitergeben werden. Die ursprüngliche Exception wird dabei als InnerException mitgegeben:
Catch (Exception ex)
{
throw new MyVeryOwnHttpException(ex)
}
So kann man in der Darstellungsschicht individuell auf die Fehler reagieren und dem Benutzer einen entsprechenden Hinweis geben:
Catch (MyVeryOwnHttpException ex)
{
log.Error(ex.InnerException);
HandleTheVeryOwnHttpException(“Die Verbindung zum Server konnte nicht hergestellt werden.\n Bitte prüfen Sie ob Sie mit dem Internet Verbunden sind.\nUnd so weiter und so fort”, ex);
}
Man kann so spezielle Arten von Ausnahmen zusammenfassen und entsprechend drauf reagieren. Es ist dem Anwender in der Regel egal, was der genaue Fehler ist. Ob das jetzt ein Verbindungsfehler ist oder der Server einen Fehler zurückgibt ist egal. Wichtig ist, dass in diesem Fall die Anwendung nicht mit dem Server kommunizieren kann.
In der Log-File steht auf jeden Fall der konkrete Fehler mit dem kompletten StackTrace und die Fehlersuche wird dadurch wesentlich vereinfacht.
In den vergangen Monaten habe ich einiges theoretisches über Event Based Components (kurz EBCs) gelesen. Das meiste von Ralf Westphal, in seinem Blog oder aus seiner Feder in der dotnetpro. Auch Golo Roden schrieb in seinem Blog über das Thema.
Verwirrung
Angespornt durch die Beiträge habe ich in den letzten Wochen selber versucht EBCs zu schreiben und zu entwickeln und bin zuerst gescheitert. Sobald ich die ersten Komponenten geschrieben und “zusammengesteckt” hatte, verlor ich relativ schnell den Überblick über die Komponenten und deren Verbindungen.
Woran lag das?
Golo wies mich auf die fehlerhafte Benennung der Events in Ralf Westphals Beispielen hin, die entgegen dem .NET Framework mit dem Präfix “On” begannen.
Ich habe also von vorne begonnen und die Events wie im .NET-Framework üblich benannt.
Beispiel:
public event Action<Customer> EntitySaving (wird vor dem Speichern ausgelöst)
public event Action<Customer> EntitySaved (wird nach den Speichern ausgelöst)
Und siehe da: die Verwirrung war beseitigt :-)
Vorteile
Die Vorteile der EBCs sind klar und wurden in den oben genannten Beiträgen auch oft genug angesprochen. Die zwei größten Vorteile sind – aus meiner Sicht – zum einen die isolierte Testbarkeit der Komponenten und die flexible Möglichkeit die Komponenten zusammenzuführen.
Refactoring
In den letzten Wochen habe ich also meinen angehenden Lizenz-Manager, einem großen Refactoring unterzogen und auf EBCs umgebaut. Ich habe allerdings vorerst meine Service-Klassen nicht komplett auseinandergerissen. Also nicht fürs Speichern, Löschen und Lesen separate Komponenten gebaut (das wäre dann der nächste schritt), sondern es bei jeweils einer Komponente mit standardmäßig drei Input- und drei Output-Pins belassen. Ich habe lediglich die generische Validierung komplett entkoppelt und dafür eine weitere Komponente angelegt, die vor jedem Speichern “eingesteckt” werden kann.
Die vorhandenen Unit-Tests musste ich leicht anpassen. Die Tests für die Servies, die hauptsächlich die Validierung getestet haben konnte ich entfernen und in die Test für die Validator-Komponente aufnehmen. Die Tests sind alle kleiner geworden, da Abhängigkeiten gar nicht mehr berücksichtigt werden müssen, wenn sie nicht zusammengesteckt worden sind. Beispiel: Die Service-Methode zum Speichern, muss keine Validierung mehr testen. Und die Tests der Validierung ist unabhängig vom Speichervorgang.
[TestFixture]
[Category("GO.LicenceManager.Services.ModelValidator")]
public class Wenn_ein_Kunde_validiert_wird
{
[Test]
public void darf_der_Vorname_nicht_fehlen()
{
Customer customer = new Customer
{
[….]
};
IModelValidator<Customer> modelValidator = new ModelValidator<Customer>();
Assert.Throws<PropertyNotSetException<Customer>>(
() => modelValidator.Validate(customer),
"'Name' must not be null or empty");
}
}
public class ModelValidator<T> : IModelValidator<T> where T : IEntity
{
public void Validate(T model)
{
Type type = typeof(T);
IEnumerable<PropertyInfo> propertyInfos = type
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
[….]
}
}
public class CustomerService : ICustomerService
{
private readonly ICustomerRepository _customerRepository;
public CustomerService(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
public void Save(Customer customer)
{
OnEntitySaving(customer);
if(customer.Id==Guid.Empty)
{
customer.Id = Guid.NewGuid();
}
_customerRepository.Save(customer);
}
public event Action<Customer> EntitySaving;
public void OnEntitySaving(Customer entity)
{
var entitySaving = EntitySaving;
if (entitySaving != null)
{
entitySaving(entity);
}
}
[….]
}
Zusammenstecken:
Customer customer = new Customer
{
[….]
};
IModelValidator<Customer> validator = new ModelValidator<Customer>();
ICustomerService customerService = new CustomerService(customerRepository);
customerService.EntitySaving += validator.Validate; // <== zusammenstecken
customerService.Save(customer);
Die Tests hätten wir damit vereinfacht, die Komponenten müssen sich nicht mehr kennen und sind komplett entkoppelt. Die Komponenten müssen aber irgendwie und irgendwo zusammengeführt werden, um zu funktionieren.
Die Komponenten müssen “zusammensteckt” werden.
Dabei ist entweder Handarbeit und eine gute Dokumentation gefordert, oder man versucht das zu automatisieren. Ralf Westphal hat dafür einen EBC-Binder geschrieben, der allerdings nur funktioniert, wenn gewisse Konventionen eingehalten werden: Unter anderem müssen die Events eben mit dem Präfix “On” beginnen…
Ich werde hierfür wahrscheinlich eine Art Binding-Datei anlegen die im XML-Format nicht nur das Binding selber regelt, sondern dieses auch dokumentiert. Mal sehen, was sich so machen lässt :-)
Vorerst werde ich im Lizenz-Manager allerdings noch die Repositories und die verschiedenen Views implementieren müssen. Bis zur See# Party werde ich wohl aber nicht mehr dazu kommen…
.NET unterscheidet zwischen Referenz-Typen und Wert-Typen. Was bei vielen Entwicklern, die das nicht wissen oder beachten, zu kleineren Verwirrungen führen kann.
Aber zuerst einmal die Definition:
Werte-Typen sind zum Beispiel System.Int32 und System.Boolean welche im .NET-Framework vordefiniert sind. Eigene Structs und Enums sind ebenfalls Wertetypen. Strukturen sind auch dann Werte-Typen, wenn sie selber Referenz-Typen beinhalten.
Referenz-Typen sind Objekte mit Klassen oder Interfaces deklariert werden.
Wichtig: Referenz-Typen halten immer nur einen Zeiger auf die eigentlichen Werte
Lektüre:
Referenz- und Wertetypen
Werttypen im allgemeinen Typsystem
Arbeiten mit .NET: Grundlagen: Wertetypen und Verweistypen
Referenz- und Wert-Typen: Was ist der Unterschied in .NET?
Da Referenz-Typen nur Zeiger sind, kommt es zur Verwirrung, wenn Referenz-Typen als Wert (VB.NET: ByVal) an Funktionen und Methoden übergeben werden. Da lediglich der Zeiger übergeben wird, kann das Objekt auch außerhalb er aufzurufenden Methode verändert werden. Das hat das gleiche Verhalten, wie bei Werte-Typen die als Referenz (VB.NET: ByRef; C# ref) übergeben werden.
Wieso die Verwirrung?
Da die Schlüsselworte ByRef und ByVal in VB.NET immer explizit angegeben werden müssen, werden sie natürlich auch immer genutzt, sind immer sichtbar. Man nutzt ByRef deshalb viel zu oft, ohne zu wissen, dass es oftmals gar nicht nötig ist.
In C# muss das Schlüsselwort ref dagegen nur angegeben werden, wenn wirklich etwas als Referenz übergeben werden muss. Das hat zur Folge, dass dieses Schlüsselwort nicht permanent sichtbar ist, man macht sich weniger Gedanken über die Art der zu übergebenden Parameter.
Also merken: In VB.NET kann ByVal eben auch ByRef sein, wenn es sich bei dem TypParameter um einen Referenz-Typ handelt! ;-)
So langsam geht es bei der See# Party in die Endphase und wir haben tatsächlich noch ein paar freie Plätze, für die man sich noch unbedingt anmelden sollte, wenn man die tollen Themen nicht verpassen möchte (Das war ein Befehl, keine Bitte!). Um die Sache noch spannender zu machen haben wir uns entschlossen eine kleine Blog-Parade zu starten und hiermit auch eine Gewinnspielaktion und eine Blog-Parade anzukündigen.
Gewinnspielaktion
Wer sich am Mittwoch den 18. August 2010 ab 09:00 Uhr zur See# Party anmeldet, hat die Möglichkeit
- eines von sechs See# Party T-Shirts und
- einen freien Zugang zur See# Party zu gewinnen
Die ersten sechs Anmeldungen erhalten jeweils ein See# Party T-Shirt, wobei die erste Anmeldung zusätzlich den freien Zugang zur See# Party erhält.
Wer meint das sei es nicht wert, sollte die Agenda nochmal ganz genau studieren ;-)
Sobald die Gewinne vergeben sind, werden die Gewinner hier auf meinem Blog veröffentlicht und per E-Mail benachrichtigt.
Blog- und Twitter-Parade
Unter allen Bloggern und Twitterern, die sich auch zur See# Party anmelden verlosen wir zwei freie Zugänge zur See# Party unter allen anderen werden wir zwei See# Party T-Shirts verlosen.
Die beiden Paraden enden am Mittwoch den 18. August um 12:00 Uhr Mittags.
Die Gewinner werden per Zufallsgenerator ausgelost und hier auf meinem Blog veröffentlicht.
Blog-Parade:
Für die Blog-Parade ist nichts anderes zu tun, als auf die kommende See# Party (wenn möglich mit Banner) und diese Gewinnspielaktion hinzuweisen. Dafür kann der obige Text einfach kopiert und entsprechend angepasst werden.
Wie üblich müssen die Blog-Beiträge auch auf den ursprünglichen Beitrag (also hier her) verlinken.
Sollte aus irgendeinem Grund kein automatischer Link in den Kommentaren eingefügt werden, schreibt einfach selber einen Kommentar mit einem Link auf euren Beitrag rein, oder schickt mir eine kurze E-Mail mit dem Hinweis auf euren Artikel (in diesem Fall setze ich den Kommentar persönlich)
Twitter-Parade:
Wer nicht mehr als 140 Zeichen am Stück hinbekommt, kann auch gerne per Twitter an der Parade Teilnehmen. Dazu einfach folgenden Text kopieren und twittern:
Gewinnspiel zur See# Party: Sechs T-Shirts und ein freier Eintritt zu gewinnen: http://tinyurl.com/26rjesq #ssp2010 #parade
Erklärungen und Kleingedrucktes
- Teilnahmeberechtigt an der Verlosung und der Blog- und Twitter-Parade ist jeder, ausgenommen die Veranstalter der See# Party und deren Angehörige.
- Jeder Teilnehmer darf mehrmals teilnehmen. Die Chancen für die Verlosung erhöhen sich dadurch allerdings nicht.
- Alle Gewinner werden per E-Mail benachrichtigt.
- Die Zustellung des Gewinns der T-Shirts aus der Blog- und Twitter-Parade erfolgt auf dem Postweg auf eigene Gewähr. Eine korrekte Angabe der Adressdaten ist Voraussetzung für die korrekte Zustellung im Falle eines Gewinns.
- Die Zustellung der Gewinns der T-Shirts aus dem Gewinnspiel erfolgt persönlich beim Empfang der See# Party
- Die Gewinner erklären sich mit einer Veröffentlichung Ihrer Vornamen und des Anfangsbuchstabens des Nachnamens in diesem Blog einverstanden.
- Die Ausbezahlung der Preise in bar ist nicht möglich.
- Der Rechtsweg ist ausgeschlossen.
- Gewährleistungsansprüche hinsichtlich der Gewinne sind ausgeschlossen.
Ich wünsche allen Teilnehmern viel Spass und viel Glück, auf das man sich auf der See# Party trifft. :-)
Gestern fand das 19. Treffen des .NET-Stammtisch Konstanz-Kreuzlingen statt. Zu Gast war diesmal Thorsten Hans der IronRuby vorstellte, nach einer Einführung in die Sprache Ruby ging es auch schon los mit Demos zu .NET Programmierung mir IronRuby
Was mich persönlich erstaunt hat und womit ich eigentlich nicht gerechnet hatte ist, dass IronRuby nicht nur eine Spielerei von Microsoft Geeks ist, sondern tatsächlich in Business Anwendungen und Szenarien eingesetzt werden.
Dadurch das IronRuby in herkömmlichen Anwendungen gehostet werden kann und im IronRuby das komplette .NET Framework zur Verfügung steht, ist es möglich die eigene Anwendung an bestimmten Stellen so flexibel zu halten, dass zur Laufzeit kundenspezifische Anpassungen durchgeführt werden können.
Thorsten zeigte dazu eine Demo, in der er die Validierung eines DTOs in ein IronRuby-Script auslagerte und so zur Laufzeit beliebig ändern könnte ohne das die Anwendung neu kompiliert werden muss.
Aber das ist nur eines der vielen möglichen Anwendungsgebiete von IronRuby.
Ich weiß auf jeden Fall, dass ich in nächster Zeit etwas damit herumspielen werden.
Im Namen aller Anwesenden bedanke ich mich hiermit nochmal bei Thorsten Hans für die sehr spannende Einführung in IronRuby. :-)
Eben habe ich gemerkt, das Thorsten mit einem Blog-Beitrag schneller war als ich: Siehe
Auch im Blog des .NET-Stammtisch wird es immer wieder Berichte zu den jeweiligen Treffen geben. Stefan Zybarth von der Combit wird sich hier austoben :-)
Ganz unbemerkt und überraschend habe ich vorgestern den 200. Blogeintrag gepostet. Dafür das mir vor zweieinhalb Jahren, von Stefan Falz, dieser Blog ganz überraschend zur Verfügung gestellt wurde. Und ich am Anfang noch gar nicht wusste, was ich hier eigentlich schreiben soll.
Übrigens war es der olle Schweizer, der mich damals dazu überredet hat, hier hin und wieder mal was mehr oder weniger Sinnvolles zu schreiben ;-)
(Eine weitere Ausnahme ist dieser Beitrag: eher Sinn frei)
PS: Bitte kein unnötiges Lob an dieser Stelle. Andere schreiben um längen mehr, besser und fehlerfreier als ich. Ich war nur recht überrascht von der Zahl 200 und für Twitter ist der Post einfach zu lang. ;-)

Es hat sich einiges getan bei den Vorbereitungen zur See# Party.
Sprecher und Themen
Nicht nur die Sprecher und Themen sind jetzt komplett und auch der schwierigste Part, die Agenda, ist nun seit diesem Wochenende auf der Website veröffentlicht.
Eine kleine Auswahl der Sprecher:
- Golo Roden
- Stefan Lieser
- Laurent Bugnion
- Roland Weigelt
- Albert Weinert
- und 11 weitere…
Eine kleine Auswahl der Themen:
- Building Windows Phone 7 applications with Silverlight
- IronRuby für .NET Developer
- Advanced ASP.NET MVC
- ADO.NET Entity Framework
- TFS 2010 Neuerungen und Highlights
- und 11.weitere…
Agenda
Am ursprünglichen Zeitplan für die Agenda haben wir noch etwas geschraubt. So haben wir die Mittagspause um eine Halbe Stunde verlängert, um Lunch-Sessions versetzt starten zu können. Zusätzlich gibt es nun doch eine Pause von 15 Minuten zwischen der Key Note und der ersten Session *fg*
Weiter zur Agenda
.NET Codeing Dojo
Ein besonderes Special können wir - dank Stefan Lieser - während der Grillparty bieten: Stefan hat sich bereit erklärt am Abend ein .NET Coding Dojo zu leiten. Da die Räumlichkeiten eh zur Verfügung stehen können die auch dafür genutzt werden. So kann ab 19:30 (nach dem Essen) das Dojo starten.
Gewinnspiel
Natürlich gibt es auch etwas mit nach Hause zu nehmen. Neben einem attraktiven Willkommensgeschenk für jeden Teilnehmer gibt es auch hier – dank der Zahlreichen Sponsoren – einiges zu gewinnen. Hier eine kleine Auswahl:
Twitter, Facebook und Co.
@dotnetkk twittert immer wieder Neuigkeiten zur See# Party unter dem Hashtag #ssp2010
Ebenso auf der Facebook Veranstaltung und auf der Facebook Seite zur .NET User Group Konstanz-Keuzlingen werden News veröffentlicht
Anmeldung
Die Anmeldung für die Teilnehmer ist nur noch bis zum am 21.08.2010 offen. Wer also noch an der See# Party teilnehmen möchte sollte sich beeilen um sich die letzten Plätze zu sichern :-)
Schnell anmelden…
Das ich den TFS und die Arbeit mit dem TFS bevorzuge ist kein Geheimnis. Der TFS ist ein sehr flexibles All-In-One-Tool, welches eine moderne Softwareentwicklung unterstützt. Die wichtigsten Stichworte sind Source-Code-Verwaltung, Bug- und Feature-Tracking, sowie Continous-Integration mit Team-Build.
Zwei zusätzliche Features, die in der Vergangenheit bei der Arbeit mit dem TFS lieben gelernt habe, sind zum einen Shelve-Sets und die Verknüpfung der Change-Sets (Check-Ins) mit einem Work-Item (Bug oder Feature):
Die Shelve-Sets bieten eine Möglichkeit, Source Code einzuchecken und somit zentral zu sicher, ohne dass der Code im Haupt-Branch und somit im Build berücksichtigt wird. Der Entwickler hat so die Möglichkeit Änderungen zwischen zu speichern.
Mit der Verknüpfung zwischen Work-Items und Change-Sets lässt sich auf die Zeile genau feststellen, welcher Code mit zu welchem Zweck geändert oder erstellt wurde.
Das war der TFS2008. Der TFS2010 bietet eine ganze Reihe weiterer interessanter Features. Angefangen bei der wesentlich verbesserten Unterstützung für Tester, bis hin zur den lang ersehnten hierarchischen Work-Items.
Privat nutze ich allerdings folgende Konstellation um meine Projekte zu entwickeln:
- Visual SVN Server für die Source Code Verwaltung
- Hudson als Build Server
- Tortoise als SVN Client unter Windows
- Visual SVN als Client im Visual Studio
Seit einiger Zeit suche ich eine Möglichkeit, mit der agile Softwareentwicklung durch Software unterstützt, optimal betrieben werden kann. Bei meinem Besuch auf der BASTA! Spring 2010 besuchte ich eine Session zu Agilen Tools. Neben Hudson als Continous Integration Server (den ich sehr empfehlen kann) wurde auch Agilo vorgestellt. Agilo ist ein (in der Grundversion) kostenloses Tool von agile42 (http://www.agile42.com) welches auf Trac basiert, zur Verwaltung von Anforderungen, Backlogs, Teams, mit Integriertem Wiki. Scrum und XP lassen sich damit hervorragend abbilden und managen.
Mit dem TFS lässt sich (mit dem Template „MSF for Agile“) ebenfalls agil arbeiten, allerdings war bisher die Unterstützung für Scrum, durch Anpassung des Templates nicht so umfangreich wie es mit Agilo der Fall ist. Zum Management von agilen Projekten war Handarbeit oder die Verwendung von zusätzlichen Tools erforderlich.
Seit kurzem (22. Juli 2010) gibt es allerdings für den 2010 eine Unterstützung für Scrum, welches die Best Practices der Scrum Community abbildet und die Scrum-Sprache benutzt. Eine kurze Einführung ist auch auf dem Blog von Brian Harry zu finden: http://blogs.msdn.com/b/bharry/archive/2010/06/07/a-scrum-process-template-for-tfs.aspx Zusätzlich zu neuen und geänderten Work-Items können BurnDown und Velocity-Cahrts im zugehörigen Sharepoint visualisiert werden. Das Process Template kann von hier (http://visualstudiogallery.msdn.microsoft.com/en-us/59ac03e3-df99-4776-be39-1917cbfc5d8e) heruntergeladen werden.
Bei der Installation des MSI-Pakets des Templates stößt man auf eine kleine Schwierigkeit, falls man die Readme-Datei nicht gelesen hat: Das Process-Template ist nach der Installation noch nicht im TFS verfügbar und muss dort erst hochgeladen werden. Den Anweisungen der Readme (im Installationsordner) sollte man folgen. Nach dem Upload des Process-Templates kein ein neues Teamprojekt anhand dieses Templates erzeugt werden.
Um alle Team-Member beteiligen zu können, sollte SharePoint angebunden werden. Ich habe nur die Basic Konfiguration (ohne SharePoint) testen können und kann so leider nichts Genaueres zum Portal schreiben.
Eine Übersicht über die neuen Work Item Typen ist hier zu finden: http://msdn.microsoft.com/en-us/library/ff731587.aspx
Ach ja: Den TFS Web Access des vergangenen Versionen habe ich nur einmal sehr flüchtig angeschaut und kann also nicht mehr viel darüber erzählen, aber der Web Access des TFS2010 ist nicht über. Natürlich nicht vergleichbar mit den Oberflächen die Agilo und Hudson mit sich bringen, aber diese Tools sind natürlich komplett webbasiert.
Aber ich möchte den TFS nicht durchweg loben. Der Grund warum ich privat weiter mit den oben genannten Tools weiter fahren möchte ist nicht nur eine Lizenzfrage, sondern auch eine Ressourcenfrage. Der TFS benötigt einen eigenen, separaten Server, da er (je nach Teamgröße) relativ viel Prozessorzeit und Arbeitsspeicher beansprucht. Je nach Teamgröße wird mit Continous Integration sogar empfohlen, Team Build auf einem weiteren separaten Server laufen zu lassen.
Agilo, Hudson und Visual SVN Server benötigen dagegen alle zusammen weniger Ressourcen als der TFS alleine. Allerdings sind alle drei Tools natürlich nicht so stark verbunden, wie alle Komponenten des TFS.
Da ich aber nur einen kleinen, gehosteten Virtuellen Server habe und auf diesem auch noch einige Webs laufen sollten, kann ich mir den TFS produktiv und auf diesem Server leider nicht leisten. Dennoch denke ich, dass ich im Geschäfft eher für den TFS entscheiden werde.
Kurz vor dem 20. Treffen veranstaltet der .NET-Stammtisch Konstanz-Kreuzlingen eine .NET-Community Konferenz in Kreuzlingen am Bodensee mit dem Ziel auch hier in der Region eine günstige und nahe alternative zu den großen, herkömmlichen Konferenzen zu bieten.
Bei der Planung ist eine Konferenz am Bodensee mit dem passenden Namen “See# Party” entstanden.

Die See# Party findet am 28. August 2010 im DREISPITZ Sport- und Kulturzentrum in Kreuzlingen (CH) statt.
Die Anmeldung für bis zu 250 Teilnehmer startet am 01. Juli 2010
Wer einen eigenen Vortrag einreichen möchte, kann gerne mit uns Kontakt aufnehmen und uns die Vorschläge per E-Mail zusenden. Mehr Informationen zu den einzureichenden Vorträgen sind hier zu finden: Call for Papers
Um die Teilnahme für alle so günstig wie möglich zu machen, sind wir auf die Unterstützung durch Sponsoren angewiesen. Wer die See# Party in irgendeiner Art unterstützen möchte findet auf der Seite “Sponsor werden” die nötigen Hinweise.
Bis jetzt bin ich sehr zufrieden mit dem gestrigen Start:
- Golo Roden hat sich bereit erklärt die Keynote zum Thema ALT.NET zu halten
- Die ersten Sprecher haben Ihre Vorschläge eingereicht
- Die ersten möglichen Sponsoren und Medienpartner haben bereits zusagen gemacht
- Die Resonanz per Facebook, Twitter und auch XING übersteigt meine Erwartungen
- Das CMS add.min arbeitet hervorragend (und ist schneller als ich es in Erinnerung hatte)
Natürlich haben wir uns ein sehr, sehr engen Zeitplan gesetzt. Allerdings läuft es bis jetzt hervorragend mit der Planung. Dabei halfen die nötigen Verbindungen und natürlich auch ein kleines bisschen Glück.
Dank großes Dankeschön geht vorab schon mal an die vielen motivierten Helfer und auch an die Firma K&K Internet GmbH die uns als Hosting-Sponsor zur Seite steht und uns das CMS add.min zur Verfügung gestellt hat.
Um das nächtliche Fahren mit der Deutschen Bahn zu testen fuhr ich am Donnerstag Abend mit genau dieser nach Köln. Meine erste und einzige Autofahrt vor einigen Jahren in Köln war eher ein negatives Erlebnis, also entschloss ich mich zu dieser sehr drastischen Entscheidung. (start fishing for compassion) Aber auch das stellte sich als eher negatives Erlebnis dar. Auf der Hinfahrt gab es weder den reservierten Platz im angegebenen Wagen, noch war es ein Ruhesessel. Der ICE auf der Rückfahrt hatte zwar eine Steckdose für meinen Laptop, allerdings war ich zu Müde zum arbeiten. Leider war der Platz im ICE auch zu unbequem zum Schlafen. (finish fishing for compassion)
Nur gut, dass “rein zufällig” in Köln auch dieses mal wieder die dotnet Cologne stattfand. Das entschädigte die An- und Abreise erheblich.
Ich war natürlich zu früh am Veranstaltungsort was allerdings durch eine Elster (die sich entweder verflogen hatte oder auch etwas vom reichhaltigen Frühstücksbuffet haben wollte) in der Lobby-Bar und Thorsten Kansy Buch Datenbankprogrammierung mit .NET 4.0. Mit Visual Studio 2010 und SQL Server 2008 R2
doch noch sehr Kurzweilig wurde.
Veranstaltet wurde die Konferenz auch dieses mal wieder von Albert Weinert, Stefan Lange und Roland Weigelt. Nach einigen kleinen technischen Schwierigkeiten bei der Begrüßung hielt Roland Weigelt die Keynote zum Thema Community, Konferenz und .NET 4.0 und VS 2010
Anschließend gab es ein volle Programm. Eine tolle Session nach der anderen. Interessant fand ich die sogenannte Lunch-Session die man während dem Essen mit verfolgen konnte. So gab es für mich Canneloni mit einem Becher griechischem Salat garniert mit Brownfield und Typemock Isolator welches von Stefan Lieser serviert wurde. Zum Nachtisch verteilte Britt King 25% Rabatt auf den Typemock Isolator…
Ebenfalls ein Erlebnis war die Session von Dariusz Parys der Windows Workflow vorstellte.
Für mich war die Session die Thorsten Hans zum Thema MSBuild auch eine Vorschau auf das 21. Treffen des .NET-Stammtisch Konstanz-Kreuzlingen. Ich freu mich drauf :-)
Wer ein paar Eindrücke von der dotnet Cologne haben möchte kann sich diese Gallery auf .NET Forum anschauen: http://dotnet-forum.de/photos/grillparty2010/slideshowpro.aspx
Von mir gibt es auf jeden Fall ein fettes Dankeschön an die Veranstalter für das tolle abwechslungsreiche Programm und für die Sponsoren, die das mit möglich gemacht haben. Und hoffe das nächste Mal wieder dabei sein zu können. :-)
Seit einiger Zeit baue ich nebenher an einem kleinen multi-mandantenfähigen Lizenzserver. Ziel ist es diese Anwendung komplett mit TDD zu schreiben.
Wie ich sicher bisweilen schon erwähnt hatte, war es bisher für mich sehr schwer, TDD wirklich konsequent einzusetzen. Wenn man Jahrelang auf die herkömmliche Art und Weise programmiert, ist es in einem kleinen privaten Projekt ein enormer Kraftakt, sein Denken so umzustellen, dass man
- Erst penibel die Anforderungen definiert
- Die Tests definiert
- Die Tests schreibt
- und dann implementiert, ohne zu viel Code zu schreiben
Allerdings hat mir ausgerechnet folgender Blogbeitrag von Thomas Bandt den Anstoß gegeben es noch einmal ernsthaft zu versuchen: TDD, BDD - Status Quo
The Bandt way of TDD
Das interessante an diesem Weg ist, dass ich einen Schritt spare: Die Anforderungen sind schon die Definitionen der Tests und das sogar Wort wörtlich. Die Anforderungen werden im Klartext, auf deutsch mit allen Umlauten als Test geschrieben. Das vereinfacht das schreiben der Tests ungemein.
Der zweite interessante Punkt ist die Kapselung wiederkehrender Aufgaben (erzeugen des SuT und der abhängigen Stubs) in eine Basisklasse.
Es flutscht
Also hatte ich beschlossen den Lizenzserver (den ich schon länger schreiben wollte) mit dem Bandt way of TDD zu entwickeln. Interessanterweise habe ich mich bei diesem Projekt bisher noch nicht dabei erwischt, an den Tests vorbei zu implementieren. Und noch schlimmer: Es fängt an Spaß zu machen, wenn man alle Tests die sich inzwischen angesammelt haben, laufen lässt und alles grün ist.
Word to Code
Nach dem die Zahl der Tests nun ständig ansteigt, habe ich mir so langsam Gedanken gemacht, wie ich diese dokumentiere. Bisher hatte ich (da es sich um ein rein privates Projekt handelt) die Anforderungen direkt in Tests umgesetzt, und dann nach einer Weile alle Definitionen der Tests in einer HTML-Datei gespeichert.
Aber die bessere Lösung stammt wieder einmal von Thomas: mit "Word to Code" hat Thomas ein kleines Helferlein geschrieben, mit dem sich in Word formulierte Anforderungen, nach den Konventionen des Bandt way of TDD, in fertige Unit Tests konvertieren lassen.
Fazit
Wer also, wie ich, selber noch Schwierigkeiten hat, TDD wirklich einzusetzen, sollte mal diesen Weg probieren. Sobald man richtig mit den Mocking und Testing Frameworks seiner Wahl vertraut ist, flutscht es wirklich. Den Aufwand den man auf die Herkömmliche Art noch ins Debugging und ins testen von Hand gesteckt hat, steckt man nun mit TDD in die Tests. Die Tests geben einem zusätzlich noch die Sicherheit, dass der eigene Code den Anforderungen entspricht :-)
Einfach mal ausprobieren :-)

Ganz stolz kann ich heute mal folgendes schreiben:
Mit dem Artikel “Keine Sorge, es piekst nur ganz kurz – Dependency Injection mit LightCore” ist mein erster Artikel in einer deutschsprachigen Fachzeitschrift erschienen.
Zu finden ist der Artikel in der Ausgabe 6.2010 des dot.NET Magazins, welche die meisten Abonnenten bereits in der Hand halten sollten.
In diesem Artikel beschreibe ich kurz das Dependency Injection Pattern und vor allem die einfache Umsetzung des Patterns mit Peter Buchers Dependency Injection Container LightCore.
Übrigens gibt es LightCore auch auf FaceBook und Twitter:
FaceBook Seite: http://www.facebook.com/pages/LightCore/
Twitter: http://twitter.com/lightcore
Mit seinem Beitrag Kleiner Helper für Linq to Sql: ToListOrDefault() hat Thomas Bandt am Wochenende eine Diskussion zum Thema “Null als Rückgabewert” angestoßen (man beachte die Kommentare). Wie nicht anders zu erwarten (:-P), wurde die Diskussion natürlich auch von Ralf Westphal aufgenommen: Null oder nicht Null, das ist hier die Frage (auch hier die Kommentare beachten).
Weiter ging es wieder Bei Thomas Bandt mit dem Beitrag Null Verständnis der es tatsächlich auf 40 Kommentare gebracht hat. Auch Ilker Cetinkaya konnte es sich diesmal nicht verkneifen ebenfalls etwas zu dem Thema zu schreiben: Null Toleranz, vorauf hin Ralf schlagfertig reagierte: Es hilft nichts, dass es darauf ankommt – nicht nur beim Null-Problemo [OOP 2010] und Ilkers Haltung kritisierte. [Update] Ilkers Antwort folgte gestern relativ schnell: Kein Yin ohne Yang, kein Null ohne Pointer (Auch hier bitte unbedingt die Kommentare lesen)
Ein scheinbar vorläufiges Fazit zur Diskussion schreibt Thomas in seinem letzten Beitrag zum Thema Null: Null Erkenntnis? Ganz im Gegenteil.
[UPDATE]
Eben hat sich auch der Karsten zum Thema geäußert: #Handwerk: Clean vs. pragmatisch?
Was hier fast wie ein Sportbericht aussieht, ist ein Diskussion über ‘Null’ als Rückgabewert und über eine fehlende Regel zu dem Thema ob und wann ‘Null’ als Rückgabe erlaubt ist, oder nicht.
Verschiedenste Lösungen kommen in allen Beiträgen und deren Kommentaren vor. So unter anderem:
- Exception statt ‘Null’
- Leere Objekte statt ‘Null’
- ‘Null’ nur passend zur Kategorie
- ‘Null’ nur mit Vorsicht
- it depends
- ‘Null’ im Katastrophenfall
Katastrophenfall ‘NULL’
Und dieser letzte Punkt ist eigentlich der einzige, an dem ich mich wirklich anstoße:
Ilker Cetinkaya [http://www.gmbsg.com/null-toleranz/]
Ich gebe in einigen Methoden NULL zurück. Meistens genau dann, wenn ich wirklich damit ausdrücken möchte, dass etwas katastrophales passiert ist.
Wenn etwas eine Katastrophe ist, sollte diese Katastrophe nur in wirklich unvermeidbaren Ausnahmen auftreten. In diesem Fall kann auch eine Ausnahme erzeugt werden. Ich bin in so einem Fall tatsächlich für eine Exception, statt einer ‘Null’ (Punkt 1).
Als Webentwickler dagegen bin ich der Ansicht das man die Erzeugung von Exceptions unbedingt mit Vorsicht genießen sollte und nur dann einsetzen sollte, wenn es wirklich unvermeidbar ist. Den Exception Handling kostet Performance. Exceptions sollten also auch Exceptions bleiben und “exceptionally used” werden. Im Web ist es IMHO wichtiger Fehler zu vermeiden, als für jeden möglichen Fall eine neue Exception zu erzeugen. Zum Thema “Fehler vermeiden” gehört IMHO auch, das Auslösen von Exceptions vermeiden, wenn es sich irgendwie vermeiden lässt. Aus diesem Grund sollte der erste Punkt “Exceptions statt ‘Null’” ebenfalls mit Vorsicht genossen werden.
Und was ‘Null’ als Rückgabewert angeht, enthalte ich mich fürs erste (was spezielle Regeln angeht) und bleibe Beobachter dieser Grundlagendiskussion. Ich bin mir einfach selber noch nicht schlüssig, was hier richtig und was falsch ist. Die Rückgabe von ’Null’ ist bequem, harmlos und tastbar, kann also nicht grundlegend falsch sein.
Im Moment tendiere ich noch zu dem Punkt “it depends” ;-)
Eben bin ich auf interessante Neuerungen der System.IO.Directory Klasse im .NET 4.0 gestoßen. Wenn man bisher alle Dateien und/oder alle Ordner eines übergeordneten Ordners erhalten wollte, konnte man das mit den statischen Methoden:
Man kann das auch in .NET 4.0 immer noch tun und erhält ein String-Array mit den gewünschten Einträgen.
Neu sind unter anderem folgende drei statischen Methoden:
Alle drei Methoden und deren Überladungen geben ein generisches IEnumerable vom Typ String zurück.
MSDN (Directory.EnumerateFiles-Methode (String))
Die EnumerateFiles-Methode und die GetFiles-Methode unterscheiden sich wie folgt: Wenn Sie EnumerateFiles verwenden, können Sie anfangen, die Auflistung von Namen aufzulisten, bevor die ganze Auflistung zurückgegeben wird; wenn Sie GetFiles verwenden, müssen Sie warten, bis das ganze Array von Namen zurückgegeben wird, bevor Sie auf das Array zugreifen können.Wenn Sie daher mit vielen Dateien und Verzeichnissen arbeiten, kann EnumerateFiles effizienter sein.
Das heißt konkret, die Verarbeitung der Daten kann gestartet werden, bevor alle Daten geladen sind. Die ideale Voraussetzung für LINQ:
IEnumerable<string> files =
from file in Directory.EnumerateFiles("C:\\documents\\folder1\\")
where file.EndsWith("*.docx", StringComparison.OrdinalIgnoreCase)
select file;
foreach (string file in files)
{
Console.WriteLine(file);
}
Einziger Kritikpunkt ist, dass kein FileInfo-, bzw. kein DirectoryInfo-Objekt zurückgegeben wird. Aber das kann man auch schnell selber erledigen:
IEnumerable<FileInfo> files =
from file in Directory.EnumerateFiles("C:\\documents\\folder1\\")
where file.EndsWith("*.docx", StringComparison.OrdinalIgnoreCase)
select new FileInfo(file);
foreach (FileInfo file in files)
{
Console.WriteLine(file.Name);
}