I recently read a post by Jocelyn Goldfein on The Right Way to Ship Software. It’s a great article that covers how different companies ship software. It’s well worth the read if you haven’t done so already. Over the last 17 years of shipping software, I can relate to her take on things.
At Haught Codeworks, we’ve had many types of clients and have altered our process to fit their business model. In the last year we’ve found a sweet spot for shipping software that feels like the right way. I’m going to outline it in this article.
Before I get to what we’ve settled on, I’d like to cover more on what Jocelyn wrote. She illustrates how different types of businesses benefit from differing shipping models. This matches our experience. Every client has specific needs, even if many of their needs are the same. Because of this, it’s vital that you understand why you follow some process and the trade-offs it offers.
When we talk to a prospective client, we first need to understand what the business needs are and the full context of the situation. Is time to market the biggest factor? Perhaps budget is more important? Maybe faulty or incomplete software is the pain point or maybe it’s that they want to take more time to ensure the software is rock solid? Every situation is a bit different and unless you understand where they sit on these spectrums, it’ll be hard to adjust the process to fit their need.
Some teams do it their way and don’t vary from their tried and true approach. There’s nothing wrong with this if they’ve had success but it means certain projects and clients won’t be a fit for them. I’ve seen some clients wish to go faster while others are more concerned about getting the design perfect. If you don’t recognize which trade-offs are key to this particular project, tensions will rise and potentially cause dysfunction between the team and the client.
Our core principles
I mentioned that we’ve found our sweet spot on the principles around shipping software. While still allowing flexibility, we find these general principles to be more or less consistent.
1) The faster you can get user feedback, the better
I can’t remember a project that didn’t change based on user feedback. Some have shifted dramatically based on early reviews from what was envisioned by the client. Some took a bit longer to shift when user adoption wasn’t as brisk as expected. This is one of my primary rules on projects. Get the app in the users’ hands and gather feedback as soon as possible. This principle guides much of how we develop software.
Diving into this topic can be a post in itself but I’ll illustrate a brief point here. Getting feedback early is only beneficial. Delaying it means you’re building your product based solely on unproven assumptions. I’ve seen over the years that many of these end up being false, and often times surprisingly so. Though I’d like to say I can predict which client’s assumptions are false, I don’t believe I can. Beyond the effort of talking to your users, there is no downside to gathering this feedback. It will either confirm your assumptions or prove their needs or motivations are different. What product owner doesn’t want that information? Furthermore the longer you delay this, the higher the chances are that you either build too much or what you build doesn’t match the user’s needs.
2) Build your demo server immediately
One of our first tasks on a project is to draft up a README document that includes all the steps and dependencies required to get the app up and running. Once we have a local version of the application running, we then build out our integration server, which is the first environment where our team deploys code. The final part of this task is to build a second environment for demos that functions like a production environment. The demo environment is where users will use the application providing us ongoing feedback.
I’ve seen many projects wait weeks or longer before they build their server infrastructure. We feel this is a mistake as the process of building the server environments and actively using them in the first week of a project offers many benefits with little downside. There’s no question you’ll need this so why wait? How can you collect feedback from users if they can’t use the software?
The key reason to set up your demo environment immediately is so you can deploy your initial builds to collect user feedback. Once this is done, it’s out of the way and you can focus on building features in rapid iterations based on that feedback. Additionally, doing this from the start will expose any technical hurdles that your application may have in how it operates in a server environment.
3) Automate the deployment process
We refer to this as Frictionless Deploys. Our goal is to make shipping a new version of the product effortless. We want automated deployment either triggered by a commit push or a single command. We also want anyone on the team to be able to deploy the app.
I remember years ago when some projects had a dedicated build master where product builds would take all day to complete and were largely manual. It was such a barrier to quick release cycles and gathering feedback early. The good news is things have changed both on the infrastructure side as well as in our web application stacks. Heroku, for example, gives you both instant infrastructure and single command deploys out of the box, and has done so for years.
Products do become more complex so the deployment process can become more challenging but it should always remain automated. Any engineering hours spent automating deployment is worth the cost. Think of it as an investment that pays a bit back each day of the project. It saves engineering time so instead of going toward manual deploys, the time can go back into working on the next feature.
Automating deployment is a requirement on all our projects and allows us to keep the user feedback loop very tight.
4) Streamline the QA cycle
Verifying both the functionality and usability of your software is critical to building and maintaining a high quality product. Doing too little allows bugs, misunderstood features and undesired behavior to slip into production. Taking too long unnecessarily slows down your release cycle and puts extra burden on the team. We handle this through a lightweight process that combines internal and external review. It provides enough quality assurance without dragging out each feature.
The initial steps involve the developer writing automated tests that verify functionality. These tests are run along with the entire test suite through continuous integration. Any test failures stop the build and alert the team. This will catch many regression issues if code changes break some other part of the application.
The second step is a peer review process through Pull Requests. A pull request bundles all the code changes with a message that our team can review in isolation before that code gets merged into the application on our integration server. In this review other team members will look over the code changes and verify that the changes, including automated tests, make sense for the requested feature. Any suggestions or improvements can be quickly and easily added until it passes review. Each pull request is analyzed independently so it doesn’t slow down other pull requests going through the same process.
The third step involves verifying the feature works as intended on our integration server and has good usability. The final step is client review before the feature can be considered done and approved for demo or production.
This process strikes the right balance to insure quality and usability without taking weeks to assure the quality of new code. Typically features go through the internal steps within a single day.
5) Continuous flow with client involvement
We briefly touched on how the client reviews completed features before they go out to demo or production. There’s more to the process.
We use a continuous flow model for completed work. When a feature is completed and verified, it is promoted to production without waiting for a scheduled release. Many projects will use timed iterations such as 2 or 3 week release cycles before any code can move to production. We find this limitation arbitrary and a holdover from old ways of building software. Since we have frictionless deploys and a streamlined QA process, why hold back an important feature or bug fix to match some preset schedule? Unless the client has specific business reasons to hold back a feature, we promote as soon as a feature is approved.
Weekly client involvement is another major factor in producing a high quality application. Their feedback is not only crucial but it needs to be timely. They need to be present as features are ready for review. This is the cause of many project failures – not having an involved client. If you go weeks without the client seeing progress or approving the changes, you’re at risk for building the wrong product.
Our best projects have a weekly client meeting with features being continuously approved throughout the week. Even if a client can only manage a weekly review, that still keeps our feedback cycle tight and allows us to iterate on their product without momentum killing delays.
6) Cut scope dramatically for your first release
The previous points centered around our workflow for building software. This point falls on the client since they control the scope of the project. One of the things we cover in our initial planning with a client is whittling down functionality for the first release. Though it seems nice to have all the features done, it is better for the product’s long term success to start with less.
There are a number of reasons this approach is better. It takes less time to build out a smaller number of features. It’s less complex and our team can work faster through the smaller feature set. This means the users can start playing with the app sooner, allowing the client to collect valuable feedback on the application. This in turn guides the client on what to adjust or add in. It’s easy to add new features as we go along so there’s no downside to putting off what you don’t need. Those features can slide into the next release.
An added benefit to not implementing everything initially is that if there is a vital feature missing, the users will reach out. You can track user demand to determine what features should be added next.
In contrast, we’ve seen many projects that had robust scope, believing that more features are better in the users’ eyes. This created lengthy release cycles with some going over a year before users got to play with the product. It added a lot of cost for building features that may or may not have been the right fit for the market. Though we don’t have statistical data, I can attest that many features weren’t used as originally planned and some could have been cut altogether with little to no detriment to users.
When you consider the approach of small releases, you can see the advantages it offers the client. They spend less time and money, getting their product in users hands earlier. They can more quickly make adjustments based on user feedback. Bringing them that much closer to finding product-market fit. What client doesn’t want that?
These principles all come together to support the notion that software is fluid and always growing. They give us the ability to quickly and efficiently guide a product from conception to completion with as little waste as possible. Keeping a tight feedback loop from both the client and their users is key to this. Advancements in our infrastructure and programming languages have made this style of software development both possible and easily attainable. Our clients and team can focus on building the best possible product with as little friction as possible.
Whether time to market or engineering cost is your primary motivator these principles work beautifully in either case. Finding the right balance of trade-offs for your product is key but we feel these general principles should be followed unless you have a really good reason not to.