Dojos für Entwickler 2

Text
Read preview
Mark as finished
How to read the book after purchase
Dojos für Entwickler 2
Font:Smaller АаLarger Aa

Einleitung








Auch in Teil 2 der Dojos für Entwickler gewinnt der, der auch übt. Was kann man gewinnen? Die Antwort ist kurz und bündig: Wissen. Stefan Lieser hat weitere 15 Aufgaben und ihre Lösungen formuliert. Stefan ist freiberuflicher Trainer und Berater und Fan von intelligenten Entwicklungsmethoden, die für Qualität der resultierenden Software sorgen. Er denkt sich die Aufgaben aus und gibt dann auch seine Lösung zum Besten. Er wird auch mitteilen, wie lange er gebraucht und wie viele Tests er geschrieben hat.



Alle Originalquellcodes in diesem devbook finden Sie zum Download unter

http://www.dotnet-developer-conference.de/downloads/DojosII.zip



Aber bevor es los geht noch schnell 3 Fragen an Stefan:








Stefan, wie bist du zum Programmieren gekommen?



Mein Vater hat einmal einen programmierbaren Taschenrechner mit nach Hause gebracht. Der hat mich sehr fasziniert. Als Ferienjob habe ich dann Datenerfassung auf einer DEC PDP-11 gemacht und dabei "nebenbei" FORTRAN gelernt. Übrigens im selben Büro mit meinem Vater. Das hat mir tiefe Einblicke in sein Berufsleben gegeben. So ging es dann ständig weiter. In der Schule Informatikunterricht, dann Informatik studiert. Und schon vor Studiumsbeginn die ersten Programmierjobs.



Mich hat C# als Sprache fasziniert. Ich fand sie von Anfang an in manchen Details eleganter als Java. Ich beschäftige mich neben .NET allerdings auch mit anderen Umgebungen.



Wie lernt man am schnellsten zu programmieren?



Auch für die Softwareentwicklung gilt, dass man es erst mit 10.000 Stunden "deliberate practice" zur Meisterschaft bringt. Insofern würde ich sagen, am schnellsten geht es, wenn man täglich übt. Damit meine ich nicht, täglich seinen Job als Programmierer zu machen, sondern wirklich täglich zu üben. Der Unterschied besteht für mich darin, dass ich beim Üben Fehler zulassen kann. Als Trompeter vergleiche ich das gerne mit dem Spielen eines Musikinstruments. Immer nur Auftreten geht nicht. Ich muss vor allem Üben. Und das klingt nicht immer schön ;-)



Welche Tipps zum schnellen und effektiven Lernen kannst du den Lesern dieses DevBooks geben?



Zum Lernen ist Regelmäßigkeit und Reflexion erforderlich. Mit den Übungen des DevBooks kann man sich einige Zeit beschäftigen. Jede Woche eine Aufgabe lösen wäre z.B. ein Weg. Sinnvollerweise sollte die im Buch gezeigte Lösung erst nach der eigenen Lösung angesehen werden, um Vergleiche ziehen zu können. Dabei geht es nicht um richtig oder falsch sondern um den Erkenntnisgewinn.



Worte an den Leser…



Ich wünsche den Lesern viel Spaß mit den Übungen. Eine Anregung könnte noch sein, die Übungen und vor allem die Lösungen gemeinsam mit Kollegen zu diskutieren. Üben in der Gruppe kann viel Spaß machen. Auch beim Diskutieren der individuellen Lösungen kann man einiges lernen. Wer keine eigene Gruppe gründen möchte, kann auch zur CCD School kommen (

http://ccd-school.de

).





Aufgabe 1











MarkDown-Control selbst gebaut

Einfach, einfacher, MarkDown



Es muss nicht immer HTML oder RTF sein. Wer Texte auszeichnen will, kann auch MarkDown verwenden. Dieses Format ist besonders einfach und aus vielen Wikis bekannt. Also lautet die Übung: Schreiben Sie ein Control, das MarkDown-Texte darstellen kann.



Ein Text erhält Auszeichnungen, damit er auf bestimmte Art und Weise dargestellt wird. Das ist nichts Neues. Anfang der 90er-Jahre wurden beispielsweise HTML und RTF entwickelt, mit dem Ziel, Texten eine Struktur geben zu können. Mit beiden Formaten ist es möglich, einen Textabschnitt etwa kursiv oder fett auszugeben:



HTML: <em>kursiv</em> <strong>fett</strong> RTF: {\i kursiv} {\b fett}



Beide Formate haben jedoch gemeinsam, dass die Syntax für die Formatierung recht aufwendig ist. So sind die gezeigten HTML- und RTF-Beispiele auch nicht vollständig, weil sie von weiteren Elementen umschlossen sein müssen, um gültiges HTML beziehungsweise RTF darzustellen.



Die Vereinfachung von Formatierungen ist das Hauptziel von MarkDown . Mit dieser bewusst total simpel gehaltenen Formatierung soll es möglich sein, das Schreiben von Texten deutlich zu vereinfachen, ohne dabei auf Formatierungen gänzlich verzichten zu müssen. So wird bei MarkDown die Formatierung einfach in den Text eingestreut und muss nicht in einen komplizierten syntaktischen Rahmen eingebettet werden. Die Beispiele für kursive und fette Hervor­hebungen sehen in MarkDown wie folgt aus:



*kursiv* **fett** ***fett kursiv***



Sie können nicht nur einzelne Textabschnitte kursiv oder fett ausgeben; MarkDown bietet auch Möglichkeiten, die Struktur des Textes zu beschreiben. Eine grundsätzliche Idee von MarkDown ist es, aus einem MarkDown-Text ein HTML-Dokument zu erzeugen. Daher lehnen sich die Formatierungen an das an, was mit HTML möglich ist. Überschriften können beispielsweise folgendermaßen erzeugt werden:



# Überschrift auf Ebene 1 ## Überschrift auf Ebene 2 ### Überschrift auf Ebene 3



Möglicherweise wird der eine oder andere Leser feststellen, dass er solche oder ähnliche Auszeichnungen schon verwendet hat: Wikis verwenden häufig MarkDown oder daran angelehnte Formatierungen.



Auch Aufzählungen in Form von Spiegelstrichlisten oder nummerierte Listen sind möglich:



* Erster Punkt * Zweiter Punkt * Dritter Punkt 1. Schritt eins 1. Schritt zwei 1. Schritt drei



Solche Formatierungen werden beim Konvertieren nach HTML in

<ul>

- oder

<ol>

-Listen Übersetzt.



Doch nun zur Aufgabe: Erstellen Sie ein

User-Control

, das einen Text im MarkDown-Format akzeptiert und als Label anzeigt. Allerdings sollen dabei MarkDown-Formatierungen berücksichtigt werden, sodass beispielsweise ein Wort in Sternchen kursiv ausgegeben wird. Wie viele der MarkDown-Elemente Sie umsetzen, ist zunächst nachrangig. Beginnen Sie ganz einfach, statt gleich eine perfekte 100-prozentige Lösung anzustreben.



Die Herausforderung liegt in zwei Bereichen: zum einen im Parsen des Textes, zum anderen in der Visualisierung. Innerhalb des Textes müssen die Auszeichnungen erkannt werden, um daraus Formatierungen abzuleiten. Im angezeigten Text dürfen die Auszeichnungen nicht mehr erscheinen. Stattdessen muss der Text entsprechend formatiert sein. Wie man das in einem

User-Control

 erreicht, ist die zweite Herausforderung. Ob Sie dabei auf Windows Forms, Silverlight oder WPF setzen, bleibt natürlich Ihnen überlassen. Allerdings würde ich persönlich die Übungszeit nutzen, mich mit XAML auseinanderzusetzen, da in Windows Forms sicher nicht die Zukunft liegt. Wie immer wünsche ich Ihnen viel Spaß beim Üben. Machen Sie viele Fehler und lernen Sie daraus! 



http://de.wikipedia.org/wiki/Markdown


http://daringfireball.net/projects/markdown/






Lösung 1











Ein UserControl für Markdown-Textauszeichnungen

Show up Mark down



Texte mit Markdown-Auszeichnungen in einem Control darzustellen, das war die Aufgabe. Natürlich ist bei der Lösung wieder alles im Fluss. Und weil das im echten Leben auch so ist, muss wieder einmal eine Lösung her, die evolvierbar ist. So ist sichergestellt, dass spätere Anforderungen einfach umsetzbar sind.



Mit Markdown steht eine Textauszeichnung zur Verfügung, die einfach anzuwenden ist . Das liegt daran, dass auf Schnickschnack verzichtet wurde. Es handelt sich nicht um eine weitere Variante des Themas „Viele Klammern werden das Problem schon lösen“. Statt also wie bei HTML auf spitze Klammern oder bei RTF auf geschweifte Klammern zu setzen, verwendet Markdown Zeichen wie etwa das Sternchen, um damit Passagen eines Textes auszuzeichnen. Das macht die Sache beim Schreiben eines Textes deutlich einfacher, weil weniger Formalismen erforderlich sind. Allerdings wird, damit einhergehend, das Parsen eines Textes nicht unbedingt einfacher. So wird in Markdown beispielsweise ein einzelnes Sternchen sowohl zur Markierung von kursivem Text verwendet als auch zur Kennzeichnung von Aufzählungen. Das zu erkennen ist die Herausforderung beim Parsen eines Markdown-Textes.





Kleine Schritte



Im ersten Schritt habe ich die Aufgabe wieder klein gehalten. Mir ist es wichtig, jeweils einen Teil der insgesamt gewünschten Funktionalität komplett fertig zu kriegen. Was nützt es mir, wenn ich zwar Markdown-Texte nach allen Regeln der Kunst zerlegen kann, davon jedoch noch nichts visualisiert wird? Folglich habe ich mich erst einmal darauf beschränkt, nur

kursiv

 und

fett

 zu erkennen und in einem

UserControl

 zu visualisieren. Text, der in einfache Sternchen eingefasst ist, soll *kursiv* dargestellt werden, Text in doppelten Sternchen **fett**.

 



Meine ersten Überlegungen drehten sich um die Frage, wie ich einen Text nach der Erkennung der Markdown-Auszeichnungen repräsentieren möchte. Wie sieht eine geeignete Datenstruktur aus? Um das Einfachste zu tun, habe ich mir überlegt, dass der Text nach der Zerlegung aus TextElementen bestehen könnte. Enthält ein Text keinerlei Markdown-Auszeichnungen, wäre der gesamte Text ein einzelnes

TextElement

.



Enthält der Text jedoch ein Wort in Fettschrift, würde ich diesen Text in drei TextElemente zerlegen:





 ein

TextElement

 in normaler Schrift,



 ein

TextElement

 in fetter Schrift,



 T wieder ein

TextElement

 in normaler Schrift.





Der Text „Ein **fettes** Wort“ würde also in die drei TextElemente „Ein “, „fettes“, „Wort“ zerlegt. Beachten Sie die Leerzeichen: nach „Ein“ und vor „Wort“ ist jeweils ein Leerzeichen.



Durch diese simple Datenstruktur kann die Zerlegung eines Markdown-Textes schrittweise erfolgen: Zuerst werden fett hervorgehobene TextElemente extrahiert. Anschließend werden aus den bereits gebildeten TextElementen weitere gebildet, um so kursive Texte darzustellen. Dazu muss die

TextElement

-Datenstruktur neben dem Text die Information mitführen, ob der Text fett und/oder kursiv dargestellt werden soll. Listing 1 zeigt die entsprechende Datenstruktur.





Listing 1

Grundlegende Datenstruktur.



public class TextElement { public string Text { get; set; } public bool Fett { get; set; } public bool Kursiv { get; set; } }



Aus diesen überlegungen hat sich der in Abbildung 1 gezeigte Flow ergeben.








 Fett und kursiv gesetzte Textteile extrahieren.



Im ersten Schritt wird der eingehende String in ein

TextElement

-Objekt umgewandelt. Weil anschließend jeweils eine Aufzählung von

TextElement

-Objekten bearbeitet wird, liefert die Funktionseinheit

Verpacke_in_

TextElement gleich eine Aufzählung, die allerdings immer nur ein einzelnes Objekt enthält.



Anschließend werden Texte extrahiert, die in Fettschrift ausgezeichnet sind. Es wäre denkbar, dass diese Funktionseinheit später auf mehr als einem

TextElement

 arbeiten muss. Das könnte zum Beispiel der Fall sein, wenn vor der Fettschrift die Überschriften extrahiert werden. Somit ist es sinnvoll, als Eingang der Funktionseinheit gleich eine Aufzählung von

TextElement

-Objekten vorzusehen.



Nach dem Extrahieren von Fettschrift folgt das Extrahieren der kursiv ausgezeichneten Texte. Wieder wird eine Aufzählung von

TextElement

-Objekten behandelt. Werden im eingehenden Datenstrom kursiv ausgezeichnete Texte gefunden, dann wird ein

TextElement

 möglicherweise in mehrere

TextElement

-Objekte zerlegt. Die Anzahl der ausgehenden

TextElement

-Objekte kann also höher sein als auf der Eingangsseite.



Nun mag dem einen oder anderen Leser durch den Kopf gehen, dass das gewählte Verfahren eventuell aus Laufzeitgründen ineffizient ist. Ja, das kann sein. Aber an dieser Stelle kümmert mich das nicht. Die Lösung ist dazu gedacht, Markdown-Texte in einem Label-Control zu visualisieren. Das heißt, es werden typischerweise wenige, noch dazu kurze Texte bearbeitet. Für die Verarbeitung von Massendaten ist dieser Ansatz möglicherweise nicht optimal.



Aber das ist gerade nicht die Aufgabenstellung. Es genügt hier also, das Einfachstmögliche zu tun. Der gewählte Weg sieht mir bis hierhin in jedem Fall gut evolvierbar aus. Weitere Markdown-Elemente zu erkennen bedeutet nur, eine entsprechende Funktionseinheit zu implementieren, die für das Zerlegen zuständig ist. Diese kann dann leicht in den bestehenden Flow eingehängt werden. Spannend bleibt dabei die Frage, ob die Datenstruktur

TextElement

 dann weiterhin ausreicht. Doch bevor ich das herausfinde, folgt nun die Implementation für das Erkennen von Fettschrift. Listing 2 zeigt einige Tests dazu.





Listing 2

Erst mal testen: Fett-Formatierungen erkennen.



public class Extrahiere_Fett_Tests { private Extrahiere_Fett sut; private IEnumerable<TextElement> result; public void Setup() { sut = new Extrahiere_Fett(); sut.Result += x => result = x; } public void Normaler_Text_ ohne_Fettschrift() { sut.Process(new{"x"})); Assert.That(result.Select( x => x.Fett), Is.EqualTo(new{false})); } public void Fettschrift_am_ Anfang_eines_TextElements() { sut.Process(new { "fett", " x" })); Assert.That(result.Select( x => x.Fett).ToArray(), Is.EqualTo(new { false, false })); } public void Mehrfach_ Fettschrift() { sut.Process(new { "f1", "f2", "y", "f3" })); Assert.That(result.Select( x => x.Fett).ToArray(), Is.EqualTo(new { false, false, false, false })); } }



Die Tests spielen diverse Szenarien durch, in denen fett ausgezeichneter Text auftreten kann. Da die Funktionseinheit als

Event-Based Component (EBC)

 realisiert ist, hat sie für die Eingangsdaten eine Methode

Process

 und für die Ausgangsdaten einen Event

Result

. Mithin genügt es für das Testen nicht, eine Methode aufzurufen, vielmehr muss das Ergebnis des Events ausgewertet werden. Daher binde ich im Setup der Testklasse an den Event die Lambda-Expression, welche das Ergebnis im Feld result der Testklasse ablegt:



sut.Result += x => result = x;



Der Inhalt dieses Feldes

result

 wird dann in den einzelnen Tests jeweils nach Aufruf der

Process

-Methode durch ein

Assert

 überprüft.



So weit zur Mechanik der Tests. Was mich an den Tests etwas stört, ist die Tatsache, dass auch die

Kursiv

-Eigenschaft in den

TextElement

-Objekten überprüft wird. Diese Eigenschaft zu prüfen ist sinnvoll, um sicherzustellen, dass die Funktionseinheit tatsächlich nur die Fettschrift aktiviert. Dennoch stellt sich die Frage, was kursive Schrift mit fetter Schrift zu tun haben mag. Das ist für mich ein Hinweis darauf, dass die Datenstruktur möglicherweise nicht optimal gewählt ist, denn so kann es zu Missverständnissen kommen. Eine alternative Implementation könnte die beiden booleschen Eigenschaften

Fett

 und

Kursiv

 zu einer einzigen zusammenfassen. Damit weiterhin alle vier möglichen Kombinationen von zwei booleschen Eigenschaften abgebildet werden, könnte ein

enum

-Typ verwendet werden, der die vier Kombinationen explizit enthält:





 T Normal,



 T Fett,



 T Kursiv,



 T FettUndKursiv.





So wäre klar, welche Bedeutung die Eigenschaft hat. Allerdings ist es nun etwas schwieriger, den vorhandenen Wert der Eigenschaft so zu ändern, dass kursiv ergänzt wird. Denn aus

Normal

 müsste dann

Kursiv

 werden, während aus

Fett

 dann

FettUndKursiv

 werden müsste. Ob die Lösung so besser aussieht, wollte ich wissen und habe es ausprobiert. Dabei zeigte sich, dass der Umgang mit einem enum-Typ die Lösung deutlich aufwendiger machen würde, daher habe ich den

enum

-Typ verworfen. Eine andere Idee wäre, den Schriftstil als zusammengesetzten Typ wie in Listing 3 zu definieren.





Listing 3

Eine Klasse für den Schriftstil.



public class SchriftStil { public bool Fett { get; set; } public bool Kursiv { get; set; } }



Doch auch das würde die Sache nicht einfacher machen, allein schon weil in den Tests der Vergleich zweier Objekte dieses zusammengesetzten Typs nicht mehr einfach so funktionieren würde. Am Ende entschied ich mich daher, es bei den beiden booleschen Eigenschaften

Fett

 und

Kursiv

 zu belassen.





Implementation



Die Implementation ging zunächst leicht von der Hand. Text, der in Fettschrift ausgegeben werden soll, muss in Markdown in doppelte Sternchen eingefasst werden. Folglich suche ich in den eingehenden

Text-Element

-Objekten nach doppelten Sternchen. Bei jedem Treffer wird ein Flag, welches festhält, ob gerade Fettschrift ausgegeben werden soll, umgeschaltet. Ferner wird der bis dahin eingelesene String in ein neues

TextElement

-Objekt verpackt und als Output der Funktionseinheit ausgegeben.



Die Herausforderung bestand darin, auch solche Fälle korrekt zu behandeln, die nicht direkt auf der Hand liegen. So kann es beispielsweise sein, dass das öffnende und das schließende Doppelsternchen in zwei unterschiedlichen

TextElement

-Objekten liegen. Um auch damit korrekt umzugehen, musste ich das Flag aus der Methode in die Klasse verschieben, damit der Zustand

TextElement

 übergreifend gehalten wird. Ohne automatisierte Tests wäre ich hier aufgeschmissen gewesen.