Abstraction and Modulization

Abstraction and Modulization

Here we are talking about how our code is stuctured within each tier and within each class.

It is key charactoristic of great code that the code's abstractions are strcutrued at the same level of functionality. Lets clear this up with an example. Far to many people write methods that do more than a single thing. So they will write a method that says creates a  Customer, and that method will first check that the data is OK, then go on to log the timestamp of when and which user created the customer object, then it may send of an email to inform some manager that a customer has been added and then write the data to the database and log a sucessful insert to the system log.

So I wont bore you by writing out a complete example because you could find lots of them all over the place.

How such a method should look is like this:

public class CreateCustomerService
{
  public createCustomer(final Customer customer, final User user)
  {
    validate(customer);
    validate(user);

    createAttempLogEntry(customer, user);

    addCustomerToDatabase(customer);

    createSuccessLogEntry(customer, user);

    postEmail(customer);
  }

... implementation of methods above...
}

The important thing to take home form this example is that all the methods operate on the same level of abstraction. Even if the validateUser(user) method is only a couple of lines of code it should still be brought out into it's own method because this maintain sinergy with the level of abstraction we are looking for.

This make the code more readable and more modular because we can obviously reuse many of the method in different circumstances.

To Pass Parameters or to use Object State.

One of the questions the always come up from time to time is, is it better to pass parameters around method-to-method within an class or should you use object state/instance variables and invoke the methods without parameters (such that they operate on the object state).

The most meaningful answer I can give you for this is that if you pass them around then there is no need to rely on state, and thus it is easier to make these methods final static methods which lean themselve better to optimisation. Also passing parameters around clearly shows when reading the code what data the method is working with. This, to my mind, is a good enought reason in itself. The easier code is to read and understand, then the better the code is. It is as simple a test as that.

If however, you are using templating or overriding methods from a parent class, then you may need to use instance variables to data communication.

In general I would say the rule would be to only use object state as a second option. Programes are far more extendable and flexible if code does not rely on state.

 

Debugging and Maintenance

Firstly, lets answer the question; What is code is for? Code is for humans to read, debug, maintain, and understand. This is the key mesure of good code - is it easy to understand what is going on and to maintain.

This is one of the most important measurements of great code verses crap code, and generally under this heading, crap code comes from old C++ developers.

Let me give you two examples of code that does the same thing, and see if you an work out which one is easier to debug:

  LatLog location = LocationUtil.getLatLong(db.getCustomer("ABC")
                           .getAddress()
                           .getGetPostcode());

  LatLog mapCenter = LocationUtil.getLatLong(postcode);
  int mapZoomLevel = 0;

  int zoom = 0;
  if(location == null)
  {
    location = UK_LAT_LONG;
    zoom = 15;
  }

 

final Customer customer = db.getCustomer("ABC");
final Address homeAddress = customer.getAddress();
final Postcode postcode = homeAddress.getPostcode();

LatLog mapCenter = LocationUtil.getLatLong(postcode);
int mapZoomLevel = 0;

if(location == null)
{
    mapCenter = UK_LAT_LONG;
    mapZoomLevel = 15;
}

So egnoring all the obvious bug errors lets look at the major signes of bad coding practice.

Inline Code

The most obvious and most anoying thing about the first code snippet is that the entire getting of the customer's location is done in a single line. If there are any faults with this line (such as a NullPointerException), the debugger or stack trace will only identify the line and not the partcular method. However on the second snippet, because the stacktrace will tell you the line number you will know at which point the problem occured.

Untidy Code

Secondly the second snippit is easier to read simply because it's layed out neat and tidy. The layout of the second snippet gives us the oppertunity to give our variables proper names which indicate what they are for. E.g.:

     Address homeAddress;

Use Features of the Language

Most Java programmer underuse the final keyword. This is used to indicate that the variable will not change its value. So by looking at the second snippet you can instantly see that the only modafiable variables are mapCenter and mapZoomLevel. This is great for debugging because once you are satified that the final variables have been assined correctly you do not have to worry about them getting reassined to some erroneous value latter on. This becomes more obvious and important when you are working with large code bases that someone else wrote. At a minimum, if the coder used the finally keyword consistantly you know that they know what they're doing. When you meet coders who refuse to use the final keyword even after you've explained what the benefits are you can pritty much mark them down as bozos.

Another good use of the final keyword is when it's used to indicate that a class or method can't be extended. This shows that the original developer put some thorough into how his code should be maintained and/or extended over time.

Additionally, there are other benefits to using the final keyword which code optimizers will pickup on and use to optimise the code (for example final methods can be repeated and in-lined everywhere by the optimiser during profiling and compile time because they can't be polymorphic).

Add comment