Road to Lisp

Beginning

It all started with a private project I wanted to develop. This was late 2013. The goal was to write a tool for my favorite role-playing game Mage: The Awakening.

Choosing the language was a tough one. I had been thinking about learning another programming language for some time. But this project seemed too big as a learning project. Also I wanted it to be finished in a reasonable time-frame. So I chose to stay with Java.

Making it „right“

While developing I used a lot of patterns, tools and techniques from my (at the time) eight years of professional Java experience. On the other hand I wanted to avoid huge and cumbersome libraries. That led to writing my own data-binding mechanism. I wanted to have a small and clean solution, quite different from the things I used at work. This is of course an extension of scope whereby the reasonable time-frame went out the window.

In the wake of „making it right“ I ended up not only writing a data-binding mechanism but in fact a small framework for UI development. The „make myself a tool“ had turned into „find a good solution for my requirements to UI programming“. Which is why the project took me more than a year to finish in the end.

On the bright side „making it right“ made do two things:

experiment and learn a lot

question previously learned techniques

Questioning OO

I did not stop the „making it right“ on the UI side, however. The domain model hat to subdue itself to scrutiny as well.

Generic data processing

At some point a thing started to bug me. I could not process objects generically.

Reflection is an obvious solution to that. Though I find it only useful for clearly delimited and generally applicable things like data-binding. Using reflection or the wrappers around it for domain logic everywhere would be unwieldy. Also it would undermine all type safety.

Another solution is model driven design tools. Tools that generate Java code. Such a tool could generate methods like get(String propertyName) for me. This approach has the disadvantage of being inflexible, no making up of new properties at runtime. And a more cumbersome tool-chain. This approach, depending on the way you implement it, also omits type-safety.

Type safety

I went down that road of manually creating objects to represent the properties. Which is a lot like Java8’s method refs, except that properties provide reader and writer methods at the same time.

This turned out to be really useful. Not only could I use these property objects to access my domain model objects‘ data (and thus avoid reflection in those cases). I could also use them to create UI declaratively. I noticed that these property objects were like little functions (or pairs) of functions. At this point it started to dawn on me that there might be something about functional programming that I might find useful. It was one of those „note to self“ moments. In my case the note said: „learn FP“.

But this approach also had drawbacks. The biggest one probably is that property classes for new properties cannot be created dynamically, e.g. at runtime. Another drawback is that it’s hard to make them type-safe. It can be made type-safe when there are no class hierarchies. But of course I had hierarchies.

So this is where I felt that the Java type system left me out in the rain. It offered no support in this case, but it did make me write „Object“ and thus put in unnecessary effort.

(Note that Scala’s type system might be powerful enough to support this problem. Though I haven’t looked into it.)

A lot of code

Another downside of above approach is that a lot of code is required. For every class and property a class (or enum) instance must be written. So this made the already verbose Java even more verbose.

And it really bugged me. Why do I have to pick from three bad options?

What’s more, in all three I’d have to let type-safety go.

Awakening

Then an idea hit me. When I can’t have type-safety anyway, what if instead of objects of specific classes, I represented my domain objects as plain maps (e.g. Map<String, Object>)?

I would get:

Generic data processing

Way less code

Good debugging support (way better than reflection)

This was a solution to my problem!

But then I got afraid. „OO can’t be wrong“ was the most prominent thought. „You cannot work without type-safety“ was another. Boy, was I wrong.

But the seed of doubt was sown. In the autumn of 2014 I took a look at some functional languages. Scala, Haskell and Clojure were the contenders.

I chose Clojure because I had always wanted to learn a Lisp, since reading Gödel, Escher, Bach 15 years ago. And because it is hosted on the JVM. This I saw as a chance, albeit slim, that I could ultimately be using Clojure at work.

But that is harder than it sounds. I’m hard at work evangelizing Clojure at the office. So far no luck.

Conclusion

My key take-aways are:

Learn functional programming

Don’t trust any programming paradigm (not even FP)

Question past decisions (whether they are your own or not)

Experiment to find the „right“ solution (in your context)

Take your time

This last one is really tough in an industry where every piece of software has an urgent deadline right around the corner. But those months analyzing and juggling ideas gave me so much opportunity to think through the problem that it proved more useful and rewarding than I could ever have hoped.

Not only is some of the code that I developed in the private project now in use in one of my company’s products. The time I put in laid the groundwork for further improvements I wrote about previously.

In retrospect it makes me grin how right I had been with „why not use maps?“. And that I chose Clojure. Funny how things tend to come together in the end.

Advertisements

Teilen mit:

Gefällt mir:

Gefällt mirLade …

Ähnliche Beiträge

Veröffentlicht von

Azel

Azel is a software developer from Germany with more than 10 years of professional experience. In his spare time he enjoys taking on personal programming projects (mostly in Clojure) and going rock climbing.
Zeige alle Beiträge von Azel