Lispiaans uren tellen met de Alibi urenteller

Bij Infi werken we al jaren met een zelfgebouwde urenteller. In het kader van 'stilstand is achteruitgang' was het hoog tijd voor verandering, dit keer in Clojure!

Het is (binnen Infi) geen groot geheim dat ik een fan ben van Clojure. Het is ook geen groot geheim dat Clojure nog niet veel tractie heeft als taal voor productieapplicaties. Hoe verenig je deze twee situaties? Makkelijk zat natuurlijk, je start een hobbyproject! En dus ben ik het afgelopen anderhalf jaar bezig geweest met het porten van onze huidige, PHP gebaseerde urenteller naar een versie geschreven in Clojure. In deze post deel ik een aantal van mijn ervaringen.

Waarom Clojure?

Mijn interesse voor Clojure begon niet bij Clojure, maar bij Lisps in het algemeen. Een grote held van mij, Alan Kay, zei dit over Lisp: "the greatest single programming language ever designed". Niet voor niets zijn zijn eerdere versies van Smalltalk sterk beïnvloed door Lisp. In een ander artikel heeft hij het over "Maxwell’s Equations of Software!", als hij een implementatie van een Lisp processor in zichzelf beschreven ziet in een halve pagina aan Lisp code. Ok, het punt is denk ik wel duidelijk, Alan Kay is fan van Lisp en ik ben fan van Alan Kay, dus als hij er zo enthousiast over is, dan moet ik me er wel in verdiepen.

Nu zijn er verschillende varianten van Lisp beschikbaar, waarvan Clojure een van de meest populaire van de laatste jaren is/lijkt. Voordelen zijn oa dat het actief ontwikkeld wordt, en dat het op de JVM draait en goede interop heeft. Dit laatste betekent dat er legio aan libraries beschikbaar is, omdat je kan putten uit het Java ecosysteem. Tenslotte is er ook een versie van Clojure die JavaScript target, en waarmee je dus ook Clojure in de browser kan programmeren.

Aanpak

Mijn plan was vanaf de start om niet compleet de huidige urenteller te vervangen, maar alleen de onderdelen die vaak gebruikt worden. Het idee is dan dat beide systemen (voorlopig) naast elkaar blijven draaien. Nu is dat makkelijker gezegd dan gedaan, voornamelijk omdat de huidige urenteller geen API heeft. Ik heb er daarom voor gekozen om direct te koppelen via de database. Om het oude systeem het nieuwe systeem niet teveel te laten beïnvloeden heb ik gekozen een Anticorruption Layer (ACL) toe te passen. Op deze manier kunnen we een netjes, nieuw model bouwen binnen de nieuwe applicatie. Gelukkig was er maar 1 database, en werd er geen gebruik gemaakt van in-memory caching of een andere vorm van Eventual consistency. Hierdoor bestaat de laatste state altijd in de database, en hoef je geen synchronizatie te doen tussen de twee applicatielagen. Binnen de Clojure applicatie is de ACL geïmplementeerd door een set protocols te implementeren die gedefinieerd worden door de domeinlaag van de applicatie.

Het meest gebruikte stuk van de applicatie is zonder twijfel het invoerscherm, en was dus de voornaamste kandidaat om opnieuw te bouwen. Zo ziet dat er nu uit:

Naast ervaring op doen met Clojure wilde ik deze gelegenheid ook gebruiken om wat te experimenteren met Information graphic design, hier heb ik me namelijk het laatste jaar ook in verdiept, voornamelijk op basis van de boeken van Edward Tufte. Mijn idee was dat je met een goede information graphic fouten kunt voorkomen bij het invoeren (bijvoorbeeld op de verkeerde post boeken), en dat je zelf inzicht krijgt hoe je je week besteedt.

Als laatste doel wilde ik zorgen voor een korte feedback loop bij het invoeren van gegevens, door al tijdens het invoeren van het formulier de graphic te updaten. Een en ander is een goede match met Om (een "ClojureScript interface to React"), waarbij je een unidirectional data flow hebt als bij bijvoorbeeld React + Redux. Dit is wat het uiteindelijk geworden is (het mag duidelijk zijn dat ik nog wel even te gaan heb qua information graphic design, sorry ET!):

Overigens heb ik de pagina in eerste instantie met JavaScript/jQuery geschreven, toen met JavaScript/React en uiteindelijk met ClojureScript/Om om eens een goede vergelijking te krijgen tussen allen. Fun fact: qua regels code scheelde het allemaal niet veel (de JavaScript was wel ES2015). Ik wacht nog op een port naar Elm!

Alibi

We (dank Ely en Matthijs) hebben het nieuwe project "Alibi" genoemd (hopelijk spreekt het voor zich waarom) en onder het Mozilla Public License Version 2 open source beschikbaar gesteld op GitHub. De ACL implementatie voor onze bestaande urenteller zit daar niet bij, maar wel een SQLite datastore implementatie. Het project zou vanuit een clean git clone moeten werken met Leiningen of Docker. Dus: geen reden om er niet even mee te spelen. Laat me vooral weten wat je er van vindt!

Conclusie

Uiteindelijk was dit project zeker een goede introductie tot Clojure en Lisps, maar misschien nog wel meer in functioneel programmeren en een update van wat er allemaal aan de frontend gaande is qua innovatie.

De laatste tijd ben ik weer wat meer in traditionele talen aan het typen (C#, Java, JavaScript), en wat ik vooral mis is de immutability van Clojure, maar ook de REPL/interactive evaluation en tests die binnen 500ms draaien. Vanuit technische overwegingen zou ik zeker een project in Clojure durven te doen, want het voelt als een zeer volwassen taal en ecosysteem en met alle Java libraries op een steenworp afstand hoef je nooit bang te zijn dat een oplossing voor een "standaard probleem" niet beschikbaar is.

Als je meer wil lezen over Alibi, ik schreef dit voordat ik aan het hele traject begon: Moving away from legacy, DDD style

[Freek is Technisch Directeur bij Infi]

We zoeken een ervaren developer!

› Wil jij je hersens bij ons laten kraken?

Wil je iets waarmaken met Infi?

Wil jij een eigen webapplicatie of mobiele app waarmee jij het bij anderen maakt?

Waargemaakt door de nerds van Infi.
Nerds met liefde voor softwareontwikkeling en die kunnen communiceren. En heel belangrijk: wat we doen, doen we met veel lol!

Wij willen het fixen. Laat jij van je horen?

Voor wie heb je een vraag?