Posts Tagged lambda

NHibernate Lambda Extensions – an open-source adventure

For our client Gerechtsdeurwaarderskantoor De Jong we built a .NET application that uses NHibernate in the data-layer to talk to the Informix database. To abstract away from the specific knowledge about the database / ORM I created the below structure:

The DomainConnector is a class that implements lots of business rules to load/save domain-objects and gets its IStorage from our IoC-container (which is Castle Windsor). The InformixConnector implements the IStorage interface, but the DomainConnector doesn’t know that. Just as it doesn’t know that the InformixConnector uses NHibernate to do the actual work.

Well, until recently that was not entirely the case. The DomainConnector needs queries to specify which objects it wants in a list (for example). Those queries were in strings and were actually HQL queries.

Mmmmmmmh, so the DomainConnector did not know what database was in the back-end (thanks to NHibernate), but did know in some way about the fact that NHibernate was used. Use invalid HQL in your query and you’re doomed.

Some times you can live with less-than-perfect code. But a couple of days ago I ran into a problem I felt I had had before. I got this message from NHibernate that it could not map some property. So what do you do? You check your mapping file and the class that it maps to and conclude that everything is perfect. So you Google. Nothing interesting.

And then (a frustrating hour later) a memory bubbles up: it is not talking about the mapping itself, it’s talking about trying to map names in a query! Yep, that was the problem. The cause? I changed the name of a property. The real cause? This property was referenced in a string and the compiler could -of course- not warn me I had to change the query-string.

I had e feeling that Lambda-expressions must be the solution to this problem (as they are currently to a lot of my problems). And Google (as a .NET afficionado should I be bing-ing?) told me there was already an open-source project that did just what I wanted:
nhlambdaextensions.

This project contains a few extension classes that allow you to use lambdas to specify your ICriteria. As they say on their homepage:

    .Add(Expression.Eq("Name", "Smith"))

becomes

    .Add(p => p.Name == "Smith")

Now you can have Intellisense and compile-time checking. No way you inadvertently type LastName in stead of Name!

So I downloaded the binaries, tried to compile, noticed that I needed a newer version of NHibernate, downloaded that and it compiled. Changed one of the DomainConnectors and ran a unit test: bingo!!! This was going to work. I was so happy, I changed all the DomainConnectors before running an intergration test. I mean: I changed all the code before actually running it against NHibernate. *** UGLY WORDS *** when I did that eventually. For some obscure reason the SessionFactory could no longer be created, so no database access…

Reverting to the previous version of NHibernate solved this (I love version-control), but then I could not compile my lambdas anymore. So what should I do now: try to solve the SessionFactory problem or revert to the queries-in-a-string version of my DomainConnector. Tough descision.

And then I had my epiphany: this is open-source code. I can download the code, add it to my project, compile it against my working version of NHibernate and have lambda-based queries. Have your cake and eat it too!

It took no more than 10 minutes to achieve this. That’s the beauty of open-source, take control. But it also gave me more responsibility than I might actually want. Now this code was sort-of my code. Would I do that for larger open-source project like NHibernate itself? No way, my client’s business depends on the use of NHibernate. I want to be sure I have a stable, correctly compiled version of it. But for this 6 classes, 500 lines of code project I feel ok.

I even solved a bug that I might contribute to the project. Did not do that yet, though. Small steps….

, ,

No Comments

Behaviour Driven Development (BDD)

Ik las recentelijk in een blog-entry van Rob Conery over BDD. Rob Conery ontwikkelt voor Microsoft een op ASP.NET gebaseerde StoreFront. Een soort starters-pakket voor mensen die een web-winkel willen maken. In het proces van het ontwikkelen van deze applicatie (die inmiddels ook op Codeplex is geopensourced onder de werktitel Kona heeft hij meerdere ontwikkel-processen en ontwikkel-methodes uitgeprobeerd. En in dat hele proces was hij er niet vies van om de hele zaak op zijn kop te gooien of zelfs helemaal opnieuw te beginnen. Alleen daarom al is hij een held. O, ja, en ook omdat ie op Hawaii woont…

Zo kwamen de afgelopen maanden Test-Driven-Development, Domain-Driven-Development en -als meest recente- Behaviour Driven Development langs. BDD is min of meer uitgevonden door Dan North (http://dannorth.net/introducing-bdd) en lost voor mij (en ook voor Rob Conery) een probleem op dat ik altijd met TDD heb gehad: hoe begin je met je tests?

Natuurlijk ga je eerst je test maken en dan pas de code die zorgt voor het vervullen van je test. We kennen het allemaal: red-green-refactor. Maar met welke test begin je, en hoe heet die test?

BDD doet iets heel simpels: denk niet meer in de term “test” maar in termen als “gedrag” en “specificaties”. Dus: “welk gedrag wil ik implementeren” en niet “welke test wil ik schrijven”. Je komt dan heel makkelijk op iets als “EmptyShoppingCartShouldReturnCountOfOneWhenProductAdded”. Dat kan ik vertalen naar een test en ik kan ook de code schrijven die de test vervult!

De volgende stap is dat je al de requirements/specs/behaviours die je kent op een dergelijke manier in je code zet. Gewoon lege methods met aan Assert.Fail erin. Dat geeft je een hele lijst van test-methodes die natuurlijk initieel allemaal falen. Maar het is dan wel zonneklaar wat je moet gaan doen om de hele zaak groen te krijgen.

Dit lijkt niet revolutionair, maar ik heb het vandaag in de praktijk uitgeprobeerd en het leverde me een zeer tevreden gevoel op. Ten eerste wist ik wat ik moest gaan coderen, ten tweede wist ik dat ik een test had voor alle code die ik zou gaan maken en ten derde wist ik -eenmaal aan het einde van de rit, alles groen- dat ik niet meer code had gemaakt dan ik nodig had.

Ik zou ook dolgraag de volgende stap maken: het inzetten van MSpec (). Albert Oudenampsen had mij al eens RSpec laten zien: in feite een Ruby-programmaatje dat het mogelijk maakte om je specificaties in bijna-menselijke-taal te schrijven en te executeren. Maar zoals wel vaker duurt het bij mij enige maanden tot jaren voordat ik zie wat Albert ziet. MSpec is op de ideeen van RSpec gebaseerd, maar is specifiek voor het .NET platform.

MSpec biedt een library die je meelinkt in je test-project en die je de taal-elementen geeft waarmee je je tests (sorry, je behaviours) schrijft en biedt je een MSpec-runner die de behaviours runt en over de resultaten rapporteert. Je neemt dus je requirements-document, schrijft in MSpec-syntax je tests en runt het hele zaakje met de MSpec-runner. Vervolgens ga je zorgen dat de specs/behaviours groen worden door net als bij TDD te gaan implementeren. Even een stukje code om er een gevoel bij te krijgen:

   1. [Description]
   2. public class Transferring_between_from_account_and_to_account
   3. {
   4.   static Account fromAccount;
   5.   static Account toAccount;
   6.
   7.   Context before_each =()=>
   8.   {
   9.     fromAccount = new Account {Balance = 1m};
  10.     toAccount = new Account {Balance = 1m};
  11.   };
  12.
  13.   When the_transfer_is_made =()=>
  14.   {
  15.     fromAccount.Transfer(1m, toAccount);
  16.   };
  17.
  18.   It should_debit_the_from_account_by_the_amount_transferred =()=>
  19.   {
  20.     fromAccount.Balance.ShouldEqual(0m);
  21.   };
  22.
  23.   It should_credit_the_to_account_by_the_amount_transferred =()=>
  24.   {
  25.     toAccount.Balance.ShouldEqual(2m);
  26.   };
  27. }

Naast het feit dat de specificatie redelijk te lezen is (als je even gewend ben aan de syntax die nogal zwaar leunt op ambda-expressies) produceert de MSpec-runner ook een HTML rapport waarop staat welke requirements je allemaal gaat implementeren, welke er al klaar zijn en welke nog niet. En dat allemaal op een manier die leesbaar is voor project-managers of problem-owners.

Nog niet overtuigd? Laat ik het dan anders zeggen: je hebt executeerbare requirements! Ja, echt, daar wordt je blij van, dat geeft je de missing-link tussen dat ene Word document dat die FO-er heeft geschreven en jouw eigenste code!

, , ,

No Comments