A common issue that arises with developing large scale software projects is boilerplate code. This boilerplate code, in some cases also called “glue code”, is code that can either instantiate objects for usage, or glue together other pieces of software so they work together, usually in the form of interface normalization. Interface normalization is normalizing the expected outputs and inputs of a given interface (e.g: a function) and making them behave in expected ways, so there are little to no side effects, and data is treated respectfully. The “hack” techniques used to implement this are usually some variation of “Duck Punching” or “Monkey Patching”. On the non-hack side, there are some paradigms that help to achieve this goal, most notably “Code as Data” and the larger set of Functional Programming, such as Functional or Reactive Functional programming.
These are all great solutions, but harder to implement in JavaScript, or anything that resembles Object Oriented programming. The problem with OOP, is that it creates complexity and sacrifices brevity, for ease-of-use. The “pure” functional style is rarely embraced, except for those with strong mathematics backgrounds, programming purists, or just plain masochists. I find myself loving the functional style, but I am far from a Math guru. In fact I’m not terribly good at it, or at least haven’t been, but It’s all coming together nowadays, and as a result, I love it!
Regardless, I like to look at code as modular “blocks” of functionality. Generally in this paradigm, you rarely, if ever, create variables outside the scope of a function, and keep things in small, singular units of functionality, preferably with only one argument. Data is almost never mutated, and thus side effects are extremely rare. Naturally, Test-Driven Development plays very nicely with this system, and scalability and predictability are more easily achieved.
Knowing all this stuff, my real concern is that of the boilerplate. I think having to write tons of boilerplate/glue code is a severe defect in the language, and should be treated as such. We should stop trying to adapt to this, assuming it to be the only viable solution, and instead create something new. I am not convinced anything new needs to be created, as there have been so many paradigms over the years I am sure something already exists.
I have to admit, not knowing an existing solution is not a good way to start this whole argument, but it is a known unknown.
What does the solution consist of?
The rules, as defined above, are that no boilerplate code should be needed. This poses some problems, of course:
- Instances/interfaces can’t be tracked, or manipulated.
- There are no references to the instantiated object, and thus we don’t know where to even start!
- We can’t cache variables to our own personal scope.
- Hell, we can’t even really control scope! We have to defer to the library for that!
- We can’t inject our own style when writing code - casing, formatting, guidelines…
Showing, not telling
Let’s move into an example, and clear away the abstraction. Let’s say we’re building an online mashup of some sort. It consumes different types of data, from four different APIs. The data is: weather information, inspirational photos, famous quotes, real-time news. Okay, it’s a weird example, but let’s go with it.
In a perfect world, we would construct is as follows:
- Plug-in the four libraries
- Create appropriate HTML “sockets” or “containers” for each library.
- Go outside and play.
Instead it’s more like this:
- Plug-in the four libraries
- Create appropriate HTML “sockets” or “containers” for each library.
- Setup DOM object “holders” for each container
- Make RESTful calls, provide callbacks to populate data
- Configure data based on what the API returns, make sure it’s normalized and looks good (duck typing, specifying data-type).
- Style content so nothing is broken (non-cosmetic)
- Test various states of interactivity (click, move, desktop, mobile, server errors, slow-connection, no-connection, etc…)
- Continually check, wait for something to break or someone to complain
The latter doesn’t sound too hot eh? Yet it’s a pretty normal development cycle though, and that’s the problem. We’re repeating the same mistakes, making it hard on ourselves—for what?
Identifying the problems
The common problems that arise in this list:
- Specifying in such detail the type of DOM object you want to use, and where to put things.
- Setting up boilerplate request types, configuring policies, setting fallbacks and errors so it degrades
- Normalize data, error handle data—basically assuming an entire collapse at all points of failure, and distrusting all data to be what it says it is.
- Trying to chase down all the scenarios of interactivity, playing whack-a-mole, inventing new processes for teams to cope by reacting (design-driven development, UX driven, goal-oriented, etc…)
So, in this case, we have a backwards approach—instead of specifying what we want, we specify what we get, and then transform it. This is very imperative, rather than functional. I hesitate to say I dislike imperative programming, because let’s face it—it has its many uses. In the case of event-driven and interaction like this, we should try to move away from imperative as much as possible, and embrace a more functional, hybrid-declarative style. This means fixing things before they break, or teaching modules to communicate with each other, instead of translating every time.
Some solution, pseudocode:
A solution I propose is specifying very generalized functions, and then expecting things to work as you want. This requires a strong convention over configuration approach, but I believe that is a wise endeavor. The point here is that a common interface is used and agreed upon, and the results work intuitively, seemingly magic, but still understandable (not voodoo).
This whole paradigm intrigues me quite a bit, so I plan on exploring it more, and figuring out what a lot of this means and how to implement it in detail. Until then, at least it’s some food for thought.