When is a task done? Every team has a different definition depending on, amongst other things, their release process and what happens after a piece of code gets completed. Even members of the team have different ideas of what makes a task done, that’s why it’s important to have a team agreement of what is their “definition of done”. Here however I want to focus on the part before the task gets marked as done and look at the actual code itself. When can we be happy to say this piece of code is ready for review or has been reviewed.

Code that works is the minimum expected of a software engineer. There’s a host of aspects surrounding the code that we should be expected to do such as testing, formatting, that the code is understandable and maintainable. But how far do we need to go before submitting that PR? Do we need to cover all expected edge cases including possible ones in the future? Do we need to add tests for every single line of code and test all variants of each input?

The answer to all these, in my opinion, is no. We don’t need to cover all edge cases, especially not future ones and we don’t need to test every line and input variant. We should, however, consider them all and make a conscious decision to include or exclude them. Ideally the task, when it’s being written, should call out the edge cases that need to be covered by the code.

It is difficult to draw the line and know where to stop adding edge cases and features but it largely depends on context. For example, a string input exposed to the public such as an API would need a lot of sanity checks but a local function probably does not. I say probably but even that depends on context. Another thing is dates and times which are notorious for having more edge cases than you expect, see this list of falsehoods and this list of more falsehoods for more edge cases than anyone can want.

Adding code for future features should be avoided in current tasks, especially if they are expected to be more than a couple of months away. The reason for this is it is near impossible to predict the future so the expected feature ends up being different if it does ever happen. We end up having over engineered the current task with most of it sitting idle for a day that may never come.

Another thing to be aware of is scope creep. This is where, as the task progresses and gets reviewed, new things get added to it. It may be edge cases but also could be new features and this is something to be very weary of adding. This can cause the task to balloon out to something far larger than expected. Sometimes this is necessary as the original task did not account for reality properly but by and large this should be avoided if possible. If the original feature can be shipped and will work without the extra bits being asked for then it should go out alone and a new task created for the new feature.

This is just some of the things to think of when you are working on a task that seems broad in scope and could go on forever. In summary judge what should be done and do that, if the scope gets out of hand then maybe it’s time to break the task up and focus on what can be done now. Let the extra unexpected scope be handled by a future task.