Over the last few days I've been working on a relatively large change to my image linking logic. This change involved some reorganization on the server side, adding name-spacing, changing the url structure, and placing 301 redirects to all 1200+ of my photos. I made this update both in hopes of keeping some relative SEO content on the photos linked in my blog and because I wasn't happy with the original implementation (especially the data storage). This post isn't about the update, though. I wanted to talk a bit about some of the principles I used on this and other projects I work on.
This update was a rather large one to my engine. I needed to change more than just a few image links - I upgraded my entire image storage system to a relational setup. Eventually this will turn into a dedicated photography site (photos.jacobemerick.com, mayhaps). Trying to change everything and push it live at once would have been asking for disaster.
Instead I broke down this change into five steps. Each step could be tested and pushed live independently, with easy rollback capabilities. I was able to visualize each step completely and debug them easily. By the time I rolled out the final piece, checking and testing the step on the live site was a well-oiled process. Most importantly, any visitors to the site would have seen minimal changes throughout the process.
Testing in Development and Production
With this update, as with any update I make, I had a fully synchronized data layer and code base. Differences between my development environment and the live one were minimal. Before any code was pushed to my live servers I tested multiple use cases to make sure that no fringe page or functionality was affected. After pushing the code I live I would repeat the testing, with temporary debugging logic sending me updates through my backend if anything unexpected occurred.
There's a lot of unexpecteds that could occur with this update. Even though very few of my photos were getting crawled and indexed I still implemented a full 301 redirect system from the old to new uris. I used that same sort of thinking for my debugging system: even though I had looped through all of my images multiple times, I still have a debugging system built in just in case any of my images were misnamed or my table had incomplete records. I wanted to make sure that the end user would not see any errors. For each data call or dependency I have a check: if that check fails, I get a nasty email and the end user sees a graceful 'Image Not Found' message... and the page continues to render as normal.
Yes, I did write smelly code. This update is not yet finished - I'd like to remove all of the old logic after I'm sure this change works in production for a few days (or weeks). Also, I'd like to play around with where I placed some of the code to keep things centralized and sensible. Smelly code can function as a great reminder for me to go back and retool it.
These are just a few of the principles I think about when working on projects. This update took a few days, but I was able to keep focused on each individual step and work my way through it. Creating and sticking to principles like these during a project can help a developer immensely, especially within a team environment. Over the years I've found that the development process of an individual or team can be just as, if not more, important than their individual related experience.