Advertisements
Posted by: jsonmez | January 5, 2012

No Class is an Island

One of the biggest challenges I’ve found with any framework is to make it self-discoverable. 

It is often difficult to build a framework or API in a way that users of that framework can easily know what exists and when to use what.

One of the main reasons why it is difficult to write a good framework is that many developers tend to create classes that are very loosely connected to other classes in that framework with which they are intended to interact.

104004A.TIF

Defining the island

When you create a series of classes, do you explicitly plan for those classes to depend on each other or do you try to design them in a way so that they are independent?

This question brings up the old topic of loose coupling and tight cohesion.

I consider a class to be an island if it is loosely coupled, but also loosely cohesive.

A class that is an island is a class that does its own thing with very little dependencies or very weak dependencies.

Imagine for a moment a CurrencyConverter class.

This class is designed to take an amount of one currency and convert it to another currency.

There are several ways we could create the API for this class.

Here is one of them:

public class CurrencyConverter
{
    CurrencyConverter(ICurrency destinationCurrency)
    { ... }

    ICurrency Convert(ICurrency sourceCurrency, decimal amount);
    { ... }
}

 

Now this seems like a pretty reasonable API, but there is a problem here.  The problem is if you have a class that implements ICurrency, you don’t have any good way to know that this class exists.

If we don’t do anything else, this class might as well not exist at all.  It is an island.

It can see classes it needs to use, but the classes that could benefit from CurrencyConverter don’t know it exists.

The developer that is using an ICurrency implementation has no good way to know that this convert exists.  Most likely a developer will end up writing their own implementation of a currency converter. 

Duplication! Bad!

The date and time link

You will often see this in code bases and frameworks.  You will have many different utility folders or classes that help do date and time operations.

The problem is that no one really knows these utility classes exist and so everyone ends up rewriting the functionality all over your code base and you have a mess.

Take a look at your own project, see if you can find all the utility classes that deal with date, time or currency.  Now check to see if those utility classes are being used everywhere they could be.  Chances are they are not.

Building bridges

We need to build a bridge to the island so that everyone can enjoy the nice beaches.

No point building your wonderful CurrencyConverter if no one knows it exists, right?

So how do we solve this problem?

It definitely is a tricky problem to solve.

The best way I have found is to tie the dependent class back to its dependency. 

Yes, I am advocating circular dependencies!

Don’t be alarmed, it is not that bad.  All you have to do is make sure that your ICurrency interface has a reference to CurrencyConverter so that someone using ICurrency will know it exists.

Now there are many ways of doing this.  Some involve using a base Currency class, others involve creating different static constructors for Currency classes.

I am going to show you a very simple example, just to make my point.

public interface ICurrency
{
    ConvertUsing(CurrencyConverter converter);
}

 

It really is that simple.  You have now built a bridge to the island that was CurrencyConverter.

Now when a developer types ‘.’ on an ICurrency implementation they will see a convert method that uses your converter and they will know it exists!  Joy!

Again, there are many ways you could build this bridge.  My intention is not to debate them here.

The point is… BUILD THE BRIDGE!

But it is a circular dependency, that is bad

Really?

It is worse than 5 implementations of currency conversion in your code base?

What we have really done here is build something that is extremely tightly cohesive.  This is not necessarily a bad thing.

What we don’t want to do is to tightly couple the currency conversion to our billing system code.  We don’t want to have some building system class being used by our CurrencyConverter.

Applying the idea further

The basic idea here is that every time you create a new class you should think about how someone will know it exists.

If the class is out there on its own and it is likely to be useful in the the future, you must do something to tether it back to its dependencies.

It is helpful to have the attitude that if a developer can’t discover your class by some other class through intelli-sense, your class might as well not exist.

Every time I create a class, I try to think of two things:

  1. How will someone use this class
  2. How will they know this class exists
Advertisements

Responses

  1. Discoverability of code is important for it’s reuse.

    Another way to ease class discovery is simplifying namespaces. Unfortunately by default Visual Studio helps proliferate namespaces in C# projects by automatically generating new namespaces for new projects and new folders inside projects.

    For conversion classes, like currency and date time, it might be worth considering a static class like System.Convert.

  2. […] No Class is an Island – John discusses the creation of classes, the concepts of loose coupling and tight cohesion, and classes relationships to others in the framework they belong to […]

  3. I like your thinking – sometimes conventions prevent you from practicality. I guess any framework has to be considered a story or plot to a movie: you need to be able to discern the characters’ motivations, history and relationship to one another. The trick is how to depict the interplay of classes.

    Tests “should” be a a way, but to be honest there are many times when I have been pooring through a framework and have NOT yet discerned what design pattern is being used, and I get lost. Maybe I need to learn more design patterns, or maybe the creators for frameworks need a better plot.

    Lord of the Rings is a good example of how to layout the background and remove confusion. Each film had two minutes of background and it set the tone for what was to unfold. Frameworks need that same preamble.

    Nice post, I look forward to reading more.

  4. The bridge looks like an implementation of double dispatch.

  5. Purists will say it’s bad, but I think it’s a very nice and pragmatic way to ease API discovery. Thanks for sharing!

  6. I think it is a valid and useful point. Using an extension method placed in the _same_ namespace as ICurrency, will give you discoverablitiy with no coupling between ICurrency and CurrencyConverter.

    FTW:

    public static class ICurrencyExtensions {
    public static ICurrency ConvertUsing(this ICurrency currency, decimal value, CurrencyConverter converter);
    }

  7. I like the idea here, though my first reaction was “isn’t there another way to enhance discoverability that doesn’t involve reliance on intellisence?” But, I guess that’s the point here – you have to find a practical way that the average client of your code is going to figure out what exists, and intellisense is practical. Writing code outside of Visual Studio is probably not a common enough case to rate in a pragmatic argument.

    Still, I’d be curious if there were other practical approaches to promoting discoverability – if you could take some kind of multi-faceted approach. On the whole, though, I think your point is an excellent one. If you don’t provide some kind of trail, you may as well have static utils classes that people have to “just know about” to use.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: