Wednesday, January 21, 2009

Small-scale DDD

I’m a fan of DDD aka Domain Driven Design.

I believe that there is value in thinking about separation of responsibilities, cohesion, coupling and romantic stuff like that. Even in completely toy projects.

Recently I wrote a little toy application to configure my WiFi router. In particular it fetches list of local networks from a text file and feeds it one by one to a admin web interface with WatiN. If you want details, then router routes half of the traffic through provider’s gateway, and the other half through VPN.

The whole thing can probably be scripted by Perl ninja in 10 lines total. But for me process was more important then the result. So I decided to over-architect a little. In particular, to play with The Onion Architecture.

First candidate for abstraction was WatiN-related magic. Libraries come and go, only application core stays forever. I created an interface that hides all manipulations with browser:

public interface IRouterWebInterface
{
 void Login();
 void OpenRoutingPage();
 void AddRoute(Route route);
 void Close();
}

The interface sits in innermost layer – Domain Model. Implementation – RouterWebInterface class – is pushed to outmost Infrastructure layer. It references WatiN, and is not referenced by anyone.

Domain Model contains just a couple of classes. Route class parses network address, mask, gateway and metric from source text format and can even verify their validity If I’ll Ever Gonna Need It. RouteList is a first-class collection of individual Routes. WifiRouter class owns method AddRoutes(RouteList ). This method uses IRouterWebInterface to Login, OpenRoutingPage, and iterate over RouteList, calling AddRoute for each of them. WifiRouter is supplied with implementation of RouterWebInterface through constructor dependency injection.

So the actual Main looks like

RouteList list = // get list from file
var router = new WifiRouter(new RouterWebInterface(
 new Uri("http://192.168.1.1/"), "admin", "admin"));
router.AddRoutes(list);

Pretty neat, if you ask me :)