Friday, July 31, 2009

Typesafe abstractions with .net generics

The common example for generics in .net (and java) is usually for typesafe collections and typesafe operations. Safety in the workplace is very important so it's a good idea to use generic collections whenever possible. However generics, especially in .net (java generics are mostly fake) can be very powerful things to incorporate as part of our design (Made up fact - did you know that catching a ClassCastException is the no.2 cause of head injury among developers? The no.1 cause is NullPointerExeption!).

So the first example i want to talk about is of using generics to help us define a clear relationship between an abstract base class and it's children.

Generally speaking, we use an abstract base class when we have some common responsibilities for all the children, but the base class itself lacks some functionality and cannot be instantiated.

We can use a generic type definition for the abstract base to further refine this relationship and provide the inheriting classes with a type specific method signature they need to implement.
Without generics we'd be stuck with the lowest common denominator (just like on the tonight show).

So here is an example of some abstract base class that does some work, and delegates the type specific work to the children:


public abstract class AbstractProductCreator <SourceType,TargetType>
where SourceType : Material
where TargetType : Product
{
public TargetType CreateProduct(SourceType material)
{ //let's call this "buisness logic" :)
preprocessMaterial(material);
//get the product from the inheriting child
TargetType product = ProcessMaterial(material);
//do some more "buisness logic"
finalizeProduct(product);
//return the completed, type specific product!
return product;

}
private void PreprocessMaterial(Material material)
{
//umm..lets say we melt it...
}
private void FinalizeProduct(Product product)
{
//put it in a shiny box?
}

//the only method our children will have to implement
public abstract TargetType ProcessMaterial(SourceType source);
//without generics this method signature would be:
//public abstract Product ProcessMaterial(Material material);

}


So our AbstractProductCreator does some type specific work with the generic level he knows and hands it to the child for the specifics, and then finalizes it before returning.

our child only needs to do what it is supposed to, and to define its own rule (what gets converted into what).
Here's an example of a famous inheritance of this base class:


class IPhoneCreator : AbstractProductCreator <RainbowsAndBunnies,IPhone>
{
public IPhone ProcessMaterial(RainbowsAndBunnies rnb)
{
//this is the actual implementation of the IPhone creation process.
return new IPhone(rnb.GetBunnies(),rnb.GetBunnies());
//its, um..copyrighted i think..so..um..dont tell anyone you saw it here..
};

}

Once we define our child, we completely define the scope of our responsibility.
Visual studio's Intellisense will also implement the skeleton of the method for us if we perform the right ceremony. (right click on the abstract class name+ implement methods if i recall correctly).

The downside of this pattern, and its an unfortunate common pitfall of generics in general - is that once you start defining something in generic terms, it tends to infect your application.
Anyone who uses an instance of our children doesn't have to worry about the generic type definition, but usually some other layer of our application that orchestrates a more fundamental mechanism doesn't really care about the specific type and wants to treat everything in more abstract terms.

This layer may want to have access to the AbstractProductCreator, but cant because this layer will have to define a variable that looks something like:


AbstractProductCreator <SomeMaterialtype,SomeOtherMaterialType> creator;

This sort of thing is really very far from what we originally intended.
So what we want is some way of abstracting things for the lower layers of the application into the most general terms they need to know about while maintaining type specific implementations in the higher layers.

So, how do we solve this problem?

There's a nice method i came up with after thinking about this problem for a few days.(challenge: without reading on, try to think of a solution. code it (the first few attempts are likely to reach some dead end). if it can compile and run, let me know how long it took you to solve it).

The solution:
Our abstract base class can already invoke the typesafe methods of it's children. now we only need some way of invoking the abstract base without all the generic additions.
To do that we add a new interface!


public interface ProductMaker
{
public Product MakeProduct(Material material);
}

//Our base class can implement this interface and

public abstract class AbstractProductCreator <SourceType, TargetType>
where SourceType : Material
where TargetType : Product
{

public Product MakeProduct(Material material)
{
//make sure someone is not trying to hand us the wrong kind of material.
if (!material.GetType().Equals(typeof(SourceType)))
throw new Exception("Type " + material.GetType() + " not supported by" + this.GetType());
//the only cast ugliness we introduce.
return this.CreateProduct((SourceType)material);
}


public TargetType CreateProduct(SourceType material)
{
//same as before..
}

}

Now the lower layers can refer to the abstract base through the interface, and not worry about the Generic type definitions at all!

i.e.

maker.MakeProduct(product);


Without generics we'd be lost. No generics means we can either do the type specific implementation and lose the abstraction, or use the abstraction but then no one can use the type specific and all the inheriting classes have to do the casts themselves.

I hope you enjoyed this article,any comments/questions/criticism/praise/award nominations are welcome as usual.

On the next episode i'll give an example of how to extend this concept into a constructing a binding layer that allows both the lower and upper layers to be separate and type specific.
I will also be exposing the manufacturing process of the mac book air.

Tuesday, July 28, 2009

Thinking outside the checkbox

I was talking to dan - a good friend of mine, and he was telling me a horror story about purchasing a shiny new netbook. He was overall very pleased with the hardware: the size, noise level, price and performance all suited him perfectly for his application - a battery backed webserver he can put in a closet and forget about. The problem was with the operating system, or rather the flood of popups, warnings, wizards and welcome messages that took a good 15 minuets to clear.

You see, dan is by no means a novice when it comes to using computers. He spent a few years doing system administration and is one of the best developers i know. But he spent the last couple of years using a macbook and probably more then that since his last windows installation. He has long forgotten what it feels like to configure a windows machine after it was installed.


When you install office 2007 there is some live plugin that can be installed. if it is installed you are faced with a welcome screen. you have a checkbox you can check if you dont want to see this message again. then you have two options - click ok, which supposedly also takes you through some configuration, or click cancel.

What do you do?

If i check the checkbox and cancel, will it show up next time? if i click ok, do i have to go to another annoying popup?
In my case it turns out neither option workes to disable this popup because a bug in the installation process failed to create the registry entry for this plugin. Since the checkbox was never saved it kept popping up no matter what combination of checkbox+ok/cancel i used.

I am a great believer in keeping things simple. it doesn't matter if you are designing a framework, designing your UI or writing a document. Things should be as simple as possible.
Solving a complicated problem in a complicated way is easy. solving a simple problem in a complicated way is easier. As a common rephrasing* of H.L Mecken's quote goes -"Complex problems have simple, easy to understand, wrong answers". This is why i try to keep things as simple as possible. The challenge is to keep the simple things simple and complex things as simple as possible.

Why am i telling you all this? Because i think that it's the lazy and indecisive designer that leaves all the options open and visible. I think they are lazy because they didn't take the time to think about how they can simplify things down to their core essentials. I think they are indecisive because they make someone else choose instead of researching and thinking about the problem enough to reach a decision themselves.

If i was designing an application with a "welcome" or "splash" or any other annoying popup screen, and 99% of the users would - as their very first user experience with my application - click on a checkbox that means "stop annoying me" and cancel, i didn't go that extra mile.Or lets be honest, that extra inch. I think that if every developer who creates such a page received a dollar whenever someone actually read the welcome screen and lost one whenever they check the box and cancel we'd have some very poor developers and very few of these messages.

I think the key is to design for simplicity.To try not to popup to many windows, make as many decisions as you can for your users. Use everything at your disposal to limit the information presented to the user to the minimum, relevant information to the particular view/function of the frame they are looking at. If a view deals with more then one "topic" or "issue", it should probably be separated. I also think one must always consider the limited nature of a checkbox before using it as the means to answer a question.
Oh, and try to avoid the "we'll make it floating/detaching/docking/toolbox" type solutions - these are usually the lazy indecisive type solutions. most users will never change your default setup. they don't care that they can configure and change almost anything. they just want to use it without spending hours configuring it to be usable.

Another thing i think desktop application developers should do is take some notes from the online world. These days many websites track very carefully how users get to their site, where do they go, where do they exist at,they follow every user's clickpath through their website, they track ad clicks, and any other statistic they can receive. This information is easy to get and can be very useful.

In the offline world this sort of thing is a bit more complicated. i did a surface search to see if there are any common frameworks for tracking this sort of thing, or any common methodology for this and i couldn't find one.
Wrapping all your controls in UI usage statistics gathering can be a bit of a hassle, but i would expect the leading providers of UI controls to pick up the glove and implement such mechanisms, along with their analysis tools. Frameworks that help create clean and usable UI will add great value to application developers.
I think developers of desktop applications should use their QA and beta testers to gather this sort of statistics btw - don't ask your users- it annoys them, and it makes them wonder how exactly you will be tracking them.

I'd like to add that usage tracking is to UI usability as profiling is to performance - it helps you solve problems and improve the situation, but it only solves a problem you already created.


As for dan, well - he did what he had planned from the start - he installed ubuntu. you can visit his netbook here.



* - the actual quote is "There is always an easy solution to every human problem—neat, plausible, and wrong."