initial commit

This commit is contained in:
2026-08-16 19:03:44 +02:00
commit f9726ca9dc
215 changed files with 29489 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
---
title: "build broken"
---
Wir haben uns in der Welt von Classic-ASP, HTML und VB6 kennengelernt, als noch die größte Herausforderung lautete: wohin mit dem on Error resume next <img src="/images/about/icon_wink.gif" alt=";)" class="wp-smiley"/> Wir waren jung und unerfahren und brauchten das Geld. Damals waren noch Begriffe wie SOAP und Webservices nicht näher zu uns als Teleportieren. Mit der Zeit merkten wir, dass unserer Wissensdurst erfüllt werden kann: mit Büchern, Blogs und Foren. Danach war es nur noch eine Frage der Zeit bis wir die ersten Lern-Projekte mit ASP.NET und C# begonnen haben. Gleichzeitig haben wir eine Art minimalistische SCRUM-Methode eingeführt.
Diese Zeit war aufregend und unsicher, wir wussten nicht, dass es ein mal dazu führt, dass wir aus einzelnen Programmierern zu einem TEAM werden. Ein agiles, sehr ehrgeiziges und buntes Team, wie wir heute sind. Wir sind bekennende Code Complete-Fans, arbeiten mit Versionierungstools und nach TDD. Wir lernen jede Woche was neues und die meiste Hilfe bekommen wir aus dem Netz. Jetzt ist die Zeit gekommen, wo auch wir in der Lage sind, anderen “jungen und unerfahrenen” Entwicklern was zurückzugeben und unsere Erfahrungen mit allen zu teilen. Deshalb ist dieser Blog entstanden.
Die Beispiele, Themen, Überlegungen, die wir hier veröffentlichen sind demzufolge nicht perfekt aber so gut wie wir sie heute beschreiben können. Findet ihr was Falsches, teilt es uns mit. Habt ihr fragen, fragt uns. Wir machen das ja auch.
Jeder Bug ist nur ein Zeichen, dass man noch nicht alles kann. Und das ist auch gut so!
+15
View File
@@ -0,0 +1,15 @@
---
title: "Impressum (§ 5 DDG)"
layout: impressum
---
**Stefan Kölle**<br>
Neumarkter Str. 86c<br>
81673 München
Telefon/Fax: +49-(89)-20006547<br>
E-Mail: buildbroken@moonweb.org
Verantwortlich für den Inhalt nach § 18 Abs. 2 MStV: Stefan Kölle, Anschrift wie oben.
Das vollständige Impressum und die Datenschutzerklärung für diese Website und das moonweb.org-Netzwerk: [hub.moonweb.org/impressum](https://hub.moonweb.org/impressum)
+54
View File
@@ -0,0 +1,54 @@
---
title: "Gibt es negative Energien in der deutschen ALT.NET Bewegung?"
date: 2009-08-26
slug: alt-net-energien
original_url: "https://aztec-project.org/blog/alt-net-energien.html"
archive_url: "https://web.archive.org/web/20250114121547/https://aztec-project.org/blog/alt-net-energien.html"
author: "Stefan Kölle"
categories: ["Clean Code Developing", "Open Space"]
---
Im Podcast [“Talking with Jeremy Miller about ALT.NET”](http://www.altnetpodcast.com/episodes/18-talking-with-jeremy-miller-about-alt-net) spricht James Avery mit Jeremy Miller über ALT.NET und die Community allgemein.
Beim ALT.NET Open Spaces in Seattle wurde wieder eine sehr negative Session angesetzt, “Why so mean?”. Scott Hanselman stellt hier sehr provokant die Frage, warum die Community immer mehr Energie aufwendet um zu Kritisieren, anstatt die neuen Technologien positiv nach aussen zu tragen. Dies kann ich nach meinen jetzigen Erfahrungen beim .NET Open Spaces in Ulm nicht bestätigen. Bei uns habe ich keinerlei negative Energie gespürt.
Andererseits sehe ich es genauso wie Jeremy: Ansätze, die teilweise gegeneinander arbeiten. DDD widerspricht meiner Meinung nach oft den bisher genutzten Kapselungen. Was nun besser oder schlechter ist kann ich derzeit noch nicht sagen, dazu kenne ich selbst DDD zu wenig. Die Mehrheit der ALT.NET Community hat wohl noch nicht einen allgemeingültigen Weg zur Verfügung, der aus dem bisher eingebrachten Wissen entstanden ist.
Was wohl langfristig nötig ist, dass wir uns über den Grundgedanken von ALT.NET wieder bewusst werden. Der entstehende Code soll clean, korrekt und erweiterbar sein. Also eine auf den Code zentrierte Produktentwicklung. Der Weg mit CCD sehe ich damit als den Richtigen und CCD spricht auch gerade einen positiven Aspekt an.
Seht ihr ähnliche Tendenzen wie Jeremy in der deutschen Community?
<img src="/images/alt-net-energien/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. **Christina Hirth**
[August 27, 2009 um 7:45 pm](/posts/alt-net-energien/)
Es scheint, dass ALT.NET die FDP der Softwareentwicklungswelt ist: die Opposition von der (gefühlten) Herrschaft vom Microsoft <img src="/images/alt-net-energien/icon_wink.gif" alt=";)" class="wp-smiley"/> Und als solche, ist seine Rolle unabdingbar!
Das heißt aber noch lange nicht, dass alles was die (CSU) Microsoft tut BÖSE ist, auch wenn sie jedem Amateur das Programieren ermöglichen. Ich meine, Dreamweaver hatte bereits vor 10 Jahren fertige Codeschnipsel für Datenbankanbindung bereitgestellt aber man musste den NICHT nutzen, man konnte es auch selbst ausprogrammieren. Also anders gesagt: keine zwingt dich, oder?
Eins ist sicher: es gibt den Heiligen Gral der Softwareentwicklung noch nicht. Und das bedeutet, man sollte alles mit Obacht genießen und sich vergewissern, dass der gewählte Weg zu dem bestimmten Projekt und zu dem bestimmten Team passt. Dann kann man auch den richtigen Code schreiben und danach ruhig schlafen, egal ob es um Microsoft-Framework oder um Castle-AddOns geht. Und die Amateur-Coder werden ihrer Arbeit nicht lange verkaufen können, wenn diese unpflegbar und unwartbar ist.
ALT.NET existiert nur weil Microsoft existiert. Solange die Community das Ziel hat, den Weg zu dem perfekten Code zu finden, können wir alle davon profitieren: sowohl pro- als auch kontra-Microsoft-Coder.
2. **[Thomas](http://blog.thomasbandt.de/)**
[August 29, 2009 um 3:06 pm](/posts/alt-net-energien/)
Ich glaube dass sowohl ALT.NET als auch bei uns CCD dazu führen, dass man sich als Entwickler einfach bewusster mit seiner Arbeit auseinandersetzt und eben “Prinzipien, Regeln und Praktiken für bessere Software” entwickelt und einsetzt, wie es bei CCD so schön heißt. Das hilft vor allem auch bei einer objektiveren Bewertung der Technologien, die MS so aus seinem Headquarter auf unsere Entwicklerrechner streamt Jahr für Jahr.
Praktisches Beispiel: DataReader, DataSet, TypedDataset, xDataSource, LINQ to SQL oder Entity Framework das alles in nicht einmal 6 Jahren. Jeweils für “the next big thing” verkauft oder gepriesen. Jetzt kann ich hergehen und jedes Mal den aktuellsten Liebling verkaufen und preisen, oder ich greife ganz pragmatisch eben zu dem für mich gerade besten und kapsele es einfach in einem Repository, so dass es beliebig austauschbar ist. Um dahin zu kommen, muss man sich aber ein paar Gedanken rund um seinen Code bzw. die Architektur des selben machen und eben nicht alles ungeprüft nachplappern oder die unsäglichen Beispiele übernehmen. Das versetzt mich dann gleichzeitig auch mal in die Lage zu sagen, dass das Entity Framework eben immer noch scheiße ist, dass die ASP.NET-MVC-Sample-Apps zusammengestümpert sind usw. Und im Übrigen macht es MS selbst auch ein ganzes Stück besser, da sie wohl nirgendwo so schonungsloses Feedback für ihre eigenen Produkte bekommen. Von den “Zusammenklickern” können sie das jedenfalls nicht erwarten.
War das jetzt eigentlich noch die Frage? Egal, ich drücke einfach mal den Absenden-Button <img src="/images/alt-net-energien/icon_wink.gif" alt=";-)" class="wp-smiley"/> .
3. **Stefan Kölle**
[August 31, 2009 um 7:28 pm](/posts/alt-net-energien/)
Spannend wohin sich meine provokante Fragestellung entwickelt.
Ich sehe also grundsaetzlich, die deutsche Community mag zwar MS auch nicht immer, aber man geht viel objektiver mit dem Thema um. Ich sehe in Amerika das Problem, dass durch eine grundsaetzlich negative Einstellung auch der spirit von ALT.NET langfristig als negativ empfunden wird.
Genau dies freut mich in der CCD Bewegung!
Gruss
Stefan
+44
View File
@@ -0,0 +1,44 @@
---
title: "Anonyme Datentypen"
date: 2009-06-10
slug: anonyme-datentypen
original_url: "https://aztec-project.org/blog/anonyme-datentypen.html"
archive_url: "https://web.archive.org/web/20250601101329/https://aztec-project.org/blog/anonyme-datentypen.html"
author: "Andreas Seebauer"
categories: ["How-To"]
tags: ["C#", "HowTo"]
---
Anonyme Datentypen sind Klassen, die erst beim Kompilieren durch den Compiler definiert werden. Die Klassendefinition befindet sich also nicht im Quellcode. Die anonymen Datentypen leiten wie jedes andere Referenzobjekt von der Klasse object ab. Sie sind als reine Datenklassen gedacht und es können keine weiteren Methoden oder Events hinzugefügt werden. Obwohl der anonyme Datentyp auf Quellcodeebene noch nicht definiert ist, muss dank Visual Studio nicht auf die Intellisense verzichtet werden.
Definiert und intstanziert werden sie mit new und einem Objektinitialisierer:
```
var mitarbeiter = new { Name = "Müller", Abteilung = "IT" };
```
var ist der implizite Typ und **nicht** der anonyme Datentyp. Er fungiert hier lediglich als container für die Instanz des anonymen Datentyps, die mit new {} erzeugt wird.
Gibt man keinen Namen für die Properties an, werden die Namen der Properties verwendet, mit denen initialisiert wird.
```
var abteilung = new { Abteilungsname = "IT" };
var mitarbeiter = new { Name = "Müller" , abteilung.Abteilungsname };
Console .WriteLine(mitarbeiter.Abteilungsname);
```
Wenn man mit Werten initialisiert, muss ein Name angegeben werden.
Anonyme Datentypen bieten sich an, wenn man Abfragen mit Linq ausführt und entweder nur eine Teilmenge des ursprünglichen Objekts braucht, oder wenn man ein Objekt erweitern will, ohne extra eine neue Klasse zu definieren.
Hier ein Beispiel aus einem Castle Monorail Projekt, in dem eine erweiterte Liste an eine vm gegeben wird, ohne eine neue Klasse definieren zu müssen. Es soll dabei eine Liste erstellt werden, in der die Mitarbeiter mit ihrem Horoskop verknüpft werden :
```
public void Action() {
IList < Mitarbeiter > mitarbeiterListe = m_service.GetMitarbeiter();
var mitarbeiterMitHoroskopListe = ( from mitarbeiter in mitarbeiterListe
select new { Mitarbeiter = mitarbeiter,
Horoskop = GetHoroskop(mitarbeiter.Geburtsdatum) });
PropertyBag[ "mitarbeiterMitHoroskopListe" ] = mitarbeiterMitHoroskopListe;
}
```
+19
View File
@@ -0,0 +1,19 @@
---
title: "ASP.MVC 2 Vortrag von Albert bei münchener UserGroup"
date: 2009-10-30
slug: asp-mvc-2
original_url: "https://aztec-project.org/blog/asp-mvc-2.html"
archive_url: "https://web.archive.org/web/20250114131627/https://aztec-project.org/blog/asp-mvc-2.html"
author: "Christina Hirth"
categories: ["MVC"]
tags: [".NET", "Community", "MVC", "Veranstaltung"]
---
Gestern Abend waren wir alle bei einem super Vortrag von [Albert](http://der-albert.com/) über ASP.MVC v2. Die neue Version soll am 22. März zusammen mit .NET 4.0 rauskommen.
Ich will jetzt nicht über all die Neuigkeiten sprechen, die wir gestern erfahren haben und worüber wir uns jetzt schon freuen müssen, nur über einen speziellen Teil: die Validierung der Daten durch Attribute.
Der Grund ist folgender: wir haben uns vor ca. 1 Jahr ein eigenes Attribut namens `ObligatoryFieldAttribut` gebaut. Dieses wird über die Properties gesetzt, die wir für die Speicherung als unerheblich markieren möchten. Die Überprüfung erfolgt dann durch Reflection.
Und was haben wir gestern erfahren? In der neue MVC-Version gibt es ein neues Attribut namens `Required`, das genau das tut!
Ihr könnt euch sicher vorstellen, was wir uns gestern gedacht haben: wir lagen genau richtig und wir waren unserer Zeit voraus! Oder haben unsere Büro-Nachbarn die eine *Microsoft Subsidiary* sind Kameras bei uns installiert 😉 ?
+190
View File
@@ -0,0 +1,190 @@
---
title: "Asynchrone Kommunikation mit dem Async-Pattern (Refactored)"
date: 2010-05-06
slug: async-refactored
original_url: "https://aztec-project.org/blog/async-refactored.html"
archive_url: "https://web.archive.org/web/20250114134342/https://aztec-project.org/blog/async-refactored.html"
author: "Thomas Christian"
categories: ["Architektur", "Pattern", "Tipps"]
---
Nach dem ich meinen vorherigen Artikel zum Thema [“Asynchrone Kommunikation mit dem Async-Pattern”](/posts/async/) vorgestellt hatte, hat Ralf Westphal auf seinem Blog [“One Man Think Tank Gedanken”](http://ralfw.blogspot.com/2010/05/asynchrone-kommunikation-mit-ebcs-statt.html) das Vorgehen zur Implementierung einer asynchronen Kommunikation mit Hilfe von Event-Based-Components vorgestellt, welches eine sehr gute Alternative zum Async-Pattern ist. Seinen Eintrag nehme ich zum Anlass, um meine Beispiel-Implementierung des Async-Pattern zu refaktorisieren, um eine bessere Trennung der Verantwortlichkeiten und somit eine bessere Lesbarkeit zu erreichen.
In das Form wird die Abhängigkeit “CalcProxy” injected.
static void Main()
{
CalcProxy calcProxy = new CalcProxy(new Calculator());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1(calcProxy));
}
Im Gegensatz zur vorherigen Version wird in der Form nun nicht mehr der Calculator direkt erzeugt und verwendet, sondern auf den injekteten CalcProxy zugegriffen.
public partial class Form1 : Form {
private readonly ICalcProxy m\_calcProxy;
public Form1(ICalcProxy calcProxy) {
        InitializeComponent();
        m\_calcProxy = calcProxy;
        m\_calcProxy.CalcCompleted += CalculatorCalcCompleted;
    }
private void Run\_Click(object sender, EventArgs e) {
int number;
if (Int32.TryParse(txbEingabe.Text, out number)) {
            m\_calcProxy.CalcAsync(number, number);
        }
    }
void CalculatorCalcCompleted(object sender, CalcEventArgs eventArgs) {
        lblCounter.Text = eventArgs.UserState.ToString();
    }
}
Der CalcProxy wiederum bekommt die Abhängigkeit zum Calculator injected und stellt für die Calculator.Calc-Methode sowohl eine synchrone als auch eine asynchrone Methode zur Verfügung.
public class CalcProxy : ICalcProxy {
private readonly ICalculator m\_calculator;
public event CalcCompletedEventHandler CalcCompleted;
private AsyncOperation m\_asyncOperation;
private bool m\_isRunning;
public CalcProxy(ICalculator calculator) {
        m\_calculator = calculator;
    }
public int Calc(int number) {
return m\_calculator.Calc(number);
    }
public void CalcAsync(int number, object userState) {
lock (this) {
if (m\_isRunning) {
throw new InvalidOperationException("Diese Operation wird bereits ausgeführt");
            }
            m\_isRunning = true;
            m\_asyncOperation = AsyncOperationManager.CreateOperation(userState);
ThreadPool.QueueUserWorkItem(ExecuteCalc, number);
        }
    }
private void ExecuteCalc(object state) {
var result = Calc((int)state);
        m\_asyncOperation.PostOperationCompleted(CalcCompletedSuccessful, result);
    }
private void CalcCompletedSuccessful(object result) {
if (CalcCompleted != null) {
            CalcCompleted(this, new CalcEventArgs(null, false, (int)result, result));
        }
    }
}
Nun enthält der Calculator nur noch die Methode die für den Calculator notwendig ist, nämlich die Calc-Methode.
public class Calculator : ICalculator {
public int Calc(int number) {
Thread.Sleep(10000);
return number \* number;
    }
}
<img src="/images/async-refactored/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. <img src="/images/async-refactored/3e7b6cb163ea9cc8549abcb8b5a03e2e.jpeg" width="32" height="32" class="avatar avatar-32 photo"/> **[Ralf Westphal](http://ralfw.blogspot.com/)**
[Mai 6, 2010 um 3:02 pm](/posts/async-refactored/)
Freut mich, dass du meinen Blogartikel hilfreich fandest. Du hast jetzt den Async-Infrastrukturcode herausgezogen. Die Businesslogik ist wieder deutlich sichtbar. Super.
Aber ich frage mich: Was machst du, wenn du drei verschiedene Klassen wir Kalkulator in der Weise async machen willst? Willst du dann drei Proxies basteln?
-Ralf
2. **[Tweets that mention build broken » Asynchrone Kommunikation mit dem Async-Pattern (Refactored) -- Topsy.com](/posts/async-refactored/)**
[Mai 6, 2010 um 4:38 pm](/posts/async-refactored/)
[...] This post was mentioned on Twitter by .NET German Bloggers, DeveloperBlogs. DeveloperBlogs said: Asynchrone Kommunikation mit dem Async-Pattern (Refactored): Nach dem ich meinen vorherigen Artikel zum Thema “Asy… <http://bit.ly/9eV2kr> [...]
3. **[Rainer Hilmer](http://dotnet-forum.de/blogs/rainerhilmer/default.aspx)**
[Juli 24, 2010 um 1:56 pm](/posts/async-refactored/)
Hallo,
ich hab ein paar Fragen zu deinem Demo.
1. Warum benutzt du immer noch m\_ als Prefix für lokale Objekte?
2. Warum benutzt du englische UND deutsche Membernamen?
3. Warum hat der CalcEventArgs-Constructor vier Parameter, obwohl de Facto nur eines im Demo benutzt wird? Ist das YAGNI oder spielt das in anderen Szenarien eine Rolle? Wofür wären dann die anderen Parameter gedacht? Kannst du das mal erläutern?
4. Wo ist der ganze Rest von dem Code?
4. **Thomas Christian**
[Juli 27, 2010 um 8:41 am](/posts/async-refactored/)
Hallo,
um deine Fragen zu beantworten:
zu 1) Das ist halt alles eine Frage des Geschmacks. Ich persönlich mag es, wenn ich auf dem ersten Blick erkennen kann, dass es sich um eine globale Variable handelt.
zu 2) Ich gehe mal davon aus, dass du auf das txtEingabe anspielst. Naja, abgesehen, von den Controls, sind alle Variablen englisch. Die Controls sind das Frontend und dort wollte ich eigentlich deutsch bleiben. In der eile ist mir wohl der lblCounter als englischer Name durchgerutscht.
zu 3) Das liegt daran, dass CalcEventArgs von AsyncCompletedEventArgs ableitet und die zusätzlichen Parameter benötigt.
zu 4) Ich weiß zwar nicht genau welchen Code du vermisst, aber ich denke mal du meinst CalcEventArgs. Bei diesem Blogeintrag handelt es sich um eine refaktorisierte Version meines vorherigen Eintrags. Dort ist auch das CalcEventArgs vorhanden. `/posts/async/`
Ich hoffe ich konnte dir die Fragen ausreichend beantworten.
Gruß Tom
+204
View File
@@ -0,0 +1,204 @@
---
title: "Asynchrone Kommunikation mit dem Async-Pattern"
date: 2010-05-05
slug: async
original_url: "https://aztec-project.org/blog/aync.html"
archive_url: "https://web.archive.org/web/20251110231532/https://aztec-project.org/blog/aync.html"
author: "Thomas Christian"
categories: ["Architektur", "Pattern", "Tipps"]
---
Bevor ich anhand eines Beispiels zeige, wie man mit Hilfe des Async-Pattern ein asynchrone Kommunikation implementieren kann, möchte ich kurz beschreiben, wo der Unterschied zwischen der synchronen und der asynchronen Kommunikation liegt und wofür die asynchrone Kommunikation nützlich ist.
**Synchrone Kommunikation**
Bei der synchronen Kommunikation handelt es sich um eine Echtzeit-Kommunikation. Das bedeutet, dass Anfragen und Antworten jeweils vollständig nacheinander abgearbeitet werden. Kommuniziert ein Prozess mit einem Webserver synchron, so ist der Prozess solange blockiert, bis er die vollständige Antwort vom Webserver erhalten hat.
**Asynchrone Kommunikation**
Im Gegensatz zur synchronen Kommunikation handelt es sich bei der asynchronen Kommunikation nicht um eine Echtzeit-Kommunikation. Das bedeutet, dass bei der Kommunikation eines Prozesses mit einem Webserver der Prozess nicht blockiert. Der Prozess verschickt lediglich die Anfrage an den Webserver und kehrt danach sofort zur weiteren Prozessausführung zurück. Der Prozess geht dabei davon aus, dass die Anfrage an den Webservice korrekt gestellt wurde. Die Antwort wird dann zu einem unbestimmten Zeitpunkt vom Webservice geliefert, und zwar dann, wenn dieser mit der Abarbeitung der Anfrage fertig ist.
**Warum Asynchrone Kommunikation**
Asynchrone Kommunikation bietet sich in unterschiedlichsten Situationen an. So ist es z.B. sinnvoll, dass eine WinForms-Anwendung asynchron mit einem Webservice kommuniziert, da der Haupt-Thread der WinForm-Anwendung sonst so lange blockiert wäre, bis der Webservice die Antwort auf die Anfrage liefert. Die Folge wäre, dass im Titel der Anwendung stehen würde, dass die Anwendung nicht antwortet (s. Abbildung 1). Viele Benutzer denken dass es sich bei dieser Meldung um einen Fehler im Programm handelt und beenden das Programm fix über den Task-Manager. Dabei lag es nur an der etwas länger dauernden Kommunikation zwischen der WinForm-Anwendung und dem Webservice.
[<img src="/images/async/keineRueckmeldung.png" title="keineRueckmeldung" width="308" height="53" class="aligncenter size-full wp-image-973"/>](/images/async/keineRueckmeldung.png) Abbildung 1
Ein weiterer Grund für eine asynchrone Kommunikation wäre, wenn eine Anwendung nur Nachrichten verschicken möchte und es im Grunde keine Rolle spielt, ob diese Nachricht korrekt verarbeitet wurde. Vorstellbar wäre hier Loggen von Aktionen. Mir wäre es jetzt egal, ob die Nachricht korrekt gespeichert wurde oder nicht. Ich will nur nicht, dass meine Anwendung, nur weil Daten geloggt werden müssen, langsamer wird. Es handelt sich ja bei den Log-Daten nicht um Informationen die für die Abarbeitung notwendig sind.
Ein weiterer Fall wäre z. B. das Skalieren von Datenbankabfragen. So könnten mehrere Threads gleichzeitig Daten von gleichen oder unterschiedlichen Datenbeständen abfragen um schnellere Antwortzeiten zu erhalten.
**Beispiel**
Um die asynchrone Kommunikation zu realisieren gibt es unterschiedliche Möglichkeiten. Ich habe mich allerdings für eine Event-Based-Variante entschieden. Der große Vorteil von einem Event-Based Async-Pattern liegt in meinen Augen darin, dass der Nutzer von asynchrone Methoden sich nicht wirklich mit Multithread-Umgebungen auskennen muss. Für den Nutzer ist es völlig transparent wie die Threads im Hintergrund erzeugt werden und wie die Synchronisation der einzelnen Thread funktioniert. Für den Nutzer ist es nur wichtig zu wissen, dass er eine Methode aufrufen kann die asynchron abläuft und somit nicht den erwarteten Rückgabewert besitzt wie die synchrone Methode und dass ein Event ausgelöst wird, wenn die Methode komplett abgearbeitet wurde und der erwartete Rückgabewert zur Verfügung steht.
Nun aber genug geredet, jetzt wird programmiert. Für das Beispiel habe ich mich für eine WinForm-Anwendung entschieden, die nichts anderes tut, als die eingegebene Zahl zu quadrieren. Diese Berechnung dauert aufgrund eines Thread.Sleep() zehn Sekunden, um eine verzögerte Ausführung zu simulieren. Die Berechnung habe ich dabei in eine extra Komponente ausgelagert, die eine Schnittstelle zur asynchronen Kommunikation bereitstellt. Dabei gilt es eine gewisse Namenskonvention einzuhalten. Neben der synchronen Methode „Calc“, wird die asynchrone Methode mit dem Zusatz „Async“ bezeichnet („CalcAsync“). Da das Async-Pattern Event-Based ist, muss ein Event bereitgestellt werden, welches ausgelöst wird, wenn die asynchrone Verarbeitung beendet wurde. Laut Namenskonvention muss solch ein Event „<Methodenname>Completed“ heißen. Mein Event heißt somit „CalcCompleted“.
Die Abbildung 2 zeigt die UI der Anwendung. Bei dem Drücken des „Run“-Buttons, soll die eingegebene Zahl asynchron quadriert werden und im Anschluss in das Feld „Ergebnis“ ausgegeben werden.
[<img src="/images/async/Form1.png" title="Form1" width="300" height="200" class="aligncenter size-full wp-image-980"/>](/images/async/Form1.png)Abbildung 2
Der Code hinter der UI sieht folgendermaßen aus. Beim instanziieren des Forms, wird eine Instanz des Calculators erstellt und ein Delegate auf das „CalcCompleted“-Event registriert. Dieses Event wird aufgerufen sobald der Calculator mit der Berechnung fertig ist.
Bei dem Drücken des „Run“-Buttons, wird die Methode Calculator.CalcAsync(…) aufgerufen.
```
public partial class Form1 : Form {
private ICalculator m_calculator;
public Form1() {
InitializeComponent();
m_calculator = new Calculator ();
m_calculator.CalcCompleted += Calculator_CalcCompleted;
}
private void Run_Click( object sender, EventArgs e) {
int number;
if ( Int32 .TryParse(txbEingabe.Text, out number)) {
m_calculator.CalcAsync(number, number);
}
}
void Calculator_CalcCompleted( object sender, CalcEventArgs eventArgs) {
lblCounter.Text = eventArgs.Result.ToString();
}
}
```
Sobald die Berechnung fertig ist, wird das CalcCompleted-Event ausgelöst und somit die Calculator\_CalcComplete-Methode aufgerufen und das Ergebnis der Berechnung in ein Label geschrieben. Der große Vorteil ist, dass man sich an dieser Stelle nicht mehr um die Synchronisierung der Threads kümmern muss, sodass man direkt auf das Label schreiben darf und es nicht zu einem threadübergreifenden Zugriff kommt.
Der Calculator sieht wie folgt aus:
```
public interface ICalculator {
event Calculator . CalcCompletedEventHandler CalcCompleted;
int Calc( int number);
void CalcAsync( int number, object userState);
}
public class Calculator : ICalculator {
public delegate void CalcCompletedEventHandler ( object sender, CalcEventArgs eventArgs);
public event CalcCompletedEventHandler CalcCompleted;
private AsyncOperation m_asyncOperation;
private bool m_isRunning;
public int Calc( int number) {
Thread .Sleep(10000);
return number * number;
}
public void CalcAsync( int number, object userState) {
lock ( this ) {
if (m_isRunning) {
throw new InvalidOperationException ( "Diese Operation wird bereits ausgeführt" );
}
m_isRunning = true ;
m_asyncOperation = AsyncOperationManager .CreateOperation(userState);
ThreadPool .QueueUserWorkItem(ExecuteCalc, number);
}
}
```
        .
        .
        .
```
}
```
Wie man im Interface des Calculator sieht, gibt es eine synchrone und eine asynchrone Methode für die Berechnung. Uns interessiert allerdings nur die asynchrone Methode. Das lock und die Prüfung auf m\_isRunning verhindern lediglich, dass die asynchrone Methode während ihrer Ausführung öfter aufgerufen wird. Das Wesentliche an dieser Methode ist der Aufruf von AsyncOperationManager.CreateOperation, denn dieser Aufruf stellt einen Synchronisationskontext bereit, der die Threads miteinander synchronisiert. Für die eigentliche Berechnung wird sich über den ThreadPool ein neuer Thread besorgt, der sich dann um die Abarbeitung der ExecuteCalc in einem eigenen Thread kümmert.
```
public class Calculator : ICalculator {
```
        .
        .
        .
```
private void ExecuteCalc( object state) {
int result = Calc(( int )state);
m_asyncOperation.PostOperationCompleted(CalcCompletedSuccessful, result);
}
private void CalcCompletedSuccessful( object result) {
if (CalcCompleted != null ) {
CalcCompleted( this , new CalcEventArgs ( null , false , ( int )result, result));
}
}
}
public class CalcEventArgs : AsyncCompletedEventArgs {
public CalcEventArgs( Exception error, bool cancelled, int result, object userState)
: base (error, cancelled, userState) {
Result = result;
}
public int Result { get ; private set ; }
}
```
Sobald die Berechnung abgeschlossen ist, wird der Thread mit dem MainThread über den Aufruf von PostOperationCompleted synchronisiert und das CalcCompleted-Event ausgelöst und das Ergebnis in das Label geschrieben (s. o.).
6 public partial class Form1 : Form {
7 private ICalculator m\_calculator;
8 public Form1() {
9 InitializeComponent();
10 m\_calculator = new Calculator();
11 m\_calculator.CalcCompleted += Calculator\_CalcCompleted;
12 }
13
14 private void Run\_Click(object sender, EventArgs e) {
15 int number;
16 if (Int32.TryParse(txbEingabe.Text, out number)) {
17 m\_calculator.CalcAsync(number, number);
18 }
19 }
20
21 void Calculator\_CalcCompleted(object sender, CalcEventArgs eventArgs) {
22 lblCounter.Text = eventArgs.UserState.ToString();
23 }
24 }
<img src="/images/async/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. <img src="/images/async/3e7b6cb163ea9cc8549abcb8b5a03e2e.jpeg" width="32" height="32" class="avatar avatar-32 photo"/> **[Ralf Westphal](http://ralfw.blogspot.com/)**
[Mai 6, 2010 um 10:34 am](/posts/async/)
Statt eines Kommentars ein Blogartikel, der eine alternative Implementation mit Event-Based Components zeigt:
<http://ralfw.blogspot.com/2010/05/asynchrone-kommunikation-mit-ebcs-statt.html>
2. **[build broken » Asynchrone Kommunikation mit dem Async-Pattern (Refactored)](/posts/async-refactored/)**
[Mai 6, 2010 um 2:37 pm](/posts/async/)
[...] « Asynchrone Kommunikation mit dem Async-Pattern Mai 06 2010 [...]
3. **[Tweets that mention build broken » Asynchrone Kommunikation mit dem Async-Pattern -- Topsy.com](/posts/async/)**
[Mai 6, 2010 um 9:17 pm](/posts/async/)
[...] This post was mentioned on Twitter by .NET German Bloggers. .NET German Bloggers said: Asynchrone Kommunikation mit dem Async-Pattern: Bevor ich anhand eines Beispiels zeige, wie man mit Hilfe des Asyn… <http://bit.ly/dfCLjB> [...]
+56
View File
@@ -0,0 +1,56 @@
---
title: "BarCamp Bodensee 2010"
date: 2010-06-06
slug: barcamp-bodensee-2010
original_url: "https://aztec-project.org/blog/barcamp-bodensee-2010.html"
archive_url: "https://web.archive.org/web/20250114114407/https://aztec-project.org/blog/barcamp-bodensee-2010.html"
author: "Stefan Kölle"
categories: ["BarCamp"]
tags: ["datenschutz", "facebook", "socialweb", "sonne"]
---
Dieses Wochenende findet das [BarCamp Bodensee 2010](http://barcampbodensee.mixxt.eu/) statt. Ich war gestern dort und habe interessante Sessions besucht.
Sehr gut fand ich die Session “Decentralized Social Web”, nachdem ich schon lange selbst über das Thema nachgedacht habe. In der Session wurde gut herausgearbeitet, Grundgedanke ist ein Protokoll wie IP zu schaffen, also ein Konzept zu entwickeln um die Daten seiner Friends und sozialen Kontakte selbst zu besitzen und diese bei sozialen Netzwerken dann zu verwenden. Der Betreiber eines sozialen Netzwerks selbst soll die Daten nicht besitzen bzw. nur in verschlüsselter Form auf sie zugreifen können. Ändert man selbst die Zugriffsrechte, besitzt die Plattform zwar noch die Daten, kann auf diese jedoch nicht mehr zugreifen.
Noch verstehen Nutzer den Mehrwert nicht und die Lösungen sind zu komplex, um dem Normaluser hier den Einstieg zu erleichtern. Ein Nutzer von sozialen Netzwerken möchte einen Service und den bekommt er derzeit bei Facebook. Diese Entwicklung ist gefährlich, da sich Facebook zur allgemeinen Datensammelstelle entwickelt, die alles kontrolliert. “My data belongs to me”. Nur sind wir technisch affinen Menschen hier zu paranoid? Der Normaluser bekommt im Moment genau das, was er möchte: eine gesicherte, schnelle Dienstleistung. Auf die Frage, wer für Facebook zu zahlen bereit wäre, kamen erstaunlich viele Meldungen, man sieht Facebook also als einen Dienstleister.
Gut jedoch zu sehen, dass sich bereits Projekte aufgetan haben das decentralized social web zu erkunden:
**Movim**
Ziel des MOVIM-Projekts (für My Open Virtual Identity Manager), ist eine vollständige und total dezentrale soziale Platform zu entwickeln, die ihre User einfach respektiert.
<http://www.movim.eu/>
**Diaspora**
The privacy aware, personally controlled, do-it-all, open source social network.
<http://joindiaspora.com/>
**Web Finger**
Personal Web Discovery, making email addresses readable again
<http://code.google.com/p/webfinger/>
Es gab noch viele weitere gute Sessions, das Wetter hat gestern gut mitgespielt und viele Teilnehmer haben sich gerne in der Sonne aufgehalten und dort genetzwerkt.
Die [love coaches von be2](http://www.be2.de/blog/) waren auch wieder dabei und [verlosen heute eine faltbare Sitzcouch](http://www.be2.de/blog/barcamp/), die Flexible Love Bank von myfab.
[<img src="/images/barcamp-bodensee-2010/IMG_0247-300x225.jpg" title="be2 Verlosung" width="300" height="225" class="alignnone size-medium wp-image-1056"/>](/images/barcamp-bodensee-2010/IMG_0247.jpg)
## Kommentare (Archiv)
1. **[Fiona](http://www.be2.de/blog)**
[Juni 6, 2010 um 9:35 pm](/posts/barcamp-bodensee-2010/)
Cooles Foto! Leider war der Beitrag zu spät für den Hauptgewinn den haben wir schon vor Ort vergeben, aber den Sofortgewinn bekommst Du noch!
2. **[Michaela](http://www.be2.de/blog/barcamp/)**
[Juni 9, 2010 um 11:59 am](/posts/barcamp-bodensee-2010/)
Vielen Dank für die Zusammenfassung der session “Decentralized Social Web”. Leider habe ich die verpasst und deshalb Daumen hoch für die nachträgliche Berichterstattung.
3. **[otourly](http://wiki.movim.eu/index.php?title=Utilisateur:Otourly)**
[Juni 13, 2010 um 11:27 am](/posts/barcamp-bodensee-2010/)
The Movim project is an open one. Mainly francophone, it is open to others languages. If you want, you coud help us by give to us ideas, translations, or blog posts’…
Kind regards,
Otourly
@@ -0,0 +1,36 @@
---
title: "Clean Code Developer The Yellow Brick Road of the Coder"
date: 2009-07-14
slug: clean-code-developer-yellow-brick-road
original_url: "https://aztec-project.org/blog/clean-code-developer-yellow-brick-road.html"
archive_url: "https://web.archive.org/web/20250601101331/https://aztec-project.org/blog/clean-code-developer-yellow-brick-road.html"
author: "Christina Hirth"
categories: ["Clean Code Developing"]
tags: ["CCD", "Community"]
---
Seit dem ich Code schreibe, steht für mich ein klarer und verständlicher Code an oberster Stelle. Ich hatte dann vor ca. eineinhalb Jahren [Code Complete](http://www.amazon.de/Code-Complete-Deutsche-Ausgabe-Second/dp/386063593X/ref=sr_1_2?ie=UTF8&s=books&qid=1247574862&sr=8-2) und [The Pragmatic Programmer](http://www.amazon.de/Pragmatische-Programmierer-Andrew-Hunt/dp/3446223096/ref=sr_1_1?ie=UTF8&s=books&qid=1247574887&sr=1-1) gelesen und dadurch die ersten Antworten bekommen, WIE man den Code unter Kontrolle hält. Anfang 2009 sind wir ich und Stefan durch den [Podcast von Hanselman und Uncle Bob](http://www.hanselman.com/blog/HanselminutesPodcast145SOLIDPrinciplesWithUncleBobRobertCMartin.aspx) auf das Thema SOLID gestoßen und darüber auch eine ausgiebige Diskussion geführt. Eins war uns klar: die Ideen, die dahinter stecken, könnten die Antwort auf unsere Suche sein.
Deshalb hat mich sehr gefreut, als ich von der Seite [Clean Code Developer](/posts/clean-code-developer-yellow-brick-road/) erfahren habe. Ihr Inhalt hat mich sofort begeistert. Sie beschreibt einen wahrscheinlich DEN möglichen Weg um ein **professioneller Softwareentwickler** zu werden.
Am letzten Wochenende auf dem [.NET Open-Space-Süd](http://ulm.netopenspace.de/) habe ich das große Vergnügen gehabt, [Stefan Lieser](http://www.lieser-online.de/blog/), einen der Gründer von [Clean Code Developer](http://clean-code-developer.de/)-Seite kennen zu lernen und so konnte ich in den 2 Tagen viel über den Weg von einem *Creepy-Code-Programmer* zu einem *Clean-Code-Programmer* erfahren.
Die Grundidee ist ganz einfach: genauso wie ein Arzt oder ein Architekt, muss auch ein professioneller Softwareentwickler Verantwortung für seine Arbeit und für die Ergebnisse dieser Arbeit übernehmen. Er/sie muss sicherstellen, dass der Code korrekt, evolvierbar und effizient ist und dass er selbst immer sein Bestes gibt. Damit ist nicht gemeint, dass jeder ein Guru sein muss. Nein, professioneller Softwareentwickler ist derjenige, der an einem Wertesystem festhält und immer die Qualität des Codes vor den Augen hat.
Viele werden sagen “Wozu die Mühe, es funktioniert auch so!”. Klar, wenn man nur für den Jetzt programmiert. Dann, nach kurzer Zeit passiert das unvermeidliche: jemand oder der Entwickler selbst muss den furchterregend schlechten Code bugfixen/verändern. All diese Entwickler, die solche Aufgaben hatten, werden Tests zu schätzen wissen. Diese Tests kosten zwar etwas Mühe aber bescheren einem einen ruhigen Schlaf.
Zu einem genauso großen Problem führt, wenn man das elementarste aller Prinzipien nicht respektiert: **D**ont-**R**epeat-**Y**ourself ([DRY](http://de.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself)). Wie oft passiert, dass man eine Methode, ein Verhalten anpassen muss und überall nach verstreuten Kopien vom Code suchen muss? Könnt ihr jedes Mal garantieren, dass ihr alle erwischt habt? Das wäre keine Frage, wenn der Entwickler des Codes das DRY-Prinzip respektiert.
Der Code, den ein Entwickler schreibt, gehört meistens nicht ihm. Ich bin sicher, keiner von uns möchte als “Creepy-Coder” beschimpft werden, wenn jemand anderer unserer Code verstehen oder weiterentwickeln muss.
Nimmt eure Arbeit ernst und werdet ein professioneller Entwickler. Ihr werdet nach kürzester Zeit die Freude an einem korrekten und qualitativen Code entdecken und auch eure Teamkollegen und Chefs werden dafür dankbar sein.
<img src="/images/clean-code-developer-yellow-brick-road/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. **[build broken » Clean Code Teil 1](/posts/cleancode1/)**
[August 11, 2009 um 12:03 pm](/posts/clean-code-developer-yellow-brick-road/)
[...] « Clean Code Developer The Yellow Brick Road of the Coder Aug 11 2009 [...]
+161
View File
@@ -0,0 +1,161 @@
---
title: "Clean Code Teil 1"
date: 2009-08-11
slug: cleancode1
original_url: "https://aztec-project.org/blog/cleancode1.html"
archive_url: "https://web.archive.org/web/20250114133226/https://aztec-project.org/blog/cleancode1.html"
author: "Andreas Seebauer"
categories: ["Clean Code Developing"]
tags: ["Basics", "Buch", "CCD", "Clean Code", "Coding"]
---
[<img src="/images/cleancode1/c0025902_49cff1bd96e00-225x300.jpg" alt="Clean Code" title="Clean Code" width="95" height="126" class="size-medium wp-image-505 alignleft"/>](/images/cleancode1/c0025902_49cff1bd96e00-225x300.jpg)
Da es für einen Entwickler wichtig ist, sich ständig weiterzuentwickeln, sollte man sich durch Austausch mit anderen Entwicklern, aktives Programmieren oder eben Bücher weiterbilden. Das Buch, das ich gerade lese, heißt Clean Code von Robert C. Martin a.k.a. Uncle Bob. Ich bin momentan bei der Hälfte des Buches und muss sagen, dass ich von dem Buch ziemlich begeistert bin. Da ich denke, dass es vielen Entwicklern helfen würde, besseren Code zu schreiben, habe ich den Text ein wenig verkürzt und zusammengefasst was natürlich nicht heißt, dass man dieses Buch nicht lesen muss. Meiner Meinung nach ist es absolute Pflichtlektüre für jeden Entwickler, der was auf sich hält.
Hier also meine kleine Zusammenfassung.
### Kapitel 1 Clean Code
In diesem Kapitel wird beschrieben, was Clean Code ist und dass man „Clean Code“ schreiben muss, um sich selbst einen professionellen Softwareentwickler nennen zu dürfen. Was Clean Code ausmacht, hat [Christina](/author/christina-hirth/) schon in ihrem Artikel [„Clean Code Developer The Yellow Brick Road of the Coder“](/posts/clean-code-developer-yellow-brick-road/) beschrieben. Außerdem wichtig sind:
**LeBlancs Gesetz : Later equals never**
und
**die Boy Scout Rule : Leave the campground cleaner than you found it**.
### Kapitel 2 Meaningful Names
Benennung in einem Projekt ist sehr wichtig, sei es um das Gesuchte zu finden oder um den Sinn einer Variablen oder einer Methode ohne langes Überlegen zu erkennen. Man sollte bei der Vergabe von Namen so gründlich vorgehen, wie man es für seinen Erstgeborenen tun würde. In der heutigen Zeit ist die Ungarische Notation absoluter Quatsch. Die IDE kennt den Typ, warum sollte man das in den Variablennamen integrieren?
### Kapitel 3 Funktionen
Die erste Regel von Funktionen lautet: Sie sollte klein sein.
Die zweite Regel von Funktionen lautet: Sie sollte noch kleiner sein als das.
Eine Funktion sollte nur eine Sache tun. Macht sie mehr als eine Sache, steigt die Komplexität. Und Komplexität ist schlecht.
Eine gute Benennung der Funktionen ist, wenn der Name beschreibt, was die Funktion macht. Dabei darf der Name ruhig lang sein, wenn es der Lesbarkeit des Codes dienlich ist.
Flagargumente sind verboten! Durch dieses Flag macht die Methode schon mehr als eine Sache und wir wären wieder bei der Sache mit der Komplexität. Böse.
Die ideale Anzahl von Parametern einer Funktion ist 0! Aber da nicht immer alles ideal laufen kann, sind 1, 2 auch okay. Aber mehr als 3 ist verboten. Okay?
Last but not least eine sehr wichtige Grundregel: Dont Repeat Yourself!
Denn: Durch Verdopplung des Codes steigt der Wartungsaufwand proportional.
### Kapitel 4 Kommentare
Kommentare sind schlecht, denn sie lügen! Ja, LÜGE! Code wird häufig verändert durch neue Anforderungen oder Refaktorisierungsmaßnahmen, der dazugehörige Kommentar aber meist nicht, wodurch schlechte bzw. in die Irre führende Kommentare entstehen. Es gilt also: Keine Kommentare sind besser als schlechte Kommentare. Man sollte die Zeit, die man für das Schreiben von Kommentaren aufbringen würde, lieber für die Refaktorierung der Methode verwenden. Denn Code sollte sich selbst erklären und ist außerdem die aktuellste Dokumentation. Nur schlechter Code muss kommentiert werden.
**Auskommentieren des Codes ist verboten!** Andere Programmierer, die den auskommentierten Code sehen, werden diesen nicht löschen, da sie denken, dass es einen Grund haben muss, dass er dort steht und dass er zu wichtig ist, um gelöscht zu werden. Somit bleibt dieser “Kommentar” auf ewig dort und müllt unseren “Clean Code” zu. Heutzutage muss man nichts mehr auskommentieren. Durch Versionskontrolle geht nichts mehr verloren.
### Kapitel 5 Formatting
Eine perfekte Formatierung gibt es nicht, vielleicht für jeden Einzelnen, aber nicht für ein Team. Jeder hat seine Vorlieben. Letzendlich ist nur wichtig, dass sich das Team auf **EINE** Formatierung einigt. Jeder in diesem Team muss sich daran halten, auch wenn es für einen selbst nicht die optimale Lösung ist. Der Nutzen einer gemeinsamen „Sprache“ ist einfach zu groß, denn Kommunikation ist das A und O.
### Kapitel 6 Objects and Data Structures
Es wird grundsätzlich zwischen Objekten und Data Structures unterschieden.
Objekte enthalten Businesslogik und sollten ihre interne Struktur nach außen hin verbergen, also keine Properties, welche die Member-Variablen des Objekts zurückgeben oder verändern lassen. Nur das Objekt selbst sollte seinen internen Status ändern können, wobei bei Objekten auf das Gesetz von Demeter zu achten ist:
Es besagt, dass Objekte nur mit Objekten in ihrer unmittelbaren Umgebung kommunizieren sollen.
Also:
Methode m der Klasse k sollte nur Methoden nutzen von:
* k
* Ein Objekt, dass von m erstellt wurde
* Ein Übergabeparameter an m
* Ein Memberobjekt von k
Data Structures sind zum Beispiel Data Transfer Objects, kurz DTOs. Das sind Klassen ohne Methoden, also reine Datenträger. Eine spezielle Form von DTOs sind Active Records. Diese Objekte haben Methoden wie Save() und Find(), enthalten jedoch keine Businesslogik.
### Kapitel 7 Error Handling
Moderne Programmiersprachen haben ein Feature namens Exceptions. Das sollte man auch nutzen. Fehlercodes oder ähnliches sind veraltet. Eine gute Exception sollte allerdings so viel Information liefern, dass man auch ohne Debuggen den Fehler identifizieren kann, sonst kann man sich die ganze Mühe auch sparen.
Außerdem noch 2 wichtige Grundregeln:
**Dont Return null** somit wird es unnötig auf null zu prüfen
und
**Dont Pass null** null an eine Methode zu übergeben ist noch schlimmer als null zu returnen
### Kapitel 8 Boundaries
Man sollte unbedingt das Adapterpattern anwenden, wenn man 3rd party Code verwendet. 3rd party code sollte an so wenig stellen wie möglich verwendet werden, um Abhängigkeiten zu vermeiden.
### Kapitel 9 Unit Tests
Die 3 Gesetze von TDD:
1. Man darf keinen produktiven Code schreiben, solange man keinen fehlgeschlagenen Unit Test geschrieben hat.
2. Man darf nicht mehr als nötig schreiben, um einen Unit Test fehlschlagen zu lassen, und Fehler beim Kompilieren bedeutet einen fehlgeschlagenen Test.
3. Man darf nicht mehr produktiven Code als nötig schreiben, um einen fehlgeschlagenen Test zu reparieren.
Außerdem gilt: Tests sollten genauso “Clean Code” sein wie produktiver Code. Tests sollten genauso evolvierbar sein. Denn wenn sich der Code verändert, muss sich der Test auch verändern.
Ein Test sollte nur ein Szenario abdecken wieder das Thema Komplexität.
Clean Tests folgen noch 5 anderen Regeln:
**F**ast
**I**ndependent
**R**epeatable
**S**elf Validating
**T**imely
Teil 2 gibt es [hier](/posts/cleancode2/)
<img src="/images/cleancode1/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. **Christina**
[August 11, 2009 um 3:26 pm](/posts/cleancode1/)
Super Zusammenfassung, ich möchte nur ein Paar kleine Ergänzungen machen:
Kleine 3-er Regel zu DRY: einmal schreiben -> OK. Zweimal schreiben -> kann man noch akzeptieren. Dreimal schreiben-> refaktorieren! (Fowler-Refactoring)
Was das KATEGORISCHE Abweisen von Kommentaren betrifft, kann ich wirklich nicht einverstanden sein. Ich kann mir Millionen von Fällen vorstellen, wo ein Name nicht aussagend genug sein kann. aber ich finde auch, dass Namen genau so wichtig sind wie DRY oder The Boy Scout Rule.
Bin schon auf die Fortsetzung gespannt <img src="/images/cleancode1/icon_smile.gif" alt=":)" class="wp-smiley"/>
2. **[Peter Bucher](http://www.aspnetzone.de/blogs/peterbucher/)**
[August 11, 2009 um 7:45 pm](/posts/cleancode1/)
Salute Andreas
Coole Zusammenfassung, gefällt mir gut <img src="/images/cleancode1/icon_smile.gif" alt=":-)" class="wp-smiley"/> .
Ein paar Anmerkungen bzw. Ergänzungen:
Das Buch “Clean Code” ist extra extrem und provokant geschrieben, es soll provozieren.
Man sollte nicht alles 1:1 übernehmen und als bare Münze hinnehmen, sondern nur das und soviel wie es Sinn macht.
Mit den Kommentaren sind nicht die JavaDocs / XmlDocs von C# / VB.NET gemeint. API Dokumentation ist nach wie vor sehr wichtig und hilfreich und sollte benutzt und aktualisiert werden.
Stell dir nur mal ein .NET Framework ohne Intellisense-Kommentare vor <img src="/images/cleancode1/icon_smile.gif" alt=":-)" class="wp-smiley"/> .
Zu dont`t return null / don`t pass null muss ich sagen, das Clean Code auf Java fokusiert ist und das dort anders sein
kann. Man sollte null mit Bedacht und Strategie einsetzen, so eine pauschale Aussage kann ich aber für C# nicht gelten lassen.
Denn zum Teil ist das bei .NET selber Konvention (ob das jetzt gut oder schlecht ist, lassen wir mal aussen vor),
oder sinnvoll gar nicht anders möglich.
Eine interessante Diskussion dazu findet sich bspw. auf:
- <http://www.mycsharp.de/wbb2/thread.php?threadid=69181&hilight=null+funktion+php+peter>
Grüsse aus der Schweiz, Peter
3. **[Rene Drescher-Hackel](http://weblog.drescher-hackel.de/)**
[August 28, 2009 um 12:29 am](/posts/cleancode1/)
Ich kann Peter hier nur zustimmen. Ergänzend sei noch gesagt was keine wertende Aussage zum Blogbeitrag sein soll dass die ganze Diskussion um Clean Code inzwischen aus meiner Sicht recht übertrieben wird. Um sauberen Code zu schreiben, muss ich weder ein Armband tragen, noch muss ich Pyramiden falten oder entsprechende T-Shirts tragen. Da fällt mir eine sehr praktische Redensart ein: “Es gibt nichts Gutes, außer man tut es”. Und so ist es auch mit der losgetretenen “Clean Code Debatte”.
Was letztlich “sauberer Code” ist, wird doch von vielen Faktoren bestimmt, die im Wesentlichen aus einem Allgemeinverständnis herrührt und aber auch vom Entwicklerteam maßgeblich mit beeinflusst wird. Sicher, man sollte nicht unbedingt ein 500 Seiten umfassendes Referenzwerk zu Rate ziehen müssen, um den Code des Kollegen zu verstehen. Gelegentlich sieht man auch immer wieder noch den ungeliebten “Spagetthi-Code”, was keineswegs erstrebenswert ist.
Aber müssen wir denn jetzt alle um jeden Preis nach den Empfehlungen des Buches “Clean Code” von Robert C. Martin unseren Code umschreiben? Nein, ich denke, manchmal ist es viel vernünftiger seinem Stil treu zu bleiben. Dennoch kann man dabei funktionellen, sauberen, lesbaren Code schreiben.
Wenn ich lese, dies und das ist “böse” und “verboten”, dann hat das etwas von “Bibel”, wo ich mich dann frage, wer gibt hier wem das Recht, Dinge als “verboten” zu deklarieren.
Also man sollte bei aller Clean-Code Diskussion immer das Ziel nicht aus den Augen verlieren und vor allem auf dem Teppich bleiben. <img src="/images/cleancode1/icon_wink.gif" alt=";-)" class="wp-smiley"/>
Grüße aus dem Frankenland.
Rene
4. **[build broken » Clean Code Teil 2](/posts/cleancode2/)**
[November 4, 2009 um 4:16 pm](/posts/cleancode1/)
[...] habe das Buch “Clean Code” von Robert C. Martin a.k.a. Uncle Bob durchgelesen. Nach dem ersten Teil hier nun die versprochene Fortsetzung meiner [...]
5. **[Anonymous](http://www.delphipraxis.net/155561-mehrere-formulare-stringgridgroesse-anpassen-4.html#post1058834)**
[Oktober 31, 2010 um 6:51 pm](/posts/cleancode1/)
[...] [...]
+118
View File
@@ -0,0 +1,118 @@
---
title: "Clean Code Teil 2"
date: 2009-11-04
slug: cleancode2
original_url: "https://aztec-project.org/blog/cleancode2.html"
archive_url: "https://web.archive.org/web/20250114122055/https://aztec-project.org/blog/cleancode2.html"
author: "Andreas Seebauer"
categories: ["Clean Code Developing"]
tags: ["Buch", "CCD", "Clean Code", "Coding"]
---
Endlich ist es geschafft. Ich habe das Buch “Clean Code” von Robert C. Martin a.k.a. Uncle Bob durchgelesen. Nach dem [ersten Teil](/posts/cleancode1/) hier nun die versprochene Fortsetzung meiner Zusammenfassung:
**10 Classes**
Die erste Regel von Klassen lautet: Sie sollten klein sein.
Die zweite Regel von Klassen lautet: Sie sollten noch kleiner sein als das.
Klassen sollten eine hohe Kohäsion haben.
Kohäsion ist ein Maß dafür, wie stark die Methoden und Daten einer Klasse miteinander zu tun haben. Zur Verdeutlichung:
Eine Klasse, in der jede Membervariable von jeder Methode der Klasse verwendet wird, ist maximal kohäsiv.
Bei Klassen sollten folgende Prinzipien beachtet werden:
* Das **Single Responsibility Principle** (**SRP**), welches besagt:
Eine Klasse oder ein Modul sollte nur einen Grund haben sich zu ändern. Eine Klasse sollte sich nur um **EINE** Sache kümmern.
* Das **Open Close Principle** (**OCP**), welches besagt:
Klassen sollten offen für Erweiterungen sein, aber geschlossen für Modifikation.
* Das **Dependency Inversion Priniciple** (**DIP**), welches besagt:
Klassen sollten von Abstraktionen abhängen und nicht von konkreten Klassen.
**11 Systems**
Separiere Konstruktion von Benutzung.
Realisiert werden kann das durch Dependency Injection.
Dependency Injection = Klassen bekommen ihre Abhängigkeiten von außen über den Konstruktor oder Setter übergeben. Dieses Pattern unterstützt das SRP, da sich die Klasse nicht mehr um das Instanzieren dieser Abhängigkeiten kümmern muss. Realisiert wird das ganze über Inversion of Control Container wie Windsor, Spring und wie sie alle heißen. Bei diesen Containern werden die Abhängigkeiten einmalig definiert, so dass man sich bei der Instanzierung nicht mehr darum kümmern muss.
Wenn Objekte zu einer bestimmten Zeit erstellt werden müssen, sollten Factories verwendet werden.
Systeme werden nicht von heute auf morgen gebaut. Sie werden nach und nach ausgebaut. Um sicherzustellen, dass dabei noch alles funktioniert, gibt es TDD, Refaktorisieren und Separation of Concerns.
**12 Emergence**
Viele Leute sagen, dass Kent Becks 4 “Rules of Simple Design” einem sehr helfen, gut designte Software zu erstellen.
Kent Beck sagt:
ein Design ist „simple“, wenn:
* alle Tests durchlaufen
* kein doppelter Code vorhanden ist
* wenn es die Absicht des Programmierers ausdrückt
* die Anzahl von Klassen und Methoden minimiert sind
in der Reihenfolge.
**13 Concurrency**
In Multithread-Anwendungen bekommt man schon bei minimaler Anforderung ein Problem mit der Komplexität. Da mit steigender Komplexität auch die Fehleranfälligkeit steigt, gibt es ein paar Prinzipien, die diese minimieren können:
Die Concurrency Defense Principles
* **Single Responsibility Principle**
Trenne multithreaded Code von nicht-multithreaded Code
* **Limit the Scope of Data**
Man sollte den Bereich, in dem multithreaded Code verwendet wird, möglichst klein halten.
* **Use Copies of Data**
Verschiedene Threads sollten nicht mit demselben Objekt arbeiten. Wenn möglich sollte mit Kopien von diesem Objekt gearbeitet werden.
* **Independence**
Threads sollten so unabhängig wie möglich sein
* **Library**
Natürlich sollte man die Bibliothek, die man für Multithread-Anwendungen verwendet, sehr gut kennen.
**14 Successive Refinement**
Um Clean Code schreiben zu können, muss man erst Dirty Code schreiben und ihn dann bereinigen.
Einer der besten Wege, ein Programm zu ruinieren, ist, massive Änderungen an der Struktur vorzunehmen, um das Programm zu verbessern. Um das zu verhindern, nutzt man die Disziplinen von TDD. Eines der zentralen Doktrinen dieses Ansatzes ist es, das System zu jeder Zeit lauffähig zu halten. Mit TDD ist es also nicht erlaubt eine Veränderung am System vorzunehmen, die das System bricht.
**15 JUnit Internals**
JUnit Internals halt… (Kapitel überlesen)
**16 Refactoring SerialDate**
War mir eindeutig zu Java-lastig… (Kapitel überlesen)
**17 Smells and Heuristics**
In diesem Kapitel zeigt Uncle Bob eine Liste von Smells und wie man sie beseitigen kann. Er lobt das Buch “Refactoring” von Martin Fowler. Dieses Buch steht eh schon ganz oben auf meiner To-do-Liste. Das werde ich also demnächst angehen.
**Zusammenfassung**
An dieser Stelle ein Dank an mein Entwicklerteam, dass ich das Buch so lange in Beschlag nehmen durfte <img src="/images/cleancode2/icon_smile.gif" alt=":)" class="wp-smiley"/> (Teil 2 ging irgendwie zäher). Einen großen Dank auch an [Peter Bucher](http://www.aspnetzone.de/blogs/peterbucher/) und [Rene Drescher-Hackel](http://weblog.drescher-hackel.de/) für ihre Ergänzungen bzw. Einwände. Man darf sicherlich nicht alles so ganz ernst nehmen und man kann es auch übertreiben (siehe Pyramiden etc.). Natürlich sollte man nicht blind durch die Welt laufen, sondern auch Dinge hinterfragen, aber man muss sagen, dass die Punkte von [CCD](http://www.clean-code-developer.de/) (das ja auf diesem Buch beruht) durchaus plausibel sind. Ich denke schon, dass [CCD](http://www.clean-code-developer.de/) unerfahrenen aber auch erfahrenen Entwicklern einen SOLIDen Weg zeigt, den man gehen kann und der sogar schon gepflastert ist. Man kann sich natürlich auch mit der Machete durch dichten Dschungel schlagen, was natürlich cool ist <img src="/images/cleancode2/icon_smile.gif" alt=":)" class="wp-smiley"/> aber halt wesentlich langsamer. Es sei denn man ist Chuck Norris.
<img src="/images/cleancode2/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. **[build broken » Clean Code Teil 1](/posts/cleancode1/)**
[November 4, 2009 um 4:20 pm](/posts/cleancode2/)
[...] Teil 2 gibt es hier [...]
+47
View File
@@ -0,0 +1,47 @@
---
title: "Visual Studio Code in HTML umwandeln"
date: 2009-06-06
slug: code-to-html
original_url: "https://aztec-project.org/blog/code-to-html.html"
archive_url: "https://web.archive.org/web/20250114134712/https://aztec-project.org/blog/code-to-html.html"
author: "Andreas Seebauer"
categories: ["Visual Studio Addins"]
tags: ["Addin", "HTML", "Sourcecode", "Visual Studio", "Wordpress"]
---
Da wir kein geeignetes Plugin für Wordpress gefunden haben, um .NET-Code wie in Visual Studio darzustellen, habe ich ein wenig gegooglet und bin auf ein Addin namens “Copy Source As HTML” für Visual Studio 2008 gestoßen. Mit diesem Addin ist es möglich, seinen Sourcecode schön formatiert in HTML umzuwandeln.
Downloadlink und Anleitung findet man [hier](http://www.jtleigh.com/people/colin/software/CopySourceAsHtml/).
Nach der Installation steht im Kontextmenü neben Copy, Paste usw. auch der Punkt “Copy As HTML…” zur Verfügung. Bevor der umgewandelte Sourcecode in den Zwischenspeicher gespeichert wird, hat man die Möglichkeit, seine Konfiguration anzupassen.
Hierfür habe ich folgende Konfiguration verwendet:
<img src="/images/code-to-html/config.jpg" alt="Config"/>
Nach der Bestätigung der Konfiguration sieht das Ergebnis folgendermaßen aus :
```
/// <summary>
/// Summary
/// </summary>
class Program {
static void Main() {
// Kommentar
Console .WriteLine( "Hello World" );
}
}
```
## Kommentare (Archiv)
1. **Stefan Kölle**
[Juni 9, 2009 um 12:23](/posts/code-to-html/)
Leider kann man den Code vom Blog dann nur schwer wieder in Visual Studio zurueck kopieren.
2. **Thomas Christian**
[Juni 10, 2009 um 11:45](/posts/code-to-html/)
Wenn man die “Number lines from” weglässt, dann kann man den Code wieder gut aus der Seite kopieren.
+149
View File
@@ -0,0 +1,149 @@
---
title: "Design by Contract jetzt auch mit C# Teil 2"
date: 2009-11-05
slug: design-by-contract-teil2
original_url: "https://aztec-project.org/blog/design-by-contract-teil2.html"
archive_url: "https://web.archive.org/web/20250601101252/https://aztec-project.org/blog/design-by-contract-teil2.html"
author: "Christina Hirth"
categories: ["Architektur", "Clean Code Developing"]
tags: ["Architektur", "Clean Code", "Unit-Tests"]
---
Der vorherige DbC-Artikel ist ziemlich “abstrakt” ausgefallen, es haben einfach Beispiele gefehlt. Das möchte ich hiermit nachholen.
Erstens muss man die IDE anpassen: im März kommt .NET 4.0 raus und da wird Design by Contract mitgeliefert. Man kann das Konzept aber jetzt schon anwenden, wenn man die [Assembly](http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx) zusätzlich installiert. Danach muss man die dll referenzieren und im Eigenschaftenfenster des Projektes im neuen Tab *Code Contracts* das Runtime Checking einstellen.
Jetzt zum Code: Nehmen wir eine ganz einfache Klasse `Bill` deren Objekte mit einem `IRepository` gespeichert bzw. geladen werden.
```
using System.Diagnostics.Contracts;
namespace ContractsPrototyp
{
public class Bill
{
public int Id { get ; set ; }
public string Number { get ; set ; }
public double Value { get ; set ; }
}
10
11
public interface IRepository
{
Bill GetBill( string number);
void SaveBill( Bill bill);
}
```
Die Kontrakte kann man in den einzelnen Methoden oder für eine ganze Klasse schreiben (unter dem Attribut `ContractInvariantMethode`) aber ich finde am schönsten, dass man die auch auslagern kann: durch eine gegenseitige Markierung können Kontrakt-Klassen und Interfaces als “Paare” definiert werden:
```
[ ContractClass ( typeof ( RepositoryContracts ))]
public interface IRepository
{
Bill GetBill( string number);
void SaveBill( Bill bill);
}
[ ContractClassFor ( typeof ( IRepository ))]
public class RepositoryContracts : IRepository
{
public Bill GetBill( string number)
{
Contract .Requires(! string .IsNullOrEmpty(number));
return null ;
}
25
public void SaveBill( Bill bill)
{
Contract .Ensures(bill.Id > 0);
}
}
```
Eine Vorbedingung wird mit `Contract.Requires` und eine Nachbedingung mit `Contract.Ensures` definiert. Beide Methoden bekommen boolische Ausdrücke. Diese Ausdrücke müssen frei von Seiteneffekten sein.
Die eigentliche Implementierung der Klasse schaut dann so aus:
```
public class Repository : IRepository
{
public Bill GetBill( string nummer)
{
//Würde das Objekt aus Datenhaltung laden
return new Bill ();
}
38
public void SaveBill( Bill bill)
{
//Würde das Objekt speichern und ihm eine Id zuweisen
if (BillIsValid( bill )) bill.Id++;
}
44
private static bool BillIsValid( Bill bill)
{
return ! string .IsNullOrEmpty(bill.Nummer);
}
}
```
Woher können wir wissen, dass das funktioniert? Es ist einfach, wir schreiben ein Paar Tests dazu!
Bei Kontraktverletzung wird eine Exception geworfen. Um diese und dadurch die genaue Verletzung überprüfen zu können braucht man etwas Workaround:
```
[ TestFixture ]
public class BillTests
{
private IRepository m_repository;
private string m_message;
60
[ SetUp ]
public void Setup()
{
m_repository = new Repository ();
m_message = string .Empty;
Contract .ContractFailed += ( sender, e ) =>
{
e.SetUnwind();
m_message = e.Message;
};
}
```
Danach sind die Tests dann einfach:
```
[ Test ]
public void Laden_mit_leerer_Nummer_verletzt_Kontrakt()
{
76
try
{
m_repository.GetBill( null );
}
catch
{
//Nichts
}
85
Assert .That( m_message, Is .EqualTo( "Precondition failed: !string.IsNullOrEmpty(number)" ) );
}
88
[ Test ]
public void Speichern_Rechnung_ohne_Nummer_verletzt_Kontrakt()
{
92
try
{
m_repository.SaveBill( new Bill {Value = 25} );
}
catch
{
//Nichts
}
101
Assert .That( m_message, Is .EqualTo( "Postcondition failed: bill.Id > 0" ) );
}
```
Ich hoffe, das Beispiel ist ausführlich genug, um die Vorteile von DbC zu highlighten. [Stefan](http://www.lieser-online.de/blog/), vielen dank noch mal für den Artikel, ich habe mich natürlich von dir inspirieren lassen.
<img src="/images/design-by-contract-teil2/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
+59
View File
@@ -0,0 +1,59 @@
---
title: "Design by Contract jetzt auch mit C#"
date: 2009-10-26
slug: design-by-contract
original_url: "https://aztec-project.org/blog/design-by-contract.html"
archive_url: "https://web.archive.org/web/20250114140450/https://aztec-project.org/blog/design-by-contract.html"
author: "Christina Hirth"
categories: ["Architektur", "Clean Code Developing"]
tags: [".NET", "Architektur", "Clean Code"]
---
Bald kommt .NET 4.0 raus, zusammen mit einem für C# neuen Konzept: Kontrakte im Code mit **Spec#** festzulegen.
Wikipedia definiert DbC folgendermaßen:
> Design by contract (kurz DbC; englisch Entwurf gemäß Vertrag) oder Programming by Contract ist ein Konzept aus dem Bereich der Softwareentwicklung. Ziel ist das reibungslose Zusammenspiel einzelner Programmmodule durch die Definition formaler „Verträge“ zur Verwendung von Schnittstellen, die über deren statische Definition hinausgehen. Entwickelt und eingeführt wurde es von Bertrand Meyer mit der Entwicklung der Programmiersprache Eiffel.
[Stefan Lieser](http://www.lieser-online.de/blog/) hat über das neue Konzept einen sehr guten Artikel in [www.visualstudio1.de](http://www.visualstudio1.de/) geschrieben, mit Begriffsklärung und Anwendungsbeispiele. Kurz zusammengefasst ist die Rede von Folgendem: anstelle, dass man in jeder Methode auf not-null or not-empty usw. prüft, schreibt man die Erwartungen als Code hin. Diese werden von Tools wie z.B. Resharper erkannt und bei fehlerhaften Aufruf der Methode, wird der Entwickler gewarnt. Am besten finde ich, dass man den Kontrakt-Code z.B. für einen Interface in eine separate Klasse schreiben kann und diese wird durch Attribute (`ContractClassFor`) gefunden. Also wird dadurch der eigentliche Code nicht größer.
Das soll nicht bedeuten, dass der Entwickler der Methode die Verantwortung von sich schiebt <img src="/images/design-by-contract/icon_wink.gif" alt=";)" class="wp-smiley"/> , sondern dass er Bedingungen der “Nutzung” offenlegt, Informationen, die bisher nur durch das Anschauen des Codes oder durch mündliche/schriftliche Mitteilung möglich war. Mit **Spec#** kann man die **Intention-Revealing Interfaces** ganz genau schreiben: mit veröffentlichten und kompilierten Bedingungen.
<img src="/images/design-by-contract/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. **[Rainer Hilmer](http://dotnet-forum.de/blogs/rainerhilmer/default.aspx)**
[Oktober 26, 2009 um 11:33 am](/posts/design-by-contract/)
CodeContracts kommen nicht erst mit .NET Framework 4. Es gibt sie schon eine ganze Weile bei DevLabs. Dieses ist mittlerweile in .NET 4 eingeflossen.
<http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx>
Wer mit der Einflechtung von CodeContracts nicht bis VS2010 warten möchte, kann es sich dort ziehen.
Ich habe dazu auch eine Quick Reference geschrieben.
<http://dotnet-forum.de/blogs/rainerhilmer/archive/2009/10/15/code-contracts-quick-reference.aspx>
2. **Christina Hirth**
[Oktober 26, 2009 um 1:55 pm](/posts/design-by-contract/)
Hallo Rainer,
danke für den Hinweis, das ist mir schon bekannt. Steht auch in den o.g. Artikel, den ich hier nicht abschreiben wollte, er ist ja nicht von mir <img src="/images/design-by-contract/icon_smile.gif" alt=":)" class="wp-smiley"/> . Außerdem würde ich ja nie über Code schreiben, den ich selbst nicht ausprobiert habe, also ist es klar, dass es jetzt schon geht.
Der andere Grund, warum ich das nicht speziell erwähnt habe, ist, dass es z.Z. zwar möglich ist, das Konzept anzuwenden, aber die Unterstützung seitens VS fehlt, es sei denn, du nutzt TSF.
Mir ging es eigentlich darum, dass es endlich möglich ist, Anforderungen als Code zu implementieren und als solche schriftlich festhalten, verfolgen und auswerten.
3. **[Rainer Hilmer](http://dotnet-forum.de/blogs/rainerhilmer/default.aspx)**
[Oktober 26, 2009 um 3:29 pm](/posts/design-by-contract/)
Hallo Christina,
ich habe eine gute Nachricht: Es gibt eine kostenfreie academic license, die den static Checker auch auf VS 2008 pro zur Verfügung stellt (mit der aktuellen Version vom 24.10.2009 auch auf VS2010 Beta 2). Die academic license darf nur nicht kommerziell eingesetzt werden.
<http://research.microsoft.com/en-us/downloads/4ed7dd5f-490b-489e-8ca8-109324279968/default.aspx>
4. **Christina Hirth**
[Oktober 26, 2009 um 7:45 pm](/posts/design-by-contract/)
Hallo Rainer,
jetzt hast du mich erwischt, das wusste ich tatsächlich nicht!
+16
View File
@@ -0,0 +1,16 @@
---
title: "Dime Casts WebCasts"
date: 2009-06-09
slug: dime-casts
original_url: "https://aztec-project.org/blog/dime-casts.html"
archive_url: "https://web.archive.org/web/20250114131549/https://aztec-project.org/blog/dime-casts.html"
author: "Stefan Kölle"
categories: ["Tipps"]
tags: ["Patterns", "WebCast"]
---
Ich bin gerade auf eine sehr interessante Seite mit einzelnen WebCasts zu .NET Themen aufmerksam geworden.
<http://www.dimecasts.net/>
Habe mir dort gleich mal [“#106 Learning the Adapter Pattern”](http://www.dimecasts.net/Content/WatchEpisode/106) angesehen, dort wird sehr schön in nur 9 Minuten erklärt wie man das AdapterPattern einsetzt.
@@ -0,0 +1,26 @@
---
title: ".NET Open Space 2009"
date: 2009-08-12
slug: dotnet-openspace-leipzig-2009-buchung
original_url: "https://aztec-project.org/blog/dotnet-openspace-leipzig-2009-buchung.html"
archive_url: "https://web.archive.org/web/20250705042252/https://aztec-project.org/blog/dotnet-openspace-leipzig-2009-buchung.html"
author: "Christina Hirth"
categories: ["Open Space"]
tags: ["Community", "Open Space", "Veranstaltung"]
---
Wir haben es gerade geschafft, die ganzen Infos vom .NET Open Space Süd zu ordnen, und schon ging es mit der Anmeldung für den nächsten [Open Space in Leipzig](http://netopenspace.de/2009/) los!
Der Andrang war so groß, dass innerhalb von ein paar Tagen die Teilnehmerliste voll wurde.
Nach meiner Erfahrungen in [Ulm](/categories/open-space/), kann ich das voll verstehen, da wird einem das Wissen mit goldenem Löffel serviert <img src="/images/dotnet-openspace-leipzig-2009-buchung/icon_wink.gif" alt=";)" class="wp-smiley"/> Und man darf auch noch selbst bestimmen, über welches Thema und wie detailliert man erfahren möchte. Und das von den besten Köpfen der Branche, eventuell sogar neben einem Bier, was möchte man/frau mehr ??
Unter dem Titel Agenda steht folgendes:
> \* wir fangen Samstag und Sonntag um 9 Uhr an, der Rest findet sich, die Organisation ist jeweils schon ab 8 Uhr da und führt Smalltalk mit dir und dem Rest, wenn du Lust hast
> \* auf den .NET Open Space kommen die richtigen Leute, denn es kommen nur die, die in den benannten Themenbereichen motiviert sind der Rest bleibt Zuhause oder geht woanders hin
> \* am .NET Open Space kannst du teilnehmen, ohne ein Guru zu sein, deine Motivation zählt
> \* erachtest du dein Thema als wichtig, nimmst du eine mögliche Diskussion selbst in die Hand und findest interessierte Teilnehmer
> \* die Agenda wird von den Teilnehmenden zum Beginn des .NET Open Space selbst erstellt
Wir haben heute unsere Zimmer reserviert, Betten verteilt <img src="/images/dotnet-openspace-leipzig-2009-buchung/icon_wink.gif" alt=";)" class="wp-smiley"/> . Mit einem Wort: wir sind bereit!
Kommst du mit?
@@ -0,0 +1,26 @@
---
title: ".NET Open Space 2009 in Leipzig"
date: 2009-10-23
slug: dotnet-openspace-leipzig-2009
original_url: "https://aztec-project.org/blog/dotnet-openspace-leipzig-2009.html"
archive_url: "https://web.archive.org/web/20260510022926/https://aztec-project.org/blog/dotnet-openspace-leipzig-2009.html"
author: "Stefan Kölle"
categories: ["Open Space", "StupidDB"]
tags: ["Community", "Open Space", "Veranstaltung"]
---
Das [.NET Open Space in Leipzig](http://netopenspace.de/2009) ging vergangenes Wochenende nun bereits in die erste Wiederholung und das [Konzept “Open Space”](http://de.wikipedia.org/wiki/Open_Space) scheint sich immer weiter zu verbreiten. Auch das [Barcamp in München](http://barcampmunich.mixxt.de/) am gleichen Wochenende war als “Open Space” organisiert.
Der Besuch in Leipzig ist in diesem Jahr schon der zweite .NET Open Space für uns. Auch diesmal war der Erkenntnisgewinn riesig, zumal man auch wirklich nette Leute aus ganz Deutschland trifft und oft merkt, die anderen Kochen auch nur mit Wasser und haben die gleichen Probleme.
Das Session-Highlight aus meiner Sicht war das Coding Dojo, in dieser Session waren nahezu alle Teilnehmer. Bearbeitet wurde das [KataPotter](http://codingdojo.org/cgi-bin/wiki.pl?KataPotter) und wie zu erwarten war, stand nach gut einer Stunde nicht einmal ansatzweise ein brauchbarer Code-Teil. Sinn der Session war jedoch gar nicht wirklich die Programmierarbeit sondern die Kommunikation der Teilnehmer, was sehr aufschlussreich war. Selbst nach der Session wurde überall weiter über das Kata diskutiert.
In den Pausen des Open Spaces wurde auch über das [Lounge Repository](http://ralfw.blogspot.com/2009/08/entspannte-persistenz-lounge-repository.html) von Ralf und unsere [StupidDB](/posts/stupiddb1/) gesprochen, wie sich zeigt ist dafür Interesse und Bedarf vorhanden. Eine unsere Tasks die wir aus dem Open Space mitgenommen haben ist daher mehr über die StupidDB zu schreiben, das Konzept genauer darzulegen und Einsatzbereiche genauer vorzustellen. Auch Democode könnte sicher vielen helfen.
## Kommentare (Archiv)
1. **[Tweets that mention build broken » .NET Open Space 2009 in Leipzig -- Topsy.com](http://topsy.com/tb/bit.ly/fA3cM)**
[Oktober 23, 2009 um 1:16 pm](/posts/dotnet-openspace-leipzig-2009/)
[...] This post was mentioned on Twitter by .NET German Bloggers, Stefan Koelle. Stefan Koelle said: Kurz gebloggt ueber #netos2009 <http://bit.ly/fA3cM> [...]
@@ -0,0 +1,29 @@
---
title: ".NET Open Space Süd 2009"
date: 2009-07-10
slug: dotnet-openspace-sued-2009-buchung
original_url: "https://aztec-project.org/blog/dotnet-openspace-sued-2009-buchung.html"
archive_url: "https://web.archive.org/web/20250114132004/https://aztec-project.org/blog/dotnet-openspace-sued-2009-buchung.html"
author: "Christina Hirth"
categories: ["Open Space"]
tags: ["Open Space", "Veranstaltung"]
---
Es ist soweit, morgen geht es los: unsere erste [Open Space Veranstaltung](http://ulm.netopenspace.de/2009/).
Wir fahren zu viert hin, alle sehr gespannt und erwartungsvoll, mit sehr viele Fragen in den Taschen.
Ich habe auch noch eine geheime Frage, worauf ich eine Antwort finden hoffe: warum sind außer mir keine Frauen dabei !! <img src="/images/dotnet-openspace-sued-2009-buchung/icon_smile.gif" alt=":)" class="wp-smiley"/>
## Kommentare (Archiv)
1. **Stefan Kölle**
[Juli 11, 2009 um 10:10 pm](/posts/dotnet-openspace-sued-2009-buchung/)
Sehr informativer erster Tag!
2. **[TheYellowBrickCode » NOS Sued kommt: Ulm heißt heuer Karlsruhe](http://www.yellow-brick-code.org/?p=160)**
[Mai 17, 2010 um 7:17 pm](/posts/dotnet-openspace-sued-2009-buchung/)
[...] der Community, ihr werdet es nicht bereuen! P.S.: wenn ich die Teilnehmerliste anschauen, muss ich die Frage vom letzten Jahr wiederholen: gibt es keine Entwicklerinnen in diesem Teil des [...]
@@ -0,0 +1,44 @@
---
title: "Bericht zum Open Space Süd 2009"
date: 2009-07-13
slug: dotnet-openspace-sued-2009
original_url: "https://aztec-project.org/blog/dotnet-openspace-sued-2009.html"
archive_url: "https://web.archive.org/web/20250601101213/https://aztec-project.org/blog/dotnet-openspace-sued-2009.html"
author: "Andreas Seebauer"
categories: ["Open Space"]
tags: ["Open Space", "Veranstaltung"]
---
Wir sind zu viert früh morgens in München aufgebrochen, um bei unserer ersten [.NET Open Space](http://ulm.netopenspace.de/2009/)-Veranstaltung teilzunehmen.
Da wir eine relativ lange Anfahrt hatten, waren fast alle schon da, als wir ankamen. Es waren um die 60 Leute.
Während der Vorstellungsrunde haben wir gemerkt, dass das Open Space nicht nur von Gurus besucht wird, sondern auch von Einsteigern. Wir hatten befürchtet, dass wir dort fehl am Platz sind, da wir relativ neu in der .NET-Community sind und noch relativ wenig Wissen weitergeben können. Aber wir wurden freundlich aufgenommen und können Jedem nur empfehlen, beim nächsten Mal dort hinzugehen. Einen schnelleren Weg, Wissen aufzubauen, gibt es nicht!
Falls sich jemand nicht mehr an uns erinnert, hier ein Bild von uns <img src="/images/dotnet-openspace-sued-2009/icon_smile.gif" alt=":)" class="wp-smiley"/>
<img src="/images/dotnet-openspace-sued-2009/16787936.jpg"/>
(von links nach rechts: [Andreas Seebauer](http://www.xing.com/profile/Andreas_Seebauer2), [Stefan Kölle](http://www.xing.com/profile/Stefan_Koelle), [Thomas Christian](http://www.xing.com/profile/Thomas_Christian9), [Christina Hirth](http://www.xing.com/profile/Christina_Hirth2))
Es gab zwar keine vorher festgelegten Themen, aber diese wurden vor Ort vorgeschlagen und danach demokratisch bestimmt. Es wurden sehr interessante Bereiche besprochen, aber leider konnte man nicht in jeden Open Space gleichzeitig. <img src="/images/dotnet-openspace-sued-2009/icon_smile.gif" alt=":)" class="wp-smiley"/>
Für uns am interessantesten waren:
MVC, DDD, IoC und DI (danke an [Albert](http://der-albert.com/), [Markus](http://mortslikeus.blogspot.com/), [Thomas](http://blog.thomasbandt.de/), [Peter](http://www.aspnetzone.de/blogs/peterbucher/), [Stefan](http://lieser-online.de/) und [Sergey](http://shishkin.org/))
Das Themenboard :
<img src="/images/dotnet-openspace-sued-2009/P1010477.JPG"/>
Am Sonntag hat uns besonders die Clean-Code-Development-Runde gefallen. Wir sind dabei, dies in unserem Team umzusetzen. Für alle, die es nicht kennen, gibt es [hier](http://www.clean-code-developer.de/) alle Informationen.
Die Organisation war einwandfrei. Das Essen war lecker und Getränke waren massenhaft vorhanden. Danke an [Thomas](http://www.artiso.com/problog/) und [Alex](http://blog.alexonasp.net/).
Raum 5 war auch das absolute Highlight. Es war immer sehr entspannend da oben.
Leider haben wir die Party verpasst, da wir nicht dort übernachtet haben. Wir hätten zu gerne Alberts Bauchtanz gesehen. <img src="/images/dotnet-openspace-sued-2009/icon_smile.gif" alt=":)" class="wp-smiley"/>
Beim Gewinnspiel hat natürlich Stefan den Hauptpreis (eine Telerik-Lizenz) gewonnen. <img src="/images/dotnet-openspace-sued-2009/icon_smile.gif" alt=":)" class="wp-smiley"/>
Auch einen Tag nach dem .NET Open Space Süd sind wir immer noch voller Begeisterung und müssen das Erlernte erst einmal verarbeiten. Für uns ist jetzt schon klar, dass wir unbedingt beim nächsten Mal wieder dabei sein wollen.
Wir raten wirklich jedem Programmierer, der besser werden möchte, das nächste Open Space zu besuchen. Man trifft dort freundliche und teilweise sehr erfahrene Entwickler, die ihr Wissen gerne weitergeben.
Bis zum nächsten Mal.
+50
View File
@@ -0,0 +1,50 @@
---
title: "Dynamisches Laden von Assemblies"
date: 2009-06-05
slug: dynamic-load
original_url: "https://aztec-project.org/blog/dynamic-load.html"
archive_url: "https://web.archive.org/web/20250601101323/https://aztec-project.org/blog/dynamic-load.html"
author: "Thomas Christian"
categories: ["How-To"]
tags: ["Assembly", "C#", "HowTo", "Reflection"]
---
In diesem Blog-Post möchte ich kurz erläutern, wie ich mit dem Problem des dynamischen Ladens von Assemblies umgegangen bin.
Vor einiger Zeit stand ich vor dem Problem, dass ich zur Laufzeit Assemblies austauschen wollte. Grund dafür war, dass ich eine Host-Applikation hatte, die Plug-Ins verwendet. Jetzt wollte ich bestehende Plug-Ins während der Laufzeit austauschen oder neue Plug-Ins hinzufügen ohne die Host-Applikation zu beenden. Dazu hatte ich ein Verzeichnis in dem sich, außer den Plug-Ins, alle Assemblies befanden. Die Plug-Ins selbst befanden sich in einem eigenen Unterverzeichnis. Selbst wenn die Plug-Ins von der Host-Applikation nicht mehr verwendet wurden, war es nicht möglich, diese Assemblies zu löschen.
Im Normalfall ist es so, dass sobald eine Assembly von einer Applikation verwendet wird, eine Referenz auf diese existiert. Diese Referenz wird leider erst gelöscht, wenn die ganze Applikation beendet wird.
Bei dem dynamischen Laden von Assemblies wird die zu ladende Assembly geöffnet, ausgelesen und dann geschlossen. Aus den ausgelesenen Bytes wird dann mittels Reflection eine Assembly im Arbeitsspeicher erzeugt. Auf die lokale Assembly hängt somit keine Referenz und es ist möglich diese zu löschen.
Meine Umsetzung sieht folgendermaßen aus:
```
public IList<Plugin> GetPlugins( string assemblyName) {
Assembly assembly;
IList<Plugin> pluginList = new IList<Plugin>();
try {
byte [] byteAssembly = File.ReadAllBytes(assemblyName);
assembly = Assembly.Load(byteAssembly);
} catch (Exception ex) {
log.Error(ex);
}
try {
if (assembly != null ) {
Type[] assemblyTypes = assembly.GetTypes();
foreach (Type assemblyTyp in assemblyTypes) {
if ( typeof (Plugin).IsAssignableFrom(assemblyTyp)) {
plugin = (Plugin)assembly.CreateInstance(assemblyTyp
.FullName);
if (plugin != null ) {
pluginList.Add(plugin);
}
}
}
}
} catch (ReflectionTypeLoadException ex) {
log.Error(ex);
}
return pluginList;
}
```
+87
View File
@@ -0,0 +1,87 @@
---
title: "Beispiel Model-View-Presenter mit WinForms"
date: 2010-02-16
slug: mvp-winforms
original_url: "https://aztec-project.org/blog/mvp-winforms.html"
archive_url: "https://web.archive.org/web/20250114132109/https://aztec-project.org/blog/mvp-winforms.html"
author: "Stefan Kölle"
categories: ["How-To", "MVC"]
tags: ["Contract-First", "MVP", "WinForms"]
---
Im Teil 1 ([MVP mit WinForms](/posts/mvp-winforms/)) habe ich die Grundgedanken zur Implementierung von MVP in WinForms vorgestellt, mit der man WinForm-Anwendungen mit UnitTests abdecken kann. In einer komplexeren WinForm-Anwendung gibt es neben dem Startform auch mehrere Unterforms, die durch das Hauptform aufgerufen werden müssen.
**Das Beispielprojekt**
Zur Demonstration habe ich ein Beispielprogramm mit MVP entwickelt, welches einen sehr einfachen Twitterclient darstellt. Das Beispiel wurde nach Contract-First komponentenorientiert gebaut und besteht neben der MVP-Komponente aus weiteren Komponenten.
[<img src="/images/mvp-winforms/Foto1.jpg" title="TwitterClient Architektur" width="200" height="159" class="alignnone size-full wp-image-900"/>](/images/mvp-winforms/Foto1.jpg)
Die weiteren Komponenten haben nichts mit MVP zu tun, sondern sollen nur zeigen, wie man MVP in diesem Umfeld integriert. -> [Den kompletten Sourcecode downloaden](/assets/TwitterClient.zip)
Die Funktionen des Twitter-Clients sollen sein:
1. Anzeige der 20 neuesten Meldungen aus der Timeline im Hauptfenster
2. Der Benutzer soll Status-Updates bei Twitter posten können
3. Die Zugangsdaten des Twitter-Accounts sollen gespeichert werden können
**Die WinForm-Komponente**
Um die Funktionen abzubilden, sind 3 Screens notwendig:
1. Hauptbildschirm mit der Timeline des Twitter-Accounts
2. Form für das Absenden eines Twitter-Status-Updates
3. Konfigurationsbildschirm für den Twitter-Account
[<img src="/images/mvp-winforms/Foto2-300x143.jpg" title="TwitterClient UI" width="300" height="143" class="alignnone size-medium wp-image-901"/>](/images/mvp-winforms/Foto2.jpg)
Jedes WinForm besteht aus einer View-Klasse (dem WinForm), einem Model, welches als Singleton im IoC-Container konfiguriert wird und einem Presenter. Die einzelnen Funktionen in den Views sind im Beispielprojekt durch Tests abgedeckt und zeigen die notwendigen Tests für diese Art der Implementierung. Gerade durch geringen Funktionsumfang kann man das Muster der Verwendung gut erkennen.
In der MVP-Komponente befindet sich auch der “Inversion of Control”-Container, der die einzelnen Komponenten zusammenfügt. Dies könnte auch in einer extra Runner-Komponente ausgelagert sein.
**Aufrufen eines weiteren WinForms**
Alle Abhängigkeiten werden per Dependency-Injection-Container an den Presenter übergeben. Da das Hauptform alle weiteren Views und Presenter instanziert, müssten diese alle bereits beim Programmstart instanziert werden. Um dies zu verhindern, habe ich eine IPresenterFactory eingeführt, die zur Laufzeit weitere Presenter nachinstanzieren kann. Die Factory selbst hält eine Referenz auf den Container und wird bei Programmstart im Container hinzugefügt. Um sicherzustellen, dass weiterhin alle anderen Abhängigkeiten über den Konstruktor definiert werden, können aus dieser Factory nur Klassen instanziert werden, die IPresenter implementieren.
**Fazit**
Mit dieser Beispielanwendung kann man eine mögliche Implementierung von Model View Presenter in der Variante Supervising Controller sehen. Es ist also auch mit WinForms eine voll getestete MVP-Implementierung zu erstellen.
Anhang:
[Kompletter Sourcecode der Beispielanwendung als ZIP](/assets/TwitterClient.zip)
<img src="/images/mvp-winforms/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. **[Jan Selke](http://jcselke.blogspot.com/)**
[Februar 16, 2010 um 9:19 am](/posts/mvp-winforms/)
Hallo,
ich finde die Anwendung sehr schön und es sind die Eine oder Andere Anregung für mich auch enthalten <img src="/images/mvp-winforms/icon_smile.gif" alt=":-)" class="wp-smiley"/> .
Die Konfiguration über Xml würde ich vielleicht noch versuchen zu eliminieren, es wird ja schönes Benennungsmuster eingehalten (CoC).
Ich habe es zwar noch nicht laufen lassen, es sah aber im TimelinePresenter so aus, als wenn noch ein versehentliches Verlassen verhindert werden könnte…
Viele Grüße,
Jan
2. **[Stefan Kölle](http://www.stefankoelle.de/)**
[Februar 19, 2010 um 5:36 pm](/posts/mvp-winforms/)
Hallo Jan,
danke fuer deinen Input, das Container.xml ist wirklich nicht schoen und koennte man sicher eleganter loesen. Du hast mich da auf eine gute Idee gebracht.
Was meinst du mit versehenliches Verlassen?
Gruss
Stefan
3. **[Jan Christian Selke](http://jcselke.blogspot.com/)**
[Februar 22, 2010 um 12:27 pm](/posts/mvp-winforms/)
Hallo nochmal,
freut mich, wenn ich damit einen Impuls geben konnte.
Zu dem versehentlichen Verlassen:
Ich habe vor Kurzem etwas über das “graceful exit” einer Anwendung gelesen. Deine Anwendung hatte ich nicht gestartet, sondern mir nur den Quellcode quergelesen. Dabei ist mir aufgefallen, dass nur ein Application.Exit beim Close ausgeführt wird, der Anwender erhält keine Chance doch in der Anwendung zu bleiben. Eventuell habe ich es auch einfach nicht gesehen (habe es ja auch nicht laufen lassen)…
Soll kein Mäkeln an Kleinigkeiten sein, sondern eher ein Beispiel dafür, dass mir die Anwendung recht gut gefällt. <img src="/images/mvp-winforms/icon_wink.gif" alt=";-)" class="wp-smiley"/>
Viele Grüße,
Jan
+127
View File
@@ -0,0 +1,127 @@
---
title: "Umsetzung des Plug-In-Patterns"
date: 2009-06-05
slug: plugin-pattern
original_url: "https://aztec-project.org/blog/plugin-pattern.html"
archive_url: "https://web.archive.org/web/20250114120158/https://aztec-project.org/blog/plugin-pattern.html"
author: "Thomas Christian"
categories: ["How-To"]
tags: ["Architektur", "C#", "HowTo", "Plug-In"]
---
In meinem ersten Blog-Post möchte ich euch in vereinfachter Form meine Umsetzung des Plug-In-Patterns vorstellen.
Voraussetzungen für dieses Pattern sind:
* eine Host-Applikation die das Plug-In laden möchte
* ein Plug-In welches es zu laden gilt
* und die Schnittstellen Plugin und IHost
Zu allererst brauchen wir eine gemeinsame Schnittstelle, die sowohl vom Plug-In als auch vom Host (die Applikation welche das Plug-In verwenden soll) benutzt werden soll. Über diese Schnittstelle kommuniziert der Host mit dem Plug-In.
Es würde sich das Interface IPlugIn anbieten. In meinem Fall verwende ich allerdings kein Interface sondern eine abstrakte Klasse, da ich bereits Logik direkt in die Schnittstelle implementieren möchte. In meinem Fall heißt die abstrakte Klasse einfach nur Plugin. Im weiteren Verlauf werde ich zu meiner abstrakten Klasse Schnittstelle sagen.
```
public abstract class Plugin {
private IHost m_host;
public Plugin( string name) {
Name = name;
}
6
public string Name { get ; set ; }
public string Author { get ; set ; }
public string Version { get ; set ; }
public bool IsRegistered { get ; private set ; }
11
/// <summary>
/// Setzt oder gibt die Host-Application.
/// </summary>
/// <value> Host-Application. </value>
public IHost Host {
get { return m_host; }
set {
if ( value != null ) {
if (m_host == null ) {
m_host = value ;
if (m_host.Register( this )) {
IsRegistered = true ;
}
}
} else {
if (m_host.Unregister( this )) {
m_host = value ;
IsRegistered = false ;
}
}
}
}
}
```
Ich glaube, der Aufbau der Schnittstelle Plugin sollte bis auf die Property “Host” klar sein. Wie man sieht, benötigt man bei diesem Pattern zusätzlich zur Schnittstelle Plugin noch das IHost-Interface.
Dieses Interface ist direkter Bestandteil der Schnittstelle Plugin. Nun kann man sich natürlich die Frage stellen, warum das Plug-In den Host kennen muss und somit von diesem abhängig ist.
Zum einen ist es in der Regel so, dass ein Plug-In für nur einen Host entwickelt wird und zum anderen wollte ich dem Host gewisse Richtlinien zum Registrieren und Lösen des Plug-Ins vorgeben.
Das Interface IHost sieht folgendermaßen aus:
```
public interface IHost {
bool Register(Plugin plugin);
bool Unregister(Plugin plugin);
}
```
Dieses Interface muss von der Host-Applikation implementiert werden, damit sich das Plug-In am Host registrieren kann. Im letzten Satz habe ich es schon angedeutet. Nicht der Host registriert das Plug-In bei sich, sondern das Plug-In registriert sich am Host. Durch das setzen der Property Plugin.Host wird die Methode Register oder Unregister vom Plug-In aufgerufen, welche der Host implementiert.
Eine vereinfachte Darstellung der Implementierung des IHost -Interfaces sieht folgendermaßen aus:
```
public class HostApplication : IHost {
private List<Plugin> m_pluginList;
3
//Konstruktor
public HostApplication() {
m_pluginList = new List<Plugin>();
7
//Lädt alle verfügbaren Plug-Ins zb. aus einem Verzeichnis
List<Plugin> plugins = GetPlugins();
foreach (Plugin plugin in plugins) {
//ruft implizit die IHost.Register-Methode auf
plugin.Host = this ;
}
}
15
public void ShowPlugins() {
foreach (Plugin plugin in m_pluginList) {
//Ausgabe der Namen aller am Host registrierten Plug-Ins
Console.WriteLine(plugin.Name);
}
}
22
public void UnloadPlugins() {
foreach (Plugin plugin in m_pluginList) {
//ruft implizit die IHost.Unregister-Methode auf
plugin.Host = null ;
}
}
29
#region IHost-Implementierung
public bool Register(Plugin plugin) {
if (!m_pluginList.Contains(plugin)) {
m_pluginList.Add(plugin);
return true ;
}
return false ;
}
38
public bool Unregister(Plugin plugin) {
if (m_pluginList.Contains(plugin)) {
m_pluginList.Remove(plugin);
return true ;
}
return false ;
}
#endregion
}
```
Das Registrieren und Lösen der Plug-Ins könnte man nun noch in einen Plug-In-Manager auslagern, worauf ich in diesem Blog allerdings verzichten möchte.
+68
View File
@@ -0,0 +1,68 @@
---
title: "prio.conference 2009 München"
date: 2009-10-31
slug: prio-conference-2009
original_url: "https://aztec-project.org/blog/prio-conference-2009.html"
archive_url: "https://web.archive.org/web/20250114125123/https://aztec-project.org/blog/prio-conference-2009.html"
author: "Thomas Christian"
categories: ["prio.conference"]
tags: ["prio.conference"]
---
<img src="/images/prio-conference-2009/prio_2009_468x60_statisch_01.gif" alt="prio_2009_468x60_statisch_01" title="prio_2009_468x60_statisch_01" width="468" height="60" class="size-full wp-image-708 aligncenter"/>
In den vergangenen Tagen fand im Marriott Hotel München die prio.conference 2009 statt. Thema dieser Konferenz war in diesem Jahr „User Interface“. Dies war meine erste prio und ich muss sagen ich bin echt begeistert. Leider waren (für mich) einige interessante Sessions parallel, sodass ich mich oft nicht entscheiden konnte, welche Session ich besuchen soll. Toll ist natürlich auch, dass sich bei solchen Veranstaltungen immer die Möglichkeiten ergeben, sich mit anderen Entwicklern zu unterhalten und zu erfahren, wie sie gewisse Dinge beurteilen, planen und umsetzen.
Meine besuchten Sessions:
- Mein neuer PC ist ein Handy
- Auflösungsunabhängige Darstellung von Benutzeroberflächen
- Passive View Command Pattern Agile User Interfaces Entwicklung mit TDD
- Responsive UIs Grundlagen
- Responsive UIs mit der Task Parallel Library
- Auf dem Weg zu guten User Interfaces
- Usability-Testing ganz einfach
- The IPhone as an Application Plattform for .Net Developer
- Herangehensweise für das Redesign einer Software
- Von der Idee zur fertigen UI für Entwickler
- Mustergültig GUI Design-Patterns
- UI das fremde Wesen
Ich für meinen Teil kann sagen, dass ich viel von dieser Veranstaltung mitgenommen habe.
Vielen Dank
## Kommentare (Archiv)
1. **[Sebastian Edelmeier](http://net-fx.blogspot.com/)**
[November 20, 2009 um 2:31 pm](/posts/prio-conference-2009/)
Hi,
war auch da, sind wir uns ggf. über den Weg gelaufen?
Ich kann mich nur anschließen war alles in allem eine Super Veranstaltung!
mfg
Sebastian
2. **Tom**
[November 30, 2009 um 8:27 am](/posts/prio-conference-2009/)
Hallo Sebastian,
das könnte durchaus der Fall gewesen sein. <img src="/images/prio-conference-2009/icon_wink.gif" alt=";)" class="wp-smiley"/>
lg Tom
+179
View File
@@ -0,0 +1,179 @@
---
title: "(Spreu + Weizen).Select(Programmierer)"
date: 2010-03-14
slug: programmierer
original_url: "https://aztec-project.org/blog/programmierer.html"
archive_url: "https://web.archive.org/web/20250114120714/https://aztec-project.org/blog/programmierer.html"
author: "Christina Hirth"
categories: ["Clean Code Developing"]
tags: ["Clean Code"]
---
Obwohl wir [Jeff Atwood](http://www.codinghorror.com/blog/) schon vor Monaten von unseren Bloggerliste gestrichen haben, ich habe ihn noch nicht aus meinem Googlereader entfernt. Er ist ein Typ, der liebt viel Wirbel zu verursachen ([Scott Hanselmann](http://www.hanselman.com/blog/) nennt ihn aus den Wörtern *friend* und *enemy* “my friendemy” <img src="/images/programmierer/icon_wink.gif" alt=";)" class="wp-smiley"/> ) aber manchmal trifft er den Nagel auf den Kopf. So auch in seinem letzten Artikel [“The Non-Programming Programmer”](http://www.codinghorror.com/blog/2010/02/the-nonprogramming-programmer.html).
>
> I wrote that article in 2007, and I am stunned, but not entirely surprised, to hear that three years later “the vast majority” of so-called programmers who apply for a programming job interview are unable to write the smallest of programs. To be clear, hard is a relative term — were not talking about complicated, Google-style graduate computer science interview problems. This is extremely simple stuff were asking candidates to do. And they cant. **Its the equivalent of attempting to hire a truck driver and finding out that 90 percent of the job applicants cant find the gas pedal or the gear shift.**
Aus den Unmengen von Kommentaren zu urteilen, ist das ein Problem, mit dem sehr viele zu kämpfen haben. Sein Artikel beschäftigt sich mit der Arbeit von Personen, die Einstellungsgespräche führen, und er versucht ein paar Tipps zu geben, wie man dieses Verfahren führen soll.
Ich musste allerdings beim Lesen ständig auf die Situation “danach” denken, wenn diese NPPs (sprich Non- Programming Programmers) bereits aus irgendeinem Grund eingestellt wurden. Aus Erfahrung weiß ich genau, was mir viel über jemanden verraten würde: weiß er/sie etwas über Clean Code, kennt er die Folgen vom Creepy Code und wie ist die persönliche Einstellung dazu? Also zusammengefasst: geht es um einen **professionellen Softwareentwickler**? Dafür würden auch ein Code-Review oder ein paar Fragen reichen.
Was haltet ihr von Coding bei der Einstellung? Ist das auch in Europa üblich? Würde das die unpassenden Personen ausfiltern? Oder soll man sich die Zeit nehmen und dem Kandidaten “ungesehen” die Probezeit anbieten? Würde das vielleicht zu viele Personen ausfiltern? Kann man sich das überhaupt erlauben in der heutigen Zeit der Fachkräftemangel? (Gut, man fragt sich natürlich, ob wir hier über “Fachkraft” sprechen dürfen…)
<img src="/images/programmierer/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. <img src="/images/programmierer/3e7b6cb163ea9cc8549abcb8b5a03e2e.jpeg" width="32" height="32" class="avatar avatar-32 photo"/> **[Ralf Westphal](http://ralfw.blogspot.com/)**
[März 14, 2010 um 1:09 pm](/posts/programmierer/)
Einen echten NPP hab ich bei Einstellungsgesprächen noch nicht getroffen. Aber Bewerber, die nahe dran waren.
Ob Programmieraufgaben in Europa/Deutschland üblich sind oder nicht, ist mir aber egal. Sie sind in jedem Fall notwendig. Eine Personalabteilung kann aufgrund von Bewerbungsunterlagen keine (!) Beurteilung abgeben, ob jmd grundsätzlich ein kompetenter Softwareentwickler ist. (Von Feinheiten, wie Bekanntheit mit der Problemdomäne oder Softskills sehe ich hier mal ab. Das ist noch ein ganz anderer Schnack.)
Schon eine gaaaanz simple Programmieraufgabe hilft bei der grundsätzlichen Einordnung eines Bewerbers. Darauf sollte man nie verzichten. Die dauert dann vielleicht 2-3 Minuten. Erste Korrelationen zwischen solch einer Aufgabe und der “Auffassungsgabe” von Entwicklern habe ich schon in kleinen Erhebungen gesammelt. Damit ist dann natürlich noch kein abschließendes Urteil zu fällen aber eine Tendenz lässt sich ablesen.
Weiter untermauern kann man dann mit Entwurfsaufgaben und längeren Programmieraufgaben. Eine Kata hilft da immer. Die kann man auch immer als Anlass nehmen, über den allgemeinen Entwicklungsprozess zu sprechen.
-Ralf
2. **[Alex](http://blog.alexonasp.net/)**
[März 14, 2010 um 3:56 pm](/posts/programmierer/)
Hallo Christina, ich überlege gerade, was schlimmer ist: ein Programmierer, der das Geschäft irgendwann von der Pieke auf gelernt jetzt aber meint, dass das fürs ganze Programmiererlebe reicht oder ein Quereinsteiger, dem Basics fehlen dafür aber gewillt ist, sich permanent zu verbessern… Wie so oft, hängt es vermutlich davon ab, was man erreichen will / muss, wenn man die betreffende Person einstellt.
Code-Reviews sind hier bestimmt kein schlechter Ansatz, aber sie sollten vielleicht nicht das einzige Einstellungskriterium sein. Auf jeden Fall sollte der Code aber gemeinsam reviewed werden, denn vielleicht hat ja auch der Reviewer eine verkehrte Sicht <img src="/images/programmierer/icon_wink.gif" alt=";-)" class="wp-smiley"/>
Ich habe in den letzten Jahren in anderen Bereichen (Maschinen-/Anlagenbau) festgestellt, dass man den perfekten Mitarbeiter nicht bekommt. Viel wichtiger ist es imho, die Stärken und Schwächen des einzelnen zu kennen (das ist ein mühsamer Prozess) und daraus ein schlagkräftiges Team zu formen.
3. **Christina Hirth**
[März 14, 2010 um 5:02 pm](/posts/programmierer/)
Hallo Ralf,
Diese heiklen Themen wie Softskills und Domänenkenntnisse habe ich absichtlich erst gar nicht angesprochen, das wäre “zu schön um wahr zu sein”.
Ich betrachte diese Bereiche wie gut geschriebenen Code: `Refaktorisierung` ist danach noch immer möglich, wenn die Basis stimmt. Das ist also, was vorhanden sein muss: eine gute Basis worüber, wie du schreibst, bereits eine Miniaufgabe etwas verrät und die Bereitschaft zu **lernen**. In einem der Kommentare zum o.g. Artikel gibt es einen Link zu einer persönlichen Definition, was einen [Senior Developer](http://thelimberlambda.com/2010/02/09/what-is-a-senior-developer/) ausmacht. Da steht diese Wissbegierde auf der 3. Stelle! Klar, nicht jede ist ein Senior Developer, aber der Lerndrang entsteht auch nicht erst nach zig Jahren.
Ich finde deine Idee mit dem Dojo in der Probezeit, nehme ich an sehr gut, die Teilnahme oder Nicht-Teilnahme an so eine kleine Herausforderung kann sehr vieles aussagen.
Du bist in der Position, in der dir die deutschen Gepflogenheiten bei der Zusammenstellung eines Team egal sein kann, ich dagegen sitze an der anderen Seite des Tisches <img src="/images/programmierer/icon_wink.gif" alt=";)" class="wp-smiley"/> Ich wünschte mir, dass mehr Leute so denken würden wie du. Vielleicht könnte das auch zu einer Aufgabe der CCD-Bewegung werden.
Christina
4. **Christina Hirth**
[März 14, 2010 um 5:11 pm](/posts/programmierer/)
Hallo Alex,
Ich bin genau deiner Meinung, es hängt fast alles davon ab, wozu die Position ausgeschrieben wurde. Die Frage ist allerdings, ob da noch Platz für Nachbesserung vorhanden ist, wo eventuell kein Wille ist. Dann bin ich mehr für den Quereinsteiger ich bin auch einer wenn der Grund für die Neuorientierung eine falsche erste Wahl war und nicht “ich habe mir mal eine Homepage gebastelt, also bin ich Programmierer”
Was den perfekten Mitarbeiter betrifft: hoffentlich gibt es ihn noch nicht, das würde das Leben der anderen im Team für immer vermiesen <img src="/images/programmierer/icon_wink.gif" alt=";)" class="wp-smiley"/>
5. **[Golo Roden](http://www.des-eisbaeren-blog.de/)**
[März 14, 2010 um 7:28 pm](/posts/programmierer/)
Hallo Christina,
mich persönlich hat es schon immer gewundert, dass ich selbst in noch keinem Bewerbungsgespräch dazu aufgefordert wurde, Code zu schreiben fände es aber prinzipiell positiv. Nicht nur, weil man sieht, wie der jenige codiert, sondern auch und das finde ich viel wichtiger weil man sieht, wie er an Probleme herangeht, wie er versucht, eine Lösung zu finden, …
Viele Grüße,
Golo
6. **Christina Hirth**
[März 14, 2010 um 7:54 pm](/posts/programmierer/)
Hallo Golo,
anscheinend ist das hierzulande wirklich nicht üblich und das ist wirklich schwer zu verstehen. Es ist zwar kein Überschuss vom Jobs am Markt, aber ein guter Programmierer hat wahrscheinlich doch eine Auswahlmöglichkeit. Und was würde mehr über die Aussichten bei einer Firma erraten, als wenn diese vom Anfang an ein bestimmtes Niveau erwartet. Das würde beiden Seiten was zusichern, oder?
Schöne Grüße,
Christina
7. **[Ilker Cetinkaya](http://www.gmbsg.com/)**
[März 14, 2010 um 10:11 pm](/posts/programmierer/)
Komisch, das hier so wenige Code bei Einstellungsgesprächen geschrieben haben. Ich habe in allen meinen letzten drei Anstellungen Code geschrieben, bevor ich eingestellt wurde. Das waren ganz unterschiedliche Dinge. Mal war es eine “Hausaufgabe”, die man innerhalb von ein paar Tagen erledigen konnte (z.B. Währungsumrechner mit Online-Währungskursen), mal war es eine 5-15 Minuten Aufgabe beim Bewerbungsgespräch (z.B. Lotto-Simulation).
Als Lead-Developer habe ich auch schon einige Einstellungsgespräche begleitet. In allen Gesprächen mussten die Bewerber Code schreiben mal auf Papier, mal direkt in VS. Ich möchte nicht zu tief in die Spezifika eines Einstellungsgespräches und die Möglichkeiten des Abklopfens technischer Fertigkeiten von Bewerbern eingehen. Fakt ist jedoch: Ich selbst stelle mich gerne einer Code-Aufgabe und ebenso finde ich es gut, wenn man eine Aufgabe dem Bewerber stellt. Fest steht aber auch: eine Coding-Aufgabe alleine reicht natürlich nicht. Schön finde ich es, wenn der Aufgabensteller aktiv mit dem Bewerber den Code durchgeht und bespricht. Leider hat/bekommt man meistens nicht die Zeit für ein so ausführliches Kennenlernen via Code schade eigentlich.
Fazit: Coding bei Bewerbung ist normal und gut. Für beide.
Bestens,
Ilker
8. **[André Krämer](http://blog.codemurai.de/)**
[März 15, 2010 um 12:21 pm](/posts/programmierer/)
Bei meinem vorherigen Arbeitgeber habe ich einige Einstellungsgespräche begleitet. Dort legte ich großen Wert darauf, dass Code geschrieben wurde. Meist ganz einfache Sachen, die man ans Whiteboard schreiben konnte. Dem Bewerber wurde nahegelegt, “laut” zu denken während er seinen Code anschreibt. Dabei habe ich wert darauf gelegt, dass der Bewerber die Aufgabe mit den gegebenen Informationen nicht eindeutig lösen konnte. Neben den reinen Codierfähigkeiten konnte ich so nämlich ein Gefühl dafür bekommen, ob derjeniege bei unklaren Anforderungen (die richtigen) Fragen stellt, oder einfach irgendwas drauf los programmiert.
Gruß,
André
9. **Christina Hirth**
[März 15, 2010 um 12:40 pm](/posts/programmierer/)
Hallo André,
endlich jemand aus der anderen Mannschaft <img src="/images/programmierer/icon_smile.gif" alt=":)" class="wp-smiley"/>
Deine Vorgehensweise finde ich sehr effizient, aber hätte es nicht passieren können, dass der Bewerbungsstress dein Bild über den Kandidaten verzehren könnte? Oder wusste er schon vor vornherein, dass die Aufgabe unvollständig ist?
Apropos, es fällt mir gerade eine neue Frage ein: wissen überhaupt die Kandidaten darüber, was für ein es Gespräch sie erwartet? Oder ist es eine Überraschung?
Schöne Grüße,
Christina
10. **[André Krämer](http://blog.codemurai.de/)**
[März 15, 2010 um 1:54 pm](/posts/programmierer/)
Dass der “Bewerbungsstreß” meine Wahrnehmung verzerrt haben könnte, kann ich nicht aussließen. Da die Aufgaben allerdings meist recht einfach waren und ich auf eine angenehme Gesprächsatmosphäre geachtet habe, hoffe bzw. glaube ich nicht, dass jemand so viel Streß hatte, dass es zu einer vollkommen falschen Wahrnehmung hätte führen können. Außerdem sollte man auch bedenkend, dass es bei der späteren Ausübung des Jobs immer wieder Situationen geben kann, in denen man unter Streß / Druck arbeiten muss. Daher simulierte die Situation vielleicht sogar ein wenig eine realistische Arbeitssituation <img src="/images/programmierer/icon_wink.gif" alt=";-)" class="wp-smiley"/>
Zur Frage ob die Kandidaten vorher wussten, was sie erwartet: Wenn sie gefragt haben dann schon <img src="/images/programmierer/icon_wink.gif" alt=";-)" class="wp-smiley"/>
Auf Nachfrage habe ich immer sehr ausführlich beschrieben wie wir vorgehen werden. Wer nicht gefragt hat, der hat halt Pech gehabt. Ich denke auch, dass es schon eine Menge über den Bewerber aussagt, ob er sich nach Erhalt einer Einladung telefonisch meldet um ein paar Fragen vorab zu klären, oder nicht.
11. **[KW12: Seitwert, Giana Sisters, Dumm 3.0, UML und mehr - Der Softwareentwickler Blog](http://www.der-softwareentwickler-blog.de/2010/03/26/kw12-giana-sisters-dumm-3-0-uml-visual-studio-2010-und-mehr/)**
[März 26, 2010 um 9:27 am](/posts/programmierer/)
[...] [...]
12. **[Nils Hitze](http://silberkind.de/evangelist)**
[April 9, 2010 um 1:40 pm](/posts/programmierer/)
Ich habe mich im Dezember/Januar auf 15 versch. Stellen beworben (als WebEntwickler) und musste nur bei EINER
auf dem Papier programmieren, ein anderer wollte wenigstens vorher Codebeispiele sehen bzw. ein minimales
MVC Projekt (ZendFramework)
Bei 50% hätte ich mich einfach durchmogeln können mit einer gehörigen Portion Buzzword Bingo.
Auch aus Bewerbersicht macht es total Sinn Coding zu verlangen, einfach um zu sehen womit man es eigentlich
zu tun hat. Bsp. Ein Arbeitgeber hat mich gefragt: Code ok, DB steht, Error Logging an, Seite weiß, was tun?
Ich hab rumgerätselt was er will, bis ich in den blauen Dunst ein “echo fail;exit;” als Breakpoint geworfen habe.
Der wollte wirklich QuickNDirty. An anderer Stelle, selbe Situation war ein Debugger bzw. der ErrorLogOutput gefragt,
also die vernünftigere Lösung.
Klar, die Chemie muss stimmen, aber ich bin prinzipiell der Meinung von Joel:
<http://www.joelonsoftware.com/articles/GuerrillaInterviewing3.html>
Nur mal so von meiner Seite als Bewerber aus.
13. **Christina Hirth**
[April 12, 2010 um 9:36 pm](/posts/programmierer/)
Hi Nils,
danke für deinen Kommentar und den Link zum Artikel. Das ist wirklich typisch Joel, der fackelt ja nicht viel rum !
Aber jetzt mal ernst, ich finde, dass er die Grundideen genau erfasst hat: ein guter Entwickler muss “Smart” UND fähig sein “to get things done”. Genau so ist es. Er sagt ja, es ist nicht genug etwas hinzukriegen, wenn man danach andere Entwickler braucht, um die verursachten Schaden zu bereinigen. Und ob man das durch Code, Code-Review oder eine theoretische Diskussion erfährt, ist ja dem jeweiligen Interviewer überlassen.
Was deine Erfahrungen betrifft: vielleicht waren deine 14 Gesprächspartner so erpicht darauf, dich einzustellen, dass sie dich gar nicht prüfen wollten, sondern dir nur den Job verkaufen? Ich glaube, dass das heutzutage sehr oft der Fall sein kann, dass man einfach nur hofft, dass der Bewerber schon “reinwachsen” wird. Das kann natürlich passieren, aber nur, wenn man die Wahl sorgfältig genug trifft.
Nur so aus Neugier: was hast du von der quick-and-dirty-Stelle gehalten?
14. **[Nils Hitze](http://silberkind.de/evangelist)**
[April 13, 2010 um 11:21 am](/posts/programmierer/)
Stimme dir und Joel da zu.
Wegen QuickNDirty, ich mag Q&D eigentlich schon ganz gerne. Das ist so eine Hemdsärmelige Angelegenheit wie beim KFZSchrauben. Knöcheltief im SourceCode sozusagen. Aber man muss erstmal sauber&gut können um dann Q&D Code zu prodzuieren der einem nicht gleich um die Ohren fliegt. Habe generell das Gefühl, viele Coder verzetteln sich und übertreiben es mit der Strukturierung. Da wird dann für Projekte monatelang am CodeStyle und sonstigem gefeilt die man in der Hälfte der Zeit sauber hätte runterschreiben könne. Oder Skalierung eingeplant für Sachen die keine Skalierung benötigen werden.
+21
View File
@@ -0,0 +1,21 @@
---
title: "Refaktorisierung mal anders erklärt"
date: 2010-01-18
slug: refaktorisierung
original_url: "https://aztec-project.org/blog/refaktorisierung.html"
archive_url: "https://web.archive.org/web/20250601101342/https://aztec-project.org/blog/refaktorisierung.html"
author: "Christina Hirth"
categories: ["Clean Code Developing"]
tags: ["Buchempfehlung", "Clean Code", "Refaktorisierung"]
---
Ich lese gerade das Buch [Agile Principles, Patterns and Practices in C#](http://www.amazon.de/Agile-Principles-Patterns-Practices-C/dp/0131857258) from Robert C. Martin und Micah Martin. Dabei bin ich auf eine so tolle Metapher gestoßen, dass ich sie hier unbedingt niederschreiben wollte (die Übersetzung ist frei von mir):
> Refaktorisierung ist, wie die Küche nach dem Abendessen aufzuräumen. Das erste Mal, wenn du das überspringst, bist mit der Kochen schneller fertig. Aber das Fehlen von sauberem Geschirr und sauberem Arbeitsplatz führt dazu, dass die Vorbereitung diesmal länger dauert. Am liebsten würdest du das Aufräumen wieder überspringen. Tatsache ist, dass du **heute** ohne das lästige Geschirrspülen wieder schneller fertig wärst. Aber der Schmutz wächst und wächst. Jedes Mal dauert es länger, das richtige Küchengerät zu finden, die vertrockneten Schmutzschichten vom Geschirr ab zu kratzen, und so weiter und so fort. Das Vorbereiten des Abendessens dauert ewig…
> Das Überspringen der Abwasch macht das Kochen eigentlich nicht wirklich schneller.
>
> Das Ziel von Refaktorisierung ist die Bereinigung des Codes, jeden Tag, jede Stunde, jede Minute. Wir wollen nicht den Code versauen. Wir wollen nicht ständig gezwungen zu sein, schmutzigen Bits und Bytes sauber zu schrubben. Wir wollen jeder Zeit in der Lage zu sein, unser System mühelos zu erweitern und zu verändern. Der wichtigste Faktor, der uns das möglich macht, ist die Sauberkeit des Codes.
Das Buch habe zwar noch nicht ganz durch, aber was ich bis jetzt gelesen habe, kann ich nur unterschreiben. Es beinhaltet die Prinzipien, wie man in einem agilen Team sauberen Code plant und Mustern und Beispiele, wie man ihn schreibt. Und wie ihr ja sieht, ist es in eine ganz tolle Art geschrieben <img src="/images/refaktorisierung/icon_smile.gif" alt=":)" class="wp-smiley"/>
<img src="/images/refaktorisierung/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
+341
View File
@@ -0,0 +1,341 @@
---
title: "Wozu dient Reflection"
date: 2009-06-24
slug: reflection
original_url: "https://aztec-project.org/blog/reflection.html"
archive_url: "https://web.archive.org/web/20250114131122/https://aztec-project.org/blog/reflection.html"
author: "Thomas Christian"
categories: ["How-To"]
tags: ["Assemblies", "Assemby", "C#", "Reflection"]
---
## Vorbereitung
Über Reflection kann man zur Laufzeit relativ einfach an alle Informationen eines Assembly herankommen. So ist es möglich, dass man von einem Assembly den Namen, Klassen, Methoden mit ihren Parametern, Eigenschaften und Rückgabewerte, usw. auslesen kann. Aber nicht nur das Auslesen ist möglich, sondern auch das Setzen.
Jetzt stellt sich für den einen oder anderen vielleicht die Frage, warum man zur Laufzeit auf diese Daten zugreifen kann. Jede Assembly verfügt über Module in denen sich die einzelnen Typen(Klassen) befinden. Für jedes Modul gibt es Metadaten, in denen die einzelnen Typen beschrieben werden. Die Assembly selbst verfügt noch über ein Manifest, in dem sich alle Informationen zum Assembly (z.B. Name, Version) befinden. Wenn man über Reflection auf Assemblies zugreift, dann werden diese Metadaten und das Manifest dafür herangezogen. Die Metadaten verfügen zwar noch über die Informationen, welche Modifizierer für Methoden, Properties, usw. verwendet wurden, aber der MSIL-Code (die Zwischensprache, die vom Endcompiler in die plattformspezifische Sprache übersetzt wird) nicht mehr. Die Modifizierer sind nur für den Compiler relevant und werden nach dem Kompilieren nicht mehr berücksichtigt. Somit ist es auch möglich über Reflection Properties, Methoden, usw. zu verwenden, die nicht öffentlich sind.
Für dieses Beispiel habe ich eine kleine Konsolen-Anwendung geschrieben (TestApplication), welche eine Referenz auf das Assembly TestProject.dll hat. Dieses Assembly hat zwei von mir erstellte Typen (Klassen) TestClass und SecondTestClass. In den beiden Klassen steckt keine Logik. Sie sind ausschließlich für dieses Beispiel erstellt worden, um ein paar Daten zu modifizieren und um zu zeigen wie die Informationen aus dem Assembly ausgelesen und verändert werden können und dass es möglich ist an nicht-öffentliche Methoden heranzukommen.
**TestClass.cs**
```
using System.Security.Cryptography;
using System.Text;
namespace TestProject {
class TestClass {
public string Name { get ; set ; }
public string Surname { get ; set ; }
private string Password { get ; set ; }
public string GetFullName() {
return string .Format( "{0} {1}" , Name ?? string .Empty, Surname ?? string .Empty).Trim();
}
public void SetPasswort( string password){
Password = password;
}
private static string CalcPassword( string password){
MD5 md5 = MD5 .Create();
byte [] data = md5.ComputeHash( Encoding .Default.GetBytes(password));
StringBuilder hashPassword = new StringBuilder ();
foreach ( byte b in data){
hashPassword.Append(b);
}
return hashPassword.ToString();
}
public static string DoSomething( string value) {
// do something
return value;
}
}
```
**SecondTestClass.cs**
```
namespace TestProject {
public class SecondTestClass {
public int Addition( int a, int b) {
return a + b;
}
public int Multiply( int a, int b) {
return a * b;
}
public double Divide( int a, int b) {
if (b == 0) return 0;
return a / b;
}
}
}
.
.
```
## Auslesen von Assembly- Type-Informationen
Mit der Methode Thread.GetDomain().GetAssemblies() bekommt man alle referenzierten Assemblies der aktuellen Domäne. Damit die TestProject-Assembly auch in dieser Domäne vorhanden ist, muss vor dem Aufruf dieser Methode eine Instanz von einem Objekt dieses Assemblies erzeugt werden.
Um sich nun alle Assemblies der aktuellen Domäne anzeigen zu lassen, könnte man folgendes schreiben:
```
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTest Class ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name
, assembly.GetName().Version));
}
Console .ReadLine();
}
```
.
Nun könnte man noch alle zur Verfügung stehenden Typen(Klassen) aus der TestProject-Assembly anzeigen.
```
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTestClass ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name
, assembly.GetName().Version));
if (assembly.GetName().Name.Equals( "TestProject" )) {
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
Console .WriteLine( " ++{0}" , type.Name);
}
}
}
Console .ReadLine();
}
```
.
Wenn man nun allerdings Informationen eines bestimmten Types haben möchte, so werden diese Informationen aus den Metadaten des Moduls geladen, in dem sich der Type befindet. Um zum Beispiel alle öffentlichen Methoden eines Types anzuzeigen, könnte man folgendes schreiben:
```
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTestClass ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name
, assembly.GetName().Version));
if (assembly.GetName().Name.Equals( "TestProject" )) {
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods();
foreach ( var info in methodInfos) {
Console .WriteLine( " ++ {0}" , info.Name);
}
}
}
}
Console .ReadLine();
}
```
.
Es fällt auf, dass auch die Methoden ToString, Equals, GetHashCode und GetType in beiden Klassen angezeigt werden, obwohl diese in den Klassen überhaupt nicht deklariert wurden. Das liegt daran, dass alle Typen von object ableiten und object diese Methoden implementiert. Was noch auffällt ist, dass nur öffentliche Methoden angezeigt werden. Möchte man sich auch die privaten Methoden anzeigen lassen, so muss man der Methode type.GetMethods Parameter übergeben. Diese Methode verlangt BindingFlags, die man mit dem Bitweise ODER-Operator (|) miteinander verknüpfen kann. Um sich nun öffentliche und private Methoden anzeigen zu lassen, muss der Aufruf der Methode type.GetMethods folgendermaßen lauten:
```
MethodInfo[] methodInfos = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
```
Dieser Aufruf gibt an, dass man alle öffentlichen und nicht-öffentlichen Instanz-Methoden bekommen möchte. Instanz-Methoden bedeutet, dass es sich um Methoden handelt, die nur mit dem Instanzieren eines Objektes zur Verfügung stehen. D.h. es werden keine static-Methoden angezeigt. Es gibt noch weitere BindingFlags, auf die ich hier allerdings nicht weiter eingehen möchte.
Das ganze könnte man natürlich noch in der Form weiter treiben, dass man sich die kompletten Methodensignaturen mit Modifizierer, Schlüsselwort und Rückgabewert anzeigen lässt:
```
static void Main( string [] args) {
SecondTestClass secondTestClass = new SecondTestClass ();
Assembly [] assemblies = Thread .GetDomain().GetAssemblies();
foreach ( var assembly in assemblies) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name, assembly.GetName().Version));
if (assembly.GetName().Name.Equals( "TestProject" )) {
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods( BindingFlags .Public | BindingFlags .NonPublic
| BindingFlags .Instance
| BindingFlags .Static);
foreach ( var info in methodInfos) {
string modifier = GetModifier(info);
string keyword = GetKeyword(info);
string parameters = GetParameters(info);
if (! string .IsNullOrEmpty(keyword)) {
keyword = string .Format( "{0} " , keyword);
}
Console .WriteLine( " ++ {0} {1}{2}{3}({4})" , modifier, keyword
, info.ReturnParameter, info.Name, parameters);
}
}
}
}
Console .ReadLine();
}
private static string GetModifier( MethodInfo info) {
if (info.IsPublic) return "public" ;
return "private" ;
}
private static string GetKeyword( MethodInfo info) {
if (info.IsStatic) return "static" ;
if (info.IsVirtual) return "virtual" ;
return string .Empty;
}
private static string GetParameters( MethodInfo info) {
StringBuilder parameters = new StringBuilder ();
ParameterInfo [] parameterInfos = info.GetParameters();
if (parameterInfos != null ) {
foreach ( ParameterInfo parameterInfo in parameterInfos) {
if (! string .IsNullOrEmpty(parameters.ToString())) {
parameters.Append( ", " );
}
parameters.AppendFormat( "{0} {1}" , parameterInfo.ParameterType.Name, parameterInfo.Name);
}
}
return parameters.ToString();
}
```
.
Nicht immer ist bereits während der Entwicklung bekannt, aus welchem Assembly man Informationen benötigt. Sodass die Methode Thread.GetDomain().GetAssemblies() nicht verwendet werden kann. Eine weitere Möglichkeit an ein Assembly zu kommen ist es direkt zu laden. Dafür bietet die Klasse Assembly die statische Methode Assembly.LoadFrom zum Laden von Assemblies. Statt dem Laden des Assembly über die aktuelle Domäne, wird das nächste Beispiel so modifiziert, dass die TestProject-Assembly direkt aus einem Verzeichnis heraus geladen wird.
```
static void Main( string [] args) {
Assembly assembly = Assembly .LoadFrom( @"c:\TestProject.dll" );
if (assembly != null ) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name, assembly.GetName().Version));
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos =
type.GetMethods( BindingFlags .Public | BindingFlags .NonPublic | BindingFlags .Instance |
BindingFlags .Static);
foreach ( var info in methodInfos) {
string modifier = GetModifier(info);
string keyword = GetKeyword(info);
string parameters = GetParameters(info);
if (! string .IsNullOrEmpty(keyword)) {
keyword = string .Format( "{0} " , keyword);
}
Console .WriteLine( " ++ {0} {1}{2}{3}({4})" , modifier, keyword, info.ReturnParameter,
info.Name, parameters);
}
}
}
Console .ReadLine();
}
```
Man sieht, dass die gleiche Ausgabe wie bereits im vorherigen Beispiel generiert wird.
## Interaktionen
Nachdem die Vorgehensweise nun klar sein sollte, möchte ich nun den eigentlich interessanten Teil demonstrieren. Wie kann man nun auf Methoden usw. zugreifen und wie können Werte aus einem Type gelesen und veränder werden? Wenn man die Methode SecondTestClass.Addition(int a, int b) aufrufen möchte, dann braucht man die Methodeninformationen von dem Type SecondTestClass aus dem TestProject-Assembly. D.h. man muss wie in den obigen Beispielen auch über alle Typen iterieren, um an den gesuchten Type SecondTestClass zu kommen. Hat man den gesuchten Type gefunden, so kann man sich von diesem alle Methoden in einem Array zurückgeben lassen. Dieses Array kann dann wieder ganz normal durchlaufen und nach der gewünschten Methode durchsucht werden. Hat man die Methode gefunden so muss zuerst eine Instanz von dem Objekt erzeugt werden und dafür gibt es den Activator, der die statische Methode CreateInstance beinhaltet. Als Parameter übergibt man ihr den Type von dem eine Instanz erzeugt werden soll. Jetzt kann man über die MethodInfo die Methode aufrufen. Dazu muss der Methode die Instanz des Objektes übergeben werden, von welchem die Methode aufgerufen werden soll und zusätzlich noch ein Array von Objekten, welche die zu übergebenen Parameter beinhaltet. Hat die Methode keine Parameter, so muss null übergeben werden. Dabei muss der Rückgabewert in den erwarteten Wert gecastet werden. Das ganze könnte dann folgendermaßen aussehen:
```
static void Main( string [] args) {
Assembly assembly = Assembly .LoadFrom( @"c:\TestProject.dll" );
if (assembly != null ) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name, assembly.GetName().Version));
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
if (type.Name.Equals( "SecondTestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods();
foreach ( var info in methodInfos) {
if (info.Name.Equals( "Addition" )) {
object obj = Activator .CreateInstance(type);
int value = ( int )info.Invoke(obj, new object [] { 2, 5 });
Console .WriteLine( " ++ {0}(2 + 5) = {1}" , info.Name, value);
}
}
}
}
}
Console .ReadLine();
}
```
Aufruf der Methode Addition
.
Bei statischen Methoden kann das Erzeugen der Instanz weggelassen werden und für den Parameter des Instanz-Objektes kann null übergeben werden.
```
if (type.Name.Equals( "TestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
MethodInfo [] methodInfos = type.GetMethods( BindingFlags .NonPublic | BindingFlags .Static);
foreach ( var info in methodInfos) {
if (info.Name.Equals( "CalcPassword" )) {
string value = ( string )info.Invoke( null , new object [] { "myPassword" });
Console .WriteLine( " ++ {0}(\"myPassword\") = {1}" , info.Name, value);
}
}
}
```
Das übergebene Passwort wurde über eine statische Methode gehashed.
.
Um den Wert einer Property auszulesen, muss anstelle von MethodInfo die PropertyInfo verwendet werden. Aus dieser kann dann über die Methode PropertyInfo.GetValue der aktuelle Wert zurückgegeben werden. Da in diesem Beispiel nach dem Instanzieren des Objektes noch keine Werte zugewiesen wurden, sind die Properties leer.
```
static void Main( string [] args) {
Assembly assembly = Assembly .LoadFrom( @"C:\ TestProject.dll" );
if (assembly != null ) {
Console .WriteLine( string .Format( "-- {0} ver.: {1}" , assembly.GetName().Name, assembly.GetName().Version));
Type [] types = assembly.GetTypes();
foreach ( var type in types) {
if (type.Name.Equals( "TestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
object obj = Activator .CreateInstance(type);
PropertyInfo [] propertyInfos = type.GetProperties( BindingFlags .Public | BindingFlags .NonPublic
| BindingFlags .Instance);
foreach ( var info in propertyInfos) {
Console .WriteLine( " ++ {0} = {1}" , info.Name, info.GetValue(obj, null ));
}
}
}
}
Console .ReadLine();
}
```
.
Wenn man nun die Properties mit Werten belegen möchte, so muss man analog zur Methode PropertyInfo.GetValue, die Methode PropertyInfo. SetValue verwenden.
```
if (type.Name.Equals( "TestClass" )) {
Console .WriteLine( " ++ {0}" , type.Name);
PropertyInfo [] propertyInfos = type.GetProperties( BindingFlags .Public | BindingFlags .NonPublic
| BindingFlags .Instance);
propertyInfos[0].SetValue(obj, "Peter" , null );
propertyInfos[1].SetValue(obj, "Müller" , null );
propertyInfos[2].SetValue(obj, "myPassword" , null );
foreach ( var info in propertyInfos) {
Console .WriteLine( " ++ {0} = {1}" , info.Name, info.GetValue(obj, null ));
}
}
```
.
## Wozu braucht man jetzt aber nun die Reflection?
Nun ja, die meisten Programme werden Reflection wohl nie benötigen oder verwenden. Es wird vorallem bei dem Entwickeln von Debuggern, Interpretern, TestTools, Logger oder auch für O/R-Mapper verwendet. Es wird also überall dort gebraucht, wo während der Laufzeit nicht klar ist, welche Assemblies verwendet werden und welche Informationen man aus diesen lesen oder manipulieren möchte.
## kurze Zusammenfassung:
Wie man gesehen hat, ist der Aufbau einer Assembly mit ihren Typen hierarchisch. Um zb. an einen Parameter einer Methode eines Types zu kommen, braucht man zuerst das Assembly welches den Typ enthält. Von diesem lässt man sich ein Array von Typen geben. Von dem gesuchten Typ lässt man sich dann ein Array von Methoden geben. Von der gesuchten Methode holt man sich nun ein Array von allen Parametern. Dieses Array kann dann nach dem gewünschten Parameter durchsucht werden.
Es gibt natürlich für all diese Methoden auch Methoden, mit denen man sich den Type, die Methodeninformation, die Parameterinformation, usw. direkt mit der entsprechenden Bezeichnung holen kann. Ich wollte hier nur auf die Hierarchie aufmerksam machen.
Wie man in diesen Beispielen erkennen konnte, ist es möglich, ohne Probleme auf alle Informationen von einem Assembly zuzgreifen, sich die Types zu laden, dessen öffentliche und auch nicht-öffentliche Werte zu lesen und zu manipulieren und auch Methoden auszuführen. Man kann sich auch lokale Werte anzeigen lassen, in dem man sich den MethodBody des Objekte geben lässt, von denen man die lokalen Werte ermitteln möchte.
+48
View File
@@ -0,0 +1,48 @@
---
title: "scrumbut"
date: 2009-11-03
slug: scrumbut
original_url: "https://aztec-project.org/blog/scrumbut.html"
archive_url: "https://web.archive.org/web/20250114121008/https://aztec-project.org/blog/scrumbut.html"
author: "Stefan Kölle"
categories: ["SCRUM"]
tags: ["SCRUM"]
---
Seit Anfang des Jahres setzen wir nun SCRUM ein, wobei es, wie man jetzt merkt, doch nur SCRUMBUT war.
> I call that phenomena “Scrumbut”. It shows up in the following way:
> “Were doing Scrum but…”
> \* our sprints are 12 weeks long…
> \* we do two normal sprints and one bugfix sprint…
> \* we do all our planning up front…
> \* we skip the daily meeting…
> \* our managers decide whats in each sprint…
> \* we havent read the books yet…
> \* our team has 30 people…
> <http://blogs.msdn.com/ericgu/archive/2006/10/13/scrumbut.aspx>
Auch bei uns wurden Anpassungen an SCRUM durchgeführt, was dazu geführt hat, dass die letzten Sprints immer schlechter wurden. Gerade die Retrospektive wurde fast nie durchgeführt, da es angeblich nichts zu besprechen gab.
Wir sind nun in Sprint 21 und nach 2 Open Spaces um ausreichenden Erfahrungsaustausch reicher. Wir halten wieder die Retrospektive-Meetings und bei dem letzten haben wir folgende Anpassungen beschlossen:
* Es wurde eine “Definition-of-done” Richtlinie am Whiteboard erstellt.
* Pair-Programming wird häufiger eingesetzt.
* Zu jedem Backlog-Item werden gemeinsam die Architekturveränderungen und die notwendigen Tasks besprochen. Bisher wurde mit den Produkt-Backlogkarten direkt gearbeitet.
Ich rate allen, die SCRUM einführen wollen, sich wirklich so nah wie möglich an SCRUM zu halten. Die Sprints 1 15 wirkten bei uns auch sehr gut, doch erst danach fiel uns auf, dass gerade die Sprint-Retrospektive ein sehr wichtiges Meeting ist. All diese Regeln sind durch mehrjährige Erfahrungen entstanden und sie haben sich schon in größeren Firmen bewährt. Warum dann nicht davon profitieren?
<img src="/images/scrumbut/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. **Mike Bild**
[November 3, 2009 um 2:53 pm](/posts/scrumbut/)
Ja, dass kenn ich nur zu gut. Wenige Regeln, schön! Doch damit ist jede menge Arbeit an der Disziplin nötig. Daher bestätigt sich hier meine Erkenntnis Jedes noch so kleine Element von SCRUM ist zum erfolgreichen umsetzen Elementar nötig. Hier und da was weglassen!? Geht nicht! Meine manchmal schmerzlichen Erfahrungen zeigten mir eben auch; Akzeptanz- oder Done -Kriterien auf, oder neben, den User Stories sind ein äußerst wichtiges Artefakt zur Reflektion und Kommunikation zwischen Team und Product Owner. In diesem Sinne, wie heißt es so schön: -Kontinuierliche Weiterentwicklung von Software und Entwicklungsprozess-! Banzai!
2. **Stefan Kölle**
[November 3, 2009 um 4:06 pm](/posts/scrumbut/)
@MikeBild: Genau, so sehe ich das mittlerweile auch. Kontinuierliche Weiterentwicklung Die Akzeptanzkriterien sollten wir bei uns auch noch genauer definieren.
+51
View File
@@ -0,0 +1,51 @@
---
title: "Softwarezellen eine Lösung um die Komplexität zu beherrschen"
date: 2010-01-27
slug: softwarezellen
original_url: "https://aztec-project.org/blog/softwarezellen.html"
archive_url: "https://web.archive.org/web/20250601101252/https://aztec-project.org/blog/softwarezellen.html"
author: "Christina Hirth"
categories: ["Architektur", "Clean Code Developing"]
tags: ["Architektur"]
---
Wir haben wie viele von uns in der Webentwicklung vor vielen Jahren mit Scriptsprachen und mit prozeduralen Spaghetti-Code <img src="/images/softwarezellen/icon_wink.gif" alt=";)" class="wp-smiley"/> angefangen. Mit der Zeit wuchs unsere Webpräsenz zu einer unüberschaubaren Anwendung mit manchen Seiten, die keiner von uns mehr anfassen wollte aus Angst vor den Konsequenzen.
Um etwas Ordnung in die Webanwendungen zu bringen, haben wir also vor 4 Jahren angefangen, nach einem 3-Schichten-Modell zu entwickeln. Wir haben neue Funktionalitäten und neue Anwendungen nur noch so gebaut und wir waren für eine kurze Zeit zufrieden. Alles lief gut. Als wir den Umstieg auf .NET begonnen haben, haben wir weiterhin nach einem Mehr-Schichten-Modell gearbeitet, wir haben nur die Anzahl der Schichten erhöht.
Die Anwendungen wuchsen weiter, wir haben immer mehr Bereiche ausgelagert und diese hauptsächlich mit Webservices angesprochen. Währenddessen waren wir daran, unser Hauptprodukt, ein Portal für unseren Kunden mit der neuen Technologie entsprechend der alten Anforderung neu zu bauen. Und dann ist es passiert: ehe wir uns versahen, hatten wir ein riesiges Projekt, das alle mögliche Anwendungen eingebunden bzw. durch Webservices angesprochen hat. Die Grenzen waren fließend, eventuelle Änderungen an anderen Anwendungen konnten das Projekt unbuildbar machen, also ein ähnlicher Zustand wie vor paar Jahren zuvor.
Die Weiterentwicklung hat nicht nur in unserer Art zu Programmieren stattgefunden, wir selbst haben uns auch weiterentwickelt, wir haben die Community kennen gelernt. Bei den Open Space-Veranstaltungen haben wir [Stefan](http://lieser-online.de/) und [Ralf](http://ralfw.de/default.html) kennengelernt und durch sie eine andere Sichtweise der Dinge: die [Modellierung einer Lösung durch Softwarezellen](http://weblogs.asp.net/ralfw/archive/tags/Software+Cells/default.aspx).
Wir haben sie zu uns eingeladen und uns die Idee erklären lassen. Das Stichwort heißt [Holon](http://de.wikipedia.org/wiki/Holon). Wikipedia definiert ein Holon folgendermaßen:
> Der Begriff Holon (von griech. ὅλος, hólos und ὀν, on „ganzes Seiendes“) wurde von Arthur Koestler geprägt und bedeutet ein Ganzes, das Teil eines anderen Ganzen ist. Es wird auch als “Ganzes/Teil” umschrieben.
Jede Anwendung ist ein Ganzes, die aus Teilen besteht, die ihrerseits auch als Ganze zu betrachten sind.
Seit dem Besuch von Ralf und Stefan haben wir uns die Artikelserie von Ralf von [dotnetpro](http://dotnetpro.de/) durchgelesen, die Webcasts ([Teil 1](https://www.microsoft.com/germany/msdn/webcasts/library.aspx?id=1032298692), [Teil 2](https://www.microsoft.com/germany/msdn/webcasts/library.aspx?id=1032298700)) angeschaut und wir haben angefangen, diese Modellierung auszuprobieren.
Wir haben noch einen langen und interessanten Weg vor uns, aber eins ist jetzt schon sicher: wir werden versuchen unsere nächste Projekte durch Softzellen modellieren.
Solange die Komplexität nicht wieder die Überhand gewinnt <img src="/images/softwarezellen/icon_wink.gif" alt=";)" class="wp-smiley"/>
<img src="/images/softwarezellen/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. **[Tweets that mention build broken » Softwarezellen eine Lösung um die Komplexität zu beherrschen -- Topsy.com](http://topsy.com/tb/bit.ly/aYQGup)**
[Januar 28, 2010 um 12:53 am](/posts/softwarezellen/)
[...] This post was mentioned on Twitter by .NET German Bloggers, DeveloperBlogs. DeveloperBlogs said: Softwarezellen eine Lösung um die Komplexität zu beherrschen: Wir haben wie viele von uns in der Webentwicklung … <http://bit.ly/aYQGup> [...]
2. **Benjamin Gopp**
[Januar 28, 2010 um 8:28 am](/posts/softwarezellen/)
Hallo,
schön zu hören, dass noch andere den CCD Weg gehen!
Wir haben mit Ralf und Stefan die School of .NET gemacht. Die Architektur hat uns am Anfang echt Schwierigkeiten gemacht. Vielleicht weil wir bisher überhaupt keine Architektur betrieben haben. Jetzt stellen wir jedoch fest, dass das Vorgehen, so wie es Ralf und Stefan es lehren wirklich einen Quantensprung bedeutet.
Hinfort mit Schichtenarchitektur und UML!
Benjamin
+170
View File
@@ -0,0 +1,170 @@
---
title: "StupidDB object-persistence-framework"
date: 2009-07-13
slug: stupiddb1
original_url: "https://aztec-project.org/blog/stupiddb1.html"
archive_url: "https://web.archive.org/web/20250114121109/https://aztec-project.org/blog/stupiddb1.html"
author: "Stefan Kölle"
categories: ["Release", "StupidDB"]
tags: ["StupidDB"]
---
Angeregt durch die Diskussion auf dem Open-Spaces zum Thema schemalose Datenbanken, werden wir heute bereits die Vorabversion unserer StupidDB als open-source releasen.
Die StupidDB entstand bei uns aus der Notwendigkeit, immer wieder Objekte und Files schnell und einfach zu speichern, dies serverlos und trotzdem skalierbar und hochverfügbar vorzuhalten. Die StupidDB lässt sich am besten wie folgt beschreiben:
> StupidDB ist ein einfaches Objektspeicherungs-Framework auf dem Filesystem. Vergleichbar mit dem WebCache kann man in der StupidDB jegliches Objekt ablegen, welches kosteneffizient auf dem Filesystem gespeichert wird. Geladen werden können Objekte und Binärdaten mit einem eindeutigen Key und einer Partition. Den echten Speicherort auf der Festplatte ermittelt StupidDB selbst. Durch Replikation des Filesystems z.B. per Windows-DFS ist zudem eine einfache Hochverfügbarkeit und Skalierbarkeit der Datenbasis herzustellen.
Angeregt durch einen [Blogeintrag von tilllate.com](http://techblog.tilllate.com/2008/08/14/webtuesday-lightning-talk-slides/) letztes Jahr, entstand bereits vor einem Jahr die erste Version von StupidDB, welches bis zum Blogeintrag nur aus einem Konzept bestand. Leo Büttiker hat zwar ein leicht anderes Konzept als unsere Implementierung, in den Kernpunkten ähnelt sich aber das Design. StupidDB bekam durch diesen Blogpost damals jedoch seinen Namen.
Für folgende Anwendungsszenarien sehen wir StupidDB als geeignet:
* Userdaten wie Fotos und Mediadaten, die eine Datenbank nur unnötig aufblähen
* temporäre Daten
* Statusdaten
* Versionierung von Daten
Als Vorteile gegenüber z.B. MogileFS, CouchDB zählt für uns vor allem, dass kein zentraler Server für die Datenbank benötigt wird, sondern nur ein Share im Netz. Die Implementierung ist dadurch enorm vereinfacht. Mit weiteren Windows-Board-Mitteln kann man danach das ganze System um Hochverfügbarkeit und Skalierbarkeit einfach ausbauen.
Die Nutzung selbst ist denkbar einfach. Folgendes Mitarbeiter-Objekt möchte ich speichern.
```
public class Mitarbeiter
{
public int Id { get ; set ; }
public string Name { get ; set ; }
public string Vorname { get ; set ; }
public string Ort { get ; set ; }
public string Plz { get ; set ; }
72
public string VollerName
{
get { return string .Format( “{0} {1}” , Vorname, Name); }
}
}
```
Dazu nutzt man die Put-Methode der StupidDB.
```
IStupidDB stupidDB = new StupidDB ( “test” );
Mitarbeiter mitarbeiter = new Mitarbeiter
{
Id = 1,
Name = “Christian” ,
Vorname = “Thomas” ,
Ort = “Rosenheim” ,
Plz = “83026”
};
stupidDB.Put( “TestPartition” , “EinMitarbeiter” , mitarbeiter );
```
Um das gleiche Objekt wieder zu lesen, nutzt man mal eine Get Methode. Die Parameter sind Partition und Key:
```
Mitarbeiter mitarbeiterAusgelesen =
( Mitarbeiter )stupidDB.GetObject(
“TestPartition” ,
“EinMitarbeiter” ,
typeof ( Mitarbeiter )
);
if (mitarbeiterAusgelesen != null )
{
Console .WriteLine( “Name des Mitarbeiters: {0}” ,
mitarbeiterAusgelesen.VollerName);
}
```
Die StupidDB selbst wird über die app.config definiert.
```
< configuration >
< configSections >
< section name = “ stupidDB “ type = “ Aztec.StupidDB.DBConfigCollection, Aztec.StupidDB, Version=1.0.0.0, Culture=neutral “ allowLocation = “ true “ allowDefinition = “ Everywhere “ />
</ configSections >
< stupidDB >
< DB name = “ test “ root = “ temp\test “ tiefe = “ 3 “ versionierung = “ false “ />
</ stupidDB >
</ configuration >
```
Wer sich den aktuellen Code einmal ansehen möchte, kann dies gerne unter folgendem Link ansehen:<https://stupiddb.svn.sourceforge.net/svnroot/stupiddb/trunk>
## Kommentare (Archiv)
1. **Doku**
[March 1, 2010 at 9:59 am](/posts/stupiddb1/)
Coole Sache, gibt es dazu eine Doku der Funktionen wie .Backup
und der möglichen werte, wie Tiefe, Versionierung etc?
Vielen Dank.
2. **[Stefan Kölle](http://www.stefankoelle.de/)**
[March 1, 2010 at 12:21 pm](/posts/stupiddb1/)
Es gibt aktuell noch keine Doku, im Code wird einiges erklaert jedoch sicher nicht ausreichend.
In der aktuellen Ausgabe der dotnetpro gibt es jedoch einen Artikel zu StupidDB, dort erklaere ich die Parameter noch einmal genauer. Auch das Thema Tiefe, Versionierung usw. <http://www.dotnetpro.de/CurrentIssue.aspx>
3. **UweD**
[March 9, 2010 at 5:47 pm](/posts/stupiddb1/)
Scheint ja wirklich toll zu sein. Leider findet man im Web noch nicht allzuviel darüber. Der Artikel in der dotnetpro sagt einiges, aber zu dem Pfad kann ich nirgends etwas finden.
Wenn ich root=“temp\test“ angebe, wo liegt das dann physisch?
4. **[Stefan Kölle](http://www.stefankoelle.de/)**
[March 9, 2010 at 5:52 pm](/posts/stupiddb1/)
Hallo, Uwe,
man kann bei root einfach einen absoluten Pfad angeben, z.B. c:\temp\stupiddb\
Ohne der Angabe eines Pfades wird die StupidDB im Ausfuehrungsverzeichnis angelegt.
Gruss
Stefan
5. **Uwe**
[January 4, 2011 at 11:17 am](/posts/stupiddb1/)
Hallo,
ich bin nun nicht so firm in C#. Gibt es Beispiel für IStupidDB.Dir ?
Danke
Uwe
6. **[Andreas Seebauer](http://www.in-your-face.org/)**
[January 12, 2011 at 12:05 pm](/posts/stupiddb1/)
Hallo, Uwe,
hier ein kleines Beispiel für die Verwendung von IStupidDB.Dir in C#:
IStupidDB sdb = new StupidDB(“meinDbName”);
string partition = “Beispielpartition”;
string key = “Beispielkey”;
// Speichern des strings “Beispiel” unter Key “Beispielkey” in Partition “Beispielpartition”
sdb.Put(partition, key, “Beispiel”);
// Auflisten aller Keys in Partition “Beispielpartition”
List listKeys = sdb.Dir(partition);
Mit den zurückgelieferten Keys können dann die Objekte via GetObject ausgelesen werden.
Ich hoffe das beantwortet deine Frage.
Gruß
Andreas
7. **Uwe**
[January 12, 2011 at 4:23 pm](/posts/stupiddb1/)
Hallo Andreas,
nein, nicht ganz!
Laut Doc gibt es
Dir Listet alle Schlüssel einer Partition) und
Dir Liefert ein IDictionary aller Schlüssel mit zugehörigem Objekt .
Mit geht es um das 2. Dir.
Uwe
+110
View File
@@ -0,0 +1,110 @@
---
title: "NoSQL mit StupidDB"
date: 2010-02-22
slug: stupiddb2
original_url: "https://aztec-project.org/blog/stupiddb2.html"
archive_url: "https://web.archive.org/web/20250114131202/https://aztec-project.org/blog/stupiddb2.html"
author: "Stefan Kölle"
categories: ["StupidDB"]
tags: ["Datenbank", "NoSQL", "Schemalos"]
---
Seit ein paar Monaten wird der Begriff [NoSQL (Not only SQL)](https://www.computerworld.com/s/article/9135086/No_to_SQL_Anti_database_movement_gains_steam) immer häufiger verwendet. Wir sind mit unserer schemalosen Datenbank [StupidDB](https://sourceforge.net/projects/stupiddb/) vor eineinhalb Jahren bereits auf diesen Zug aufgesprungen und jetzt hat sie einen Überbegriff bekommen: auch StupidDB ist NoSQL!
Auf dem [BarCamp in Nürnberg](http://www.bcnue2.de/) war NoSQL auch ein Thema und [Jonathan Weiss](https://twitter.com/jweiss) hat in seiner Session gut dargestellt, dass relationale Datenbanken nicht immer die Lösung für alle Probleme sind. NoSQL Datenbanken speichern meist dokumentenorientiert und sind dadurch nicht an ein festes Schema gebunden. Relationale Datenbanken haben ein fixes Schema und erlauben dynamische Abfragen der Daten, bei NoSQL ist dies umgekehrt. Weitere Informationen zu [NoSQL bei Wikipedia](https://en.wikipedia.org/wiki/NoSQL).
Im [März Heft der dotnetpro](https://web.archive.org/web/20160119224824/http://www.dotnetpro.de/articles/onlinearticle3220.aspx) stelle ich ausführlich den Einsatz von StupidDB vor. Das Heft ist am 18.2.2010 erschienen und sollte jetzt in jedem gut sortierten Kiosk erhältlich sein.
Für alle, die sich Heft nicht griffbereit haben, ich habe bereits Mitte letzten Jahres in einem Blogpost den [Einsatz von StupidDB](/posts/stupiddb1/) beschrieben. Hier sieht man zumindest die Grundzüge der StupidDB. Das aktuelle dotnetpro Heft lohnt sich jedoch trotzdem, da hier noch weitere Artikel zum Thema NoSQL zu finden sind. Unter anderem das [Lounge Repository](https://loungerepo.codeplex.com/) von [Ralf Westphal](http://www.ralfw.de/default.html) und auch CouchDB.
Als neuester Vertreter in der NoSQL Bewegung gilt MongoDB. Eine Opensource Implementierung die nun auch Sourceforge einsetzt. Auch dafür gibt es schon [Blogposts](http://odetocode.com/Blogs/scott/archive/2009/10/13/experimenting-with-mongodb-from-c.aspx) und Tests mit .NET.
Zudem hat [Ayende Rahien](http://ayende.com/Blog/Default.aspx) im Herbst letzten Jahres auch seine [Rhino Divan DB](http://odetocode.com/Blogs/scott/archive/2009/10/13/experimenting-with-mongodb-from-c.aspx) vorgestellt. Interessant klingt auch [Object Lounge](http://blog.technewlogic.de/StaticContent/Pages/ObjectLounge_Main.aspx).
Es scheint also ein Bedarf an alternativer Datenpersistenz zu bestehen, wird sich zeigen wohin dieses Jahr die Reise bei NoSQL geht.
Wer sich den aktuellen Code einmal ansehen möchte, kann dies gerne unter folgendem Link ansehen:
<https://stupiddb.svn.sourceforge.net/svnroot/stupiddb/trunk>
Verwendet ihr schon NoSQL?
## Kommentare (Archiv)
1. **Nils**
[February 27, 2010 at 3:59 pm](/posts/stupiddb2/)
Und wo kann man sich diese schamlose ah, schemalose Datenbank nun runterladen?
2. **[Stefan Kölle](http://www.stefankoelle.de/)**
[February 27, 2010 at 6:33 pm](/posts/stupiddb2/)
Hallo Nils,
ich habe in der Tat vergessen in diesem Blogpost die URL noch einmal zu posten.
Habe ich nun nachgeholt.
Der aktuelle Sourcecode ist hier zu finden:
<https://stupiddb.svn.sourceforge.net/svnroot/stupiddb/trunk>
Bin gespannt was du dazu sagst…
Gruesse
Stefan
3. **ronald**
[March 26, 2010 at 10:37 am](/posts/stupiddb2/)
Hallo,
ich wollte die stupiddb austesten, leider kann ich die dll nicht zum download finden. bei der url, welche im dotnet-pro artikel beschrieben, finde ich keine files zum download. (> oder ist das so gewollt)?
vielleicht kann mir jemand helfen 🙂
dank ronald
4. **[Stefan Kölle](http://www.stefankoelle.de/)**
[March 26, 2010 at 2:15 pm](/posts/stupiddb2/)
Hallo Ronald,
StupidDB gibt es im Moment nur direkt im SourceCode, die aktuelle Version kann man direkt per SVN downloaden:
<https://stupiddb.svn.sourceforge.net/svnroot/stupiddb/trunk>
Vielleicht sollten wir demnaechst auch die binaere Version davon bereitstellen.
Gruss
Stefan
5. **ronald**
[March 26, 2010 at 2:53 pm](/posts/stupiddb2/)
ich habe leider kein svn. ich habe probiert die files einzeln runterzuladen, aber dann kommen viele Fehler. Finde deinen Vorschlag gar nicht schlecht oder code als ZIP für alle NICHT-svn Benutzer. Wäre super. Vielen Dank vorab, Ronald
6. **[Stefan Kölle](http://www.stefankoelle.de/)**
[March 26, 2010 at 3:36 pm](/posts/stupiddb2/)
Werde mich am Wochenende um die Gezippte Version kuemmern…
7. **[Stefan Kölle](http://www.stefankoelle.de/)**
[March 27, 2010 at 8:04 pm](/posts/stupiddb2/)
Hallo Ronald,
die DLL und der Sourcecode kann nun als ZIP direkt runtergeladen werden:
[http://www.aztec-project.org](http://www.aztec-project.org/)
Gruss
Stefan
8. **ronald**
[March 29, 2010 at 9:09 am](/posts/stupiddb2/)
danke für die bereitstellung. habe es ausprobiert sehr schönes teil 🙂 hatte keine probleme bei der erstellung einer demo (unter hilfe von eurem blog)
ich habe etwas ähnliches gebaut, um einstellungsdaten für anwendung zu speichern (z.B. com-port, parameter für prüfprogramme usw.) letztlich funktioniert meine app ähnlich wie eure > Key Value, generisch. den speicherort habe ich mit “providern” gelöst, somit kann der anwender entscheiden, ob die files auf der festplatte landen oder vielleicht doch in einer sql-db oder was ganz anderes.
vielleicht für euch hilfreich um eine GUI bereitzustellen:
die gui habe ich mit propertygrid gelöst. um dort dann z.B. Listeneinträge zu ergänzen, muss dann eine spez. liste erstellt werden, welche ICustomTypeDescriptor impl., ein eigener PropertyDescriptor (generisch) muss auch erstellt werden.
das brauchte ich, weil betreuer von einem automaten, ohne xml-kenntnisse die daten pflegen müssen.
grüße ronald
+53
View File
@@ -0,0 +1,53 @@
---
title: "Testen von nicht öffentlichen Methoden"
date: 2009-08-12
slug: test-public-methods
original_url: "https://aztec-project.org/blog/test-public-methods.html"
archive_url: "https://web.archive.org/web/20250114141241/https://aztec-project.org/blog/test-public-methods.html"
author: "Christina Hirth"
categories: ["How-To", "Unit Testing"]
---
Wir fragen uns seit langem, wie man `internal` Methoden testen kann, da eins klar ist, die Kapselung darf nicht wegen der Testfähigkeit verletzt werden.
Letzte Woche hatte zum Glück auch jemand anderer dieses Problem und er hat gleich bei [CCD-GoogleGroup](http://groups.google.com/group/clean-code-developer) nachgefragt. Und so haben wir auch erfahren, wie die Lösung lautet:
> für “internal”-Elemente gibt es auch die Option mit [assembly:
> InternalsVisibleTo("TestAssembly")] zu arbeiten. Alternativ kannst du die zu
> testenden Klassen auch per “Add existing item” und dann “Add as link” (siehe
> kleines Dreieck neben dem “Add”-Button) zum Testprojekt hinzufügen.
(Danke [Alex](http://groups.google.com/groups/profile?enc_user=oc5IRhcAAAAuR_jK16wX7vC61npQCQRRuMwB60D2RE2h9ZtdV0_Uhw))
Danach war nur noch ein wenig Surfen nötig, um alles zu erfahren:
[msdn](http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx) sagt:
InternalsVisibleToAttribute Class
Specifies that types that are ordinarily visible only within the current assembly are visible to another assembly.
**User comment:**
It is not documented anywhere to my knowledge, but if you want to grant “InternalsVisibleTo” permission to more than one assembly, you need to understand the syntax.
To do this you should NOT insert multiples instances of:
`[assembly: InternalsVisibleTo("FirstAssembly")]`
Instead do this:
`[assembly: InternalsVisibleTo("FirstAssembly"),
InternalsVisibleTo("SecondAssembly"),
InternalsVisibleTo("ThirdAssembly")]`
The former syntax is legal but fails, because each instance simply redefines and replaces any earlier ones, the latter syntax works as required.
<img src="/images/test-public-methods/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. **Thomas Christain**
[August 12, 2009 um 8:28 pm](/posts/test-public-methods/)
Das ist natürlich eine super Sache.
Sowohl internal Klassen, als auch internal Methoden werden für die gekennzeichnete assembly freigegeben.
+193
View File
@@ -0,0 +1,193 @@
---
title: "Unit-Tests für WebForms"
date: 2009-09-07
slug: unittests-webforms
original_url: "https://aztec-project.org/blog/unittests-webforms.html"
archive_url: "https://web.archive.org/web/20250114121657/https://aztec-project.org/blog/unittests-webforms.html"
author: "Christina Hirth"
categories: ["How-To", "Unit Testing", "Webanwendungen"]
tags: ["Unit-Tests", "Webapplication"]
---
Obwohl die allgemeine Meinung ist, dass es sehr schwierig sei, kann man mit folgendem Workaround Webforms sehr einfach und sehr umfangreich testen. Bedingung 1: als Projekt kein Web Site Project sondern eine Web Application erstellen. Bedingung 2: Business Logic in die entsprechende Schicht auslagern.
Nehmen wir zum Beispiel ein einfaches Formular. Nach Absenden des Formulars sollen die Werte aus den 2 Feldern addiert werden. Wenn man per QueryString einen Parameter `multiple` übergibt, soll das Ergebnis damit multipliziert werden.
<img src="/images/unittests-webforms/TestableWebForm.jpg" alt="Testable WebForm"/>   <img src="/images/unittests-webforms/TestableWebForm_Sent.jpg" alt="Testable WebForm Sent"/>
Und nun zum Quellcode: Die automatisch erstellte .designer.cs muss entfernt werden, was man sowieso tun sollte, da man automatisch erstellten Code also Code, den keiner außer Microsoft unter Kontrolle hat vermeiden sollte.
Die Inhalte der .designer.cs also die Definitionen der Web-Elemente werden in der Klasse als `Public Properties` erstellt und instantiiert, um bei Zugriffen wie `TextBox.Text` keine NullReferenceException zu bekommen.
```
using System;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using framework.Testable.Web.UI;
5
namespace TestableWebForm
{
public class DefaultPage : System.Web.UI. Page
{
10
#region Controls
public HtmlForm Formular;
public TextBox Value1 = new TextBox ();
public TextBox Value2 = new TextBox ();
public Label Result = new Label ();
public Button Submit = new Button ();
#endregion
```
Um das Verhalten testen zu können, haben wir Adapter für die Klassen `System.Web.UI.Page`, `System.Web.HttpRequest` und `System.Web.HttpResponse` geschrieben, und zwar für die Properties und Methoden die uns vorerst interessieren: z.B. `Page.IsPostBack, Page.Request, Response.Redirect(string url, bool endResponse)`. Bei der Benennung haben wir einfach den Namespace `System` mit `framework.Testable` ersetzt und wir haben natürlich zu jedem Testable-Objekt einen Interface erstellt.
```
1
namespace framework.Testable.Web
{
namespace UI
{
public interface IPage
{
bool IsPostBack{ get ; }
IHttpRequest Request{ get ; set ; }
IHttpResponse Response{ get ; set ; }
}
12
public class Page : IPage
{
private readonly System.Web.UI. Page m_page;
private IHttpRequest m_request;
private IHttpResponse m_response;
18
public Page( System.Web.UI. Page page )
{
m_page = page;
m_request = new HttpRequest ( m_page );
m_response = new HttpResponse ( m_page );
}
25
public bool IsPostBack
{
get { return m_page.IsPostBack; }
}
30
public IHttpRequest Request
{
get { return m_request; }
set { m_request = value ; }
}
36
public IHttpResponse Response
{
get { return m_response; }
set { m_response = value ; }
}
}
}
}
```
Um alle gemockte Objekte setzen zu können, haben wir unserer `Page`-Klasse auch Setter für `Request` und `Response` gegeben. Da man `Request.Params` nicht setzen kann, d.h. `Request.Params[]` immer ein NullReferenceException verursachen würde, haben wir das Auslesen der `Request`-Parameter in eine Methode `Request.GetParamValue(string name)` ausgelagert.
Das war ungefähr alles: in der Seite nutzt man dann anstelle der eigenen Request und Response-Objekten die `Testable`-Objekte.
```
public class DefaultPage : System.Web.UI. Page
{
private IPage m_page;
public void SetTestableObjects( IPage page )
{
m_page = page;
}
24
public void Page_Load( object sender, EventArgs e )
{
if (m_page == null ) m_page = new Page ( this );
int multiple = 1;
if (! string .IsNullOrEmpty( m_page.Request.GetParamValue( "multiple" ) )) multiple = Convert .ToInt32( m_page.Request.GetParamValue( "multiple" ) );
if (m_page.IsPostBack)
{
Result.Text = ( ( Convert .ToInt32( Value1.Text ) + Convert .ToInt32( Value2.Text ))*multiple ).ToString();
}
}
```
Damit ist die Web-Anwendung bereit zum Testen. So schaut zum Beispiel ein Test für das Laden der Seite aus:
```
using framework.Testable.Web;
using framework.Testable.Web.UI;
using NUnit.Framework;
using Rhino.Mocks;
using TestableWebForm;
6
namespace Tests
{
[ TestFixture ]
public class WebFormTests
{
private IPage m_page;
private IHttpRequest m_request;
private IHttpResponse m_response;
private DefaultPage m_defaultPage;
16
[ SetUp ]
public void Init()
{
m_page = MockRepository .GenerateStub< IPage >();
m_request = MockRepository .GenerateStub< IHttpRequest >();
m_response = MockRepository .GenerateStub< IHttpResponse >();
m_page.Request = m_request;
m_page.Response = m_response;
}
26
[ Test ]
public void PageLoad_Loading_EmptyFields()
{
// Arrange
31
32
// Act
m_defaultPage = new DefaultPage ();
m_defaultPage.SetTestableObjects(m_page);
m_defaultPage.Page_Load( null , null );
37
// Assert
Assert .IsEmpty( m_defaultPage.Value1.Text );
Assert .IsEmpty( m_defaultPage.Value2.Text );
Assert .IsEmpty(m_defaultPage.Result.Text);
}
```
Und so für PostBack inklusive QueryString-Parameter:
```
[ Test ]
public void PageLoad_PostBackWithRequestValue_ResultIsCorrect()
{
// Arrange
const int value1 = 1;
const int value2 = 2;
const int value3 = 3;
m_request.Expect( a => a.GetParamValue( "multiple" ) ).IgnoreArguments().Repeat.Twice().Return( value3.ToString() );
m_page.Expect( a => a.IsPostBack ).Return( true );
72
// Act
m_defaultPage = new DefaultPage ();
m_defaultPage.SetTestableObjects( m_page );
m_defaultPage.Value1.Text = value1.ToString();
m_defaultPage.Value2.Text = value2.ToString();
m_defaultPage.Page_Load( null , null );
79
// Assert
Assert .IsTrue( m_defaultPage.Result.Text == ( (value1 + value2)*value3 ).ToString() );
}
```
Dieses Vorgehen hat uns nicht nur den seit langen gesuchten Weg zum Testen von Webanwendungen geebnet, sondern zwingt auch den Entwickler dazu, alle Funktionalitäten, die nicht in einer Webseite sondern in die dll-s gehören, auszulagern. Damit dürfte es auch der richtige Weg der Clean Code Developers für die Arbeit mit WebForms sein.
Was die Adapter-Klassen betrifft: inzwischen haben wir auch System.IO “adaptiert” und bald werden die anderen System-Klassen folgen, je nach Bedarf.
[Download VS2008-Projekt](/assets/TestableWebForm.zip)
<img src="/images/unittests-webforms/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
+59
View File
@@ -0,0 +1,59 @@
---
title: "Webcamps München"
date: 2010-06-11
slug: webcamps
original_url: "https://aztec-project.org/blog/webcamps.html"
archive_url: "https://web.archive.org/web/20260605232306/https://aztec-project.org/blog/webcamps.html"
author: "Andreas Seebauer"
categories: ["Veranstaltung"]
tags: ["HTML", "MVC", "webcamp"]
---
[<img src="/images/webcamps/camps.png" title="camps" width="122" height="120" class="size-full wp-image-1067 alignleft"/>](http://www.webcamps.ms/#munich_panel)
<img src="/images/webcamps/IMG_0165-225x300.jpg" title="IMG_0165" width="135" height="180" class="alignright size-medium wp-image-1068"/>Um unsere ASP.NET-MVC2-Kenntnisse mal wieder etwas aufzufrischen, haben ein paar von uns das zweitägige [Webcamp](http://www.webcamps.ms/#munich_panel) von Microsoft in München/Unterschleißheim besucht, an dem man unter den Teilnehmern auch ein paar bekannte Gesichter wie [Pete Sacchet](http://blog.sacchet.de/), [Christian Deger](http://www.deger-it.de/) und [Golo Roden](http://www.goloroden.de/) angetroffen hat.
Am ersten Tag wurden die Grundlagen von MVC2, Entity Framework, JQuery und IIS vermittelt. Dabei wurde anhand einer Rich Web Application gezeigt, wie MVC2, das Entity Framework und JQuery zusammenspielen können. Am zweiten Tag mussten die am Vortag zusammengestellte Teams ein Projekt auf diesen Themengebieten basteln und vorstellen.
Moderiert wurde das Ganze von [Jon Galloway](http://www.webcamps.ms/Speaker/jongalloway) und [Christian Wenz](http://www.webcamps.ms/Speaker/christianwenz), die am zweiten Tag bei Problemen mit Rat und Tat zur Seite standen.
Erhofft hatten wir uns von den zwei Tagen, einiges über MVC2 und JQuery zu erfahren. Enttäuscht wurden wir nicht, da uns noch unbekannte HtmlHelper, Validierungsmethoden sowie ein paar Tricks im Umgang mit Visual Studio gezeigt wurden. Das Entity Framework einmal im Einsatz zu sehen, war ganz nett, aber für uns nicht allzu interessant, da wir im Moment mit NHibernate arbeiten und damit ganz gut fahren.
<img src="/images/webcamps/IMG_0157-225x300.jpg" title="IMG_0157" width="203" height="270" class="size-medium wp-image-1074 alignnone"/><img src="/images/webcamps/IMG_0158-225x300.jpg" title="IMG_0158" width="203" height="270" class="size-medium wp-image-1071 alignnone"/><img src="/images/webcamps/IMG_0159-225x300.jpg" title="IMG_0159" width="203" height="270" class="size-medium wp-image-1072 alignnone"/>
Ja, zu essen gab es auch was. War lecker, wie man sieht.
Als Projekt am zweiten Tag haben wir uns für ein Buchungssystem von Ferienwohnungen entschieden. Wir waren leider nicht offiziell dabei, da uns diese Idee erst nach den Pitches eingefallen ist.
Das einzig Negative an der ganzen Veranstaltung war das Netz im Hotel Dolce Munich. 100 Leute, die gleichzeitig versuchen, über eine gefühlte DSL-Leitung zu saugen, saugt einfach. Der Proxy des Hotels setzte noch einen drauf und leitete Aufrufe auf localhost um, was den Start der Applikation in der Entwicklungsumgebung sehr schwer machte :>.
Nachdem man dann das WLAN deaktiviert hatte, konnte es dann auch losgehen.
<img src="/images/webcamps/IMG_0161-300x225.jpg" title="IMG_0161" width="300" height="225" class="size-medium wp-image-1076"/><img src="/images/webcamps/IMG_0162-300x225.jpg" title="IMG_0162" width="300" height="225" class="size-medium wp-image-1077"/><img src="/images/webcamps/IMG_0163-300x225.jpg" title="IMG_0163" width="300" height="225" class="size-medium wp-image-1078"/><img src="/images/webcamps/IMG_0164-300x225.jpg" title="IMG_0164" width="300" height="225" class="size-medium wp-image-1079"/>
Um uns möglichst nah an den Projekten in der Arbeit zu orientieren, haben wir erstmal Folgendes gemacht: SVN angelegt, Features, die wir aufnehmen wollten, erörtert, Architektur gezeichnet, Komponenten herausgearbeitet, Contracts erstellt, Komponenten angelegt, Komponenten implementiert. Und schwupps war die Zeit um. :> Wir sind leider nicht mit unserem Projekt fertig geworden, haben aber trotzdem in den zwei Tagen einiges gelernt.
Glückwunsch nochmal an die Gewinner des Wettbewerbs (Schiffe versenken).
<img src="/images/webcamps/KickItImageGenerator.ashx" alt="kick it on dotnet-kicks.de"/>
## Kommentare (Archiv)
1. <img src="/images/webcamps/3e7b6cb163ea9cc8549abcb8b5a03e2e.jpeg" width="32" height="32" class="avatar avatar-32 photo"/> **[Ralf Westphal](http://ralfw.blogspot.com/)**
[Juni 11, 2010 um 12:11 pm](/posts/webcamps/)
Na, das ist ja schön zu hören, dass sogar an Architektur und Komponenten und Kontrakte gedacht wurde.
War das von den Veranstaltern so intendiert?
-Ralf
2. **[Andreas Seebauer](http://www.in-your-face.org/)**
[Juni 11, 2010 um 3:40 pm](/posts/webcamps/)
Hallo Ralph,
natürlich nicht <img src="/images/webcamps/icon_smile.gif" alt=":)" class="wp-smiley"/> . Für die Veranstalter war es nur wichtig, dass man sich mit den Technologien beschäftigt. Ob der Code clean war oder nicht, war völlig egal.
Wir wollten es eben so machen wie an der Arbeit.
Gruß
Andreas
+210
View File
@@ -0,0 +1,210 @@
---
title: ".NET-Webservice mit ASP-Classic ansprechen"
date: 2009-06-19
slug: webservice-mit-asp-classic
original_url: "https://aztec-project.org/blog/webservice-mit-asp-classic.html"
archive_url: "https://web.archive.org/web/20250114140710/https://aztec-project.org/blog/webservice-mit-asp-classic.html"
author: "Christina Hirth"
categories: ["Webservice"]
tags: [".NET", "ASP-Classic", "Refaktorisierung", "Webservice"]
---
Seit einiger Zeit sind wir dabei, unser Portal zu refaktorisieren. Das entfernte Ziel ist, alles in .NET um zu bauen. Das betrifft zur Zeit über tausend Seiten aber wir möchten noch in diesem Leben fertig sein <img src="/images/webservice-mit-asp-classic/icon_wink.gif" alt=";)" class="wp-smiley"/>
Dazu kommt noch, dass wir selbstverständlich agiles Softwarentwicklung betreiben, was eine ständige und rhythmische Iteration vorsieht, keine Mega-Projekte mit ungewissem Ende. Also haben wir die verschiedenen Bereiche identifiziert und diese werden einer nach dem anderen neu gebaut.
Die neuen DLL-s in .NET werden mit Hilfe von verschiedenen Webservices angesprochen. Das führt allerdings unweigerlich dazu, 2 Technologien ASP-Classic und .NET(C#) miteinander sicher kommunizieren zu lassen. Das funktioniert so:
Dieser hier könnte der besagte .NET Webservice sein:
```
1 POST http://www.webAdresse.de/Webservice.asmx HTTP/1.1
2 Host: webServer
3 Content-Type: text/xml; charset=utf-8
4 Content-Length: length
5 SOAPAction: "http://tempuri.org/AendernEtwas"
6
7 <?xml version="1.0" encoding="utf-8"?>
8 <soap:Envelope xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
9 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
10 <soap:Body>
11 <AendernEtwas xmlns="http://tempuri.org/">
12 <id>int</id>
13 <person>
14 <nachname>string</nachname>
15 <vorname>string</vorname>
16 </person>
17 </AendernEtwas>
18 </soap:Body>
19 </soap:Envelope>
```
Um ihn aufzurufen, brauchen wir in ASP folgendes:
```
1 'Webserviceaufruf mit Angaben von Methodennamen und Parameter-XML
2 Function webserviceCall(ByVal methode, ByVal xmlParameters)
3 Dim objRequest, strRet
4 Set objRequest = Server.createobject("MSXML2.XMLHTTP")
5 With objRequest
6 .open "POST", "http://www.webadresse.de/Webservices.asmx", False
7 .setRequestHeader "Content-Type", "text/xml; charset=utf-8"
8 .setRequestHeader "SOAPAction11", methode
9 .send xmlParameters
10 End With
11 strRet = objRequest.responseText
12 if CInt(objRequest.status) <> 200 then
13 'Fehlerbehandlung, wenn Aufruf fehlgeschlagen
14 end if
15 Set objRequest = Nothing
16 webserviceCall = strRet
17 end function
```
Die Parameter werden so übergeben:
```
strParameters = "<?xml version=""1.0"" encoding=""utf-8""?>" & VbCrLf
strParameters = strParameters & "<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"">" & VbCrLf
strParameters = strParameters & " <soap:Body>" & VbCrLf
strParameters = strParameters & " <AendernEtwas xmlns=""http://www.webadresse.de"">" & VbCrLf
strParameters = strParameters & " <id> & id & </id>" & VbCrLf
strParameters = strParameters & " <person>" & VbCrLf
strParameters = strParameters & " <nachname><![CDATA[" & nachname & "]]></nachname>" & VbCrLf
strParameters = strParameters & " <vorname><![CDATA[" & vorname & "]]></nachname>" & VbCrLf
strParameters = strParameters & " </person>" & VbCrLf
strParameters = strParameters & " </AendernEtwas>" & VbCrLf
strParameters = strParameters & " </soap:Body>" & VbCrLf
strParameters = strParameters & "</soap:Envelope>"
```
Und das wäre dann alles, jetzt muss die Funktion nur noch aufgerufen werden:
responseText = webserviceCall("AendernEtwas", strParameters)
Das Ergebnis kann man danach mit Microsoft.XMLDOM ausgelesen werden.
Noch ein paar Bemerkungen:
- .NET ist im Gegensatz zu ASP-Classic case sensitive und eine stark typisierte Sprache, also obacht auf
1. die korrekte Schreibweise der Parameternamen in XML und auf
2. die Datentypen: strings müssen mit **CDATA** umklammert, Enums mit dem Namen angesprochen und Datumswerte in ISO 8601-Datumsformat (YYYY-MM-DDThh:min:sec.millisecond) angegeben werden.
## Kommentare (Archiv)
1. **kai**
[Dezember 15, 2009 um 10:36 am](/posts/webservice-mit-asp-classic/)
Wie sieht es mit den Visual Studio 2008 Webservices aus?
Kann ich diese ebenfalls mit deiner Consumer-Funktion aufrufen?
Bekomme leider folgenden Fehler:
msxml3.dll- Fehler 80004005
Unbekannter Fehler
/root/sub/test/test.asp, line 34
2. **Christina Hirth**
[Dezember 15, 2009 um 10:49 am](/posts/webservice-mit-asp-classic/)
Klar, das funktioniert mit allen SOAP-Webservices. Die Fehlermeldung ist typisch Microsoft, kann alles mögliche bedeuten <img src="/images/webservice-mit-asp-classic/icon_wink.gif" alt=";)" class="wp-smiley"/>
Was steht bei dir in Zeile 34?
3. **kai**
[Dezember 15, 2009 um 11:07 am](/posts/webservice-mit-asp-classic/)
Oh… mir fällt gerade auf (ich nahm diesen Webservice, weil er LÄUFT und im Netz funktionsfähig ist), dass dieser Webservice eine Guid über einen Login generieren muss, deswegen funktioniert es mit Sicherheit nicht! <img src="/images/webservice-mit-asp-classic/icon_wink.gif" alt=";)" class="wp-smiley"/>
Werde erstmal weiter schauen, trotzdem vielen Dank für die schnelle Antwort! <img src="/images/webservice-mit-asp-classic/icon_smile.gif" alt=":)" class="wp-smiley"/>
Falls es nichts wird, melde ich mich noch einmal!
4. **kai**
[Dezember 15, 2009 um 11:34 am](/posts/webservice-mit-asp-classic/)
strRet = objRequest.responseText steht in dieser Zeile.
Mit <http://localhost:port> und einer C#-Anwendung (lokal) kann ich auf den Dienst zugreifen, von meinem IIS-Server mit entsprechend geänderter
SOAP-URL (<http://IP:port>) und ausgeschalteter Firewall kommt es zu der Fehlermeldung.
Ich benutze die automatisch mit generierte HelloWorld-Funktion, welche ich via ASP aufrufe.
Was meinst du, könnte die Fehlerursache sein?
5. **Christina Hirth**
[Dezember 15, 2009 um 12:13 pm](/posts/webservice-mit-asp-classic/)
Wie schaut der Aufruf aus ? Und kannst du den Webservice mit der Adresse, die bei “.open “POST”, “http://www.webadresse.de/Webservices.asmx”, False” steht, erreichen?
6. **kai**
[Dezember 15, 2009 um 12:59 pm](/posts/webservice-mit-asp-classic/)
Mh, nein, dieser Development-Server, welcher das Visual Studio automatisch bereitstellt stellt beim F5 drücken ist scheinbar nicht von “außen” erreichbar, kann man dies irgendwie “umstellen”?
7. **kai**
[Dezember 15, 2009 um 1:00 pm](/posts/webservice-mit-asp-classic/)
Ich will nicht spammen, wollte dir das aber noch mit auf den Weg geben: Vielen Dank für den Code! <img src="/images/webservice-mit-asp-classic/icon_smile.gif" alt=":)" class="wp-smiley"/>
8. **Christina Hirth**
[Dezember 15, 2009 um 1:03 pm](/posts/webservice-mit-asp-classic/)
Hei Kai, kein Problem <img src="/images/webservice-mit-asp-classic/icon_smile.gif" alt=":)" class="wp-smiley"/>
Du musst diesen Webservice Publishen, ihn auf einen erreichbaren Webserver veröffentlichen. Dann müsste alles passen.
9. **kai**
[Dezember 15, 2009 um 3:03 pm](/posts/webservice-mit-asp-classic/)
Ja, habe ich jetzt gemacht.
Und jetzt habe ich das erst mit den strParameters verstanden, ich dachte die bräuchte man nur, wenn man der Methode des Webservice via SOAP Parameter übergeben wollen würde, dies war bis gerade auskommentiert.
Es waren also 2 Sachen zu bewältigen… <img src="/images/webservice-mit-asp-classic/icon_wink.gif" alt=";)" class="wp-smiley"/>
Jetzt läuft es, vielen Dank! <img src="/images/webservice-mit-asp-classic/icon_smile.gif" alt=":)" class="wp-smiley"/>
Eine Frage bleibt bei mir aber noch offen!
Ich habe die Funktion mit “” als Methode aufgerufen und es funktioniert trotzdem.
Ist der Parameter überhaupt notwendig? Eigentlich teilt man doch schon über den Soap-Envelope (strParameters) mit, welche Funktion des Webservice man aufrufen möchte oder nicht?
Wirklich, vielen Dank, Christina! <img src="/images/webservice-mit-asp-classic/icon_smile.gif" alt=":)" class="wp-smiley"/>
10. **Christina Hirth**
[Dezember 15, 2009 um 3:20 pm](/posts/webservice-mit-asp-classic/)
Ich weiß nicht genau, aber ich könnte mir sehr gut vorstellen, dass weil im Webservice eine einzige Funktion vorhanden ist, ist diese sozusagen die “Default”-Adresse <img src="/images/webservice-mit-asp-classic/icon_wink.gif" alt=";)" class="wp-smiley"/>
Aber die Frage ist interessant, ich werde das bei der nächsten Gelegenheit überprüfen.
Es freut mich sehr, dass du auch so begeistert bist, wie ich damals war, als es das erste mal diese alte Technik-neue Technik Kommunikation hingehauen hat
Sehr gerne und schöne Feiertage !
11. **kai**
[Dezember 15, 2009 um 3:29 pm](/posts/webservice-mit-asp-classic/)
Habe den Methoden-Parameter jetzt komplett aus deiner Funktion herausgenommen und folgende Zeile auskommentiert:
.setRequestHeader “SOAPAction11″, methode
Und es tut immer noch das, was es soll.
Deine Default-Theorie kann es leider nicht sein, weil ich bereits 2 Methoden in meinem Webservice habe.
Sehr interessant… <img src="/images/webservice-mit-asp-classic/icon_smile.gif" alt=":)" class="wp-smiley"/>
Nunja, hauptsache es funktioniert, WIE ist nur halb so wichtig! <img src="/images/webservice-mit-asp-classic/icon_wink.gif" alt=";)" class="wp-smiley"/>
Wünsche dir ebenfalls schöne Feiertage, bin für heute erstmal raus.
Bye, bye.
12. **[cortez1975](http://gmail.com/)**
[Januar 24, 2012 um 9:45 am](/posts/webservice-mit-asp-classic/)
The ashes life running now the 1992 academician was suspended, and a unattended distributorless blaze society parking was topped in contemplation of the exposable sweetkins predict conservation. [http://ogymes.com](http://ogymes.com/)