Archive for October, 2006

Principles of Object Oriented Design

Some of the principles and guidelines on which oo design of software systems is based are discussed here:

The Open-Closed Principle
This principle was coined by Bertrand Meyer in 1988. It states that: The modules, methods, and classes should be open for extension, while closed for modifications. It encourages software professionals to write their code in such a manner that adding new functionality would involve making minimal modifications to existing codebase. Making changes to existing code is always tricky and runs the risk of introducing new bugs and problems.

Liskov’s Substitution Principle
The principle states that: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T. In other words, when your code is expecting an object of a base class, you should be able to pass an instance of your derived class without any problems and without changing the behavior of your program!!

Loose coupling (dependeny), High cohesion
Cohsion refers to how strongly the operations within a routing (class) are related. Coupling refers to the strength of connection or dependency between two routines (classes). Coupling is the complement to cohesion.

Favor composition over inheritance
Inheritance isn’t necessarily the best answer when you have to spread a changeable task over several generations of classes. Separate the part of the code that will change the most from the rest of your application.

Leave a Comment

Interfaces and Abstract Classes in .NET

An interface is a contract. When a class implements an interface, it needs to fulfill that contract. Lets take a look at differences between interfaces and abstract classes in C#.

Item Interfaces Abstract Classes
Member declarations Interface members have public access by default. A custom access is illegal. Class members can have access other than public.
Members Interfaces cannot contain any member fields (indexers, events, methods and properties are allowed). An abstract class may contain data members as well.
Method Definition An interface may only contain declarations. An abstract class may also contain definitions or implementations.
Inheritance A struct or a class may implement (or inherit from) multiple interfaces. A (abstract) class may inherit from only one (abstract) class.Also, a struct cannot inherit from a user-defined class (they inherit from System.ValueType).
Inheritance 2 An interface may inherit from multiple interfaces. An (abstract) class may inherit from only one (abstract) class.
Usage Interfaces may be implemented explicitly or implicitly. An abstract class is always inherited from implicitly.
Static An interface may not contain any static methods. An abstract class may contain static methods.
Binding Interface use late binding, but since the methods in an interface are not virtual, the polymorphic behavior is limited to only one level down in the inheritance hierarcy.* An abstract class may define abstract or virtual methods. Their implementations are late bound, and may be overridden in any derived class in the inheritance hierarchy.

* Say I have an interface ITest and 2 classes as follows:

interface ITest
{
void JustDoIt();
}
class Base: ITest
{
public void JustDoIt() {System.Console.WriteLine(“Base”);}
}
class Derived: Base, ITest // Derived class implements ITest
{
public void JustDoIt() {System.Console.WriteLine(“Derived”);}
// Note – Visual Studio warns that: ‘Derived.JustDoIt()’ hides inherited member ‘Base.JustDoIt()’. Use the new keyword if hiding was intended.
}
class Derived2: Base // Derived class does not implement ITest
{
public void JustDoIt() {System.Console.WriteLine(“Derived2″);}
// Note – Visual Studio warns that: ‘Derived2.JustDoIt()’ hides inherited member ‘Base.JustDoIt()’. Use the new keyword if hiding was intended.
}

Derived o = new Derived();
o.JustDoIt(); // prints “Derived”;
((Base)o).JustDoIt(); // prints “Base”
((ITest)o).JustDoIt(); // prints “Derived”

Derived2 o2 = new Derived2();
o2.JustDoIt(); // prints “Derived2″
((Base)o2).JustDoIt(); // prints “Base”
((ITest)o2).JustDoIt(); // prints “Base”

Methods in an interface are not virtual by default. But the implementation CAN make them virtual, and this is allowed. For example, you could have an implementation like:

class MyBase: ITest
{
public virtual void JustDoIt() { System.Console.WriteLine(“MyBase”); }
}

Now you can override JustDoIt in a class that inherits from MyBase and you get no warnings. Additionally you get full polymorphic behavior just like having an abstract class. The distinction between abstract classes and interfaces really starts to get fuzzy here.

In fact, if you could make MyBase abstract, and you don’t have to define even a default implementation for JustDoIt. I don’t know what purpose this serves! :)

abstract class MyAbstractBase: ITest
{
public abstract void JustDoIt();
}

Leave a Comment

Access Modifiers in .NET

Here is some interesting information about Access Modifiers in .NET that you may not know.

  1. .NET supports 4 access modifiers – public, protected, private and internal. First three are obvious, the last one – internal, provides public access within that assembly, and private access outside it for type members. When used with types, internal hides accessibility of type outside the assembly.

    Typically, these access modifiers are used only one at a time. The only exception is ‘protected internal‘ – it is used to specify public access within the assembly, and protected access outside it.

  2. All the members of an enumeration have public access by default. You cannot provide any other access. Ditto for interfaces.
  3. Members of a struct can only have public, internal and private acess. Having protected acess members doesn’t make any sense structs cannot be inherited from. The default accessibility of members in structs and classes is private. (This is interesting in comparison to C++. In C++ there is no difference between classes and structs except the default access is public in structs and private in classes)
  4. While declaring interfaces, classes, structs and enumeration, the allowed access modifers are public and internal. These control access at assembly level, not namespace level. The default is internal.
  5. The exception to the above rule is when you declare classes, structs, enumerations or interfaces within another class or struct, instead of at the namespace level. While doing so, you may use public, internal and private within structs and public, protected, private, internal and protected internal within classes.
  6. .NET supports only public inheritance. So an access modifier is never used in inheritance relationships (unlike C++) – public is implied by default.
  7. Classes and structs may have static constructors. Static constructors are parameterless, and are used to initialize static members when that type is first referenced. With static constructors, no access modifiers are permitted.
  8. Here are some restrictions on using accessibility levels (copied from MSDN/C#)
    1. The direct base class of a class type must be at least as accessible as the class type itself
    2. The explicit base interfaces of an interface type must be at least as accessible as the interface type itself.
    3. The return type and parameter types of a delegate type must be at least as accessible as the delegate type itself.
    4. The type of a constant must be at least as accessible as the constant itself.
    5. The type of a field must be at least as accessible as the field itself.
    6. The return type and parameter types of a method must be at least as accessible as the method itself.
    7. The type of a property must be at least as accessible as the property itself.
    8. The type of an event must be at least as accessible as the event itself.
    9. The type and parameter types of an indexer must be at least as accessible as the indexer itself.
    10. The return type and parameter types of an operator must be at least as accessible as the operator itself.
    11. The parameter types of a constructor must be at least as accessible as the constructor itself.

Comments (2)

C# Value Types

C# data types fall into two main categories – Value Types and Reference Types. (C# also supports Pointer Types in unsafe contexts, but we shall skip that at the moment.)

Value types consist of two main categories – Structs and Enumerations. The entire Value Type hierarcy looks like this:

Value Types
   Enumerations
   Structs
      User defined structs
      bool
      Numeric types
         Integral types
         Floating-point types
         decimal

All value types are allocated on the stack. Once a value type falls out of scope, it is automatically removed from the memory. When you assign one value type to another, required memory is allocated on the stack, and a member-by-membery copy (also called shallow copy) is performed to set the new item to correct (same) state. To make deep copies, use a class. Remember that C# does not have support for Copy constructor, so when you use a class, you need code an explicit method (say Clone()) to make a deep copy. Also note that System.Object does provide a protected method called ‘MemberwiseClone()’ that makes shallow copies.

The base class for all value types is System.ValueType. System.ValueType is an abstract class with a protected constructor. It inherits from System.Object and overrides the virtual methods. All structs implicity inherit from System.ValueType. You may think of a struct as a light weight class. Here is some interesting information about structs:

1) Say you have a struct “Fruit”. You may declare the a variable as “Fruit a;” or as “Fruit a = new Fruit();”. Both are equivalent, and memory is allocated on stack in each case.

2) Structs can contain methods, but these methods cannot be virtual. Afterall, you cannot inherit a struct, so the ability for polymorphic behavior would be futile. However, you CAN override certain methods of the base classes (System.ValueType, System.Object).

3) Structs can contain member fields. These fields may be value types or reference types. Structs may contain static (class-scope) members as well.

4) .NET provides a default constructor behind the scenes for each struct. This constructor initializes all members to their default values. You cannot provide your own implementation of this default constructor – .NET complains that ‘Structs cannot contain explicit parameterless constructors.

5) You can provide custom constructors to user defined structs, but while doing so, you need to initialize all member fields of that struct (value type and reference type). If you don’t .NET complains ‘Field YourStruct.field must be fully assigned before control leaves the constructor‘. The only way of using a custrom constructor would be with the ‘new’ keyword, like ‘Fruit a = new Fruit(“Banana”);”.

Allright, while we are talking about value types, here is a fun question – can you guess what happens to the memory when the following code is executed?

int a = 1; // Line 1
object o = a; // Line 2
int b = (int) o; // Line 3

Basically, the first line allocates some memory on stack for integer a and intitializes it to value 1. Line 2 starts the fun. Since object does not inherit from System.ValueType, .NET allocates memory in heap and copies the value from a (1 in this case) to the memory (called Boxing). Line 3 allocates memory on stack for b and initializes it to the same value as refered by a (called Unboxing).

Lets talk about enumerations now. All enumerations inherit from System.Enum, which in turn inherits from System.ValueType. System.Enum also implements interfaces IComparable, IFormattable and IConvertible.

By default, the storage used for each item in an enumation is Int32. You may change this to any other integral type except a char. Following code demonstrates how to do this:

enum MyFruits : byte
{
Apple=1,
Banana=2
}

Although you may seldom need to do this, you can use the GetUnderlyingType() method of System.Enum to get the data type used to store its values. You can use the static GetValues() method of System.Enum to obtain its items as name-value pairs as an array.

Leave a Comment

Think different

I love those ideas where designers take something mundane and ordinary and change a simple element in to produce a memorable experience for users. Mind you, the experience may not always be pleasureable, but it engages the user and gives them something to talk about.

Here are some examples:
This elavator looks like it is missing the floor. Also, notice the mirrors on the walls.

These handbags are a lot of fun.

This urinal has an etching of a fly. Guess why? (ok, I agree, this idea is not memorable)

You can see outside, in this toilet in Britain. Would you dare to use it?

Leave a Comment

Web 2.0

Tim O’Reilly wrote an interesting article titled “What is Web 2.0“. Although the article is over an year old, the information is quite relavant and applicable. Some lessons from the article are captured below:

leverage customer-self service and algorithmic data management to reach out to the entire web, to the edges and not just the center, to the long tail and not just the head. (think Google AdSense)

Network effects from user contributions are the key to market dominance in the Web 2.0 era.(think Wikipedia; Collaborative spam filtering)

The race is on to own certain classes of core data. (Or, how can you add value to classic data and turn it around into a desired service? Examples here would be Amazon’s value adds to ISBN registry and Google’s additions to maps database)

Operations must become a core competency. (This is one of the big lessons that I am learning in my new job at Guru that efficient operations can be the key between struggle and success. Even the slightest efficiency that can be extracted in any process, must be made good use of. This lesson is very challenging to take to software development processes where the answer to most problems is supposedly to throw more money or more people in!!)

Rich user experience! (think AJAX, Flex)Web 2.0 Design Patterns:

  1. The Long Tail Small sites make up the bulk of the internet’s content; narrow niches make up the bulk of internet’s the possible applications. Therefore: Leverage customer-self service and algorithmic data management to reach out to the entire web, to the edges and not just the center, to the long tail and not just the head.
  2. Data is the Next Intel Inside Applications are increasingly data-driven. Therefore: For competitive advantage, seek to own a unique, hard-to-recreate source of data.
  3. Users Add Value The key to competitive advantage in internet applications is the extent to which users add their own data to that which you provide. Therefore: Don’t restrict your “architecture of participation” to software development. Involve your users both implicitly and explicitly in adding value to your application.
  4. Network Effects by Default Only a small percentage of users will go to the trouble of adding value to your application. Therefore: Set inclusive defaults for aggregating user data as a side-effect of their use of the application.
  5. Some Rights Reserved. Intellectual property protection limits re-use and prevents experimentation. Therefore: When benefits come from collective adoption, not private restriction, make sure that barriers to adoption are low. Follow existing standards,
    and use licenses with as few restrictions as possible. Design for “hackability” and “remixability.”
  6. The Perpetual Beta When devices and programs are connected to the internet, applications are no longer software artifacts, they are ongoing services. Therefore: Don’t package up new features into monolithic releases, but instead add them on a regular basis as part of the normal user experience. Engage your users as real-time testers, and instrument the service so that you
    know how people use the new features.
  7. Cooperate, Don’t Control Web 2.0 applications are built of a network of cooperating data services. Therefore: Offer web services interfaces and content syndication, and re-use the data services of others. Support lightweight programming models that
    allow for loosely-coupled systems.
  8. Software Above the Level of a Single Device The PC is no longer the only access device for internet applications, and
    applications that are limited to a single device are less valuable than those that are connected.
    Therefore: Design your application from the get-go to integrate services across handheld devices, PCs, and internet servers.

Leave a Comment