This is a quick note on the virtues of traceability. I’m not talking about tying git commits to business objectives, I have little interest in that. I’m talking about knowing what in the world is going on in your project.
A while ago I was helping a fellow software engineer debug his application. I noticed he had three separate versions of jQuery being loaded into his app. I asked him to show me where these were being included. He had absolutely no idea. We scoured the page for
require statements, etc. but could not for the life of us figure out how this was happening. After digging for a couple of days my friend finally found the cause. It turned out that deep down in the database (MarkLogic) there were a few templates that made all three jQuery’s globally available.
Global variables are easy to get started with but lead to pain and suffering as your project grows. Even popular frameworks like Angular suffer from early decisions to use globals (e.g. the injector uses global strings to resolve dependencies, which means you have to namespace everything you write to avoid collisions). These days though pretty much everyone agrees that global variables are terrible for your health and sanity. But the current “best practices” today still include the reckless use of global assets.
Hey Where Did You Come From?
A recent project I’ve worked on has a large and complex Grunt configuration. When
grunt build is run, it takes many source files, applies a few transforms, and dumps a lot of global assets into the build directory. HTML templates, CSS files, images, vendor libs like lodash & Angular, all become magically available to the application. I’m not picking on Grunt; projects using Gulp live in a similar mess, their global mess is just created a little more elegantly. The problem is these global assets are not implicitly tied to the code that use them. There is no traceability. If you remove a feature that relies on some of these assets, there’s a very good chance those assets will continue to live on, unused, in your project. Going back later and pruning these out of your app is a difficult exercise with a lot of risk. There has to be a better way.
Trace All the Things
With this topic in mind, I’ve been trying to build one of my projects to make everything traceable. Every dependency, every asset, implicitly linked in the source code so that nothing ever becomes “magically” available. The best tool I’ve found so far for this is webpack. I use it instead of build tools like Grunt or Gulp, and every asset is linked to a
CSS is traceable:
var css = require("css!./file.css");
Images are traceable:
var url = require("file!./file.png");
You get the idea. I don’t need to grep my entire project to find where a CSS class name is used, I already know. I don’t need to wonder if certain SVG files are still used or not.
Having every asset traceable to a
require statement not only solves the globals problem, but also has the side benefit of a better development cycle. Using the webpack dev server the browser will now automatically refresh whenever you change any file being required. I’ve found this very convenient when working on a SVG prototype, every time I export a new SVG from Sketch my browser refreshes with the newly compiled code.
I’m learning that traceability is one of those “root problems” that once solved, makes a myriad of other problems simply vanish. Taking the time necessary to get wins like this is a better best practice.