2007/05/30

Linq und Memoization

Gestern habe ich mir ein Video von Wes Dyer angeschaut. In diesem Interview beschreibt Wes (ein Mitarbeiter des C#-Kompiler-Teams und ein ziemlich smarter Typ) die Vereinfachung eines Singleton-Pattern mittels Extension Methods. Da mir das ganz gut gefallen hat, beschloss ich das ganze mit der Beta von 'Orcas' auszuprobieren und hier nachzuvollziehen. Nachfolgend also dieses Beispiel.

Eine typische Implementation des Singleton-Pattern sieht meist etwa so aus:


public class Foo
{
private static Foo _instance = null;

public static Foo GetInstance()
{
if (_instance == null)
_instance = CreateFoo();

return _instance;
}

private static Foo CreateFoo()
{
//some interesting stuff
return new Foo();
}
}

Das ist soweit trivial und sollte keinem von uns Kopfzerbrechen bereiten. (Auf den Sinn und die Notwendigkeit des Patterns und allfällige Singletonitis wollen wir hier nicht eingehen) In einigen Sprachen ist dieses Pattern bereits sogar in die Standart-Bibiliothek integriert worden. (e.g Ruby)

Etwas – zugegebenermassen nur sehr wenig – komplizierter wird es hier, wenn wir Gruppen von Instanzen verwalten wollen. Zum Beispiel stellen wir uns für das gegebene Beispiel vor, dass wir pro Zahl eine eigene Instanz verwalten wollen. Ein erster Versuch könnte uns zum Beispiel zu folgender Implementation führen:

public class ComplicatedFoo
{
private static Dictionary<int,ComplicatedFoo>
_dictionary = new Dictionary<int,ComplicatedFoo>();

public static ComplicatedFoo GetInstance(int n)
{
ComplicatedFoo foo = null;
if (!_dictionary.TryGetValue(n, out foo))
{
foo = CreateComplicatedFoo(n);
_dictionary.Add(n, foo);
}
return foo;
}

private static ComplicatedFoo
CreateComplicatedFoo(int n)
{
//some interesting stuff
return new ComplicatedFoo();
}
}

Wir nehmen also erstmal ein Dictionary zu Hilfe um diese Struktur abzubilden. Wenn wir dies aber genauer anschauen, stellen wir fest, dass es sich hier um die Verbindung von einer Funktion (inkl. Parameter) und einem Resultat handelt. Mit anderen Worten: Memoization.
Memoization implementieren wir in C# 3.0 mittels einer ‚Extension Method’. Im unserem Fall mit einer Methode mit einem Argument und einem Resultat könnte diese Methode so aus:

static class FunctionExtensions
{
public static Func<A, R>
Memoize<A, R>(this Func<A, R> f)
{
var map = new Dictionary<A, R>();
return a =>
{
R value;
if (map.TryGetValue(a, out value))
return value;
value = f(a);
map.Add(a, value);
return value;
};
}
}

Wenn wir nun diese Memoization-Funktion auf unsere vorige Implementation anwenden, so führt uns das zu folgendem Code:

public class FunctionalFoo
{
private static Func<int, FunctionalFoo>
getInstance = ((Func<int, FunctionalFoo>)
(n => CreateFunctionalFoo(n))).Memoize();

public static FunctionalFoo GetInstance(int n)
{
return getInstanceMemoized(n);
}

private static FunctionalFoo
CreateFunctionalFoo(int n)
{
//some interesting stuff
return new FunctionalFoo();
}
}

Der Vorteil dieser Implementation ist natürlich, dass wir unsere Memoize-Funktion beliebig wiederverwenden können. (Gesetzt wir haben die entsprechende Signatur in unsere CreateFoo-Methode.)

Ziemlich cool IMHO. Thanks Wes!

2007/05/20

Mocks vs Stubs

Ein Blog welches ich seit einiger Zeit - mit der mir verfügbaren Sorgfalt - verfolge, ist jenes von Jay Fields. Ein weiterer ThoughtWorker der stets mit qualitativ hochwertigen Posts aufwartet.

Den Unterschied zwischen Mocks und Stubs haben wir ja bereits hier definiert. Bei meinen eigenen TDD-Streifzügen bin ich jedoch zur Überzeugung gekommen, dass auch hier wieder keines von beiden für sich allein genommen die silberne Kugel ausmacht. In einem bereits etwas älterem Post von Jay habe ich dann diesen, für mich sehr sinn-stiftenden Abschnitt gefunden, den ich gerne mit euch teile möchte:


Using a mock to verify the class under test interacts in an expected manner with a dependency is natural. However, tests should verify behavior of a dependency independently of other dependencies. For all dependencies who's behavior is not currently under test a stub is preferred. By using stubs in this manner you convey the message that only the interaction of the class under test and the mocked dependency is important.


Eine etwas mehr 'Absicht-getriebene' Definition. Und da ich versuche, Code zu schreiben, welcher die dahinter liegenden Absichten bestmöglich kommuniziert, gefällt mir diese stützende Beschreibung besonders gut.