Conversations you need to have with your team to keep iterating quickly on tech products

Sunday, July 3, 2022 

The joy of developing a tech product is the speed at which we can bring ideas to life and see how they affect users’ lives. We want to build features as quickly as possible to see the tangible results of our work, but also to enable the rest of the organization to give demos, reach out to users, update investors, conduct user research, etc. Many decisions throughout development influence how well you’re able to keep up the speed of development, but often individuals and teams are unable to express how their needs connect to the rest of the organization.

This article highlights some of the important questions to talk about with your team and choose different approaches.

Quality of life during daily work

Development of a digital product is not just writing code, designing the UI, or whatever we think of when we think of what developers and designers do. A lot of work goes into getting to actually being able to do that work.

One factor is the work environment. Do people have enough time to focus on their work, or are they being distracted by unpredictable interruptions from other team members? Are meetings useful, or can the majority of the issues be handled asynchronously (leaving more energy for more impactful meetings?) When does communication turn to micromanagement that negatively impacts productivity and the final quality of the product? A work environment where these things are tracked and openly talked about is necessary here to address complex business and human needs that will arise during the process. Decide together what you want to track, whether they’re still the right things to track over time and how to adjust processes over time, resisting the temptation to focus on metrics that don’t directly impact people’s quality of life working together.

The other one is the work I have to do daily to do my work:

  • How long does it take before I can start working on a task? How long does it take to start the programs I need, terminals and browsers I need to open, etc.? For a developer this can be opening various terminals to run various processes (compilation, front-end, back-end, etc.) and different browser profiles to test the program as two different users. On my favorite projects, I optimize to just running one command and testing complex multi-user workflows in a single command.
  • How long does it take for me to see the results of a change? For developers and designers working on the code of a product, this means how long the compilation takes, how long the page/program takes to load and how many manual actions I have to take to test the change every time I change the code.
  • How much back and forth is needed to agree on a specification or get enough information in a bug report to start diagnosing and fixing the bug?
  • How much work is involved in deploying changes to users? How many manual steps are needed? How much confidence is there that no unexpected bugs will occur and lead to emergencies that introduce stress and disrupt schedules?

There are many ways to improve these, many of them depending on the combination of technologies used and processes in your team. One of the easy ones is automated testing. Done well, they can shorter iteration cycles and serve as documentation. Done badly, they can be a burden making products difficult to iterate on. This article describes the approach I advocate, although I’d add that effort should be put in to keep them easy to write and quick to execute (there’s a substantial difference in how often they’re going to be ran and how they improve the speed of development between whether they take 300ms, 1m, 20m or 1h to run.)

Another approach I’ve successfully implemented is scenario replays, which allows people to skip manual actions after modifying code (including complex multi-user workflows), share modified workflows easily with designers for review and bug reports with automatic reproductions sent back to developers.

In the end, it comes down to looking at everything you do not from what the generally accepted speed and friction to get your work done are, but constantly looking at how easy things should be thinking from first principles and how to get there.

Cleaning up code (also called refactoring)

As we implement new features, we might take shortcuts or make choices that don’t slow us down as new requirements come in. Over time, this means the product becomes harder to change (also called technical debt), increasing the amount of unexpected bugs and making it harder to estimate how long implementing new features will take.

The first part to talk about is when to clean up code. Can the code quality increase by just allocating some more time to plan each feature and decreasing the amount of difficult code written in the first place? Is there a budget included in each feature for cleaning up previous work? Do certain parts of the code get labeled as in need of cleaning, documented how it hinders development and how it can be cleaned up, after which the cleaning up happens the next time a new feature needs to touch that code?

Whatever the approach, there’s going to be trade-offs that continuously need to be talked about and communicated. This leads us to the next issue which is determining how you’re going to evaluate which approach is working. Some useful metrics might be:

  • How often did adding new features cause bugs in existing funtionality?
  • How easy is it for developers to understand the code they're going to modify or add to when working on a new requirement?
  • How easy is it to verify certain functionality still works, either manually or automatically?
  • How many unrelated automatic tests fail when implementing new requirements?
  • How many bugs were not anticipated or caught by automated tests? Why?
  • Can I easily navigate the code using IDE features, or do I have to resort to text-based search?

Try to keep these measurements closely related to what actually impacts your organization. “How many levels of indirection do I need to follow in order to understand this code?” is a much better measurement than “is this code implemented according to the SOLID methodology?” (If SOLID is right for your team, it should show up in the measurements you’re tracking.) A great lecture about this by Casey Muratori can be found here (skips to timestamp, 10 minutes from there are worth it you’re time-constrained.)

Also, these need to be communicated in a way that everybody understands. “Messy code” gives very little information. “This introduces unpredictable scheduling delays” or “This means that every time the designer needs to change something simple, they need to occupy one hour of a highly paid developer’s time in addition to their own time” is something that connects more directly to business needs.

Choosing which technologies to adopt

The technologies on which you build your product and business process can make or break your product. Often however, these decisions are based on hypes, personal preferences and other wrong reasons. However you decide, you’ll benefit tremendously if you agree on how you evaluate technologies.

My first rule is that if a technology is presented with no downsides, somebody might be trying to sell you something, or there’s a lack of understanding of the problem and the solution space. Relational databases vs. non-relational databases both have their up- and downsides. Vanilla JS, React or any other approach to structuring front-ends have their up- and downsides. The job of an engineer is to have a broad toolbox and do their best to identify the right tool for the job. Sometimes, it may even be better to write code in-house instead of pulling in a complex dependency. Or, the dependency is so simple that it’s not worth the risk to pull in an external dependency that you don’t know control the quality, nor size and complexity of.

There are many factors that depend on the specific choice you're making, but here are some questions you might want to ask:

  • What is the risk of getting this technology choice wrong? Can we easily swap it out, or will that incur a lot of costs?
  • How easy is the technology to understand and how complex is its implementation in comparison to the problem it’s trying to solve?
  • How well is it documented?
  • Has it proven itself in a use case similar to ours?
  • If switching, does it give us an advantage big enough to warrant the costs?
  • Does it fit into our development workflows? (GraphQL for example when I tried it out was impossible to easily automatically test with a codebase distributed across multiple packages?)
  • How does it impact the performance and usability of the product?
  • How easily does it adapt to changing requirements as the product evolves?
  • When creating complexity to allow for scale, how much scale do we actually need?

Every specific choice ranging from programming languages, to databases, to designer tools each have their own specific considerations. The common thread is that choices should be made based on tangible factors informed by what options are available and logical reasoning (do I need a 2MB Javascript file that increases loading time for users by 2 seconds to make a good contact form, even though that’s what a lot of people in the industry might advocate?) The more you can agree on the factors you use to evaluate the technology, the easier the conversations will be and the better the outcome. Or, in the worst case, you can acknowledge where you didn’t have enough info, but needed to make a decision anyway.

Honest estimations

Knowing when work is done so the rest of the organization can build on it is important, yet often software development takes a very ad-hoc approach to estimation. At one end of the spectrum we have chronic underestimations, on the other hand we have teams that accept that “it’s done when it's done.” What your approach is to estimations depends on your specific context. Is anyone in the organization prevented from doing their work until the work is done? Are there hard time limits like demos, investor meetings, etc.?

The most important things to know beforehand are:

  • What is the acceptable time range in which this gets done?
  • Do we have enough information to have a high confidence this range can be met?
  • How many unknowns do we foresee, influencing how much buffer we need to calculate?
  • Can we distribute the work and if so, how much communication and knowledge transfer overhead do we need to calculate?

After that, everything depends on your specific needs. You might break down a project into separate components, like:

  • Planning and communication during preparation
  • Coordination before and during execution
  • Resolving prioritized technical debt
  • Developing individual new components
  • Integrating new components into the product
  • Writing testing protocols and hand-off to QA
  • Time spent testing by QA
  • Fixing issues surfaced by QA
  • Deploying changes to production

Different components have different degrees of predictability and you might discover new things along the way influencing the accuracy of the estimations. The only way to improve the estimations by continuously iterating on the process with conversations and experiments. A few other things to keep in mind:

  • Estimates must be honest and to the maximum ability of those involved. If people we do the estimations for do not like an answer of “70% chance it’ll cost 3 months, but 20% chance it takes 5 months”, the answer cannot be “OK, I’ll get it done 3 months” just to make people happy. This will lead to unexpected delays instead of learning as an organization to adapt to reality.
  • If there’s too much uncertainty in an estimation, sometimes things can be done to improve certainty. If it’s the first time using an external service, going over your requirements and doing some experiments to see whether the service fits your requirements can help. Also, if a particular part of the product has not been touched for a long time, first investigating how easy it will be to work on can help.
  • Bugs are in their own special category. Before understanding the cause of the bug, there’s no way to tell how long it will take to fix it. Discovering the cause might take 5 minutes or 2 days. The fix might be a simple error, or an architectural flaw that requires a complete rewrite of certain parts of the system. Therefore, it can help to first execute a research phase, timeboxed to the severity of the bug, after which the bug can be fixed or the rest of the work can be properly planned.

Final words and a warning

I hope you’ve come away with some ideas of how to start conversations that often never get started. A common thread through all these topics are:

  • Figure out what is important to talk about and to agree on between which parties.
  • If there’s no clear way to agree on something, find things that you can track that will be helpful, changing what you track along the way.
  • Determine the risks and potential benefits of everything you're going to try out, and track those.
  • Keep what you track as grounded in real business needs as possible, not in theoretical frameworks, personal preferences, social proof or numbers that are unreliable proxies of your business needs.
  • Accept that some issues are complex and will take a lot of iteration to get right. The more clear and honest everyone can express themselves, the better you can find solutions together and the quality of the solution will be.

That being said, please don’t ever micromanage. Keep track of important things, including how autonomy and being able to schedule one’s communication influence individual and team productivity, happiness and shared learning. Also, people who don’t know about what they’re trying to manage and try to tell people how to do their jobs is a reliable way to lose great talent. The end goal should be to support each other in every direction to do their job well and get out of the way where necessary. Everything suggested in this article are things you can agree on and throw away when you observe that they aren’t being useful for your team anymore.

Was this article useful to you? If so, I help people and organizations to collaborate better, sometimes using cutting-edge methodologies, to build great products with awesome engineering cultures. Just reach out to me and we can figure out together where I could be useful.