Guideline to efficient technical discussions

Technical discussions are a vital activity on an engineering team. They allow for knowledge transfer, enable the collaborative process, and provide a powerful feedback mechanism to—early in the development cycle—detect flaws in designs. However, technical discussions can also present problems to a team in terms of time wastage and becoming points of friction.

This document provides guidelines for healthy ways to have such technical discussions.

Clearly identify the purpose

Technical discussions should always serve a purpose on a team. They can be for planning a new feature, fixing a bug, simplifying the codebase, or something else entirely. Everyone needs to be on the same page about why we’re discussing something now.

There’s room for freeform technical discussions as well, simply for the fun of it. Engineers generally enjoy exploring interesting technical points. However, we should be clear that, if engaging in such discussions, there is not a specific purpose, and it is not intended to further product development.

Trace back to a product requirement

Every piece of work we do should ultimately trace back to something the product needs. If we can’t identify what product requirement drives the work we’re doing, we shouldn’t be doing the work. Period.

Speculative development in case we have a feature requirement in the future is almost always a bad idea and should be avoided. It will lead to unclear technical designs (due to unclear requirements), YAGNI (you ain’t gonna need it) code, higher maintenance burdens, and engineers trying to—in a vacuum—design a product requirement.

If an engineer is concerned that we may be writing ourselves into a corner with a design, and thereby making a future feature more difficult, the correct response is:

  • Engineer calls it out to the engineering lead
  • Engineering lead is responsible for communicating with product on roadmap and future requirements
  • Engineering lead decides whether to explore the topic further with product, or take the requirement off the table for further discussion

Under no circumstances should code be written or designed around an unstated product requirement!

Text versus audio/video call

Text and calls are both valid forums for technical discussions, and both have advantages.

  • Text advantages
    • Easier to take time to clarify thoughts between messages
    • Easier to explain ideas with code, diagrams, etc.
    • Less disruptive to the workday
    • Natural log of the discussion, allowing other team members to check in on the discussion without sacrificing their time, and easy reference in the future
  • Call advantages
    • Faster iteration
    • Easier to clarify misunderstandings (usually)
    • Higher bandwidth: people usually talk faster than typing and can use additional mechanisms to express ideas (hand gestures, tone of voice, etc.)

Be judicious about choosing one approach versus another. Generally, the best approach is:

  • Start with a text prompt in a shared engineering channel
  • Explore the ideas in text briefly, see if there’s easy consensus
  • Identify if additional research is needed before discussing
  • If the questions still exist at that point, jump on a call

Acknowledge counterpoints

An important aspect to technical discussions is to acknowledge counterpoints to your position. Specifically:

  • What are the costs/disadvantages of the approach you’re suggesting?
  • Are there other approaches, either advocated by a team member or by no one?
    • If by a team member: repeat back to them what you believe they are advocating for to ensure no misunderstanding. Repeat back what you believe are the advantages to their approach.
    • If no one has advocated a different approach:
      • Steelman (opposite of strawman) the alternative approach
      • If you can’t think of an alternative approach and no one else can either: maybe there’s nothing to discuss at all 😉
  • There are a variety of means to assess how important an advantage or disadvantage is. Not all points are weighted equally! Just as some examples:
    • It’s literally impossible to implement this for valid technical reason: really important
    • I subjectively don’t like it but can’t enunciate why: not important
    • This will have a high performance cost: important, but context matters. One-off batch job that will run for 20 minutes instead of 5 minutes? Stop talking, write the code, and have a 15 minute coffee break. Tight inner loop that will run thousands of times per second? Explore every nook and cranny.
    • This reminds me of a problem we had before: not important on its own. Consider taking time to think through why it’s reminding you of a previous problem, and then tie that back to product requirements that may be impacted by this decision.
    • Everyone else does it a certain way: semi-important. It’s a useful data point, but not a final decision. Sometimes communal wisdom is a good thing: it avoids common tarpits and makes code easier for people to understand. But if everyone is doing something stupid, make the argument that the emperor is naked.

Identify and accept core disagreements

Some times there will simply be a core disagreement that cannot be overcome. Identify and accept this. People has different preferences, wildly different experiences, and have been bitten by different bugs in the past. It’s completely reasonable to end with a disagreement on the path forward. In such cases:

  • Judge how important the disagreement is to you. Engineers in general, and our team in particular, tend to overemphasize how vital each decision is. Really think through: if the “wrong” decision is made here, how bad will it be?
  • Generally, we should follow a “dealer’s choice” approach. If two engineers disagree, the person writing the actual code makes the decision on the path forward. This is a practical matter: the person writing the code will be frustrated having to compromise their beliefs and write worse code, and will have a better understanding of how to take their approach to writing code.
  • If a disagreement is so important that an engineer cannot allow “dealer’s choice” to win, raise it to the engineering lead to make a decision. And then move on: further discussion is not needed.

I’m going to reiterate something because it’s a perennial problem: discussions need to finish sooner than they do currently. The priority for our team is to deliver product, not to discuss how to deliver product. We probably need the equivalent of a safe word to exit a discussion. I propose “OK, decision time.”

Ensure the right people are involved

There’s a difficult tightrope to walk between involving too many and too few people in a discussion. Both have costs:

  • Cost of too many people:
    • Discussions are more difficult to manage
    • More time spent sharing context that the core team may already understand. (Extreme example: bring a non-developer into the discussion and begin explaining what a deadlock is to bring them up to speed.)
    • Disrupts people’s ability to deliver their actual work
  • Cost of too few people:
    • Valuable insight may be lost
    • Someone may feel left out and frustrated that a decision was made without them.
      • Note: This attitude overall needs to change. We cannot have a design-by-committee team. Some decisions will be made by a smaller group of people and explained afterwards. Questions are valid, and redesign may be necessary. But those cases should be far fewer than we’re actually seeing.

One easy rule to put in place: dev sync is not the time for this. Dev sync is a short daily meeting to update the team on progress. Detailed technical discussions may not occur there.

Document outcomes

Outcomes must be documented. This is especially relevant to technical discussions held in calls, but applies to text based discussions as well. This ensures that the people involved in the discussions walked away with the same understanding, and allows the rest of the team to get a summarized version of the decisions.

Documenting does not mean writing a long detailed document exploring everything. It can be a short one-line sentence in Slack, a comment in Jira, an inline comment in the codebase, or something else. For example:

  • We decided that hCaptcha logic should live in the frontend code itself and not in the SDK
  • We’re going to flatten our file structure by moving foo.txt to the root directory