Realtime hit counterweb stats

Archive for the 'Software Engineering' Category

Context is key: Test Coverage

Saturday, August 7th, 2010

The notion that Test Coverage alone can provide an adequate metric for determining how well a particular piece of code, or worse, an entire codebase, is being tested has always troubled me as, in my experience, this can be a very misleading assumption.

Like so many of my previous themes, with Test Coverage context trully is key as, relying on a predetermined percentage threshold as a true measure of successful testing fails to take into account the numerous factors involved. For example, the preceived thoroughness of a systems tests can easily be increased – beit mistakenly or intentionally – by testing parts of the system which could be considered irrelevant; such as getters, setters and the like.

Personally, I prefer (and advocate) focusing first on testing the most critical behaviors and state of a particular piece of code. The tests should not be limited to just testing the expected cases but also, and of equal importance, the testing of exceptional and negative tests.

I could go on about this in great detail however I recently came across a really good post from googletesting (which I found via Mike Labriola) which I think pretty much sums it up.

Misplaced Code

Tuesday, June 22nd, 2010

Often I come across what I like to call “Misplaced Code”, that is, code which should be refactored to a specific, independent concern rather than mistakenly being defined in an incorrect context.

For instance, consider the following example to get a better idea of what I mean:

var url:String = Application.application.url;

if ( url.indexOf( "localhost" ) {

} else if ( url.indexOf( "dev" ){

} else if ( url.indexOf( "staging" ){

}
etc…

Taking the above example into a broader context, it is quite common to see code such as this scattered throughout a codebase; particularly in the context of view concerns. At best this could become hard to maintain and, at worst, it will result in unexpected bugs down the road. In most cases (as in the above example) the actual code itself is not necessarily bad, however it is the context in which it is placed which is what I would like to highlight as it will almost certainly cause technical debt to some extent.

Considering the above example, should code such as this become redundantly implemented throughout a codebase it is quite easy to see how it can become a maintenance issue as, something as simple as a change to a hostname would require multiple refactorings. A much more appropriate solution would be to encapsulate this logic within a specific class whose purpose is to provide a facility from which this information can be determined. In this manner unnecessary redundancy would be eliminated (as well as risk) and valuable development time would be regained as the code would need only be tested and written once – in one place.

So again, using the above example, this could be refactored to a specific API and client code would leverage the API as in the following:

switch( DeploymentContext.host )
{
    case DeploymentContext.LOCAL_HOST :
         …
         break;
    case DeploymentContext.DEV:
         …
         break;
    case DeploymentContext.STAGING:
         …
         break;
}

This may appear quite straightforward, however, I have seen examples (this one in particular) in numerous projects over the years and it is worth pointing out. Always take the context to which code is placed into consideration and you will reap the maintenance benefits in the long run.

Simple RPC Instrumentation in Flex

Sunday, September 20th, 2009

On occasion developers may find a need to quickly measure the time it takes for a request to a remote service to return a response back to the client without the need to employ an automated testing tool to perform the instrumentation. This information can prove quite valuable for performing application diagnostics on the client and, when measured in terms of code execution, monitoring at the execution level will always be a bit more precise than that which can be measured by using a Network proxy alone, such as Charles or Fiddler, etc.

Obviously there are numerous solutions which can be implemented to monitor the elapsed time of a service invocation, however it was my goal to provide a unified solution which could easily be implemented into existing client code without significant refactorings being required.

In order to achieve this I first needed to consider what the typical implementation of a service invocation is in order to isolate the
commonality. From there it is only a matter of determining a solution that meets the objective in the most non intrusive manner possible.

To begin let us consider what a “typical” service invocation might look like for the three most common services available in the Flex Framework; HTTPService, RemoteObject and WebService.

// HTTPService
var call:AsyncToken = service.send();
call.addResponder( this );

// RemoteObject
var call:AsyncToken = service.someMethod();
call.addResponder( this );

// WebService
var call:AsyncToken = service.someOperation();
call.addResponder( this );
 

Based on the 3 above implementations we can deduce that the common API used when performing a service invocation is AsyncToken. So to provide a unified solution for all three common Services we could either extend AsyncToken or provider an API which wraps AsyncToken. For my needs I chose to implement an API which simply monitors an AsyncToken from which the duration of an invocation can be determined, thus I wrote an RPCDiagnostics API which can be “plugged” into an AsyncToken client implementation.

RPCDiagnostics provides basic performance analysis of a Remote Procedure Call by providing a message which displays information about the operation duration via a standard trace call. In addition, an event listener of type RPCDiagnosticsEvent can be added to facilitate custom diagnostics and Logging.

RPCDiagnostics can easily be implemented as an addition to an existing AsyncToken or in place of an AsyncToken. The following examples demonstrate both implementations.

Implementing RPCDiagnostics onto an existing AsyncToken:

var call:AsyncToken = null;
call = RPCDiagnostics.monitorToken(service.send(),"methodName");
call.addResponder();
 

Implementing RPCDiagnostics in place of an AsyncToken:

var call:RPCDiagnostics = null;
call = new RPCDiagnostics( service.send(), "methodName" );
call.addResponder();
 

Implementing a listener to an RPCDiagnostics instance:

var call:RPCDiagnostics = null;
call = new RPCDiagnostics( service.send(), "operationName" );
call.addResponder();
call.addEventListener( RPCDiagnosticsEvent.EXECUTION_COMPLETE,
                       handler);
 

The RPCDiagnostics API and dependencies can be downloaded via the Open Source AS3 APIs page or from the below links:

RPCDiagnostics
RPCDiagnosticsEvent
Execution

Design Considerations: Naming Conventions

Friday, July 31st, 2009

Intuitive naming conventions are perhaps one of the most important factors in providing a scalable software system. They are essential to ensuring an Object Oriented System can easily be understood, and thus modified by all members of a team regardless of their tenure within the organization or individual experience level.

When classes, interfaces, methods, properties, identifiers, events and the like fail to follow logical, consistent and intuitive naming conventions the resulting software becomes significantly more complex to understand, follow and maintain. As such this makes changes much more challenging than they would have been had better naming been considered originally. Of equal concern is the inevitability that poor naming will lead to redundant code being scattered throughout a project as when the intent of code is not clearly conveyed with as little thought as possible developers tend to re-implement existing functionality when the needed API cannot easily be located or identified.

Code is typically read many, many more times than it is written. With this in mind it is important to understand that the goal of good naming is to be as clear and concise as possible so that a reader of the code can easily determine the codes intent and purpose; just by reading it.

Teams should collectively define a set of standard naming conventions which align well with the typical conventions found in their language of choice. In doing so this will help to avoid arbitrary naming conventions which often result in code that is significantly harder to determine intent, and thus maintain. Of equal importance is the need for various teams from within the same engineering department to standardize on domain specific terms which align with the non-technical terms used by business stakeholders. Together this will help to develop a shared lexicon between business owners and engineers, and allow for simplified analysis of requirements etc.

Ideally, code should follow the PIE Principle (Program, Intently and expressively) – that is, code should clearly convey purpose and intent. In doing so the ability to maintain a software application over time becomes significantly easier and limits the possibility of introducing potential risk to project deliverables.

In short, conventions are very important regardless of a teams size; beit a large collaborative team environment, or a single developer who only deals with his own code. Consistency and conventions are a key aspect to ensuring code quality.