Don’t crash and burn!
This is part 2 of a 3-part series on my first glance at the professional world. Part 1 of this series can be found here.
Over the last 4 weeks, I have been working on refactoring the UI of our main application. I have worked with the codebase before, but I only skimmed the surface. This project requires me to look deep into the application to understand how all the views are populated. A little background on the application. It’s a Rails 4.2 app, the front-end is handled by Bootstrap, Bourbon framework (an amazing open-source project from Thoughtbot), and a wide variety of Jquery plugins. Due to the large amount of dependencies, the serving time of the application is not as fast as we would like it to be, as well as limited support for legacy browsers ( IE6,7,8). Therefore, for this redesign, we will significantly reduce the amount of dependencies by “rolling our own” front-end. Except for the text editor and the date picker plugins, everything is written from scratch in JQuery and SASS.
- How to come up with a strategy to tackle large projects.
- How to not crash and burn ( a.k.a avoid burning out, and maintain productivity from beginning to end )
- Expectation management, and how to give accurate, realistic deadline.
Planning, planning, planning
Initially, when working on this project, I found myself trying to dive in as quickly as possible. I basically picked a random section of the application, and jumped straight in. As anyone could expect, that decision ended up coming back and biting me in the rear. Let me explain what happened, and why it’s so bad to rush in like that.
There are multiple sections of the application that need to be redesigned (more than 15 different sections varying in both size and complexity). It’s logical to isolate each section into its own feature branch, then after each individual branch is fully tested, they can all be merged into a staging branch for a final integration test. At this point, it still make sense for me to randomly choose a section and work one at a time. However, my system fell apart when I realized even though the sections are separated, they share resources (assets, stylesheets, application-wide JS functions). I did not realize this until I’ve already finished 2 sections. At that point, I have to face 2 big problems:
- The shared resources have already diverged slightly between the 2 branches.
- How to move forward with the rest of the sections. 3
First mistake: Lack of planning and understanding of the workload on a macro level
At this point, I still did not realize that I am in big trouble. Instead, I settled for the “quick & dirty” solution. I picked one of the 2 branches as the baseline, on which the rest of the sections will branch out. I rebased the baseline branch onto the second branch. Thus, at this point, I have successfully solved the problems that I have. The divergent of the shared resources has been solved. The rest of the feature branches will be based on the baseline branch. I happily moved on with the project.
Lesson learnt: Know your enemy, identify and understand your problems first
Second mistake: Settle for sub-optimal solution resulting in technical debt down the line
Now that all of the sections are all based on the first baseline branch, the technical debt finally appears. Remember the part where I said each section need to be in its own feature branch ? It’s no longer case. Every feature branch contains 2 sections, the section from the baseline branch and the section of the feature branch. At this point, I’m in huge trouble. Any changes made to the first section has to be applied across all of my branches. That creates merging problems down the line, as well as creating noise in the commit history of the branches.
Lesson learnt: Avoid the quick and easy solutions at all costs. They may save you time now, but they cost a lot more to fix later on.
Third mistake: Dirty commits!!!!
As mentioned in the previous mistake, a byproduct of the multiple features on one branch is the noise in the commit history. Since I was working under the pressure of time, I tend to make one big commit that modifies multiple aspects of the feature. There tend to be one big commit that adds the assets, modifies the views template, and adds new methods to the controller. It’s convenient for me to do it that way, but it is almost impossible to do any kind of code reviews on my branches. The list of file changed for each commit would be filled to the brim with assets files (images, stylesheets, JS files…) making important changes to the controller extremely difficult to find. Instead, I should have separate the commits into 3 categories: supporting commits ( adding assets), non-breaking changes (add/edit/remove views templates), and breaking changes (changes made to the controllers/models/routes). This way, anyone could quickly identify and prioritize the breaking changes to review.
Lesson learnt: Move irrelevant information of the commits. Separate breaking and non-breaking changes into separate commits. Keep the commit messages concise and meaningful.
As a recap, here are the lessons that I learnt:
- Know your enemy, identify and understand your problems first
- Avoid the quick and easy solutions at all costs. They may save you time now, but they cost a lot more to fix later on.
- Move irrelevant information of the commits. Separate breaking and non-breaking changes into separate commits. Keep the commit messages concise and meaningful.
This blog post has grown to be long to for a quick read, so I decided to move the rest of the concepts: avoiding burning out, and expectation management to the another post.