Maintainable project workflows
In a world where there are more tools than there are developers, how can we take back control of our projects to ensure maintainability for the future?
By Luke Whitehouse on
Let's face it, development is hard! If it's not a heated discussion on Twitter about what build tool is the new cool or whether we should use Flexbox over CSS Grids, it'll be a Medium article on why we should start adopting Vue.js instead of React.js because of its Github star rating. Quite frankly it can get exhausting and I don't know about you but sometimes it can feel like you're a deer in headlights.
We've essentially created this ecosystem of eternal reinvention which is both unhealthy for our sanity and projects moving forward.
Over the past year I have become a proponent for Anti-fun. Yeah, I see you scowling through the monitor but hold off on the pitchforks just yet. It's not that I don't want the Industry to progress forward, I just want to ensure that I'm doing so in a manner that doesn't come at the expense of project maintainability. Allow me to explain.
Understanding the problem
Perhaps you disagree with that opening statement, maybe you're comfortable with the current ecosystem and that's fine, quite honestly you might be right, after all this is just one developer's perspective. However, give me a chance to explain that perspective and maybe in doing so you'll come to understand my reasoning, or at the very least, provide some solutions or counter arguments that I've not thought of.
Let's take 'build tools' as a case study i.e. Gulp, Grunt and Broccoli. These are just some of the current building blocks we use to compile our assets into production ready code, such as Sass to CSS or ES2015 into current day browser-compliant JavaScript. However, Build tools are very much in flux at the moment, as are many technologies in Web Development, so this'll be a prime example of the problem I've seen a lot of people facing. Simply put, there's so many of them, as Dylan Beatie so beautifully sings in his music cover of "We didn't start the fire", dubbed "We're Gonna Build a Framework" below.
Comedy aside, on the one hand this is great, competition is a natural stepping stone to innovation. However, due to this congested market and everyone having their own preferences, it starts to infringe upon your projects, becoming more of a burden that you have to constantly keep up to date with; a time sink that you cannot afford to entertain when working with tight deadlines or projects which are in it for the long haul.
You can apply this same concept to a lot of different situations in Web Development, JavaScript frameworks being another example but whatever the technology, the problem remains the same. Every week there's a new way of doing something, a new technique to learn and filter through your team. On projects with tight budgets (I'm all for the Practical Developer remember! #personalbrand) we simply don't have the time to toy around with new ideas.
https://twitter.com/ThePracticalDev/status/794172824604803076
Despite this, we've all been guilty of it, and I'm no exception. It's the fun of being a developer, that things are constantly progressing and you're helping to continue that. Yeah, we could install a new PostCSS plugin which has support for flux capacitors, but those 30 minutes of development, testing and then integration could all be spent on the project itself. With that in mind... time for a story!
Once upon a time...
in a galaxy far far away... nope wrong story.
Let's set the scene. It's 2014 and I've just joined Mixd as a Front-end Developer. I was full of ideas, eager to please and ready to learn. Anyhow, a few months in and I had to do some updates on an older project. Like most, we use a Front-end framework to act as a baseline, but this particular project was running an older version to the one I'd been accustomed to. Still, it was rocking a basic set of Grunt tasks, using Compass for compiling into CSS and a few other basic packages, so I thought nothing of it and started setting up the project.
However, upon trying to install my dependencies, I was hit with a bunch of errors. Now remembering that in 2014, like most, I didn't have that much experience with build tools, so debugging proved difficult to say the least. After a good few hours I narrowed down the errors to one package, but couldn't for the life of me figure out why this wasn't working on my machine, when people had clearly used it before me. It turned out that the package in question relied on another package (packageception™) which had now been deprecated and was no longer available to install. This sucked, I then had to spend another couple of hours finding a suitable replacement, testing it out and then letting the rest of the team know about it. That's at least half a day wasted for nothing more than the equivalent of 15 minutes work.
This isn't an edge case either, as you may recall a not so dissimilar problem last March where a core dependency for many NPM packages was taken off the market, leaving them completely unusable.
Whilst I appreciate dependencies cannot be avoided, I'm focusing on what we can avoid. Rather than using random third party solutions that may not be around within the next year, or techniques which we may deem unworthy in the coming years, we should be looking at the bigger picture.
Does this really matter?
It sounds silly but sometimes I feel that we get so bogged down in what we could do, we forget about whether we should.
Picturing yourself as the client, would you really want a project that's only to be usable for 2 years? Sure your developer will be happy but is that really a good investment? Who are we building this for again?
Tackling the problem
OK so hopefully you're on board with me to some extent. If not, I'm sure you'll agree that we need to make sure our projects are as future proof as possible. So, what can be done to ensure that?
Here's a few things I'd recommend based on personal experience working with teams and solo.
1. Release based frameworks and/or boilerplates
First and foremost, any innovation should come from your boilerplates or frameworks, which I strongly suggest you invest in if you don't already have one, be that a modification of a preexisting one or built from scratch.
Once you have a framework, start working with releases in mind. So what do actually I mean by that? Well, aside from Version Controlling your framework, you should also be keeping a release history. A release history!? Yep! Every time you make an update to your framework, you should version a new release of it, no matter if it's just for yourself, your team or even the public.
Now, I'd recommend going with the Semantic Versioning, which you've more than likely already seen projects using it even if you've not realised. The website summarises the technique as:
Given a version number MAJOR.MINOR.PATCH, increment the:
MAJOR version when you make incompatible API changes, MINOR version when you add functionality in a backwards-compatible manner, and PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
Breaking that down into our use case of a framework, we can describe Semantic Versioning as:
- a Major release is where you make a ground-breaking change which will not provide backwards-compatibility. For example, a feature that was functional in version
1.0.0
may be unavailable in2.0.0
; - a Minor release is where you've added functionality which does not break the previous versions, meaning a user could upgrade to this version without any risk of breaking their project, and finally
- a Patch release is for bug fixes and small quick-fixes that will not cause problems for users upgrading (its backwards compatible).
Say you were building a front-end framework, you'd be starting off with your initial release of 0.0.1
. Now, a day or two later and you've realised you made a mistake on one of your classes, maybe you missed off a property? That would be a PATCH
release as this will be backwards-compatible for people using the first release (0.0.1
) to upgrade to.
Now you're at 0.0.2
and you want to add Livereload to your project, that'll be a new MINOR
release, as you're adding a feature which will be backwards compatible for previous versions because all you're doing is adding to the framework, rather than taking away.
That bumps you up to 0.1.0
, what next? Imagine in a months time you've realised that you want to use a build tool such as Gulp for the framework. As this will change the fundamentals of the project, you'll be looking at a MAJOR
release, as previous versions will not be able to upgrade because they may already be using something that conflicts with Gulp. That'll mark your first MAJOR
release at 1.0.0
.
The benefit of using a technique like this is you provide your users (even if thats just yourself) an easy way to track whether or not upgrading will be a time consuming process or not. If theres a new MAJOR
release then you will be able to factor that into the time allocations for future projects, or any downtime you give yourself in between.
Whilst this is all going to slow down innovation, it will ensure that you're able to come back to an older project with the knowledge upfront of whether you're going to have any problems working on it, which you can then escalate into your time allocation and billing where necessary. This won't solve the problem I described above, but at least you won't be left like a deer in headlights when you come onto an old project for the first time like I did.
2. Researching the potential feature
Taking a little time out to fully look into the feature you want to implement may seem obvious but I can bet theres numerous JavaScript plugins and NPM packages that you've not bat an eyelid at, am I right? Looking at the feature at face value is not enough, the code and techniques may be great, but are they going to be in 6 months time?
Instead, imagine any new features as a project you want to invest in. Now if you're looking to invest into a project, you need more than just whether or not the project is cool. Instead, you need to understand the project owner, their beliefs, their plans for the future, their future plans for the project. Will they be looking to provide long term support, or will they abandon ship after 3 months as their previous projects suggest? If this is an open source project, how does the owner interact with their contributors?
Theres no right or wrong answer, this is purely a chance for you to take a good long hard look at whether or not this feature is going to cause you more pain than its worth. Predicting the future isn't easy, but it helps to at least look into it, you'd be surprised what you can find from a Github profile or two.
3. Putting your business hat on
The first two points are all well and good, but at the end of the day you either work for a business or this is your business and so business decisions must be made. (Thats a lot of business!)
Ask yourself for a second, is this feature really worth the effort? Could I do the task at hand quicker with a different approach which is more future proof? Will the business make a profit from this or is it down to personal preference. Perhaps the business won't make any money on but the product they'll be delivering at the end of it will be much better as a result? All things to consider.
Again, just like with the researching, theres no right or wrong answer, the key thing is to think a little.
Concluding thoughts
I hope this post hasn't discouraged you from innovating, but rather encouraged you to do so in a way that does not come at the expense of the maintainability of your projects and general speed.
A lot of this is going to come from experience, finding out the correct way for yourself and/or your team to work. The fact that you're considering these things is a start!
If you have any thoughts on this subject I'd love to hear about it, whilst the post was based on Front-end code I'm sure you can agree that the principles can easily be carried over to most subsets of Web Development.