$ gem uninstall hairball
The tl;dr.: A programmer’s tale of when the simplifying library didn’t simplify.
Blinded by the new and shiny #
I watched the latest Google IO and was instantly impressed by the polymer project. And as a new hire I was eager to try and wow my co-workers by including something new and shiny into my code (which would eventually lead me to my demise).
To get me up to speed with their systems they tasked me with a complete rewrite of one of their smaller systems. The project was to be built upon the play framework, a framework offering the option of programming in either Scala or Java.
Thinking that you know better #
After one and a half week much of the core logic had been written and it was time to include a basic web interface for this application. When I had first created the play 2 application it had scaffolded out a number of folders including a view folder. Inside that view folder I discovered .scala.html files.
I spent some time checking out Play’s templating language, but since I had not heard much of it before I wrongfully wrote it off as something that wasn’t widely used and thus clunky. It wasn’t new and shiny. “To make it really nice I should include something like polymer.js,” I thought.
Three days passed in which I toiled on what was supposed to just be a simple web GUI containing a form element and a list of completed reports. I had included polymer and after a ricocheting between my editor and its online documentation I had achieved a GUI which included some Polymer paper element eye candy on the surface. And below the surface I had started shaping a glorious symphony of interconnected web components. I had quickly achieved 80% of what I wanted from the web GUI which was to elegantly moduralise the html through the use of syntactically sugared web components.
The last 20% of functionality involved dynamically updating the UI through web sockets and queuing up form requests. At that point the code was still such that making requests against the server would block while the application went and made expensive calls against a database. As you might deduce by now, I was trying to accomplish this project from quite the wrong angle. And I was starting to realize that myself. I was realizing that the client logic was starting to become everything but simple.
Custom elements within custom elements were calling other elements, dynamically bound up within and without with expressive expressions. All the while concocting that code I had thought, “naturally it would take some getting used to when they see this code. But it would be so simple that they would understand it quickly. Maybe they would even use it in some other projects. After all, it was the new shiny.”
Yep, naive thoughts by a new hire seeking to impress.
The client code had grown a bit by now and it was still unfinished. And in the daily scrum I had to humbly note that, “there’s still some work left on the GUI.” After the meeting I would return to my code and cringe at the emerging complexity caused by me wanting to create a dynamically updating page.
I was having second thoughts by now but it just seemed that it would be so wasteful to scrap three days of work and spend even more time recreating the functionality. Additionally, though I didn’t doubt that I would be able to eventually complete the GUI I was dreading the moment I would have to show the frontend code. I even imagined how this code would run in production for some time before someone would perhaps want to add some more functionality. They would download my code, load it up on an editor only to to be forced on a hasty journey into the Polymer docs to figure out what would go where.
At this point I must note: Polymer is easy. It’s even easy to learn. But what was challenging for me was to truly know the boundaries of Polymer’s syntactic sugar. For all its simplicity there are a quite a few of concepts to grasp. Such as where can I put an expression and what are its limits (what’s an expression you might ask)? What types of html bindings are there, are they bi-directional and always executed? Or should I perhaps in this particular case make use of Polymer’s message passing? Regardless, I might well use Polymer in another project but for this project which already had a full-blown framework behind it it was quite overkill.
More days passed and I shifted my efforts to completing other also needed functionality in my code. I was postponing the GUI work. But it had gone far enough by now.
The lesson(s) #
I finally bit the bullet and asked one of my co-workers to look at my code. I explained my predicament and they were totally understanding. My project didn’t have any deadlines set externally so it wasn’t a time crisis in that sense even though I had blown the time estimations. After airing my thoughts I finally decided to rewrite the GUI to not include Polymer.
I spent half a day rewriting three days of work using the play framework’s templating language. The reasons it was fast were:
- They had existing project code I could look at.
- Since the Html views were compiled scala functions I would run into errors in my code immediately.
- I greatly narrowed the scope (and my ambitions). I was building an internal application which would generate reports and offer a web GUI to provide an overview of run reports and que report jobs through a Html form. Instead of trying to make use of web sockets I instead did a simple browser redirect after the form submission. They wanted a confirmation box for confirming the form request so I made use of Javascript’s standard confirmation box. Despite its humble appearance it does its job. Besides that, it didn’t take too much effort to replicate the visual look I had already achieved with Polymer. Furthermore, I realized that forcing Javascript into creating synchronous form requests due to a synchronous backend was much like propping a square peg into a round hole. Making the backend asynchronous removed the need for JS form queuing trickery in the frontend. In sum, good coders don’t add more code to fix bad code, they take the bad code out.
The real lesson was learning more about what makes a simple solution. It’s real easy to include a library which promises simplicity. However, there are always tradeoff’s and with libraries that promise simplicity that cost is often a time cost of learning its conventions and hidden intricacies. What’s more, programming is also about building with empathy for the programmers that would have to work with your code in the future.
Hope you learned something by all of this. I sure did. :)