Aug 9, 2024 The Right Kind of Lazy Is your laziness an asset or an impediment to your career growth?

Harrison Strowd

The software engineering community often alludes to the benefits of being lazy as a analogy for efficient execution. However too often this “laziness” becomes a scapegoat for avoiding mundane activities that are actually the grease that keeps things running smoothly within an organization. It’s time we drew a clearer distinction between the types of laziness that are productive/valuable and those that actually end up coming back to bite us.

Good Lazy: Just-in-time Optimization

Despite being done with the best of intentions, the tendency to prematurely optimize a feature or application is a common pitfall for teams and engineers across nearly all stages of experience. Here is one scenario where it truly pays to be lazy and leave tomorrow’s problems to be solved tomorrow. The justification for adding currently unnecessary capabilities is often that “we know we’ll need it eventually” but the reality is we are better engineers than fortune tellers. Not only is it difficult to predict what features will be needed down the road, it’s most likely that our current understanding of the problem to be solved or how the solution should be built will change between now and when the feature is actually needed. Waiting to build this feature will both allow you to do so with a more complete and accurate understanding of the problem and will also give you the most freedom and flexibility in how we design the best solution.

While overestimating the value of these premature optimizations can be very costly on its own, it is also quite common to underestimate their costs. First and foremost is the opportunity cost of the time to develop the feature. Instead of building a valueless feature, you could have been solving problems for your users. Furthermore, this unused functionality still incurs ongoing maintenance costs as you develop and maintain the system as a whole. Finally, if/when this feature becomes necessary it is likely to need modifications to fit the updated context and understanding of the problem being solved. In the best cases, this rework of the feature can be relatively straightforward but in some cases it will require significant refactoring of the implementation which can significantly increase the overall cost of developing the feature.

Bad Lazy: Leaving No Trace

When was the last time you come across a commit messages like “Fixes the thang”, a pull request description of “No description provided.”, or an entire sequence of changes like the following:

Bad Commit History

When you’re assigned to code review these changes, this is slightly annoying and wastes a bit of your time to dig up the true context for the changes being made, but when you’ve got a production bug that needs to be fixed ASAP and the root cause is traced back to a change like this, this type of laziness can end up doing real damage to your business.

At the end of the day I find this behavior typically stems from one of a few mindsets:

  1. Selfishness: It’s a harsh label but the truth is that the author of these changes prioritized their own time and efficiency at the cost of their teammates’. While this isn’t typically done with malicious intent, it demonstrates a lack of discipline necessary to spend time capturing clear, concise code artifacts even when we get tired, busy, or distracted.
  2. Being Funny/Cute: Trying to be funny in commit messages or playing up inside jokes within our teams has a cost that is often overlooked. This is frequently done under the guise of building culture or camaraderie within the team, which is a worthwhile endeavor, but should not come at the cost of reduced clarity in code artifacts or impediments to effectively maintaining the system.

It takes a bit of self reflection, but these states of mind are something we can detect and should choose to avoid.

Good Lazy: Enforced Consistency

Following consistent patterns within a code base (e.g. casing, tabs/spaces, types of quotes, max line length, etc). makes it much easier to get ramped up on a new system and to maintain that system over time. When managed by hand, these patterns can be difficult to enforce and time consuming to maintain, particularly as new engineers join the team and need to learn the set of patterns followed within the application. Automating this process using a linter that supports auto-correction, such as Rubocop, Prettier, etc, removes the mental burden of keeping track of and implementing changes in accordance with the coding practices adopted by the team. This ends up saving a ton of time and mental bandwidth, particularly when considered cumulatively across an entire team, that can instead be put to use shipping features that actually deliver value for your customers.

Getting this type of tooling setup from the initial launch of an application is certainly the easiest approach but it’s never too late to get started. Most of these tools include helpful features, such as customizable rule sets, a list of files/checks to ignore, and configurable thresholds, that allow teams to integrate the tool into their CI/CD pipeline with very little disruption to the codebase or development processes. Once setup the team can gradually migrate the codebase toward increased adoption of the set of selected best practices. While it’s still true that there’s no such thing as a “free lunch”, using an auto-correcting linter is pretty darn close.

Bad Lazy: Outsourcing to ChatGPT

While the allure of asking ChatGPT to implement your next feature may be high, there are some significant risks to this approach that are worth keeping in mind.

  • The Buck Never Stops with the AI: At the end of the day, if you copy the output of an AI bot and anything goes wrong with these changes, it will be your responsibility to explain and correct this logic. If you failed to fully understand and validate this functionality, you won’t be able to sufficiently answer questions about your approach or find and correct a nuanced bug in an efficient manner.
  • AIs are Imperfect: When the solution proposed by an AI bot contains a bug it can be extremely difficult for an engineer to find and fix this bug. In such cases the total time spent can quickly exceed the time it would have taken to develop a solution from scratch. In the worst case, if the bot’s bug cannot be fixed, the engineer is forced to start over from scratch with nothing to show for the time they spent debugging the solution proposed by the AI bot.
  • The AI Crutch: While AI bots can potentially help less experienced engineers execute more efficiently in the short term, this results in the engineer missing out on a lot of valuable learning that occurs when you struggle through a problem and experience the complete set of steps that lead to the eventual solution.

To be clear, ChatGPT and other AI co-pilot tools are valuable resources that are great to leverage in an advisory manner, to unblock your progress, or as a sounding board for alternative approaches you may not have considered, but at the end of the day, all final work products should be fully owned by the authoring engineer without assuming the correctness or superiority of the solution proposed by an AI. Rather than asking an AI bot for a complete solution to the task at hand, consider posing a smaller, targeted question that allows to bot to unblocked your progress but leaves the remainder of the solution for you to proceed through.

In Summary

This is far from an exhaustive list but should serve as a starting place for thoughtfully considering where you choose to be lazy and where you recognize the value in a little bit of elbow grease. As with so many aspects of software development, there is judgement to be applied in each of the scenarios described above. Treating these examples or similar precept as a strict rule to be followed, regardless of the context or circumstance, will eventually lead to disappointing results. Regardless of whether you're taking the easy street approach or grinding it out, there is no substitute for giving thoughtful consideration to the decision and understanding the tradeoffs.

Have you recently come across other examples of either good or bad forms of "lazy"? We'd love to hear about them. Drop us a line at hello@gobetweenlab.com and let us know.

Welcome and Explanation

The Opinion Zone™ is a place for thoughts that Dan, Harrison, and Truman share about what it means to build good software products at a sustainable pace in a calm and helpful environment.
Topics range from how to work well with folks, to software design patterns, to whatever else may be on our minds. We think that advice can be misleading and we try to be careful about how we share our thoughts. We'd love to hear what you think, below.
Leave a comment

Thoughts for our thoughts

We hope you find our writing useful and, perhaps, that it gives you something to think about. We read everything we receive and we'd love to hear from you.