Donnerstag, 25. November 2010

KataFizzBuzz ala Reactive Framework

class Program
{
    static void Main(string[] args)
    {
        FizzBuzzer(1, 100).Subscribe(Console.WriteLine);
        Console.ReadLine();
    }
 
 
    internal static IObservable<string> FizzBuzzer(int start, int stop)
    {
        return Observable.Generate(start, x => x <= stop, x =>
                                    {
                                        if (IsFizz(x) && IsBuzz(x))
                                            return "FizzBuzz";
                                        if (IsFizz(x))
                                            return "Fizz";
                                        if (IsBuzz(x))
                                            return "Buzz";
                                        return x.ToString();
                                    }, x => x + 1);
    }
 
    internal static bool IsFizz(int x)
    {
        return (x % 3 == 0);
    }
 
    internal static bool IsBuzz(int x)
    {
        return (x % 5 == 0);
    }
}
 
[TestFixture]
class FizzBuzzTest
{
    [TestCase(1, 1, "1")]
    [TestCase(3, 3, "Fizz")]
    [TestCase(5, 5, "Buzz")]
    [TestCase(15, 15, "FizzBuzz")]
    public void FizzBuzzAlgoShouldNotFail(int from, int to, string result)
    {
        Program.FizzBuzzer(from, to).Subscribe(x => x.Should().Equal(result));
    }
}

Sonntag, 21. November 2010

Online Coding Dojo - Kata Tennis - Retrospektive

Für mich was das letzte Online Coding Dojo der .NET Online User Group durch seine Vielzahl an Wendungen im Verlauf des Abends außerordentlich spannend. Das nette Thema Game-Play rundete das Abendprogramm als besonders unterhaltsam dann nochmal ab. Leider konnte ich nicht bis zum Ende der Timebox teilnehmen und holte am Abend noch eine eigene Implementierung nach. Nachdem nun einige spannende Lösungsvarianten vorgestellt wurden, habe ich meine nun auch veröffentlicht.

Die Kata - KataTennis
Mir fällt eine Lösungsfindung ohne die Struktur einer Skizze immer etwas schwer, deshalb zeichnete ich neben der parallel stattfindenden Implementierung im Randori-Stil meine kleine Welt der Problem-Domäne.

Mir hilft diese Art der Anwendungsplanung - ohne Code - Klarheit über Code-Struktur, Funktionseinheiten und Datenstrukturen, die Funktionsweise, ihrer Interaktion und der Anwendungszustände zu erhalten. Das entscheidende für mich dabei ist, der grobe Überblick und Trennung der Aufgaben in Teilaufgaben. Ich versuche dann, wärend der Implementierung den Gedanken zu halten und in die gewünschte Funktionsweise umzusetzen. "Schwierige" Fälle beantworte ich vorerst nicht - sie bleiben mit einem gedanklichen Fragezeichen offen und werden an geeigneter Stelle mit einem test-, trace- und/oder debugger-getriebenen Vorgehen explorativ-iterativ bis zu Erfüllung der Akzeptanzkriterien "ausgecodet". Ich bin kein TDD-Hardliner, daher stellen Unittests auf verschiedenen Abstraktionsebenen meine Akzeptanzkriterien, und die aus Skizze erstellte Code-Struktur mein "System under Test" bereit. Aus diesem Mix, Planung und TDD Setup entsteht die API. In diesem Falle auch meine Variante der KataTennis.

Ganz besonders hat mir, da ich sonst kein Freund von Enums bin, die Idee "Game-States über Enums" abzubilden gefallen. Die Domäne wurde, auch im Code, um einen wichtigen Punkt, der verständlicheren Domänensprache, erweitert. Toll - ich hab das übernommen, aber ein kleiner Wermutstropfen bleibt - Operationen auf Enums, wie Increment (++), Decrement(--) sind zwar möglich, können allerdings zu ungewollten Exceptions führen. Hier gilt: Aufpassen bei Operationen über das maximale oder minimale Enum-Value-Scope hinausgehende.

Lehre
Die inzwischen entstandene Breite der Lösungsvarianten zeigt mir, wie unterschiedlich abstrakt das Problem der Spielstatushaltung, des Gameplays, des Code-Verständnisses und des Testens interpretiert werden kann. Mir war eine Trennung von Game-Play und Game-State, eine zentrale Steuerung der Transitionen über Constraints sowie eine relativ "natürliche" Verwendung der API wichtig. Schwer tat ich mich bei den Unittests der Game- und Play-States. Obwohl ich von der Notwendigkeit überzeugt bin, empfand ich das im Szenario als etwas lästig. Ich halte meine Augen und Ohren für eine umgängliche Lösung offen.

Fazit
Für mich ist es immer wieder erstaunlich, wie viele Lösungen eines Problems mit unterschiedlichen Ansätzen und Ideen verwirklicht werden können. Cool - da freue ich mich schon auf das nächste .NET Coding-Dojo.