1

We were asked to review a client application's code that involved ~1.5 million lines of code. The application has major stability and experiences frequent crashes and we are assigned the task of finding the root cause of such issues by doing a manual static code review. The goal is to prevent exceptions. It is not our goal to handle them better once they've occurred.

I have two examples below to illustrate defensive programming to prevent an exception: in the case of non-mandatory logic, and mandatory logic.

First example (non-mandatory logic): Defensive coding (the "if" condition in block 2) precedes usage of "obj". If "obj" is null, then the "if" condition skips the logic that would otherwise cause an exception. We may have instances in the code where the "if" condition doesn't exist - and it should be added to prevent an exception. We want to know the extent (effort) to which we should be adding this defensive logic.

2nd example (mandatory logic): In the second example, where the "if" condition checks for null (block 3), it is not valid to skip the logic because the logic is mandatory. In this case, the "if" condition must throw an exception. This defensive logic will not improve stability: an exception will be raised whether due to the null reference exception or due to the "if" condition throwing an exception.

We have been asked to find patterns in code which result in exceptions being thrown i.e. why the object did not get set - the problem is in the logic in block 1. (in this example: because it gets set only when SomeCondition is not false).

bool someCondition = false;
DataSet obj = null;



/*** Begin block 1 ***/

if(someCondition)
{
    obj = new DataSet();

    //Fill the obj with data
    Populate(obj);
}

/*** End block 1 ***/



/*** Begin block 2 ***/

//Perform some non-mandatory logic
//defensive coding
if(obj != null && obj.Tables["Employee"] != null && obj.Tables["Employee"].Rows[5] != null)
{
    DataRow row1 = obj.Tables["Employee"].Rows[5];
    row1["FirstName"] = "Bob";
}

/*** End block 2 ***/


/*** Begin block 3 ***/

//Perform  mandatory logic
//defensive coding
if (obj == null && obj.Tables["Employee"] == null && obj.Tables["Employee"].Rows[5] == null)
    throw new Exception("Object obj cannot be null");
 DataRow row2 = obj.Tables["Employee"].Rows[5];
 row2["Role"] = "Manager";

/*** End block 3 ***/

We are doing a manual review of the code, but it is a huge ASP.NET MVC application which talks to backend WCF services and we are struggling to find patterns. Is it possible to do something other than manually? Are there any tools that can help us find such patterns.

VS0930
  • 21
  • 3
  • I'm voting to close this question as off-topic because it belongs on http://codereview.stackexchange.com. – Cᴏʀʏ Nov 12 '15 at 20:04
  • Have you seen http://stackoverflow.com/questions/38635/what-static-analysis-tools-are-available-for-c? – Cᴏʀʏ Nov 12 '15 at 20:06
  • 6
    1.5M lines of code written by developers who don't really know what they're doing is a *mountain* of technical debt. There really isn't a tool or quick fix to address that problem. Static analysis tools can *help* by reporting on things they think may be issues. But problems in a codebase like that go *far* deeper than just a few null reference exceptions. – David Nov 12 '15 at 20:07
  • I would seriously consider/recommend a rewrite. In this particular case, it will likely cost way less than trying to patch it and still have something unstable. Provided of course that they don't use the same developers as the first time... – mprivat Nov 12 '15 at 21:09
  • @Cᴏʀʏ I am not asking anyone to review my code which is what codereview.stackexchange.com is for. I am asking for ideas on how the code can be reviewed and to address the problem described in the question – VS0930 Nov 12 '15 at 23:40

2 Answers2

0

Fault -> Error -> Failure

I'll highlight the definitions from Hanmer, Robert (2013-07-12), Patterns for Fault Tolerant Software (Wiley Software Patterns Series) (pp. 3-4). Wiley. Kindle Edition.

The terms fault, error and failure have very specific meanings.

A system failure occurs when the delivered service no longer complies with the specification, the latter being an agreed description of the system’s expected function and/ or service. An error is that part of the system state that is liable to lead to subsequent failure; an error affecting the service is an indication that a failure occurs or has occurred. The adjudged or hypothesized cause of an error is a fault. [Lap91, p. 4]

Your mission, as you've chosen to accept it:

The goal is to prevent exceptions. It is not our goal to handle them better once they've occurred.

So we're talking fault prevention where a fault is the source or cause of the error (which is the exception).

In your example, if I trace back to the source of the problem, it's in the someCondition in block 1 that at some point had a false value resulting in the obj not being initialized. There's likely another fault that caused that condition to be wrong. It's like a chain.

If you want to prevent exceptions, then why not fix that source of the faults? Defensive code (also explained in Hanmer's book) is good because stuff happens and it helps to detect faults. But the example you give seems ineffective because you're just avoiding an error (as opposed to removing the fault).

Furthermore, although the block 2 approach will work to prevent an immediate exception, the assumption that you make about code being "non-mandatory" had better be correct. Otherwise, in some other place in the code the work done by that logic block (that you skipped with a goal simply to prevent an exception) could create another fault in the system.

Is it possible to do something other than manually? Are there any tools that can help us find such patterns.

From this answer, there's a recommendation for ReSharper (but I've never used it). But some equivalent of lint for ASP.NET is what you can try to find.

I realize your project is in C#, but there's a lot of advice at SEI CERT Oracle Coding Standard for Java that could apply (conceptually). If the application makes use of threading, there are several rules that could be useful in C#.

Stability problems, IMO, can't be "tooled out" so easily.

Community
  • 1
  • 1
Fuhrmanator
  • 11,459
  • 6
  • 62
  • 111
0

If you're using the latest version of Visual Studio, you can write your own analyzers or use open source ones like Code Cracker to identify (and often correct) patterns in Exception handling (and other coding aspects).

https://code-cracker.github.io/diagnostics.html

For instance, Code Cracker has a couple of analyzers that I've used for similar code assessment purposes which detect empty catch blocks, another common exception handling anti-pattern. Pay attention also to how the exceptions are logged and whether or not you are using descriptive error messages (this link also has a list of exception management best practices and references): http://deviq.com/descriptive-error-messages/

ssmith
  • 8,092
  • 6
  • 52
  • 93