Code is evil. It’s hard to understand, hard to get right, and hard to maintain. Every extra line of code you write is a bit of legacy that someone, probably you, is going to have to care about for as long as it’s used. Our first law as programmers should be to strive to write as little code as possible.
One of the things that really helps me write less code is conventions. By knowing that a particular thing will always be implemented in a certain way, we can write generic code that deals with the general case rather than the specific one. With Object Oriented languages like C# you do this with polymorphism. Build generic solutions around interfaces and follow conventions about how those interfaces are implemented.
I’ll show you some examples from my little eCommerce project, Suteki Shop.
The first convention I follow is to make every entity in my model implement the IEntity interface:
public interface IEntity { int Id { get; set; } }
It’s almost trivial, but it means that I know when a instance of an object is an entity and I know how to access its Id. A large proportion of my entities have a name property, so I generalise that too with INamedEntity:
public interface INamedEntity : IEntity { string Name { get; set; } }
For some of my entities, their order is important. They implement:
public interface IOrderable { int Position { get; set; } }
Others can be active or inactive:
public interface IActivatable { bool IsActive { get; set; } }
And the list goes on.
Now I know what is an entity and how to access its Id, it’s very easy to write a generic repository:
public interface IRepository<T> where T : class { T GetById(int id); IQueryable<T> GetAll(); void SaveOrUpdate(T entity); void DeleteOnSubmit(T entity); }
We had an excellent debate about this a while back (check out the comments). I now would never claim this has anything to do with Domain Driven Development :)
Because I know if an entity is orderable I can write a generic orderable service:
public interface IOrderableService<T> where T : class, IOrderable { IOrderServiceWithPosition<T> MoveItemAtPosition(int postion); int NextPosition { get; } }
So now I can write generic code that persists entities to the database. I can easily write a generic controller, generic views, generic grids that show things in order. Because I know if an entity can be represented as an Id, Name pair, I can write generic code for drop down list boxes.
I start to get to the point where introducing a new entity is simply a question of defining its class. Development can proceed at a very rapid pace without writing much code.
The great thing about this approach is that if I want to create something more complex I can write it. I don’t have to use my generic controller I can create a specialised version if necessary.
Of course none of this is new, but it’s sometimes easy to forget how easy it is to leverage simple polymorphism to radically reduce the amount of code you need to write.
2 comments:
I find interface-based programming does not save me from re-typing, but it saves me from re-thinking. To save myself from re-thinking and re-typing, I use classes as opposed to interfaces. Your thoughts?
Hi Duncan,
One obvious drawback of defining polymorphism in terms of abstract base classes is that there is no multiple inheritance, so my Country class could not be both a NamedEntity and Orderable. An ABC defines what something IS rather than what it does. It also implies implementation rather than a simple type contract, which you want to avoid since the implementation is the thing that you want to vary case by case.
Post a Comment