editione1.0.1
Updated August 7, 2023When 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.
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.
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.
โ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.
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.
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.