All posts

Code Soup

Developing software is a lot like making soup. If you don't cook that often, just know that salt can make or break a dish. Too little salt and the soup tastes bland, too much salt and it's basically ruined.

The point, or rather the question, is, how do you think a chef knows if their soup needs more salt? You could make the case that if they follow their recipe exactly then they can trust the process and know that their soup tastes good. Or, they could, ya know, taste the soup, hopefully using a clean spoon, but there are no guarantees.

If you've never watched a cooking show, then let me be the first to tell you, the good chefs always taste the food before putting it in front of a customer. This is quality control 101.

Now think of "tasting the soup" as the equivalent of "testing your code". Would you put your code in front of a customer without first testing it yourself? The phrase "testing your code" could have a variety of interpretations, so let me explain what I mean.

Before creating a PR to the upstream branch, you have dogfooded (put yourself in the end-user's shoes and used the software as they would) your changes at least once? For a few minutes did you stop being Juan Carlos the software engineer by transforming yourself into Juan Carlos the customer service associate (whose job entails using the crappy CRM software you wrote)?

Did you login with a test account with customer service associate-level permissions? Did you use the app's navigation as the user would? Did you perform whatever task the user will be performing once your software is released? Did you have the developer tools open? Did you keep an eye out for console errors? Did you keep an eye on the server logs and watch for errors and warnings?

How about performance? Does the application "feel" fast? Is there one API endpoint that's taking 5+ seconds to respond? Maybe we need a new DB index?

This is what I mean by "dogfooding" the product. Ideally your definition of "testing the code" would also include things like unit, integration, and e2e tests.

Back to the soup analogy, so a chef tasting the soup (with a clean spoon) is the same as a developer testing their code before merging it upstream and releasing it to production.

Hopefully this all makes sense because here comes the fun part. Life is a team sport and many of us work as members of a development team or engineering organization. We share codebases with other developers.

Using our analogy, our codebase is our soup. When we're developing on a feature branch on our laptop it's like we're cooking our own pot of soup in our own kitchen. The batch of soup we made in our own pot in our own kitchen tastes just the way we like it, and we're sure the customer will like it too.

Not so fast. The other chefs on our team have all been working on their own batches of soup, in their own pots, in their own kitchens. Since you and two colleagues all finished your soups at the same time, your manager says "hey, let's combine these three soups into one big pot of soup, and then serve that combined soup to the customers".

You use rock-paper-scissors to decide that you get to dump your soup into the larger soup pot first. Then your other colleagues each take their turn pouring their own batches of soup into the giant pot. Your manager finishes off the mixture by giving it a good stir over medium heat, fusing the flavors together.

And now for the million dollar question. Does the combined soup need more salt? How on earth could we find out? That's right, someone needs to re-taste the soup (hopefully with a clean spoon).

Did the three batches of soup come together perfectly? Great, ship it. Is the combined soup a little bland? Add a few pinches of salt to taste, then ship it. Is the combined soup way too salty and pretty much ruined? Toss it out and start a fresh batch. Whatever you do just don't put the ruined soup in front of a customer (the equivalent of deploying a bug to production).

If you're wondering "then why even mix the soups in the first place?", it's because in software development we're constantly mixing our soups. Whenever we merge a branch into another branch in Git, we have just mixed the soup.

This is why it's a standard development practice to have at least one lower non-production environment. Some teams have several lower environments (ex: dev, sandbox, qa, staging, etc.). The lower environments let us test the combined and stirred soup before it's placed in front of a customer (in production).

Once everyone has agreed that the soup in staging tastes just right, it's safe to be deployed to production and put in front of the customer.

One take away from all of this, I think it shows the importance of automated testing (Playwright, Selenium, Jest, etc.). It's easy to fall into the trap of tasting your soup, then rebasing off of the upstream branch (mixing your soup in to the larger pot), and then not going back and re-tasting the soup.

Just because your code worked before you rebased, doesn't mean it will still work after you rebase, even if there were no merge conflicts. The only way to know the soup still tastes good is to re-taste it, and the only way to know your code still works is to re-test it.

A note on this post. I wrote it myself, in my own words, with no AI assistance. I'm a firm believer in building software with AI, and much of this site was made that way, but the writing in these posts is entirely my own.