Team code - step two
Now that we've set up the space and the tone within the team, we now need to look at how the team deals with code. Our objective here is to ensure that all the code being developed by pairs is integrated seamlessly, and is consistent with a standard acceptable to the team. By driving step two we'll go a long way to support step one.

Coding standards
Whether you decide to go forward with Agile or not, coding standards are an excellent best practice. This step involves having the team create a set of coding standards that the they fully understand and adhere to. Coding standards give us some advantages:

  • They make it easy to read each other's code and thus anyone can make changes.
  • The code becomes an excellent source of information for future teams working on it, or if a team member leaves.
  • New team members have a set of guidelines -- no guessing.
Most teams take an existing framework and build their own set of standards around that. The key here is to start simply, address issues that the team is struggling with right away and then move forward as you need to. Don't impose standards for the sake of a standard either -- this something the whole team needs to buy into, believe and work by. A snippet of 3Q's Coding Standards document is presented below.

CamelCase

Everything's in CamelCase, class names start with caps, method and field names don't.

Don't ever put curly brackets on the same line as anything else.

Fields start with an underscore:_fieldname
Variables don't:variableName
Method:public void methodName(String stringValue)
Interface exposure

Public methods go at the top of a class, followed by protected methods, followed by private ones. It may also be a good idea to place any methods which inherit from abstract classes or implement interfaces towards the top.

It should be possible to flick onto a class and instantly get a feel for its function and how it fulfils that function, without having to scroll down or squint.

Method and class names

Descriptive as they need to be. Noticed different developers have different thresholds for readable methods, prefer to glean context from the surrounding class, and even the parameters in the method. This is debatable, but certainly it should be possible to get the meaning from a method by reading its name, so:
doIForAllX()
is bad, but:
setupAllTableRowItems()
is good.

And possibly:
createRows()
is better.

[getVar vs calculateVar, straight getter vs a method]

[don't mix query with assignment]

Method abstraction

Code inside a method should be of the same level of abstraction as all the other code in the same method. In this way the natural course of events in a class can be made clear. For example:

public void initializeDataBase()
{
  _connection = createConnection ();
  setUpTable();.
  For (int i=0;i<tableRows;i++)
    SetUpTableRow(i);
}

This is not so much hard to read as it makes you squint. We at 3Q value our eyesight so we pull the code into neat little steps, like so:

public void initializeDataBase()
{
  setUpConnection();
  setUpTable();
  setUpTableRow();
}

This makes it possible to:

  1. Get a feel for what's going on
  2. Easily navigate into the exact part of the class we want (if we're interested in the table row setup, we ctrl-click on setUpTableRow().
The Law of Demeter

A class should have access only to those methods directly accessible from its fields or variables. References to objects sent in or objects the class instantiates itself are good to go also.

Basically, don't do this...

public int calculateRetirementFund()
{
return getClient().getRetirementDetails().getRetirementFund();
}

...but do this instead:

public void calculateRetirementFund (RetirementDetails details)
{
return details.getRetirementFund();
}

This helps give scope to the class and cuts down unneeded method calls and delegation.

Sequence Selection Iteration

Methods can generally categorised into these three types. A sequence of events, one after the other, a search or filter on a collection, and an iteration over a collection or array.

Collecting methods, Vector create, vector setup, vector dosomething

Collections crop up over and over again, and with the same problems each time, mainly to do with typecasting. If you have arbitrary runtime casting built into a collection, there is a chance that the wrong type will find its way in, resulting in cast exceptions.

Making the collection type-specific allows for compile-time checking against what's added into the collection, as well as making it easier to fit in custom collection methods based around that type.

Don't use temporary vars - replace temp with query

Reference the Refactoring book for this -- "Replace temp with query", best not to hold on to temporary variables, it increases the complexity of the code for the reader, and reduces the options for further refactoring of the algorithm.

Testing antipatterns

Large setup indicates an ill-conceived pattern. You should only need to set up those objects which directly relate to the class you are testing.

Make unit tests as fine-grained as possible, this allows for more portable code, as well as pushing it towards cleaner, more decoupled implementation.

Testing through backpointers

Backpointers are just plain nasty and should be avoided. There are noticeable exceptions to this case, the state pattern being one. Know your reasons for implementing a backpointer. If the reason is "it'll work" then you're missing something.

View testing - instantiating triads in tests.

In a well-built app, the view layer should be abstracted away from the domain to such an extent that you need never create a view to test the app. Coarse-grained testing will need to be changed more often. See testing antipatterns.

This is just a short example from something that is evolving. Again, start simply, keep it basic and get agreement from everyone.

Related links

Log in


Sign up | Forgot your password?

What's on?

  • Optus Deal

    Broadband + home phone + PlayStation®3 in a single package price!