Blog

My future self appreciates a simple codebase

At the moment, I regularly have to develop Treegrid UI components. It’s been quite a lesson in API design and made me realize how design patterns exist to create great architecture, not a great API.

My recent work focuses on making treegrid components work with Crown’s backend. The backend contains a variety of data structures which, while being quite diverse, need to be manipulated through a common programmatic interface. To that end, I designed and implemented an adaptor, DDSTreeGrid, around EasyUI’s Treegrid component and a declarative data represenation of our backend views (view).

// Example adaptor interface
function DDSTreeGrid ($element, loader, mapper, view) {

  this.getSelected = function () { ... }
  this.selectAll = function () { ... }
  this.deselectAll = function () { ... }
  this.onSelectionChanged = function () { ... }
  this.getEntries = function { ... }
  
  // ...
}

// Example view structure
var view = {
  label: "Users",
  url: "api/users.json",
  apiParams: { showfriends: "false" },
  mappings: {
    [ field: "Username", apiField: "uname" ],
    [ field: "Full Name",
      via: function (apiResponse) {
        return apiResponse.forename + apiResponse.surname;
      },
      sortable: true
    ],
	[ field: "Email", apiField: "email" ],
    [ field: "Dummy column", always: "dummy value" ]
  }
};

My code (below) parses view structures to generate both AJAX loaders, via generateLoader, and backend-to-frontend mappers, via generateMapper. To increase flexibility, The resulting loaders and mappers are dependency injected into DDSTreeGrid. This allows loaders and mappers to be decided at runtime:

var view = { /* see above */ };
var $treegrid = $("#registered-users-treegrid");
var loader = generateLoader(view);
var mapper = generateMapper(view);

var treegrid = new DDSTreeGrid($treegrid, loader, mapper, view);

Dependency injection sure is useful. This implementation was sucessfully deployed in a contact list, administrator panels, and clinical data views. Dependency injection does come with one annoying cosequence though: something further up the hierarchy now has the responsibility of resolving the dependencies. Ignoring dependency injection containers, that “something” is usually the developer.

As a consequence of dependency injection, any code wanting to use a DDSTreeGrid need to construct a well-formed view, a mapping function, and a loading function. While that’s logical to me, other developers are going to find it annoying. Worse, even I’ll probably forget how it works later down the line.

I’ve found that expecting developers, including myself, to study complex annoying APIs is unrealistic - there’s too much code in the world to comprehend it all. So, with my embarassment-averse future-self in mind, I present an engineering bodge, .ofView. ofView is a simple factory helper method on the DDSTreeGrid class that internally injects the most commonly used dependencies:

// In the implementation:
DDSTreeGrid.ofView = function($element, viewName) {
	// Get a view definition via its name by doing a
	// schema lookup on the server. This is more rigid
	// than bespokely coding a view but less hassle.
	var view = DDSView.fromViewName(viewName);
	var loader = generateLoader(view);
	var mapper = generateMapper(view);

	return new DDSTreeGrid($element, loader, mapper, view);
};

// In library user's code:
var $element = $("#my-treegrid");
var treeGrid = DDSTreeGrid.ofView($element, "BackendViewName");

.ofView might seem like a cheap hack to circumvent dependency injection but it covers 90 % of use cases. DDSTreeGrid’s constructor still covers the remaining 10 %. .ofView helps in those “I need to get a TreeGrid showing quickly oh crap oh crap what dependencies did I need again?” situations that tend to crop up just before a critical deadline.

I’ve spent many long evenings coding “perfect” classes with full dependency injection, perfect parameters, and a perfectly pure outer-interface but, over time, I’ve come to appreciate the usefulness of a few “quick n’ dirty” helper methods to cover the “get the job done” situations. So that’s how I design code now - I design an “ideal” architecture on which easier-to-comprehend methods sit.

Perhaps I should publish this as a new design pattern - the “hide the underlying design patterns” design pattern. It’s a pattern that simplifies the otherwise modular nature of the codebase. A facade of simplicity, if you will. Oh god, wait a minute…


Language Agnosticism

I initially learnt javascript because I was desperate to have marquee effects on my Microsoft FrontPage website, actionscript to build menus in a basic flash game I tried to make, C++ for a half-life mod, and so on.

Jobs seem a little more focused than my approach. When I was jobhunting, most programming job postings were language- or framework-centric. They weren’t looking for someone generally experienced in full-stack web development. They wanted someone who specifically has at least 2 years of angularjs experience or specifically has Rails4 JSON API coding experience. I’m guessing this is a consequence of reality: commercially established applications are architected on—and have built technical debt in—a particular language or framework.

So, with that in mind, I have devised the ideal strategy for maximizing earning potential:

Pick one language, preferably the most popular (Javascript/Java/C#/C++ at time of writing), in addition to a popular framework (angularjs/ember.js/ASP MVC/etc.) and focus everything on that.

This, if executed properly, will guarantee a £40+ k salary. However, I’m wary of my own advice. I must be paranoid though. These frameworks (e.g. angularjs) are backed by mega corporations (Google) so they literally can’t die off. It’s a sure thing. I thought that, until experiencing a framework that once had a similar status.

I’m currently developing on an IBM Notes backend. From around the late nineties to the early noughties, IBM/Lotus Notes was considered a de facto standard development platform for enterprise solutions. The reasons closely mirror why today’s de facto platforms are popular: good patch support, decent documentation, many developers using it, stable, supports clustering, plenty of jobs, and so on.

Fast forward to 2015 and apache/IIS/ngix serve over 85 % of websites. Notes is at around 0.05 % (source). Fudamentally, the loss of popularity is only IBM’s concern. Unless you’re a developer that took the strategy above.

Back then, Notes was a sure thing. Employers paid big for Notes developers because it was cheap and fast to launch a product with Notes’s tightly integrated architecture. Cheap university graduates—who were generally “true neutral” in their language alignment—got whisked up into Notes jobs. The IDE, LotusScript, and LotusFormula were easy to pick up, so there was little need to go and learn Java.

I’d bet money that you can substitute “Notes” in the previous paragraph with some of today’s tech and come to a scary conclusion. I did and, as a consequence, I’ve spent the last 3 years practising programming diversification. In those years, I’ve leant the basics of a few wildly orthogonal languages (C, Ruby, Haskell, Prolog, Lisp, and C#) and toolchains (grep, paste, join, awk, etc.) and found the resulting experience to come in very useful.

I’ve been programming as a hobby longer than my diversification term (over 10 years, crikey) and I’m now beggining to encounter coding challanges that are interesting enough to merit writeup. Those writeups, along with the occasional rant, will go in this blog.