Implementing the Cluster Pattern

Feb 6, 2013 at 1:46 PM
Edited Feb 6, 2013 at 1:52 PM
Richard.
I am busy trying to implement your cluster pattern for multiple models and API projects.
I managed to successfully implement a Result Interface Association (entity property) between 2 models using the pattern.

However, when taking it further, I am running into problems regarding interfaces and generated EF entities.

I'll try to explain a simple scenario:
In my first model, I have the following Entities: Vehicle, StockType.
Vehicle as a navigation property of type StockType.
So, I now define a API contract project for the above model. It contains IVehicle and IStockType. Matching the model IVehicle has a property of type IStockType.
I let Vehicle and StockType implement the interfaces IVehicle and IStockType respectively.

But then I get the following error:
'My.Model.Vehicle' does not implement interface member 'My.Model.Api.IVehicle.StockType'. 'My.Model.Vehicle.StockType' cannot implement 'My.Model.Api.IVehicle.StockType' because it does not have the matching return type of 'My.Model.Api.IStockType'.

Is this the only solution?

It also seems like a major maintenance overhead to build an entire interface graph to match the parts of the model we need exposed.

Am I missing something?
Coordinator
Feb 6, 2013 at 6:57 PM
Edited Feb 6, 2013 at 6:58 PM
The important thing to remember is that the primary purpose of the Cluster model is to reduce the coupling within a large and complex domain model. There are several other secondary benefits that flow from this.

As well as being interfaces rather than classes, it is very important that the APIs be very 'thin' compared to the implementations. They should expose the absolute minimum of the structure of the domain objects within that cluster.

Therefore the first question I would be asking is: why does something outside the Vehicle cluster (I'm guessing that's what the cluster is - you don't give any indication of the name or raison d'etre for this cluster) need to know the vehicle's stock type. It might be that that is an indicator that the boundaries of the clusters might be wrong.

That's not to say it is definitely wrong. But I am always wary when a type needs to expose another type through the API.

(BTW, I don't know how many values there are for StockType: if only a few then you might be better off with that as an Enum - and it is OK to expose Enums in the API.)

If you decide that you really have got the cluster boundaries right and that you must expose the StockType property of the Vehicle (and it can't be an Enum), then, yes, you will have to have an IStockType interface. And since the Vehicle (class) StockType property won't conform, you'll have to provide a separate property or function on the Vehicle that returns an IStockType to conform.

All a but ugly, which is why I come back to the main question - is it right to expose this? I can't really say with no knowledge of the system.

Another golden pattern is to ask: can the exposure of this property be replaced by some higher value methods instead. To pick my favourite (and real) examples, don't expose a Date DateOfBirth property when you can more usefully expose methods of the form IsOlderThan(int age) - which add more value, hide the implementation, and prevent accidental duplication of the data. I could list many more examples of this ...

P.S. In Ireland, where we are implemented a huge version of this pattern with (already) nearly 20 clusters and growing rapidly - I face questions of this kind every week. Getting the design right is not trivial - but that's the price you pay to achieve the benefits. Oh, and it needs to be policed - we use a combination of FXCop rules and manual policing. Left unpoliced, in a large team developers will add types and properties into each APIs at an alarming rate ;-)
Feb 6, 2013 at 7:18 PM
Edited Feb 6, 2013 at 7:24 PM
Thank you much for the feedback. I will give this some brain cycles.
Are you referring to EF5 enums?

What lead me down this path was the creation of an IVehicleRepository for injection into the other model, and of course this could only return IVehicle, and not Vehicle, and hence VehicleRepository also returned Vehicle, and so the cascading began. :)
So in terms of repositories, for injection into the other models, would you recommend specialized, lean versions specifically for this purpose?
Coordinator
Feb 6, 2013 at 9:56 PM
EF5 provides better support for Enums, certainly - you can have a property of an Enum type. But I was using this pattern even with EF4 - you just have an int property marked up with the DataType attribute - and you need to do some casting between Enum and int.

"So in terms of repositories, for injection into the other models, would you recommend specialized, lean versions specifically for this purpose? "

If you want to follow the cluster pattern then, yes, any service accessible from another cluster must be defined by an interface and can only return interfaces and accepts interfaces, primitives, or Enums as parameters. But keep looking at that question of why you are exposing IStockType - and whether that can be eliminated - or whether StockType should be something associated with a Vehicle by another cluster. Again, I can only guess because I don't know what you mean by StockType.