Asking for Clarification

14 minutes
From

editione1.0.1

Updated August 7, 2023

When youโ€™re working on a new feature, a bugfix, or almost any project, you may not have all the information you need in order to complete the task. The devil is in the details, and an experienced senior developer knows when they need to ask the project owners to clarify small but important details before proceeding.

Sometimes, the small details wonโ€™t change the implementation much, but other times, a slight clarification to the projectโ€™s requirements could have major ramifications for the design and implementation of your solution.

Here are a few things to consider when you may not have all the information you need to move forward with a project.

Break Down the Requirements

Before asking for clarification, first try to break down the requirements into the smallest pieces of individual features you can. Try to think about your task in terms of the following requirements:

Inputs. Determine which inputs are required, which ones are optional, and what the expected values or ranges should be for each input. This helps you dig deeper into what inputs you should expect so that you can build logic around them to prevent bad data from getting into your system.

Try to think in terms of how the system will handle different scenarios. You will naturally come up with some additional questions for your teammates or the product owner if you can think of edge cases where a user may enter some unexpected input.

โ€‹exampleโ€‹
  • The name field is only one input field in the design. What if someone only gives us their first name when we need their full name? Should we break it into two fields so we can make each one required?

  • Are we verifying emails to make sure they are deliverable, or is basic email format validation good enough?

  • Will the number always be an integer? Or should we expect decimals too?

  • Will the data streaming from the widgetโ€™s sensor always be in a range between 0.0 and 1.0? What should we do if we receive a negative number from the sensor? And can this value be null if there is an issue with the sensor?

The more clarification around your inputs, the more robust your validation logic and error handling will be. Common errors occur when a program encounters unexpected inputs, so if you can ask good questions to clarify any missing requirements, youโ€™ll be able to prevent errors before they happen.

Outputs. Double-check what type or format your outputs should be in, especially if you expect the output to become the input in another program or function. This is easier if youโ€™re using a strongly typed language, and it is critical if youโ€™re using a scripting language.

Unlock expert knowledge.
Learn in depth. Get instant, lifetime access to the entire book. Plus online resources and future updates.
Now Available

โ€‹exampleโ€‹Here are some examples of what to ask when clarifying output requirements:

  • Should we output the data in CSV, TSV, JSON, or give the user options for all three?

  • Does the data weโ€™re outputting contain user-submitted content? Does our templating framework escape outputs automatically? How can we avoid XSS attacks?

  • How many results do you want in the API response? Should we paginate the results?

  • What should the precision on our floats be when we format them during rendering?

Error handling. Reliable software programs contain robust error handling. Reliable programs gracefully recover from certain errors and display helpful information to the user if the program is unable to proceed. In order to write code like this, you have to anticipate ways in which your program can fail. If you understand all of the things that can go wrong with your code, you can then add logic to handle those errors gracefully or to exit the program and display a helpful error message to your users.

โ€‹exampleโ€‹Here are more example questions related to error handling:

  • If the API request fails, how many times should we retry? Should we only retry for specific status codes?

  • What error message should we display to the user if they hit [insert rare corner case here]?

  • Should I throw an exception if we hit [insert weird edge case here]?

If youโ€™re unsure of how to proceed when a block of code may fail, ask your coworkers or the project stakeholder. They will often help clarify how you should handle errors in certain situations.

Business logic. The business logic encodes into your program the core set of business rules that determine how it should store, modify, and delete data. Many times, this logic will closely resemble real-life concepts such as inventories, invoices, accounts, or processes.

Making assumptions in business logic can lead to misunderstandings in how the business operates, so itโ€™s always important to clarify any ambiguity before proceeding. A small bug in your business logic can have enormous downstream effects such as data loss, duplicate data, or many other unintended consequences.

โ€‹exampleโ€‹Here are a few example questions for clarifying business logic.

  • Should we start the free trial when the user creates their account or after they verify their email?

  • Should we send an alert as soon as the sensor temperature reaches the high heat threshold, or after itโ€™s above the threshold for more than X seconds?

  • Should we disable the form after the user submits their answers, or should we allow multiple submissions?

If you donโ€™t have all the information you need to complete a task, youโ€™ll need to ask for clarification. Itโ€™s your responsibility to find gaps in the requirements and to ask questions that will clarify any ambiguities and fill in those gaps. The better youโ€™re able to fill in the missing requirements, the better software youโ€™ll write, and that starts with communicating clearly to others when you arenโ€™t sure how to handle specific scenarios in your code.

Making Assumptions

Programmers enjoy autonomy in their role. When youโ€™re starting out in your career, youโ€™ll need some help when completing your tasks, and thatโ€™s okay. By the time you start a new task, a lot of the big decisions will already have been made for you, and your job will be to implement a predetermined solution. This is good because it allows you to focus on writing quality code rather than trying to implement a solution where the end result isnโ€™t crystal clear.

When you are implementing a set of requirements someone else has already figured out, you can focus on good coding fundamentals and understanding how your changes fit into the larger context of the codebase. In a well-architected system, sometimes youโ€™ll be able to add powerful new functionality by making a few small tweaks, and in doing so, youโ€™ll see firsthand how good code should be written. Youโ€™ll pick up new ideas over time and form your own opinions based on what youโ€™ve seen work well in the past. In the process, youโ€™ll build confidence to make more decisions on your own in the future.

As you gain experience and grow into a seasoned developer, youโ€™ll naturally want to make more decisions on your own rather than be told how to implement solutions. This is a good thing, but it can be a difficult time in your career to navigate. At some point, youโ€™ll find yourself at a crossroads where youโ€™re confident enough in your ability to devise a working solution, but your ideas may not be sufficient for what the senior engineers had in mind.

Youโ€™ll disagree on how some solutions should be implemented. These conflicts are difficult because emotions often get the best of people. Sometimes, youโ€™ll be right, but other times, the senior engineers will rely on their experience to override your decisions. Sometimes, they will have legitimate reasons based on experience to push back on your decisions, but other times, it may come down to personal preference.

Itโ€™s easier said than done, but as a junior engineer you need to do your best to take your emotions out of the development process. If you can separate your decision-making process from how you view your coding ability, youโ€™ll be able to navigate through your career better.

As you gain experience, youโ€™ll encounter ambiguity in requirements that might seem insignificant in the context of the task, and itโ€™s natural to want to make decisions on your own. You were hired because youโ€™re smart, and your employer values your ability to make good decisions, so why wouldnโ€™t you want to make certain decisions on your own? After all, Steve Jobs famously said that โ€œit doesnโ€™t make sense to hire smart people and tell them what to do; we hire smart people so they can tell us what to do.โ€

The longer you work as a software engineer, the more youโ€™ll gain a better feeling for what to do when faced with ambiguity, but be careful in these situations. Making your own decisions can be rewarding, but if youโ€™re not careful, you may be making decisions based on flawed assumptions.

An assumption is a prediction that something is true without proof or evidence. The thing that makes assumptions dangerous is that theyโ€™re often made based on experience, and as a junior engineer, you may not have enough experience to safely make certain assumptions. Senior engineers, on the other hand, may have relevant experience to contradict your assumptions, which often leads to conflict.

When a senior engineer pushes back on your solution, you may feel like youโ€™re being personally attacked, but try to view their experience as an opportunity to learn why theyโ€™re pushing back. Most of the time, itโ€™s as simple as asking why they think your assumption is wrong. You may be surprised that they mention some reason you hadnโ€™t considered or some edge case that you didnโ€™t think was possible.

The important thing to understand in these situations is that there are still a lot of things you donโ€™t understand about software development. The same can be said about senior engineers as well, but itโ€™s especially true for those who have only been working professionally for a few years. You may think you know quite a bit, but the reality is that youโ€™ve only scratched the surface.

So how do you avoid these conflicts while youโ€™re building up the confidence to make your own decisions? The answer is to make assumptions, but verify those assumptions before implementing any of your decisions. Itโ€™s a subtle detail, but itโ€™s an important one. You can still make decisions on your own when the opportunity arises, but verify with your manager, a senior member on your team, or a project stakeholder before proceeding with any development work.

When you verify your assumptions before beginning any coding, youโ€™ll avoid any situations where youโ€™ll have to redo your work because you made a decision that wasnโ€™t correct or that someone disagreed with. Itโ€™s faster and cheaper to refactor an idea than it is to refactor code, so itโ€™s always good to double-check with others that your assumptions are correct and that youโ€™re not missing some important context before implementing your decisions. If your assumptions are correct, thatโ€™s great! Youโ€™re getting smarter and your experience helped you come to the correct decision. If not, ask for clarification on why your assumptions were incorrect, or why your decisions wonโ€™t work in the given situation. And by coming to a conclusion before writing any code, youโ€™ll be able to avoid conflicts after youโ€™ve put in time and effort coding an incorrect solution. Itโ€™s a win-win for everyone involved, and in the worst case, youโ€™ll walk away learning something new about why your decision was flawed and what you can do better next time.

Asking to Learn

At the beginning of this section, we discussed why children ask questions, and how it helps them connect ideas and form a better understanding of the world around them. In a way, most engineers also do this without even thinking about it. By asking the different types of questions youโ€™ve learned about in this sectionโ€”asking for help and asking for clarificationโ€”youโ€™ll naturally learn things from the answers youโ€™re given. Youโ€™ll learn why you should choose one software design over another, or why you should consider a certain edge case when you didnโ€™t think it mattered.

In some cases though, youโ€™ll just have curiosity for how something works or why something is the way it is. You wonโ€™t necessarily be asking for help or to clarify anything, but youโ€™ll still have questions. In this case, youโ€™re just asking a question for the sake of learning.

Sometimes itโ€™s good to challenge the status quo and ask your teammates why something is the way that it is. In some cases, the answer may be underwhelming. You may receive an answer such as โ€œwell, thatโ€™s just how weโ€™ve always done it.โ€ In asking these questions, youโ€™re challenging the other engineers to think through why theyโ€™ve always done it that way, and what they could do to improve a process or part of the codebase.

Youโ€™re reading a preview of an online book. Buy it now for lifetime access to expert knowledge, including future updates.
If you found this post worthwhile, please share!