1

I'm currently designing a system that, no matter how hard I try to break, slow network, failures, random server deaths, it can recover and it can re-build again. Each action it does is a fragment and it can pick up from where it left off. Each fragment is signed with a "done or not" and, again, it can resume work no matter what happens.

Do I stop just because of development time? I've covered all user-cases. I just want my framework to be robust, but how do I know where to draw the line and is someone that doesn't draw the line impractical because he's leaving issues on the table?

I've covered all my core and lots of exotic cases where it can fail. Anything besides now is in the area of "good to have".

When do I stop?

My time is rather unlimited, and can make sure things work out nicely, but I'm at cross-roads where if I do more checks, it becomes difficult to read through even for me.

8
  • If you have enumerated your vulnerabilities, and have tests that fairly represent those vulnerabilities, and your tests pass, you are done. There is nothing more we can tell you. Nov 13, 2019 at 22:14
  • "avoid asking subjective questions where … your question is just a rant in disguise: “______ sucks, am I right?”" (help center)
    – gnat
    Nov 13, 2019 at 22:18
  • 1
    What's your measure of success? Keeping in mind that it is impossible to guarantee 100% uptime and impossible to guarantee that bugs will never exist, noone would ever promise such a thing to a user anyway. It would be more typical to have a Service Level Agreement (SLA) to work against (e.g. uptime percentage, time to respond to live incidents, etc.), then to continuously collect stats to show whether your system works within the parameters agreed in your SLA. If you can collect stats which demonstrate that your system is working as per that agreement, then your job is done. Nov 13, 2019 at 22:54
  • @BenCottrell Thank you. That is very, very useful in forming my thinking about how to better architect. I guess I should try to objectively measure what's an acceptable failure rate and test against that assmption. Nov 13, 2019 at 23:00
  • 2
    Final users will find a way to make it fail. Nov 13, 2019 at 23:59

5 Answers 5

2

While your time now might be unlimited, in normal projects it's not.

Your time costs someone money, which means that any error handling you write needs to cost less than the money you would lose if it would actually occur. That means you need to make at least informal (e.g. in your head) risk and cost-benefit evaluations to check if the time spent on catching a problem is actually worth the effort. This ends up being mostly a matter of experience with the systems involved.

As an example: If you spend two days protecting your order processing code against a network outage, your hoster hasn't had an outage in the last three years and the effect of the outage would be that customers couldn't reach your website to place orders anyways, it's probably not worth putting in that much effort.

Another example: If you spend two weeks to make sure your stock broker system resumes after a server death and the result of not resuming would be thousands of uncommitted stock transactions being lost then yes, that would definitely be worth the effort.

If you aren't being paid and your time essentially has no (monetary) value then you can spend whatever time and effort you want on securing it, because dividing benefit by cost will in that case always result in infinity.

If the code gets too complex due to additional error handling, it's a matter for refactoring, which would usually be covered by the cost-benefit calculation as additional cost. In your case, you can spend as much time on refactoring it until you can understand the code even with all the additional error handling.

In summary: If your time is free and unlimited, only you can decide whether adding more error handling is necessary or worth it. If it's neither free nor unlimited, you catch all errors that are cheaper to catch than to happen.

1

if I do more checks, it becomes difficult to read through even for me

This is the worrying part. As you spend more time crafting your code it should become easier to read.

Considering the sheer unlimited time at your disposal, some of it may be well spent on eradicating many of those if statements of which I suspect there are a lot in your code. Recognize logic and apply some structure rather than repeat logic and add conditions. If you post a typical piece of code I think we will be able to give you some pointers.

1
  • I agree with the first statement and I've actually went back to audit a lot of my codebase to see exactly if I can RELY on what's coming in order not to do a check. I've cnealed a lot of my code that way. My problem is that I'm writting PHP and I don't have the tools you guys have. Nov 14, 2019 at 17:36
1

A lot of it depends on what kind of an application you are building and what SLAs you intent to provide.

No system has been build to handle all the scenarios perfectly so that the developer can rest. But you have to stop somewhere, and as long as your system does what you intend it to do on most of the occasions (which is SLA), and are able to recover if the system behaves (the time for which is an SLA again), you should be fine.

3
  • SLA is a very blunt measure and usually doesn't cover anything other than the live system. You want to be identifying problems way before the code gets to this point.
    – Robbie Dee
    Nov 14, 2019 at 11:46
  • But Daniel has mentioned in the question - "I've covered all my core and lots of exotic cases where it can fail. Anything besides now is in the area of "good to have"". Beyond this, the point where one stops further development or optimisations is when your system meets the set expectations right? Or else there is always scope for that one little improvement which can be done.
    – skott
    Nov 14, 2019 at 12:08
  • 1
    As I outlined in my answer, test cases are but one small part of the approach.
    – Robbie Dee
    Nov 14, 2019 at 13:40
0

This seems to boil down to how one builds confidence with their code. Well, lots of ways:

Rubber duck it

Talk through the design with someone else and see if they can spot any problems. As the old saying goes, if you can't explain it simply, there may be some complexity there that needs teasing out.

Code review

Someone else may have a view on how the code could be improved or spot some problems you hadn't seen.

Lots of cheap tests

Unit tests are cheap tests - the more of these you have the better. Yes, coverage tests are good but make sure the behaviour is adequately tested.

Run it

Design and unit testing is all very well, but does it run as intended when put together?

Destruction testing

Try and break the thing - throw invalid data/conditions at it - how does it stand up?

Push it out thru the layers

It always works on the developer machine. Try a deployment to test, UAT and beyond. You'll encounter different issues at every hurdle.

Let someone else take it for a spin

What is obvious for you might not be for someone else.

Code fatigue

If you look at the same code time and time again, you stop seeing the obvious. Take a break and walk away. Do something different and come back and look at it with fresh eyes. You can help yourself by keeping your methods and modules small.

0

There is no such thing as conclusively knowing you've tested everything you can. Test everything that makes sense. That definitely includes the sofware specs, and developers can add further tests that they deem necessary.

Going slightly off the silly deep end, since there are only finite possibilities in any finite codebase, you could theoretically test literally everything, but this would go WELL beyond any reasonable amount of test coverage.
No employer is going to pay the wage that accompanies the amount of time you need to test literally every permutation of the application's state. Test what is reasonable to test.

Don't succumb to thinking that you will get it right the first time. That applies to both your code and your tests.

It can happen that your tests forget to cover a certain scenario. Sometimes, a failure state is so contrived that no one could reasonably see it coming (until it presented itself) and therefore no one pre-emptively wrote a test to catch it.

In such a case, you deal with the issue when it presents itself, wonder why the tests didn't catch this, realize that there is no test to catch this, and then write a test to catch this.

Not the answer you're looking for? Browse other questions tagged or ask your own question.