Tuesday, July 5, 2011

Software Design is “good” or “bad”

Good Design:
1. Flexible (easy to change or extend),
2. Robust (reacts well to changes i.e. doesn’t break everywhere) and
3. Reusable (the parts of the system are very decoupled and we can extract them and use them in other projects)

Bad Design:
1. (Rigidity) It is hard to change because every change affects too many other parts of the system.
2. (Fragility) When you make a change, unexpected parts of the system break. Fragility is the tendency of a program to break in many places when a single change is made.
3. (Immobility) It is hard to reuse in another application because it cannot be disentangled from the current application. A design is immobile when the desirable parts of the design are highly dependent upon other details that are not desired.


Java Common Mistakes (Atnipatterns)

This blog collects some bad code that may not look so obiously bad for beginners. Beginners often struggle with the language syntax. They also have little knowledge about the standard JDK class library and how to make the best use of it.

In the end a lot of your application's performance depends on the overall quality of your code. By the way you should never underestimate the importance of memory footprint. Even though the Garbage Collection is quite fast, most server-side code's scalability is dominated and limited by its memory usage of per request/transaction duration.

1. Java Common Mistakes (part 1)
2. Java Common Mistakes (part 2)
3. Java Common Mistakes (part 3)


Monday, July 4, 2011

Java Common Mistakes (Part 3)

1. Accessing non-static member variables from static methods (such as main)
Particularly when first introduced to Java, Many programmers have problems with accessing member variables from their main method. The method signature for main is marked static - meaning that we don't need to create an instance of the class to invoke the main method. For example, a Java Virtual Machine (JVM) could call the class MyApplication like this :-

MyApplication.main ( command_line_args );

This means, however, that there isn't an instance of MyApplication - it doesn't have any member variables to access! Take for example the following application, which will generate a compiler error message.

public class MyApplication {
public String my_member_variable = "somedata";
public static void main (String args[]) {
// Access a non-static member from static method
System.out.println ("This generates a compiler error" + my_member_variable );
}
}

If you want to access its member variables from a non-static method (like main), you must create an instance of the object. Here's a simple example of how to correctly write code to access non-static member variables, by first creating an instance of the object.

public class MyApplication {
public String my_member_variable = "somedata";
public static void main (String args[]) {
MyApplication myApplication = new MyApplication();
// Access member variable of myApplication
System.out.println ("This WON'T generate a compilation error" + myApplication.my_member_variable);
}
}


2. Null pointers
Null pointers are one of the most common errors that Java programmers make. Compilers can't check this one for you - it will only surface at runtime, and if you don't discover it, your users certainly will.

When an attempt to access an object is made, and the reference to that object is null, a NullPointerException will be thrown. The cause of null pointers can be varied, but generally it means that either you haven't initialized an object, or you haven't checked the return value of a function.

Many functions return null to indicate an error condition - but unless you check your return values, you'll never know what's happening. Since the cause is an error condition, normal testing may not pick it up - which means that your users will end up discovering the problem for you. If the API function indicates that null may be returned, be sure to check this before using the object reference!

Another cause is where your initialization has been sloppy, or where it is conditional.

Sometimes your variables (the array of strings) will be initialized, and other times they won't. One easy solution is to check BEFORE you attempt to access a variable in an array that it is not equal to null.

3. Confusion over passing by value, and passing by reference
This can be a frustrating problem to diagnose, because when you look at the code, you might be sure that its passing by reference, but find that its actually being passed by value. Java uses both, so you need to understand when you're passing by value, and when you're passing by reference.

When you pass a primitive data type, such as a char, int, float, or double, to a function then you are passing by value. That means that a copy of the data type is duplicated, and passed to the function.
If the function chooses to modify that value, it will be modifying the copy only. Once the function finishes, and control is returned to the returning function, the "real" variable will be untouched, and no changes will have been saved. If you need to modify a primitive data type, make it a return value for a function, or wrap it inside an object

When you pass a Java object, such as an array, a vector, or a string, to a function then you are passing by reference. Yes - a String is actually an object, not a primitive data type. So that means that if you pass an object to a function, you are passing a reference to it, not a duplicate. Any changes you make to the object's member variables will be permanent - which can be either good or bad, depending on whether this was what you intended.

On a side note, since String contains no methods to modify its contents, you might as well be passing by value.


4. In Java, a single equal sign ( = ) is an entirely different operator than a double equal sign ( == ). In most cases, use the double equal sign when creating a loop or conditional statement and use the single equal sign everywhere else. For example:
To compare a and b for equality, use a==b; (note the double equal sign).
Where b has the same value as a, use a=b; (note the single equal sign).

5. Forget to initialize Object Arrays
A Java array declared for an object type is really an array of object references. Creating the array, with new, simply creates empty references. The elements of the array are all set to null. You have to set each element to a real object reference in order to fill the array. Many students misunderstand this and they think that creating an object array creates all the actual objects. (In many cases, this is a concept that the student carries over from C++, where creating an array of objects does create all the objects by calling their default constructor.)

In the following example, the student wants to create three StringBuffer objects to hold some data. This code will compile, but will throw a NullPointerException on the last line where one of the (non-existent) objects is used.

Mistake Example:

// Create an array of data buffers
StringBuffer[] myTempBuffers;
myTempBuffers = new StringBuffer[3];
myTempBuffers[0].append(data);

To correct this problem, it is important to remember to initialize the elements of any Java array.

// Create an array of data buffers and initialize it.
StringBuffer[] myTempBuffers;
myTempBuffers = new StringBuffer[3];
for (int ix = 0; ix < myTempBuffers.length; ix++)
myTempBuffers[ix] = new StringBuffer();
myTempBuffers[0].append(data);

6. Putting several public classes in one file
Java source code files have a special relationship to the classes in those files.
The rules can be summarized as follows:

1. Any Java class is defined in exactly one source file
2. At most one public class may be defined by any one source file
3. If a public class appears in a source file, the name of the file and the name of the class must be the same (case sensitive).

Sometimes, a student will forget the second rule in their rush to code up a lab exercise or project. They'll put two or more public classes into a source file.

7. Forgetting to make sure that system resources (network or database connections, streams) are freed by calling close() in a finally block. Assuming that you can't produce a memory leak in Java because it has garbage collection

8. Using the Singleton design pattern in an environment with multiple class loaders

9. Omitting break from case statements

10. Using a variable before it is given a value

11. Forgetting that arguments are passed by reference to methods if they are objects

12. Mistyping the name of a method when overriding

13. Forgetting that Java is zero-indexed

14. Capitalization errors
This is one of the most frequent errors that we all make. It's so simple to do, and sometimes one can look at an uncapitalized variable or method and still not spot the problem. You can easily train yourself to make less of them. There's a very simple trick you can learn :-

1. all methods and member variables in the Java API begin with lowercase letters
2. all methods and member variables use capitalization where a new word begins e.g - getDoubleValue()

15. Hashtable, HashMap and HashSet are overrated
These classes are extremely popular. Because they have great usability for the developer. Unfortunately they are also horribly inefficient. Hashtable and HashMap wrap every key/value pair into an Entry wrapper object. An Entry object is surprisingly large. Not only does it hold a reference to key and value, but also stores the hash code and a forward reference to the next Entry of the hash bucket. When you look at heap dumps with a memory analyzer you will be shocked by how much space is wasted by them in large applications like an application server. When you look at the source code of HashSet you will see that the developers were extremely lazy and just used a HashMap in the backend!

Before using any of these classes, think again. IdentityHashMap can be a viable alternative. But be careful, it intentionally breaks the Map interface. It is much more memory efficient by implementing an open hashtable (no buckets), doesn't need an Entry wrapper and uses a simple Object[] as its backend. Instead of a HashSet a simple ArrayList may do similarly well (you can use contains(Object)) as long as it's small and lookups are rare.
For Sets that contain only a handful of entries the whole hashing is overkill and the memory wasted for the HashMap backend plus the wrapper objects is just nuts. Just use an ArrayList or even an array.

Friday, July 1, 2011

The Principles of Object Oriented Design/Classes

The principles of object oriented design are abbreviated under the acronym SOLID which stands for:

S - The Single Responsibility Principle (SRP)
O - The Open Closed Principle (OCP)
L - The Liskov Substitution Principle (LSP)
I - The Interface Segretation Principle (ISP)
D - The Dependency Inversion Principle (DIP)

These principles represent
1. a set of rules that allows us to improve the way we design and
2. set up the dependencies between our classes and
3. it allows us to create more flexible, maintainable, reusable and robust code.

Thursday, March 10, 2011

Inheritance and Polymorphism

Inheritance and polymorphism are really just two ways of looking at the same class relationship. Inheritance is looking at the class hierarchy from the bottom up. A subclass inherits behaviors and attributes from its superclass. A subclass automatically possesses certain behaviors and/or attributes simply because it is classified as being a subclass of an entity that possesses those behaviors and/or attributes.

Inheritance is useful from a code reuse perspective. Any (non-private) code in the superclass does not have to be replicated in any of the subclasses because they will automatically inherit those behaviors and attributes. However, one must be very careful when transferring common code from the subclasses to the superclass, as the proper abstraction represented by the superclass may be broken.

Polymorphism, on the other hand, is looking at the class hierarchy from the top down. Any subclass can be used anywhere the superclass is needed because the subclasses are all abstractly equivalent to the superclass. Different behaviors may arise because the subclasses may all have different implementations of the abstract behaviors defined in the superclass.

Polymorphism is arguably the more useful perspective in an object-oriented programming paradigm. Polymorphism describes how an entity of a lower abstraction level can be substituted for an entity of a higher abstraction level and in the process, change the overall behavior of the original system. This will be the cornerstone that enables us to build OO systems that are flexible, extensible, robust and correct.

Thursday, December 23, 2010

UML one liner

1. The UML gives everyone from business analyst to designer to programmer a common vocabulary to talk about software design.
2. Use Case diagrams help you specify the user goals that the system must carry out.
3. Class diagrams show the physical structure of the objects in the system and their static relationships.
4. Sequence and collaboration diagrams show the dynamic interactions between instances used to carry out a single use case.
5. Use case diagrams describe what a system does from the standpoint of an external observer. The emphasis is on what a system does rather than how.
6. A model is an abstraction of the underlying problem.
7. The domain is the actual world from which the problem comes.
8. Models consist of objects that interact by sending each other messages.
9. Objects have things they know (attributes) and things they can do (behaviors or operations). The values of an object's attributes determine its state.
10. Classes are the "blueprints" for objects. A class wraps attributes (data) and behaviors (methods or functions) into a single distinct entity.
11. Objects are instances of classes.
12. An actor is a person, organization, or external system that plays a role in one or more interactions with your system.
13. Use Cases are used to specify the functional requirements of the system.

Wednesday, December 22, 2010

UML: Unified Modeling Language

Unified Modeling Language or UML is the standard language for describing, visualizing, and documenting the object-oriented (OO) systems. UML is a collection of a variety of diagrams for different purposes and each type of diagram models a particular aspect of OO design in an easy to understand and visual manner.

The UML standard specifies exactly how the diagrams are to be drawn and what each component in the diagram means. UML is not dependent on any particular programming language, instead it focuses one the fundamental concepts and ideas that model a system.

It is a standardized language in which to specify the artefacts and components of a software system, how the diagrams are to be drawn and what each component in the diagram means. It is important to understand that the UML describes a notation and not a process. It does not put forth a single method or process of design, but rather is a standardized tool that can be used in a design process.

The UML gives everyone from business analyst to designer to programmer a common vocabulary to talk about software design.