Friday 28 October 2011

My Hammers

 

If all you have is a hammer, everything starts looking like a nail

 

image image
* Image source * Image source

Have you ever felt like certain patterns/classes/libraries just work in EVERY situation or solves any problem that is REALLY HARD.

These certainly feel like hammers and in fact golden hammers in a world full of nails.

Of course you should always question yourself if it is on any extreme, and that if you are really trying to hit screws with hammers then maybe its time to think of another approach.

In any case I will talk about the tools that works for me in so many situations and that are most of the time, EASIER to understand, FASTER to write and more maintainable.

In either case I’m sure to never leave home without them

So let me jump in in no particular order…

#1. The Builder

image This feels appropriate to start with not just for the name but it takes care of all those complex creations you may have in an application.

If you find yourself saying:

I don’t want to use DI because it makes my object creation more complex.

Then you might want to consider using a builder.

The builder may also reduce or replace singletons in your application.

The builder pattern as described by Wikipedia:

The builder pattern is an object creation software design pattern. The intention is to abstract steps of construction of objects so that different implementations of these steps can construct different representations of objects. Often, the builder pattern is used to build products in accordance to the composite pattern, a structural pattern.

You can certainly read the documentation to an example implementation, but in fact just like all patterns they will vary greatly in their implementation and in my opinion they have added additional layers of complexity to this than what is needed.

The most important thing here is (abstract steps of construction).

So for instance just to follow on the concept of abstraction, in the documentation there is a use of a director, which is something you DON’T HAVE TO DO.

I found this post on stackoverflow with the exact same question.

So this really is just an abstraction to the steps of construction of an object and can be:

  1. A method.
  2. A Class with one method
  3. A Base class and many steps of construction, with many child builders
  4. A Class accepting other Builders as constructor arguments
  5. A Class with fluent API to specify some optional or additional properties.
  6. A Builder can be 1:1 or 1:* meaning being able to construct more than one type of object.

The organization of this logic is therefore determined to what makes sense and it depends on the size and complexity of construction, so I would extract more builders and base classes as construction complexity increases, the same rules as any class keep responsibilities only as big as they need to be.

With that said I will just pick an average example.

Say we had a controller which had a bunch of dependencies that needed creation, we could create the following builder:

public class ControllerBuilder
{
public Controller Build()
{
return new Controller(BuildDao());
}

protected virtual Dao BuildDao()
{
return new Dao(this.BuildContext());
}

protected virtual IDataContext BuildContext()
{
return new LinqDataContext();
}
}

And in our unit test project I can construct the exact same controller for my unit test, however modify override a small part to replace with the appropriate dependencies for in memory tests.

public class MemoryControllerBuilder : ControllerBuilder
{
protected override IDataContext BuildContext()
{
return new MemoryDataContext();
}
}

Usage of this then becomes something like this:

public class WebPage
{
public void Page1_Load()
{
Controller controller = new ControllerBuilder().Build();
}

public void Page2_Load()
{
Controller controller = new ControllerBuilder().Build();
}
}

The builder aids you application in achieving better Inversion of control, Dependency injection and still keeping things explicit

#2. The Dictionary

image The dictionary is probably one of the most powerful, flexible, high performing hammer/tool in modern languages like C# that is like sunlight, vital but often overlooked or taken for granted.

In the past many older languages never had dictionaries out of the box and third party vendors went out their way to create implementations of dictionaries, today in C# this is available out the box for FREE.

Many remember hash tables. And since generics in C# this became the generic Dictionary. They are in fact the same thing underneath.

Each object provides a GetHashCode() which is a unique key that the dictionary uses to sort objects for fast lookup.

The dictionary truly can turn many things into a nail, try to imagine wherever you used a dictionary for something what the alternative would be. You would find that the alternative is much less elegant and performing.

The dictionary makes many patterns SO EASY they seem trivial at worst for example:

Service Locators

Factories

Mappers

Also anything needing lookup, Dictionaries are great for:

Loose-Coupling and supporting principles like Open-Close.

The Dictionary can be responsible for many new powerful patterns.

If you browse to Wikipedia and look up Design Patterns you won’t really notice the mapper pattern really being documented even though in fact it should be.

By simply combining strategy and factory using a dictionary we can create a very powerful pattern to map objects from strings/enumerations or any constant type to abstractions and therefore following a whole bunch of good principles like Open-Close and so many other and yet this seems so simple we hardly think about it at all.

Example:

Say we have an enumeration as follows: (Simply indicating an environment that is configured)

public enum Environment
{
Production,
Test
}

The example is extremely trivial to keep things simple and short but imagine a situation where this can grow to a much larger size.

We would normally code this as follows:

switch (environment)
{
case Environment.Production:
return @"c:\production";
case Environment.Test:
return @"c:\test";
default:
throw new Exception("Invalid environment");
}

Once again the example is very simple, but pretend that we could be doing much more complicated things depending on environment.

If we wanted to convert this to the strategy pattern (also called provider). We would declare a provider like this:

public abstract class EnvironmentPathProvider
{
public abstract string GetPathName();
}

Then we would create the different strategies like this:

public class ProductionEnvironmentPathProvider : EnvironmentPathProvider
{
public override string GetPathName()
{
return @"c:\production";
}
}

public class TestEnvironmentPathProvider : EnvironmentPathProvider
{
public override string GetPathName()
{
return @"c:\test";
}
}

And now our usage looks like this:

public Dictionary<Environment, EnvironmentPathProvider> BuildProviderMap()
{
var map = new Dictionary<Environment, EnvironmentPathProvider>();
map.Add(Environment.Production, new ProductionEnvironmentPathProvider());
map.Add(Environment.Test, new TestEnvironmentPathProvider());
return map;
}

public string GetFileLocation(Environment environment)
{
EnvironmentPathProvider provider = null;
if (BuildProviderMap().TryGetValue(environment, out provider))
{
return provider.GetPathName();
}
throw new Exception("Invalid environment");
}

We added more code which seems unnecessary, but it is only in this initial example and after this our code will not increase much and we are much more open close and extensible in our program. And we are combining  more than one good OO principles.

So next time you use a dictionary spare a thought for this awesome hammer.

#3. The Lambda

image It will be hard to say how useful this really is and give enough reasons to say why.

I will try and say that when the books on design patterns were written they were written to take most languages into consideration. For the danger of not being hunted down by old elitists with long beards I will refrain from mentioning a language or specific. But I do believe that lambdas sometimes replaces the need for certain patterns.

From MDSN:

A lambda expression is an anonymous function that can contain expressions and statements, and can be used to create delegates or expression tree types.

The article provided also gives some great examples.

Linq would also not be possible without this. This also makes new patterns emerge like IoC, Factories, Mappers etc.

How to use this is probably beyond the scope of this article, it simply is that useful, this certainly is more than just a golden hammer but more like a platinum hammer in my toolbox.

 

#4. The Interface

image The ultimate abstraction.

There is no better way to isolate yourself from concrete implementations of code.

Interfaces also makes multiple inheritance possible without some of the trouble associated with it.

An interface contains only the signatures of methods, properties, events or indexers. A class or struct that implements the interface must implement the members of the interface that are specified in the interface definition.

From MDSN:

An interface contains only the signatures of methods, properties, events or indexers. A class or struct that implements the interface must implement the members of the interface that are specified in the interface definition.

Principles like ISP (Interface segregation principle) are worth noting and keeping in mind when designing interfaces.

So next time you are dealing with an external dependency or API library consider protecting yourself against the volatility of change and use interfaces.

#5. Linq

image Language integrated query:

Language Integrated Query (LINQ, pronounced "link") is a
Microsoft .NET Framework component that adds native data querying capabilities to .NET languages, although ports exist for Java[1], PHP and JavaScript.

I’d have to admit that this has increasingly become a more popular tool for me over time.

At first we saw linq as a great tool for querying databases particularly due to its type safety. But also for the provider support (one query can work on a number of platforms).

However from how this has grown for me over time and from what i see that can be done with this just within the language on objects, Lists, PLINQ.

Suddenly it just seems like so much effort to write

foreach (BaseController controller in controllers)
{
...
}

vs.

controllers.ForEach(controller => .. )

So that concludes the list of hammers for now, these might change over time but for now I consider them vital tools.

No comments:

Post a Comment