Friday, June 27, 2008

Dependency Inversion Principle

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.

Sunday, June 15, 2008

Best practices for statics

1. .NET also supports type constructors also known as static constructors, class constructors or type initializers. A type's constructor is guaranteed to run before any instance of the type is created and before any static field or method of the type is referenced.

a. Implicit static constructor

class AType {
static int x = 5;
}


When this code is built, the compiler automatically generates a type constructor for AType. This constructor is responsible for initializing the static field x to the value 5.

b. Explicit static constructor



class AType {
static int x;

static AType() {
x = 5;
}
}


When you run FxCop, b would give a warning "Do not declare explicit static constructors." The rule description tells you that an explicit static constructor results in code that performs worse. The recommendation from FxCop is to initialize static fields where they are declared. The reason for this is that implicit static constructors can be run at anytime the runtime where as if an explicit static constructor is defined, the runtime must run the type constructor at a precise time—just before the first access to static or instance fields and methods of the type and the precise timing restrictions lead to the performance drop hinted at by FxCop. The checks that the runtime performs in order to run the type initializer at a precise time adds overhead.

2. Exceptions in static constructors

a. The runtime will stop any exceptions trying to leave a type constructor and wrap the exception inside of a new TypeInitializationException object. The original exception thrown inside the type constructor is then available from the InnerException property of the TypeInitializationException object. One reason this special behavior might occur is that the second time you try to access a static property of the type, the runtime does not try to invoke the type constructor again, but throws the same exception observed in the first iteration. The runtime does not give a type constructor a second chance. The same rules hold true if the exception is thrown from a static field initializer. As you saw earlier, the code for a static field initializer executes inside an implicit type constructor.

b. A TypeInitializationException can be a fatal error in an application since it renders a type useless. You should plan to catch any exceptions inside of a type constructor if there is any possibility of recovering from the error, and you should allow an application to terminate if the error cannot be reconciled.

c. When an exception is thrown, the runtime will begin to look for the nearest catch clause whose filters specify that it can handle the exception.

3. The rule of thumb here is to avoid touching the static members of another type from within a type constructor. Although the chances of seeing the previous scenario are slim, the effects would be difficult to debug and track down since there are few diagnostics available.

4. Static members are not inherited. Though static members are not inherited, they can still be accessed with derived class type.

5. If you have a class with only static members, you would not want to
a. Allow it to get derived (use sealed keyword)
b. Allow it to be instantiated (private default constructor)

A solution to both of this is the static classes.

The new syntax allows the compiler to enforce a number of new rules.

a. You cannot declare a variable of type Static1 because it is marked as a static class.
b. You also cannot derive from Static1, or add any non-static members to the class.
c. Note also that it's an error to derive a static class from any class other than object.

6. You should also remember that static classes that preserve state between method calls should be made thread safe by default. Making a class thread safe requires additional care during the implementation and testing of the class. Before going down this road, ask yourself if the extra overhead is absolutely necessary.



7. The .NET Framework guarantees thread safety on static type initialization.



class Singleton{
public static readonly Singleton Instance = new Singleton();
}