Abstract all the things

Or yet another way to deal with the woes of front end development

Ahmed Nuaman
6 min readNov 19, 2014

I love front end development. The best part about it is instant gratification; the beauty in just saving a file and reloading (or auto-reloading) your browser and boom, there are your changes.

However with great fun comes problems, sometimes great problems. One of the biggest problems (in my opinion) is having too much configuration everywhere to make stuff work. I’m talking about your build tasks (for, say, Grunt or Gulp, etc…), dependancy management (through Bower and/or NPM maybe), and so on. These are things that a developer shouldn’t really need to worry about.

Now many may argue that these aren’t problems but just requisites that come with the territory that is developing for the front. I disagree. I believe that everything should and can be DRY, that developers should be able to just focus on writing code without the headache of dealing with misconfigurations or missing dependancies.

It’s all about the tools, about the tools, no config

In my current role one of my major requirements is tooling up the development teams with the ability to write, test, and deploy front end applications fast. And by fast I mean in a day or two. This is important as a lot of these apps allow the users to run a limited number of tasks, thus allowing a streamlined and simple user experience.

The biggest challenge was the fact that the majority of these developers hadn’t ever touched JavaScript, HTML, or CSS. They were mainly Java, C#, or Python developers, and mostly worked on Windows. They were used to using “intelligent” IDEs that dealt with their imports, testing, building, and gave them real-time updates about their code. How could JavaScript even compete?

The answer was actually quite simple: abstract as much of the configuration away from the developer. That’s essentially what IDEs do, they make it easy. The idea is that the developer shouldn’t have to worry about all the fun that comes with setting up build systems, installing dependancies, getting tests-linters-hinters in place, and so on; it ought to work out the box.

“Yo dawg, I heard you like tools”

So where does one begin? Well the beauty of the tech community at the moment is the amount of bootstrapping tools that developers can pick up, customise, and then distribute. One in particular is a favourite of mine (and probably many other people) is Yeoman. We use a number of tools for our front end development but everything starts off with our generator.

Yeoman is great. Yep the docs are a bit iffy and testing can be a bit painful, but with enough persistence you can create a pretty cool and complete generator ready for your team to use.

One thing that I found was missed in the docs and other generators was simple patterns to stop code duplication. One thing that frustrated me about the way generators are written is the idea that you keep template files within the generator:

app/
templates/
_bower.json
_package.json
some_more_code.js

The problem here is that it’s pretty hard to develop a template app while it’s tied in with generator code. If you have a look at, say generator-angular, the template files are baked in; this, in my opinion, makes it really tricky to validate your template app. My approach was slightly different:

  1. Create a template app, like normal, and stick it in its own repo
  2. Create your generator but don’t create any template files
  3. Configure your generator to pull down a specific version of your template and use that for the generation

This approach is pretty simple and it makes sense. It means that you can trial features properly in the context of one of your apps before you roll it out to your users. It’s also means that updating is a lot less painful as your template code and generation code is kept separate.

However, remember when I said the docs were a bit iffy, this is where we need a bit of magic: actions/remote. This little gem of a function allows you to specify a remote template for Yeoman to use; it can be a git repo (on Github) or an archive (.zip, .tar, or .tar.gz I believe). If that sounds too painful you can also use remoteDir to specify a folder, somewhere, that can be used as the remote.

“But we don’t use Github…”

So what if you want to use your remote but you’re not on Github? Well, that’s pretty easy: by default most decent hosted git repo management systems allow you to specify to grab an archive, for example with Gitlab you could do:

http://gitlab.your-company.com/group/project/repository/archive.tar.gz?ref=0.2.0

The beauty here is that you can pull in code from multiple sources and compile them together using your generator. This decoupling is, in my opinion, the perfect zen for keeping your generators.

It’s all about having your cake and eating it

One thing that frustrates me a lot about bootstrappers and generators is that all they do is get you started. When the codebase has been updated or new libraries are used then the developer is often left with a lengthy and sometimes confusing changelog to follow. This is less than ideal.

This just requires a bit of cunning design, especially for your template app code. I mentioned earlier about dependancy managers (Bower, NPM, etc…) and build tools (Grunt, Gulp, etc…); imagine if you could control all the configuration for these managers and builders, it would solve a lot of problems, especially when dealing with a legacy codebase.

The approach that worked well here is to move these configuration files into their own repos and all your apps do is simply pull down a version of those repos, for example, you would go from:

“devDependencies”: {
...
“grunt-contrib-compass”: “1.0.1",
“grunt-contrib-compress”: “0.12.0",
“grunt-contrib-copy”: “0.7.0",
“grunt-contrib-cssmin”: “0.10.0",
“grunt-contrib-imagemin”: “0.9.2",
“grunt-contrib-jshint”: “0.10.0",
...
}

To:

“devDependencies”: {
“grunt”: “0.4.5",
“grunt-tasks”: “http://gitlab.your-company.com/group/grunt-tasks/repository/archive.tar.gz?ref=0.0.15"
},

What’s lovely here is that all the configuration for building the app and (for us) base code that’s used within the application (for registering app modules; code that most developers find themselves rewriting over and over again) is kept out of the developer’s hair so that they can focus on writing their code.

The latest and greatest

The beauty here is that when the developer wants to update all they do is bump the version rather than having to go through a huge-ass dependancy list. It also helps to keep the codebase really clean and simple so you don’t have hundreds of repos potentially having the same configuration files. Ah, so much zen.

But surely we can go further right? I mean most configuration files need to be readable by a system (eg JSON, YAML, etc…)? So this can be taken further and instead of the developer having to manually update their files to bump the version, the generator should do this for the developer; after all that’s what it’s supposed to do.

The approach is pretty simple:

  1. The developer runs the upgrade task on the generator
  2. The generator checks out the latest code version that it has defined
  3. The generator then simply parses the configuration files (bower.json, package.json, etc…) and bumps the versions for newer dependancies

The beauty here is that such a simple task makes such a big difference for the developer and a happy developer means a happier team. Furthermore the advantages of being able to update all of your applications with a simple command means that dealing with fixing bugs, performance enhancements, etc… becomes a lot easier, and developers are more likely to move their code forward, rather than the “if it ain’t broke, I’m not gonna fix it” attitude.

It’s the design that matters most

I’ve purposely omitted the nitty gritty bits as they’re always subjective to each project/company/group, but the most important thing here is make sure you know who you’re building for. The design of your components, tools, configuration, etc… will matter most as these are the bread and butter that your users will scrutinise, and that’s all part of the buying in process. Throw in that with loose coupling and smart workflow means that you can adapt the direction of your tools to suite your users’ needs.

Peace.

--

--

Ahmed Nuaman

Founder @wearescouting, world famous dachshund wrestler, I love my family, plus I’m a British Arab; much success.