Sundarrajk's Weblog

Archive for the ‘Code Quality’ Category

Your Code As a Crime Scene: Use Forensic Techniques to Arrest Defects, Bottlenecks, and Bad Design in Your ProgramsYour Code As a Crime Scene: Use Forensic Techniques to Arrest Defects, Bottlenecks, and Bad Design in Your Programs by Adam Tornhill
My rating: 4 of 5 stars

A very different way of looking at problems in the code. The author suggests various non-traditional means of identifying problems in software development.

Number of times a code has changed, code churn (number of lines added, removed), number of developers working on a single piece of code, code changing together.

The primary requirement for all of this that the version control should be adhered to correctly. Every developer should have a personal login Id and should use it to checkin at regular intervals.

Many of the techniques provided in the book are available in the form the tool from https://github.com/adamtornhill/code-…. These are only starting tools. These need to be coupled with other tools like d3.js https://d3js.org/ to get a good representation of the status of the code.

A must read for all software developers.

View all my reviews

A very good analogy between refactoring bad code with cleaning up split juice. http://www.disciplinedagiledelivery.com/spilled-juice/. One would clean up juice split in our homes as we know that if left somebody can step on it and walk all over the place or it can dry up and attract ants and other insects to it, in short the consequences are not good.
Similarly consequences of leaving bad code as is are not good, but then why do software programmers not clean up bad code? Why do they leave it as is?

1. Thou shalt not copy-paste code
2. Thou shalt name appropriately even if it means typing long names.
3. Thou shalt write and automate Unit Test Cases
4. Thou shalt write small methods and small classes. (#)
5. Thou shalt document, not how it works, not what it does($), but how it can be used and why it exists
6. Thou shalt have only two levels of indentation in any method.
7. Thou shalt not write god classes (*).
8. Thou shalt update your, logically complete, code changes at least one a day to the version control system.
9. Thou shalt update your development environment at least once from the version control system.
10. Thou shalt be humble enough to accept errors or inefficiencies in your code as pointed out by your reviewers, peers or juniors and be open to correct them.
Notes
(#) Because all good things come in small packages.
($) What it does or contains should be known from the name.
(*) God classes are classes that do too many things. Whole application depends on a few classes.

1. Thou shalt configure static code checking, run it, and fix violations that are raised by the tool.
2. Thou shalt version your code in the Version Control System.
3. Thou shalt adopt Continuous Integration. (*)
4. Thou shalt let the end user to use the system regularly during development to get her feedback.
5. Thou shalt make an effort and understand the business process of the domain.
6. Thou shalt discuss with client the requirements in detail and if required ask, what may be perceived to be stupid/obvious questions, rather than assuming.
7. Thou shalt document all assumptions and share and discuss with the client the assumptions.
8. Thou shalt not drive the development team to work more than 10 hours or make it work on Saturdays and holidays.
9. Thou shalt not add more developers to try and finish the project earlier. (#)
10. Thous shalt not skip testing and performance testing of the system before any release.
Note
(*) Check out code from the Version Control, Compile the code, Run static Code checking, run the Automated Unit Tests and generate reports.
(#) Read mythical man month by Fred Brooks

Introduction

This is the third post in the series of posts based on the book JavaScript – The Good Parts by Douglas Crockford. The previous post covered details of how one can create and use functions in JavaScript. This post details out the features of functions in JavaScript. JavaScript functions have features which are not present in other languages and one needs to understand these details to write better JavaScripts and to understand the JavaScript written in the JavaScript libraries.

Arguments to a Function In addition to the explicit parameters passed to a function two more parameters are passed to a function.

  1. this: The value of this variable is discussed in detail below
  2. arguments: This is an Array like variable which has the list of arguments passed to the function

The value of “this” argument The value of the “this” argument passed to a function depends on how the function was invoked.
Invoking a function through “call” function of JavaScript
A method can be executed using the “call” of JavaScript.
When a global function is invoked
When a function defined in a global scope is invoked the value of “this” is the global object.
When Function is invoked as a method
When the function is defined inside another function it is called a method. When such a function is invoked the parent function is the value of “this”. All the attributes and function defined in the parent scope are accessible to this function through the “this” object.
If one has an inner function in a method then the “this” for this inner function will be the method. For the inner function to have access to the outer parent function of the method the method must expose it as its local variable. Typically this variable is called “that”
Example:

myObject.double = function () {
var that = this; //this is myObject
var helper = function () {
that
.value = add(that.value, that.value);
}
helper
();
}

“this” value in function “double” will be myObject.
“this” value in function “helper” will be “double”.
The function “helper” does not have direct access to myObject. It will have access to only the local variables of the function double. Unless double exposes the myObject through “that” helper method will not have access to myObject.
When function is invoked as a new
Although JavaScript provides prototype based inheritance it provides the classical way of instantiating an object using the “new” keyword. When a function is invoked using the “new” keyword the value of “this” will be the object that is created out of this invocation.
When function is invoked using the “apply” or “call” method
All functions can be invoked via apply or call method. The difference between apply and call is that apply takes an array for the list of arguments to the function being invoked and call takes individual arguments instead of an array.
Invoking using “call”

someFunction.call(thisArg[, arg1[, arg2[, ...]]]);

The thisArg1 is the object that will be passed as the value of “this” to the function someFunction
Invoking using “apply”

someFunction.apply(thisArg, [arguments]);

The thisArg1 is the object that will be passed as the value of “this” to the function someFunction
Example of using “call”

var Quo = function (string) {
this.status = string;
}
Quo.prototype.getStatus = function () {
return this.status;
}
var statusObject = {status: "A-OK"};
//statusObject does not inherit from Quo.prototype, but we can invoke getStatus and get the value
//of status as follows:
var status = Quo.prototype.getStatus.call(statusObject);
//the value of status will be "A-OK".

An example for apply will look the same, except that the arguments will be passed as an array.

The argument “arguments” In addition to “this” “arguments” is another variable that is available in each method. This is a list of arguments passed to the method. “arguments” is not an array in a true sense although it does behave array like. So functions that are normally available in array are not available with this variable.

Return from a function Every JavaScript function returns a value irrespective of whether there is a return statement or not. For functions that do not return anything this value is “undefined”.
The only exception is when a function is invoked with a “new” does not return anything. The “this”, the object created, is returned.
Pass by Reference All objects are always passed by reference. All primitive variables are passed by value.

Passing variables Passing variables is Pass by Value.

function myfunction(x){
// x is equal to 4
x
= 5;
// x is now equal to 5
}
var x = 4;
alert
(x); // x is equal to 4
myfunction
(x);
alert
(x); // x is still equal to 4


Passing Object Passing objects is pass by reference.

function myobject() {
this.value = 5;
}
var o = new myobject();
alert
(o.value); // o.value = 5
function objectchanger(fnc) {
fnc
.value = 6;
}
objectchanger
(o);
alert
(o.value); // o.value is now equal to 6

Passing functions Passing functions is a little more complicated. See the example below to understand how it functions, why it functions and how to actually achieve pass by reference.

function myobject() {
this.value = 5;
}
myobject
.prototype.add = function() {
this.value++;
}
var o = new myobject();
alert
(o.value); // o.value = 5
o
.add();
alert
(o.value); // o.value = 6
function objectchanger(fnc) {
fnc
(); // runs the function being passed in
}
objectchanger
(o.add);
alert
(o.value); // sorry, still just 6

Why does this happen? The problem here is the use of the “this” keyword. It”s a handy short-hand for referring to the current object context. When passing a function as a parameter, though, the context is lost. More accurately, “this” now refers to the context of the object making the call instead of the object’s function we just passed in. For standalone functions, this would be the window object and for functions called from an event, this would be the event object.
So how do we achieve this?
Option 1: When you know the method If you know the method of the object that will be called then it”s fairly easy. Just pass in the object instead of the function and call that instead. Using the objectchanger from the last example you”d get the following:

function objectchanger(obj) {
obj
.add(); // runs the method of the object being passed in
}
objectchanger
(o);
alert
(o.value); // the value is now 7

Option 2: When you don”t know the method If you don”t know the method of the object being passed in then you need to pass both the method and the object as parameters and use the call method. call is part of the JavaScript specification and allows a function to run in the context of another object. As a result, the this keyword will reference the right object: the object we passed in.
Here”s our objectchanger function one more time:

function objectchanger(fnc, obj) {
fnc
.call(obj); // runs the method of the object being passed in
}
objectchanger
(o.add, o);
alert
(o.value); // the value is now 7

Note the use of the method call.

The Pragmatic Programmer: From Journeyman to MasterThe Pragmatic Programmer: From Journeyman to Master by Andrew Hunt
My rating: 5 of 5 stars

A one line review would read “A Pragmatic Book”. True to its title the book is all about Pragmatic Programming.

The authors provide Practical advice on different aspects of programming not limited to coding, design or architecture. They also cover team setup, tools to be used.

The book should be made a compulsory training material for all developers before they start programming professionally. We will start seeing a drastic improvement in the quality of applications that are being developed.

View all my reviews

This is the ninth and the last in the series of posts based on the book Effective Java by Joshua Bloch. In the previous post we saw best practices in using Threads in Java.

This post talks about the best practices in Serialization. This topic may not seem to appeal and/or be relevant to the many developers who are today writing Web Applications directly. What the developers need to keep in mind is that everytime they are using EJB, they are dealing with Serialization, everytime they are faced with session replication, they are dealing with serialization, everytime they are planning to cache something using an application like memcached or many of the other NoSQL databases they are dealing with Serialization. Serialization creeps in without the knowledge of the developer and so it is important to understand the best practices.

Implement Serialization Judiciously

Making a class Serializable, theoretically only requires only implementing the interface Serializable.
1.       Once a class is made serializable then it becomes very difficult to change the class without supporting all the earlier releases and this will be a tedious exercise. To circumvent this problem one will need to design and implement one’s own custom serialize method.
2.       The second problem is that everytime one deserializes the class one needs to be wary about bad data coming into the class. If not checked correctly one can end up with security issues.
3.       The testing of the class with new version of the class becomes more and more difficult.
If an alternate form of serialization like conversion to XML is available that should be considered as opposed to serialization of bytes.
Consider using a custom serialized form

If we use the default serializable format then one can never change the class.
1.       Do not accept the default serialized form without first considering whether it is appropriate
2.       Even if you decide that the default serialized form is appropriate, you often must provide a readObject to ensure invariants and security
3.       Declare an explicit serial version UID in every serializable class you write.
Write readObject methods defensively

A readObject method will be required to be implemented to validate that the class is in the right state. A malicious client can provide data which would normally not have been accepted via the constructor. Even if one validate the data after the stream a malicious program can provide the input stream for creation of the object and later modify the attributes of the class to invalid data or different data. To avoid this make a copy of the objects in the readObject method so that the original read objects can no longer be altered by the client that provided the stream.
Provide a readResolve method when necessary

A singleton class no longer remains a singleton if it implements serializable as now one will be able to create another instance by deserializing the earlier serialized class. To prevent this one needs to implement the readResolve method
1.       A readResolve method is required not only for Singletons but all classes that control instance creation on its own.
2.       Instead of creating the instances as suggested in the readObject method in the earlier topic one could return a new instance from readResolve to prevent the same problem as mentioned earlier.
Conclusion
With this we come to the end of the series of posts based on the book Effective Java by Joshua Bloch. It is wonderful book and should be read by all the Java programmers. The author comes with tons of experience in Java and the advice that they proffer in the book are extremely important to all developers.
This is the seventh post in the series of posts based on the book Effective Java by Joshua Bloch. In the previous post we read about General Programming practices to write good code in Java.

This section speaks about the best practices in handling Exception. This is one area that many do not understand properly and many of the problems arise due to lack of handling Exceptions.
Use Exceptions Only for Exceptional Conditions

Do not use exceptions to handle situations which can be handled without exceptions. E.g
try {
    while(true) {
        a[i++] .f();
    }
catch(ArrayIndexOutOfBoundsException e) {
}
Instead use
for (i = 0; i < a.length; i++) {
    a[i].f();
}
Exceptions as the name indicates should be used to handle Exceptional situations; they should never be used for ordinary control flow.
Use checked exceptions for recoverable conditions and run-time exceptions for programming errors

There are three types of exceptions in Java
1.       Checked Exceptions: These are exceptions that can be handled by the client. E.g. IOException, FileNotFoundException.  The compiler will force the user of the API to handle such exceptions. I.e. the user needs to either declare it in the methods throws clause or needs to put the code within a try – catch block where the Exception is handled.
2.       Run Time Exceptions: E.g. ArrayIndexOutOfBoundsException, NullPointerException. These are subclasses of java.lang.RuntimeException. The compiler will not force the user of the API to handle such exceptions.
3.       Errors: These are serious errors from which the users cannot be excepted to recover. OutOfMemoryError is an example of this. These are subclasses of java.lang.Error.
The Checked Exceptions should be mentioned in the throws clause so that the user of the API can handle it or pass it on to its caller to be handled by it.
Runtime exceptions should normally not be thrown or handled. But run-time can be used to indicate programming errors. E.g. one could throw an IllegalArgumentException if any of the parameters passed to the method does not meet the preconditions expected of it.
Errors should normally never be thrown or handled by any method.
Avoid unnecessary use of checked exceptions

 A method should throw as less a number of checked exceptions as possible. Throwing more checked exceptions makes it difficult for the user of the API to use the API and the user ends up handling a generic Exception. Throw checked exceptions if and only if the user of the API can recover from the exception that has been raised.
If some exceptions can be prevented by providing APIs for checking conditions that can throw the exceptions provide this function so that the user can use this API instead of handling a RunTimeException. E.g. if a method of a class can be invoked conditionally then provide a method by which the user can check if the method can be invoked before invoking the method so that we can throw a Run Time exception from the method if there is an issue.
E.g. instead of forcing the user to write a code as follows:
try {
    obj.action(args);
} catch(MethodAccessDeniedException e) {
    //Handle Exception
}
We could provide a method called has Access and allow the user to write  code as
if (obj.hasAccess(args)) {
    obj.action(args);
} else {
    //Handle no access situation
}
If a user invokes obj.action(args) without first checking for has Access then the user may get an RunTimeException.
Throw Exceptions Appropriate to the Abstraction

Sometimes if APIs throw Exceptions which are seemingly out of place it can be very confusing. This typically happens if one were to throw an Exception generated at the lower level directly to the upper level. To avoid this, higher layers should catch lower level exceptions and in their place throw exceptions that are explainable In terms of the higher-level abstraction. When doing this it is important to ensure that the lowest level of Exception and the stack trace associated with it is not lost. This can be achieved by using Exception chaining.
try {
    ….
} catch(LowerLevelException e) {
    throw new HigherLevelException(e);
}

Document all Exceptions thrown by each Method

Always document the exceptions that will be thrown by method. Never use a generic exception like java.lang.Exception or java.lang.Throwable to indicate the Exception thrown. This gives the user of API no idea of what actually is the Exception that is being thrown from the API.
1.       Document every checked Exception that the method can throw using the @throws tag and include them in the throws keyword in the method declaration.
2.       Document every unchecked Exception that the method can throw using the @throws tag, but do not declare it in the throws keyword along with the checked exceptions in the method declaration.
3.       If an exception is thrown by many methods in a class for the same reason then it is not wrong to document this at the class level indicating the reason for the methods throwing this exception.
Include failure-capture information in detail messages

When a program fails due to an unhandled exception the system automatically prints the stack trace which includes the detailed message in the Exception. This will typically be the only information somebody has to figure out what went wrong. So to make this comprehensive the message should contain the all the parameter values and field values that contribute to the exception. One way to ensure that the Exception has all the details required is to create a constructor which forces the user to provide the required information by default.
Strive for failure atomicity

Generally speaking, a failed method should leave the object in the state that it was in prior to the invocation. A method with this property is said to be failure atomic.
The ways to achieve this are
1.       Make the class immutable. This will ensure that the object is never altered irrespective of the exception thrown from any method
2.       Check the parameters and fields for validity before proceeding with the method execution. This will ensure the exception is thrown even before the object is mutated.
3.       Another option is to write a recovery code which can be invoked before an exception is throw to restore the object the state prior to the invocation of the method that is throwing the exception.
4.       The last option is to make a temporary copy of the object and work on it and if no exception occurs restore the new state to the original object. This can be an expensive operation and should be done if an only if really necessary.
This should be avoided if it makes the code more complex or if it drastically reduces the performance of the system.
Don’t ignore Exception

Of an exception is caught then it should be handled correctly. One should not have a code as follows:
try {
    …
} catch (SomeException e) {
}
An empty catch block defeats the purpose of exceptions which is to force the user to handle exceptional situations.
At the minimum have a comment explaining why the exception is being ignored.

In the next post we will read about best practices of using Threads in Java.

This is the sixth post based on the book Effective Java by Joshua Bloch. In the previous post we read about best practices to write good methods in Java.

This post covers General Programming practices which will help writing good quality code.

Minimize the scope of the local variables

Declare variables at the last possible moment. Defining variables before they are really required can mean that the scope of the variable may turn out to be more than necessary, it may inadvertently be used before it is logically initialized, it can be used accidently after its scope has finished. All of these can have disastrous impact on the application. Also somebody reading the code can tend to forget the type of the variable if it is used far away from where it is declared.
Every local variable should contain an initializer. The only exceptions can be variables which are required in the finally block when exceptions are handled.
Know and use the libraries

It is important to learn the libraries available and leverage them. Libraries including standard Java library are changing and becoming more powerful as time progresses and unless one keeps track of the changes one would end up performing unnecessary coding to achieve something which can be better done by some library method.
Understand and then keep abreast of changes to at least java.lang, java.util and java.io.
Avoid float and double if exact answers are required

The float and double types will not give precise values. They are not suited for monetary calculations. Rounding off will also not help. Use BigDecimal or int or long for monetary calculations.
Also when using BigDecimal ensure to instantiate as follows:
BigDecimal tenPaise = new BigDecimal(“0.1”);
not
BigDecimal tenPaise = new BigDecimal(0.1);
Note that in the second case we end up using a float value inadvertently and this will result in the BigDecimal getting a value close to 0.1 and not exactly 0.1, whereas in the first case since we have used a String as the parameter it will give a precise value of 0.1.
Avoid Strings where other types are more appropriate

Do not use String type variables to represent data which is actually of a different data type. E.g. when data is received from a browser or read from a file it typically is in the form of a string and one tends to carry forward the same till it is necessary to deal with the actual data type. Instead convert the strings to the correct data type at the first opportunity and convert them back into strings only at the last possible moment.
Do not concatenate string representation of strings to form a key for a Map. Instead use a helper class which implements the correct equals and hashCode method to contain the fields that are required for the key.
Beware the Performance of String Concatenation

Using the “+” operator to concatenate strings is a big overhead. Instead use a StringBuffer if one needs the variable to be thread safe or better still use StringBuilder if one is sure that it is not necessary for the variable to be thread safe.
Additionally prime the StringBuffer or StringBuilder with the expected size it is expected to grow to if it is possible.
Prefer Interfaces to Reflection

Reflection in Java is a very powerful feature which allows one to interact with the objects at runtime by discovering what the object supports and using them.
But this comes at a cost and should be avoided as far as possible. Instead of reflection one should consider use of Interfaces.
Reflection comes with the following disadvantages:
1.       All benefits of compile time checking is lost.
2.       The code required to perform reflective access is clumsy and verbose.
3.       Performance of code using reflection will be slower than code that does not use reflection
If the issue to determine the class at runtime then one should define an interface, use the interface in the code and at run time use reflection to instantiate the class (factory pattern). This way we can keep reflection to the minimum while retaining benefits that accrue with usage of interfaces.
Note that all Object Relation Mapping libraries use reflection.

Use Native Methods Judiciously

Java provides a way to execute native code. This was used to get better performance and/or to use some native library functions. But given the progress that JVM has made one should use native calls if and only if that is the last resort to use a library that is available only in the native format. It is not worth the trouble of using native calls for improved performance.
Optimize Judiciously

Many a times the developers have the tendency to optimize as they are writing the code. Here are some aphorisms about optimization that should be known and adhered to by all:
1.       More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason – including blind stupidity. William A Wulf
2.       We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Donald E. Knuth
3.       We follow two rules in matter of optimization
a.       Rule 1: Don’t do it
b.      Rule 2 (for experts only): Don’t do it yet – that is not until you have a perfectly clear and unoptimized solution.
M. A. Jackson
Corollary is “Strive to write good programs rather than fast ones”.
But the same time
1.       Strive to avoid design decisions that limit performance. It is difficult to change APIs, wire-level protocols, and persistent data formats. These should be considered carefully at design time to provide good performance right at the start.
2.       Consider performance consequences of your API decisions.
3.       Measure performance before and after each attempted optimization.
Adhere to generally accepted naming convention

There is a generally accepted naming convention for the Java language. Adhere to this naming conventions and avoid violating these unless there is real reason to do so. It will make the program understandable and maintainable by a larger audience. Some conventions are
1.       Package names should be in lower case
2.       Package names can have abbreviated words
3.       Class names should start with a Capital letter
4.       Method, Attribute and Variable names should start with lower case
5.       Typically Acronyms used in Class, Method, Attribute or Variable names are capitalized although there is no general agreement on this
6.       Generally Class, Method, Attribute and Variable names should have full words
7.       Use a Camel Hump notation to separate words in classname, methods, attributes and variables.
8.       Underscores are used only for constants
9.       Constants are defined with a set of Capital letters and Underscores
10.   Interfaces are named as classes or as adjectives ending with “able” or “ible”
11.   One could follow the convention of naming all interfaces starting with an “I” although this is not a convention that is followed by all. This avoids the necessity of adding an “Impl” to indicate implementation of the interface.
12.   All methods that return a Boolean value start with “is”.

In the next post we will read about best practices in Exception Handling in Java.

This is the fifth in the series of posts based on the book Effective Java by Joshua Bloch. The previous post was about best practices in converting C structures to Java.

This post gives tips and best practices on how to write good methods in the classes.

Check Parameters for Validity

Methods that expect parameters expect the parameters to adhere to certain rules. In all public methods one should validate the parameters to ensure that they adhere to the expected rules and if not they should throw the right exception. It is also important that the constraints on the parameters be well documented.
For private methods we should ensure that we pass only the right attributes and instead of checking and throwing exceptions use Assertions.
It is very important that the parameters to the constructors are validated correctly.
The only exception under which one should not validate the parameters is, when there is a huge overhead in the validation.
Make Defensive Copies when needed

Normally a class should not expect an external class to be able to change the values of its attributes without its knowledge. But when a class contains mutable objects it is easy to allow clients to change the attributes without the class knowing it.
E.g. consider the following class:
public final class Period {
    private final Date start;
    private final Date end;
    public Period(Date start, Date end) {
        if (start.compareTo(end) > 0) {
            throw new IllegalArgumentException(start + “ after “ + end);
        }
        this.start = start;
        this.end = end;
    }
    public Date start() {
        return start;
    }
    public Date end() {
        return end;
    }
}
This class seems to be immutable as the only way to set the values of the start and end dates are through the constructors. But the Date class itself is a mutable class and there are two ways in which the values of the class can be changed:
1.       A client which passes the start and end date to the constructor can hold on the instance of the date and then at a later stage can change the value of these dates using the setYear, setMonth or any of the other methods.
2.       Similarly there is nothing to stop a client from invoking something as Period.start.setYear(someYear).
To avoid these we need to make copies of such mutable classes. In the constructor we can create new Date objects and store them instead of the passed date objects.
    public Period(Date start, Date end) {
        this.start = new Date(start.time());
        this.end= new Date(end.time());
        if (this.start.compareTo(this.end) > 0) {
            throw new IllegalArgumentException(start + “ after “ + end);
        }
    }
Now even if the client changes the objects that it passed to the constructor the values of the dates in the class will not change. Note that the validation was done after the copy was done. This is to prevent the situation where the value of the dates are changed after the validation and before the creation of the new dates in some other thread.
Also the clone method is not used as Date can be subclassed and a subclassed Date cannot be trusted.
Similarly we need to change the start and end methods to:
    public Date start() {
        return start.clone();
    }
    public Date end() {
        return end.clone();
    }
This will ensure that no client will be able to change the start and end attributes of this class. Note that clone has been used here as we are sure that we are using the java.util.Date and not a untrusted subclass of Date.
This is very important if we are writing a library for use by a large audience over which we have no control.
Defensive copying can be avoided if we are working with a set of trusted clients.
Design Method Signatures carefully

The following should be kept in mind when writing methods:
1.       Choose method names carefully: A method name should convey to its user the exact operation it is performing. It should not be necessary to further explain it in the method comments. What will be required in the method comments will be to specify how it can be used and what the parameter constraints are.
2.       Do not go overboard and provide too many convenience methods: Too many makes understanding the class that much difficult and that much more difficult to test. Provide convenience calls only when it is expected that the method will be used frequently. If in doubt do not provide.
3.       Avoid long parameter list: It will be very difficult to use a method which has a large number of parameters even if the users have the benefit of an IDE which prompts for parameters. This is even more problematic if there is sequence of parameters of the same type. Consider creating a helper class or splitting the methods into multiple methods which requires lesser number of parameters.
4.        When a parameter being passed to a method has an interface define the parameter as the interface rather than the concrete class that implements that interface. E.g. if a list is expected as an input specify the parameter of type List rather than specifying it of type ArrayList.
5.       Use Function Objects judiciously: Function Objects have their place in software but when overused it can make understandability of the program very difficult. It is not be shunned but it is to be used only in situations where it makes sense and allows others to understand it easily.
Function Objects are Objects which contain only Functions and no attributes. These are typically used to handle callbacks in Java. E.g. a GUI event handlers, or a class that implements Comparator interface and implements only the compare method.
Use Overloading Judiciously

One needs to be careful when overloading functions and very clear. We need to keep the following rule when we use overloading “selection among overloaded methods is static (i.e. determined at compile time), while selection among overridden methods is dynamic”. So if we overload methods then the method to be executed will be determined at compile time and irrespective of the actual run time datatype the predetermined method will be invoked.
As far as possible avoid having overloaded methods with the same number of parameters. This makes overloading very safe. If one needs to write overloaded methods with the same number of parameters then the parameter types should be very different from each other to avoid confusion.
Return Zero-length Arrays and not nulls

If a method returns an Array and conditionally it returns a null then client that invokes this method needs to check for nulls before proceeding. And if some client were to forget checking for null we will end up with Null Pointer Exception.
Instead if we return a zero length array as the output then no client needs to check for the validity of the array and we can avoid Null Pointer Exceptions.
Note that in most case the clients would have a loop which would be looping through the array and doing some processing and this will be unaffected if one returns a zero-length array.
Write doc comments for all exposed API elements

It is important to document all the public methods and attributes of a class. This will help the users of the class use it in a much better way. It is advisable to also document the protected and private methods if one wishes the code to maintainable.
The method comments must have the following:
1.       What the method does. This should pretty much be clear from the name of the method but in certain scenarios it will help if there is some additional information provided. It should never mention how the method functions.
2.       Do not have two methods or constructors with the same summary description.
3.       It should mention all of the preconditions, i.e. all the conditions that should be true before the method can be invoked.
4.       It should mention all of the postconditions, i.e. all of the things that will be true after the method has been invoked.
5.       It should mention any side effects of invoking the method
6.       The thread safety of the method should be specified especially if it is not thread safe
7.       The purpose of the parameter along with its constraints should be specified
8.       All the exceptions that the method can throw should be documented and if possible with the condition under which it can be thrown
9.       Do not have comments for getters and setters unless something unusual is being done in the method.

In the next post we will read about best General Programming practices.


Categories