Wrapping up a release for a software product is almost never the end of the development work. When teams are buttoning things up, they frequently make some tradeoffs in order to meet deadlines, and certain desirable changes may not be made due to the risks they add to getting a stable release out.
Our team has just completed a round of post-release grooming, and we all feel very good about it. This step has allowed us to tie up many of those loose ends, left the product in a much better state, and most notably, will allow us to tackle future work with fewer roadblocks and cussing. I’d like to share some of the areas we covered.
Obviously, archiving the builds/installers is crucial, since that is what was actually released. However, there are a handful of other things that should be done to aid support and future development work.
Tag it and bag it
Tagging the release in your VCS repo is essential so that you know exactly what went into the build. This also allows any crucial bug fixes to be applied if something turns up after the release.
By making only the necessary changes on top of the release tag, you can buy down the risk of introducing things that should be saved for future releases. This also allows work towards other releases to be branched off and kept separate from the latest release, allowing more freedom for the development team to move forward.
Here at Atomic, we have also learned (albeit the hard way in some cases) that you can’t trust that project dependencies that live on the Internet will be around forever. Therefore, we make it a point to archive physical copies of all of the dependencies released so they can be patched, if necessary, even years down the line.
Furthermore, the development environment itself should be archived, if possible. Since OSes change, and are also patched as time goes on, you may have trouble building your project down the line. Tools like Vagrant are handy for creating consistent virtual machines from scratch, but we often archive a fully built virtual machine as part of a release… just in case!
Once the release has been sufficiently archived, it’s an opportune time to conquer some of the riskier tech-debt cleanup.
Updating to the present
It’s usually best not to update libraries and frameworks close to a release. There are many things that can happen with dependencies, and some pieces may have API changes and internal behavioral changes.
In our case, we use Ember for the front end of our web application. Though things worked well in the Ember v1.13 we used in this release, it is not prudent to plan on staying on old and likely unsupported versions going forward. We took the time to upgrade to the latest Ember 2.0 LTS package, which is guaranteed to be supported and get critical bug fixes for an extended period of time.
Upgrading these frameworks may not give you the same version you will use for future releases, especially if the project is set on the back burner for months or years. However, future upgrades will likely take much less time and be less problematic.
Tackling technical debt in the code base
Technical debt in the code base can hamper future development in many ways. Code that is highly coupled (a.k.a. spaghetti) can be hard to detangle and lead to ugly hacks (a.k.a. meatballs) in order to get a release out. Eventually though, this plate of spaghetti needs to be cleaned up. Now that you got the release out, it’s time to convert your spaghetti into penne and squash the meatballs!
Conquering architectural issues will allow those meatballs of hacks to find their proper homes. Well-architected code is much more malleable to fit future needs, and it is easier to read and understand, as well.
The sanity you recoup will be priceless. Clearing roadblocks will make it easier to add cleaner, less buggy code in the future. This leads to happier and more productive developers, new features and bug fixes that are easier and more deterministic, and, ultimately, happier stakeholders and more timely, stable releases down the road.
Sanity Check.. and Sanity Gained!
Now that you have shuffled things around and gotten your codebase into a better place, make sure to do a decent amount of regression testing! Get all the automated tests passing, if they aren’t already. If you don’t have a decent pile of automated tests, you probably shouldn’t have embarked on this cleanup in the first place. Test suites are your friends and have likely saved your ass already, but when refactoring the internals of your system, they are crucial!
Finally, do some exploratory testing on the subsystems you have modified and on the whole system. A good round of regression testing on the result will help ensure that the project is in a stable state for future feature work to proceed. Then you can focus future testing mainly on specific changes, without muddying the waters with defects that may arise while cleaning things up.
I hope that most of this is common practice for you and your co-developers. If not, I urge you to strongly consider adopting these practices. If you have any other points to make or tips to add, I would love to hear them!