When Fluent API:s help

When Fluent API:s help
november 2, 2012 squeedconfig

Through my work, I often run across an API pattern that looks like this: it consists of the API definition itself and some definition of how to consume the API. An example:

Three typical options

If you look at the get method in this API, one typically has three options on defining it’s behaviour (or contract):

  • return a BillingPeriod object
  • return null if there’s nothing to return
  • throw an exception if there’s nothing to return

From what I’ve seen, returning null is common as well as throwing an exception. Every now and then (way too often according to the bug tracker) the usage of API on either of these patterns fail – the consumer of simply forgets to check with the boolean method before calling the getCurrentOrNextPeriod().

I really really really think that putting ”null” in source code should be frowned upon and only used in very rare circumstances. The problem with returning null is that you have to check if you received a null reference instead of a reference pointing to an actual object. Throwing an exception may be a ”safer” way saying ”HEY you really shouldn’t proceed now since you asked me to get something that I can’t provide, and you shouldn’t have asked me for stuff I don’t have in the first place and so you probably may do other harmful stuff if I don’t interrupt you now right away”.

A fourth option

A fourth option would be to return a Nullable – a pattern suggested by Uncle Bob and others. This is simply a reference that you can ask: ”do you point to an actual object, or will you give me a null reference back?”
which would let us rewrite the API to:


But, while this surely adds information saying ”there may not be a BillingPeriod – you should check first”, it still relies on the programmer to call the hasValue() method before getValue().

Wait, there’s a fifth option!

But, there’s also a fifth option. With a more ”fluent” API one may enforce a completely fail safe usage pattern:

which would make a consumer look like this:

This would force the consuming programmer to use the API properly and in a safe way.

Yes, it requires some more code from the programmer that provides the API, but it’s not that much and it does reduce errors in the consuming programmer’s code! And bugs that are discovered ”late” (when the API is used (in production)) are always much more expensive than bugs discovered ”early” (when the API is produced).

2 Kommentarer

  1. Ulf H 6 år sedan

    Bra tänkt, känns som ett ganska vanligt problem. Generellt sett så fungerar exceptions väldigt bra och ställer högre krav på på att felaktigheter/undantag hanteras på ett kontrollerat sätt men din sistnämna taktik är också rätt ”smidig”. Ställer mig väldigt frågande till Nullable-taktiken dock, extremt överflödig? 🙂

  2. Fredrik Wendt 6 år sedan

    Tack. Skall kanske tilläggas att jag är en ivrig motståndare till checked exceptions också – i normalfallet finns inget man kan göra åt ett checked exception förutom att slänga vidare. Resultatet blir att allt slänger alla exceptions överallt => all kod geggas ned med throws AllExceptionsInTheWorld och det bidrar inte till läsbarhet och därmed underhållskostnad.
    De enda ställena man brukar kunna göra något vettigt med exceptions är i lagergränser, där man kan se till att tillföra relevant information för loggning samt ge användarvänligare felmeddelande. Och i dessa lager bör man redan ha ett mönster för att fånga alla typer av fel (ev logga,) och ge tillbaka en bättre beskrivning än det man får från underliggande lager.
    Så, unchecked (Runtime)Exceptions istället när det verkligen går fel – i andra fall, designa API:et så ”det inte går att göra fel”.

    Jag tycker således att Fluent är bättre än Nullable, som är bättre än check+get-metod som kastar exception, som är bättre än get-metoder som returnerar null. Fördelen med Nullable är att den kommunicerar att ”du, vi har valt att designa systemet så att du kan få null tillbaka – se till att kolla det innan du anropar get-metoden”.
    Fluent > Nullable > check+get med RuntimeException > get med null som möjligt returvärde

Lämna ett svar

E-postadressen publiceras inte. Obligatoriska fält är märkta *

*

Denna webbplats använder Akismet för att förhindra skräppost. Läs mer om hur dina kommentarsuppgifter behandlas.