This week’s post is pretty short. I’ve already written about overengineering, but this adds a personal touch.
I had to rewrite my Jet Train demo to use another data provider, switching from a Swiss one to a Bay Area one. One of the main components of the demo is a streaming pipeline. The pipeline:
Most of the transform steps in #2 enrich the data. Each of them requires implementation of a
BiFunction<T,U,T>
.These implementations all follow the same pattern:
BiFunction
.It looks like this snippet:
fun enrich(json: JsonObject, data: String?): JsonObject =
if (data == null) json
else JsonObject(json).add("data", data)
In the parlance of Object-Oriented Programming, this looks like the poster child for the Template Method pattern. In Functional Programming, this is plain function composition. We can move the null-check inside a shared function outside of the bi-function.
fun unsafeEnrich(json: JsonObject, data: String?): JsonObject =
JsonObject(json).add("data", data) // 1
fun <T, U> nullSafe(f: BiFunction<T, U?, T>): BiFunction<T, U?, T> = // 2
BiFunction<T, U?, T> { t: T, u: U? ->
if (u == null) t
else f.apply(t, u)
}
val unsafeEnrich = BiFunction<JsonObject, String?, JsonObject> { json, data -> // 3
unsafeEnrich(json, data)
}
val safeEnrich = nullSafe(unsafeEnrich) // 4
BiFunction
.BiFunction
variable from the functionBiFunction
into the safe one We can now test:
println(safeEnrich.apply(orig, null))
println(safeEnrich.apply(orig, "x"))
It works:
{"foo":"bar"}
{"foo":"bar","data":"x"}
When I finished the code, I looked at the code and thought about the quote from Jurassic Park:
Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.
I’m no scientist, but I felt it applied to the work I just did. I realized that I refactored in order to comply with the DRY principle. When looking at the code, it didn’t look more readable and the code added to every function was minimal anyway. I threw away my refactoring work in favor of the WET principle.
There are two lessons here:
Previously published at https://blog.frankel.ch/example-overengineering/