Friday, June 27, 2008

Design Principle : Dependency Inversion Principle

Depend upon abstractions. Do not depend upon concrete classes.

Before delving deeper into the principle we should understand

a. What is a dependency ?
b. What is it trying to invert ? And to understand this we should understand what happens in the normal case which the principle says should be inverted ?

What is dependency ?

When a class refers another class, it is said to be dependent on the other class. Consider the following example,


Class A{
}

class B{
A obj;
}


The class B has a member variable of class A and so it is dependent on A. The dependency can be set either using constructor or setter methods.

What is the 'un-inverted' way ?

An application has high level classes and low level classes. The low level classes would implement the basic functionality and the high level classes would implement complex logic and in turn use the low level classes.
A natural way of implementing such structures would be to write low level classes and once we have them to write the complex high level classes. Since the high level classes are defined in terms of others this seems the logical way to do it.

High Level Module --> Low Level Module

Besides, as mentioned by Martin Folwer in his article he has used the word inversion because...

more traditional software development methods, such as Structured Analysis and Design, tend to create software structures in which high level modules depend upon low level modules, and in which abstractions depend upon details. Indeed one of the goals of these methods is to define the subprogram hierarchy that describes how the high level modules make calls to the low level modules. Thus, the dependency structure of a well designed object oriented program is “inverted” with respect to the dependency structure that normally results from traditional procedural methods.




What is DIP ?
  • High-level modules should not depend on low-level modules. Both should depend on abstractions.
  • Abstractions should not depend on details. Details should depend on abstractions.

According to this principle the way of designing a class structure is to start from high level modules to the low level modules:

High Level Classes --> Abstraction Layer --> Low Level

But why ?

1. If the high level modules would depend on low level modules, it would be difficult to reuse the high level modules in different contexts. And it is high level modules we generally want to reuse.

2. Its the high level modules which have business logic. Yet,when these modules depend upon the lower level modules, then changes to the lower level modules can have direct effects upon them; and can force them to change. But it should be high level modules that ought to be forcing the low level modules to change.

Advantages of DIP

1. The use of DIP makes the high level modules reusable as they are not directly dependent on low level details/modules. It helps in creation of reusable frameworks.

2. It helps in creation of code that is resilient to change. And, since the abstractions and details are all isolated from each other, the code is much easier to maintain.

Layering and DIP

According to Booch, “...all well structured object-oriented architectures have clearly-defined layers, with each layer providing some coherent set of services though a well-defined and controlled interface.”

For example, lets consider the three layers A->B->C. In this case the layer A is sensitive to all the changes down in layer C. Dependency is transitive.

Using DIP, A->IB->BImpl->IC->CImpl

Here, each of the lower layers are represented by an abstract class. Each of the higher level classes uses the next lowest layer through the abstract interface. Thus, none of the layers
depends upon any of the other layers. Instead, the layers depend upon abstract classes. Not only is the transitive dependency of A Layer upon C Layer broken, but even the direct dependency of A Layer upon B Layer broken.

Program to interfaces, not implementation

The point is to exploit polymorphism by programming to a supertype so that the actual runtime object is not locked into the code. And the supertype can be an interface or an abstract class.

Guidelines (Not rules !!!)

1. No variable should hold a reference to a concrete class. (If you use new, you would hold reference to a concrete class. Use factory to get that around.)

2. No class should derive from a concrete class.

3. No method should override an implementation method of any of its base classes.

Saturday, June 14, 2008

Encapsulation - a big chunk of the PIE

Most of the programmers would respond saying...Encapsulation is about making variables private and exposing them using public properties or methods i.e. you have put the variables in a capsule !!!

This is indeed true but there is something more to encapsulation. If we go by this definition we have capsuled the properties.

The things that can be encapsulated are

1. Private Data
2. Public properties !!!
3. Behavior !!!

2 and 3 would be something new to people familiar with the classic definition of encapsulation. So encapsulation is not just about keeping data in your classes separate from rest of your application it is also about grouping your application into logical parts i.e. protect information in one part of your application from other parts. It is also known as information hiding (and now you know this information is not just data) or separation of concerns.

Why to encapsulate ?

When you break the behavior or properties out from a class, you can change the behavior without changing the class. So by breaking up the different parts of your application, you can change one part without having to change all the other parts. So encapsulation makes your code easier to change and leads to a flexible software.


When to encapsulate ?

1. Anytime you see duplicate code, look for a place to encapsulate.

2. Encapsulate what varies.

How to encapsulate ?

Take the portions that you want to move out from a class and move them into a new class and you have achieved encapsulation. So one way of encapsulating is by creating classes.

Now lets talk about encapsulating properties and behavior.

Encapsulating properties (group of properties)

Lets assume you have the following two classes

1. Book
-Name
-Author
-SerialNumber
-Price

2. BookStore
-Book[] Search(Book)
-AddBook(Book)

The Search method takes Book parameter for searching the books. The Book parameter is used to hold the search specification by user i.e Name and Author. The user can't specify SerialNumber and Price and hence they would be null when passed to Search.

Something is wrong !!! The Book object does not seem to represent a single concept, it is representing both the Book entity and search specification. So time to create a new a new class BookSpec which has Name and Author as properties.

1. Book
-Name
-Author

-SerialNumber
-Price

2. BookStore
-Book[] Search(BookSpec)
-AddBook(Book)

3. BookSpec
-Name
-Author


Still something that can be impoved...duplicate code. The Name and Author are same in both BookSpec and Book. So lets move Name and Author out of Book and instead let it refer BookSpec.


1. Book
-BookSpec
-SerialNumber
-Price

2. BookStore
-Book[] Search(BookSpec)
-AddBook(Book)

3. BookSpec
-Name
-Author


So you have encapsulated a group of properties from Book class into BookSpec class. So would you still say encapsulation is just about private properties :)

Infact, we have also touched upon an interesting pattern called the Specification pattern which we would be discussing in a separate post. You can refer to Martin Fowler's article but it would need
a lot of patience ;)

Encapsulating behavior

Say we have a Car class..

Car
-Start()
-Stop()
-Drive()

Anything wrong !!! Do you think that car drives itself ? Isn't it the driver who would driver the Car ?

So lets create two classes

Car
-Start()
-Stop()

Driver
-Drive(Car)

Though not a very good example, still I think we have seen how behavior can be encapsulated in a new class.

Let me know if the post was helpful !!!

Why did the title say that encapsulation is the big chunk of the PIE (Polymorphism, Inheritence and Encapsulation). Don't you think that Inheritence and Polymorphism are specialised forms of encapsulation ? Ah....forget it if it confused you.

Single Responsibility Principle, Don't repeat yourself

A pretty straight forward principle but at the same time difficult to detect its violations.

A few definitions...

1. Each object is interested in doing its job, and only its job.

2. Every object in your system should have a single responsibility and all the object's services should be focussed on carrying out that responsibility.

3. A class should have only one reason to change.

4. Cohesion is another name for SRP. If you are writing highly cohesive software, then that means you are correctly applying SRP.

How to detect SRP violations ?

1. Objects should do what their names indicate.
2. Each object should represent a single concept.
3. Unused properties are a dead giveaway. If you have an object that is being used with null prperties most often, then you probably have an object doing more than one job. Why is the property there in the first place ?

Would suggest reading through the article at objectmentor.com

A some what related principle is DRY (Don't repeat yourself). It says 'Avoid duplicate code by abstracting out things that are common and placing those things in a single location.' Duplicate code would always lead to maintenance nightmares !!!

DRY is about having each piece of information and behavior in your system in a single place. It is also called as Say it once and Only once.

Q. How does removing code duplication help in improving cohesion ?

One of the best ways to improve cohesion in your system is to eliminate duplication wherever you spot it. It's probably best if you assume that you don't know exactly how your system is going to change in the future, but you can improve your code's ability to accept change by maintaining good cohesion and coupling in class structures. One of the best ways to improve the cohesion quality of your codebase is to simply pull out duplication into separate classes that can be shared across the codebase.

Sunday, June 1, 2008

Delegation - Simple yet powerful concept

What is delegation and why is it powerful ?

Delegation is very simple to understand. Thats what all the team leads and track leads do every time, isn't it ? Don't work on your own but delegate it to the team members :)

In object oriented programming, delegation is used to describe a situation where one object defers task to another object, known as delegate.


class A {
public virtual void Foo() {
Console.Write("Object A doing the job.");
}
}


class B {
A obj = new A();

public virtual void Foo(){
obj.Foo();
}
}

Any object of class B will delegate execution of function Foo to object of class A.

But is that a big deal ? There would be many classes in my system and they would use each other.
1. So is every call made by an object to another object is delegation ?
2. And why is so powerful ?

For 1, I would say Yes. If an object calls a method of another object it is delegation.

For 2, lets rewrite the above example as

class A {
public virtual void Foo() {
Console.Write("Object A doing the job.");
}
}
class B{
A obj = null;
public B(A a){
obj = a;
}
public virtual void Foo(){
obj.Foo();
}
}
A obj = new A();
B obj2 = new B(obj);
obj.Foo();

Now, one can change the behavior of objects of class B without having to change the code of class B itself, by deriving new delegates from A and that makes it powerful. (Obviously it makes of dynamic binding in that case.)

One of the task that an object should always delegate is checking for equality of other objects.

class A {
private String name;
public A(String name){
this.name = name;
}
public String Name{
get{
return this.name;
}
}
public override bool Equals(object obj){
A obj1 = obj as A;

if (obj1 == null){
return false;
}
return String.Equals(obj1.name, this.name);
}
}


Lets assume that two instance of A would be considered equal if they have the same name, then one of the ways to check for equality is as below

A obj1 = new A("test");
A obj2 = new A("test1");
if (obj1.Name == obj2.Name){
}

But this is not a good idea as any change in class A might lead to a change in the class where this piece of code is written. The other better option is to delegate it to class A as

if (obj2.Equals(obj1)){
}


All said and done, delegation helps

1. Your application stay loosely coupled. That means your objects are independent of each other i.e. changes in one object don't require you to make changes to other objects. Delegation shields your objects from implementation changes to other objects in your software.

2. It makes your code reusable. It lets each object worry about its own task. This means your objects are more independent of each other i.e. loosely coupled. And looslely coupled objects can be taken from one application and easily be reused in other as they are not tightly tied to the other object's code.

Another question that comes to my mind...is delegation always achieved through composition ?

Also, when you would compile class A above, you would get a warning

'ConsoleApplication1.A' overrides Object.Equals(object o) but does not override Object.GetHashCode(). Leaving that for self study :)