Monday 23 March 2015

Using the Model-Store pattern in Inversion (part 1)

This post is the first in a series about using a Model-Store pattern in the Inversion behavioural micro-framework for .Net (see: https://github.com/guy-murphy/inversion-dev).

Model-Store Pattern

This is a general pattern than involves representing domain data as immutable models, and allowing the segregation of reading and writing of data in a manner that enables CQRS-like behaviour and optimisation in an application stack.

The key components of the pattern are domain model objects that exhibit an internal builder class that is used to mutate an existing object or create a new one (for this pattern's purposes, these are effectively the same thing), and a generalised store interface that is friendly towards service location, service injection and segregation. The store interface also enforces separation of concerns, enabling the storage methods and caching strategies to be transparent to the application.

Models

I despair when joining a project and discovering that they are three foot deep in AutoMapper entrails and everything has a DTO equivalent for talking to a Web Service somewhere, or some kind of perverse partial class used as a View Model. Why create something that can't be used everywhere? Why can't we all just get along and respect each other as who we are?

The day I started to keep my data objects free of extraneous crap was a good day.

Just a POCO ...

Assuming that we have a User entity in our domain, our POCO for this might look like the following:


Taking control of changes

However, this can be changed by anybody, so in order to put that under control, we can make the properties read-only and only settable from the object's constructor.


This uses the ability to set a public property to only have a private setter, thereby cutting down on some code real-estate and making sure code external to the object instance cannot modify the value of a property.

Immutability

However, the next step would be to enforce this policy for code internal to the object instance as well.


Extra constructor added that takes its values from an existing User object. This is mostly for completeness.

This is now more like a truly immutable data object. The instance is guaranteed by the CLR to have unmodified fields after initialisation.

Mutation

When working with objects, at some point we will need to represent a change in value. This is known as mutation and it entails a little bit of extra internal structure to support it. The advantage of enforcing this really shows when dealing with multi-threaded applications, where a thread can guarantee that an object pointed to by specific reference will not change during the lifetime of that instance. Any change to the object creates a new instance. Using immutable objects in multi-threaded applications can lead to entire swathes of management code and concerns falling away.

Two components are needed to support mutation. First, an internal Builder class, and second, a Mutate method.

The internal Builder class

The Builder class is contained within the domain object class, as below. It contains publicly modifiable versions of the properties belonging to the immutable outer class.

It represents a mutable version of the data. This can be used and accessed by external code to prepare new or changed data. 


The ToModel method puts the Builder object's values into a new instance of a User object which has immutable properties.

The FromModel method puts a User object's values into a Builder object which has mutable properties.

The Mutate method

This method is responsible for facilitating a change to an immutable object by accepting a change that is represented by an anonymous method, and returning a new instance of the object that contains the changed data.


It creates a new instance of this model's Builder class, initialised with the current immutable instance's data. Then, it applies the passed anonymous method, or mutator, to the builder.

The mutator looks something like this:


The result of the mutation is returned as a User object, and normally this would cause a casting exception as Mutate is defined as returning a User object, but the addition of the following two methods allow us to override the implicit casting behaviour of the immutable User class and the mutable Builder class in a granular fashion:


Therefore, when the Mutate method returns a Builder object as a User, the implicit operator for User that takes a Builder as an input instead returns the result of the Builder's ToModel method - i.e. the immutable version of the Builder's data.

Similarly, when some code casts from a User object to a Builder object, then the implicit operator for Builder will be called, returning the result of new Builder(model), where model is the User object being cast.

Default values for fields

To provide fields with default values, they should be applied to the Builder object, as instantiating the immutable object requires either an existing User object or a full set of values for the properties.

One way of doing this is to change the parameterless constructor in the Builder class so that it contains the initialisation of properties with default values.



Another way would be to provide a private backing-field for a property that is being given a default value in the Builder object:


Dictionaries and Lists

There are existing implementations of immutable classes of Dictionary and List that may be used in the immutable outer class, but they require a little bit of initialisation and translation during construction and conversion. 

Suppose we want to add a Metadata collection to our User object which will be represented by a string,string dictionary. To do this, we specify an ImmutableDictionary in the outer class:


And the public, read-only property:


The two constructors of the outer class need some modification. The first constructor needs to be passed a dictionary of metadata to instantiate its immutable data from:


The second constructor is passed a complete User object, so the signature doesn't change but the body will have to take its metadata from there:


In the Builder class, the metadata is represented by just a normal dictionary:


And that will need initialising in the parameterless constructor:


The other constructors and methods adjust to accommodate:


For ImmutableList, the pattern is just the same.

Also, for the record, I hate using var, but the alternative didn't format very well. Weak excuse, I know.

Immutables, Immutables, Immutables, all the way down

Now that we have the User object with its immutability and Builder class, supposing we implemented its Metadata property as another immutable class instead of just an ImmutableDictionary.


Importantly, the Builder's Metadata property is of type UserMetadata.Builder. That type choice plus the implicit cast overrides (assuming there is one in the UserMetadata class as well) allows a chaining of the mutable versions of the objects, which means that within a Mutate method called on the User object, the mutable version of the Metadata is in scope and will be converted back into an immutable version when the result of Mutate is cast back to a User (internally it will chain the calls to ToModel).


Implementing the IData interface

Finally, in order to make this generally useful within the Inversion ecosystem, we make the object implement the Inversion.IData interface:


Implementing this interface allows Inversion to include the object in a ViewStep model which can be processed by the render pipeline. It's not a hard requirement for an object used in an Inversion application to implement IData, but it does enable the object to be represented easily by XML/Json in a way that easily interfaces with the framework.


The casting to IData in the Data method makes it explicitly clear to the compiler that we want the implementation of the IData's Data method within the Metadata object instance.

The full versions of the User and UserMetadata classes can be found here:

https://gist.github.com/fractos/6c7f53dd88aeb4c00b5f

Next part ... Stores

Coming soon.
Update: Fixed the source code for the Mutate function.

Wednesday 18 March 2015

Bending the world so log4net can work

log4net.

Firstly, why the Hell would you change the public key of a strongly named assembly between versions?

Secondly, WHY THE HELL WOULD YOU CHANGE THE PUBLIC KEY? Jesus.

Yes, I've read http://logging.apache.org/log4net/release/faq.html#two-snks and that just reeks of the development team having some kind of argument with people outside of their anointed circle of coders.

Anyway, there's a requirement on some old CMS code in a project I'm working on, and the DLLs have got a reference to log4net 1.2.10 while the rest of the world is staring down the barrel of 1.2.13.

Incidentally, I think it's really bad form to put numbers into assembly names, and, further, to have version 1.2.13 to be a completely different NuGet version (2.0.3). Seriously, what the fuck?

I found this post which really helped - you can reference two different versions if they use a strong name as long as you stick them in different folders, whilst keeping a reference in the project to the later one but setting Copy Local to false. I also added a pre-build event on the website which would make the folders if they didn't exist and copy the appropriate DLLs into each.

http://stackoverflow.com/questions/3158928/referencing-2-differents-versions-of-log4net-in-the-same-solution

However, the finishing touch was that since this was an endpoint - i.e. a website where lots of DLLs are bundled up together - then it needed to have the right path; in this case, it needed "bin\" prepended to it:


Currently reading: