To be fair it’s only 227 days when you eliminate weekends. And we should probably consider holidays, vacation days, and the company retreat. The WP Migrate DB Pro team (Jeff, Matt, and Peter) also recorded 800 hours supporting customers, 180 hours contributing to this blog, and pushed out two minor releases.
And I don’t mean to downplay what we’ve accomplished in this release. Our file uploader will work on nearly any server no matter its upload limits and shows a nice progress of the file upload in action as well as the processing of that file. No small feat. We also fixed lots of tricky bugs and refactored some ancient parts of the codebase.
Still, I think we could have gotten this release out in just over half the time if it had been better managed. That is, if I had done a better job managing the project.
Mistake #1: Loosey Goosey Planning
The first and probably biggest mistake I made was not making sure we flushed out the scope of this release and kept it as minimal as possible. Often times I define the scope by drawing up mockups, but for the import feature I didn’t feel mockups were necessary. Wrong. Basically I left it to the team to loosely define the scope in a meeting without me. They reported back on what they had decided and I replied:
As you can see, I’ve completely left it to the team to design the import feature. Design is not what they were hired for and yet they did a pretty damn good job. Those two GitHub comments aren’t exactly a detailed specifications document though. And they’re not a replacement for mockups either. In retrospect, Matt’s comment is just screaming for mockups.
My reply ignored all the questions still up in the air and just told the team to handle it themselves. Ugh. The result is that we built features for this release that we could have easily put off to another release (e.g. import CLI subcommand) and we built features that we ended up ripping out in the last few weeks before release.
Three weeks before release Jonesy raised the following issue during his testing:
Notice the “Find & Replace Options” section? That whole section of options was removed in the three weeks leading up to release. I’m almost certain that if I had done mockups for this we would have recognized that these options were confusing and weren’t all that useful anyways.
I want to be clear that making sure the scope was well-defined was my responsibility and I dropped the ball. The team was left to steer the ship on their own with no one on the rudder. If you ask the team, they’ll tell you they feel like it was their responsibility as well, but ultimately I dumped all the responsibility on them and walked away when I should have been paying attention.
Solution #1: A Planning Process
I’ve since put a process in place for planning future releases. Nowadays as a release is just about to enter the testing phase, the team lead arranges a meeting with myself and the rest of the team to kickoff planning the next release. We look at our spreadsheet of features and fixes ranked by demand, impact, and effort:
Then we take a look at our Projects board in Trello, go through all the cards and decide if any should be shuffled to a different column:
Then we decide what the focus of the next release will be. We discuss what the ideal implementation would be. Then we ask ourselves, “What is the smallest release that will still be super useful for our customers?” Then one of the members of the team takes the notes from the meeting and prepares a specifications document with diagrams whenever possible.
We also have a “Debrief” meeting once a release is out the door where we discuss what worked well and what could be improved upon in the next release cycle.
We’re also experimenting with due dates as a regular check: Should we release now? If the answer is “No” then based on what’s left we pick another date and repeat.
Mistake #2: Cheating on Technical Debt
There’s definitely a balance that needs to be struck between refactoring old code and implementing new features. Sometimes you need to take two steps back to take one step forward. This is especially true for software that’s been in constant development for five years now. I don’t think I’ve struck the right balance here.
My direction to the team has been to refactor as little as possible because when code is refactored bugs are often introduced. While that can be true, with unit tests and acceptance tests in place the risk of bugs are greatly reduced. But what if there are no tests for a certain section of code because that code is not testable? We need to refactor just to make it testable. We have a chicken and egg problem here and the team, following my direction, has mostly left those sections of code alone.
Since I’m not coding myself, it’s easy to just tell the team not to spend time refactoring and focus on getting the release done. But I’m certain that if I was up to my elbows in the code I’d be the first one saying this and that needs to be refactored. Pressing on can be a lot slower than refactoring first and a hell of a lot more painful for developers.
Solution #2: Servicing Technical Debt
Going forward, we’re going to make a concerted effort to refactor sections of the code that are feared by the team. Each release should see an improvement in some area of the product.
As you saw in the above tweet, we’ve also been designing a new data transfer library that we can use across the whole product, no matter if we’re transferring database data, Media Files data, or theme and plugin data. Currently WP Migrate DB Pro has separate code for transferring database data and Media Files data. We didn’t want to create yet another island of code for transferring the theme and plugin files. The plan is to build this new generic transfer library into the new Theme & Plugin Files addon and release it. Once it’s been out in the wild for awhile and we’re confident it’s solid, we’ll refactor the Media Files addon and the database data transfer pieces to use it.
Mistake #3: Late Reviews
Another mistake I made was not reviewing progress regularly. I was getting progress updates, but was satisfied with “Things are going well.” Obviously that’s not good enough. I should have been requesting demos early on and installing the plugin myself to kick the tires. The first time I installed the plugin to try it was 5 months into the 1.8 dev cycle. That’s far too late.
Solution #3: Early and Regular Reviews
I’ve put feedback loops in place to fix this. I have a meeting with the team lead of each product every week to discuss progress, current challenges, and future challenges. And as soon as something is ready to show, I’ll request to see it in action.
Mistake #4: Working in Isolation
This is something we’ve struggled with across all our products. An individual takes on the task of building a new feature and goes off for 8-12 weeks without pushing any code for review. They give updates throughout that time, but they are surface level and don’t dig into the details. This is pretty much what happened between November through January for the import feature.
Solution #4: Code Push Policy
We now have a policy that ideally you push code every day and at most every few days. You shouldn’t wait until something is finished to be pushing it. And reviews need to happen earlier. Rather than putting a massive batch of code up for review after weeks of development, large features need to be reviewed incrementally.
As an experiment, the WP Migrate DB Pro team is breaking up the work into smaller chunks and working much more closely together. Instead of one person working a big piece alone, it will be broken into smaller pieces and worked on together. I don’t think I’d like this way of developing myself as I imagine I’d be falling over other developers and stepping on their toes, but the team would like to try it and I think it’s worth the experiment. If it works for the team, great. If it doesn’t, we’ll try something else.
To summarize the latest WP Migrate DB Pro release, I told the team I wanted them to build an import feature and then walked away. No requirements document, no mockups. As a result the release took nearly twice as long as it should, cost the company a lot more, and demoralized the team. The good news is that we’ve discussed all these mistakes and made changes to our processes and the way we work to reduce the likelihood they’ll happen again.
Although I’m disappointed that we didn’t get the release out in the 4-5 month target window we were aiming for, I feel we’ve learned from our mistakes and have grown stronger as a team.
Have you worked in a team that has run into any of these challenges? I’d love to hear your story in the comments.