Saturday, 26 September 2009

I love this photograph.

We have an olive tree growing in a huge pot in our garden, which ended up horribly waterlogged and looking rather unhappy, so this afternoon I set about the back-breaking task of digging it out, emptying the (disgusting) waterlogged soil from the bottom of the pot, and generally sorting the whole thing out.

Turns out you get quite a lot of earthworms in 500 litres of waterlogged soil - and whether he was attracted by the worms, or just curious, this little robin showed up in the garden. I ran inside to grab a camera, hoping he'd still be there when I got back - and he was. He stayed around for most of the afternoon, perching on the tree, the washing line, the shovel, chasing spiders around - at one point he was sitting literally two feet away from me, and actually started singing. It was absolutely mesmerising.

The photo is complete luck; he was hopping around so much I didn't have time to frame or set up a shot, so I just snapped him whenever he stopped for a moment. I was thrilled that this one came out so well.

Thursday, 17 September 2009

A Better Example of Command-Query Separation

Daneel3001 just posted this little quartet on Twitter:

@udidahan decisions. And I guess the command will either succeed, or fail by raising a compensating action (booking couldn't succeed).

@udidahan Yet, there are some cases where the command will not enable the domain, cinema room here, won't have the freedom to make much.

@udidahan You were rightly stating that grid like views of data as having negative effect on understanding intent of user actions.

@udidahan Maybe instead of using the hotel booking analogy for explaining CQS you could have used the cinema seat booking.

- and that reminded me of one of my all-time frustrations with the internet – booking theatre tickets – which, coincidentally, dovetails very neatly with something Udi Dahan was describing last night.

I work in Leicester Square. I walk past a dozen theatres every day, so if I want to see a show, it really doesn’t matter when I go and see it. I can go any time – and yet, every single theatre and ticket website starts the search process by saying “which day do you want to go?” – and then this happens:

Me: Friday.
Computer: Sorry, sold out.
Me: OK, Wednesday.
Computer: Sorry, sold out.
Me: OK, Tuesday.
Computer: Great! Tuesday! We can do that! Now, choose a seating section:
Me: Dress Circle, please.
Computer: Sorry – sold out.

What I really want is a to be able to say “I want to see Mamma Mia. I want to sit anywhere in the front ten rows, anytime between now and Christmas, and I can’t make Sep 23rd or any Saturday” – and, as Udi put it, let the computer do the busy-work. I know that the data is in there. I know that there are algorithms capable of fulfilling that request. Why the hell am I sitting here brute-forcing a solution and whacking the back button like I’m playing Track & Field 2 all over again?

Most current ticket-booking websites will reduce your request to “seats H24, H25, H26 and H27 for Chicago at 19:00 on Saturday 25th” – but that request is just too detailed, and far too prone to failure, and doesn’t reflect AT ALL what I’m actually trying to achieve. Maybe I’m only in town for Saturday night and don’t care what show I see. Maybe I desperately want to see Chicago but I’m prepared to go on any night. Maybe I’d be happy with two pairs of tickets instead of four together. I’d love a website that actually asked me what I wanted on my terms instead of presenting me with a bunch of data and expecting me to do the grunt work.

Command-query separation would appear to be the first step towards this – but it seems that what’s really important here is that your command model reflects the intention of your users, rather than the shape of your data.

AltNet Beers – Command/Query Separation with Udi Dahan

Tonight was the twelfth of SerialSeb’s alternative network beers events, and this evening we were lucky enough to have Udi Dahan joining us. Clearly a lot of people in the room were very interested in hearing what Udi had to say because for the first time in history (I think?) the usual altnet musical chairs didn’t happen – the speakers hardly changed for the entire hour. That said, I feel like tonight raised a whole lot of fascinating questions for me, and I’m thoroughly grateful to Udi for taking the time to share his insight, to Seb for organizing the whole thing, and to Tequila\ and Thoughtworks for beer and pizza – thanks!

Command/query separation is a relatively new concept to me, and I’m sure I’ve got the wrong end of the stick here, but I’m going to share my reflections on this evening anyway so I can look back on this in a year or so and laugh at myself. Feel free to laugh now if you’ve already got your head around all this.

Anyway. The underlying principle of CQS seems to be that reading data and changing data are actually fundamentally different operations in any business system, and that trying to use the same architectural style for both of these operations can lead to all sorts of chaos.

It also seems pretty obvious that CQS is a topic with a lot of potential “false peaks”. Maybe you’ve refactored your Customer object to use a ChangeName() method instead of exposing property setters for Forenames and Surname. Maybe you’ve exposed a bunch of denormalized data based on optimised stored procedures for your common query scenarios, and you’re still using a rich domain model to do your inserts and updates. In each case, you probably think you’re doing command/query separation – but there’s more to it than that. Until tonight, I thought CQS just meant having some special methods on your data access code for returning big lists of stuff in a hurry. Now, I’m pretty sure I don’t really know what it is at all.

A couple of great highlights from Udi’s contribution to the discussion tonight:

  1. Users are always working with stale data. The information on their screen could potentially be stale by the time they actually see it. In any multi-user system, people are always making decisions and requests based on stale data. (“This is obvious, it’s physics – you can’t fight it. Well, you can, but you’ll lose”)
  2. Separating queries from commands allows the commands to model the user’s intention more clearly – which in turn allows the software to deal gracefully with conflicts and failures (“Sorry, room 133 is taken – would you like room 155?”), where a more granular system might just throw an exception because the data is no longer valid. (“Booking failed – not in the database!”)
  3. The reason we create domain models is really just that we need somewhere to store all our complex business rules, but it’s easy for elements of business rules to leak into the controllers or presentation layers when we’re manipulating domain objects directly.
  4. The ideal CQS approach is that every business operation involves exactly three things:
    1. Find a domain entity
    2. Execute one method on that entity
    3. Commit the transaction.
  5. With this approach, it’s impossible for any business logic to ‘leak’ into the presentation or controller layers – because they’re not making any decisions. Every business operation, complete with all the validation and processing and rules associated with that operation, has to be exposed as a single entry point to the domain model.
  6. The domain entity that exposes the method will probably behave as an aggregate root for the purpose of that operation – but different entities will act as aggregate roots for different operations. Again, this was a bit of an eye-opener for me; talking about DDD gave me the impression that an aggregate root was a fixture of your business model, not something you could chop and change based on what makes sense for a particular operation.

Finally, an analogy of my own that came to me on the way home, that might help, or might be horribly naive and misguided, but which I rather like and which I’ll share here in the hope of provoking some conversation. ‘Traditional’ domain modelling is like home baking; your data store is a supermarket, where the various products on offer are your objects. They’re all there, laid out for you to search through and count and process. To do anything complicated – like making a soufflé – you need to acquire all the various objects required for that operation, then manipulate and combine them in all sorts of complicated ways to achieve the result you’re after. If anything goes wrong – you forget the butter, or you over-cook the eggs – boom! No soufflé for you. Transaction aborted.

CQS seems far more like eating at a fine restaurant. You don’t choose your meal from an array of component products; instead, you get given a menu – a read-only representation of the domain that’s optimised for rapid retrieval. Based on the information on the menu, you then execute a command – you tell the waiter what you’d like to eat – but the structure of that command expresses your intention far more explicitly than the complex series of interactions involved in doing it yourself. If the data that informed your decision is stale - say they’ve just run out of haddock -the command carries enough context that the waiter can offer you the sea bream instead, or perhaps the mackerel, and the entire dining transaction isn’t abandoned.

I guess the question is, do you want your users to feel like they’re making a soufflé, or dining in a Michelin-starred restaurant?

Monday, 14 September 2009

Determining FluentNH Schema Mappings based on Entity Namespaces

Sardinia Sunrise by you.I’m setting up some Fluent NHibernate mappings for a rewrite of some of our legacy code, and one of the issues I’ve hit is that we make extensive use of cross-database views and joins – the data supporting our app is split across three separate SQL Server databases (which, thankfully, are all hosted by the same SQL Server instance).

Turns out this is pretty easy to do – Mike Hadlow has a great post here which covers the fundamentals.

I’ve extended this principal a bit, using the Conventions facility provided by Fluent NHibernate, so that you can determine the SQL database for each entity based on your entities’ namespaces, so I have a model that looks (very) roughly like this. Let's imagine that my core web data is in a database called WebStuff, my accounts system is in CashDesk and my CRM database is in DylanCrm. Each mapped entity is declared in a sub-namespace of my common Dylan.Entities namespace, with these sub-namespaces named to reflect the database they’re mapping:

namespace Dylan.Entities.WebStuff {
	public class WebUser {
		public int Id { get; set; }
		public Customer AssociatedCustomer { get; set; }
	}
}

namespace Dylan.Entities.CashDesk {
	public class Invoice {
		public int Id { get; set; }
		public Customer Customer { get; set; }
	}
}

namespace Dylan.Entities.DylanCrm {
	public class Customer {
		public int Id { get; set; }
		public IList Invoices { get; set; }
	}
}

NHibernate will quite happily retrieve and update data across multiple databases, by prepending the schema name to the table names - so you end up running SQL statements like SELECT ... FROM CashDesk.dbo.Invoice WHERE .... If you're only mapping a handful of tables, it's easy to specify the schema for each table/object as in Mike's example - but you can also use FluentNHibernate.Conventions to achieve the same thing.

First off, you'll need to add a new class which implements IClassConvention and modifies the Schema property of each class mapping:

public class SchemaPrefixConvention : IClassConvention {

	private string ExtractDatabaseName(string entityNamespace) {
		return (entityNamespace.Substring(entityNamespace.LastIndexOf('.') + 1));
	}

	public void Apply(IClassInstance instance) {
		instance.Schema(ExtractDatabaseName(instance.EntityType.Namespace) + ".dbo");
	}
}

Once you've done that, you just need to reference this convention when you set up your mappings; if you're using the auto-mapping facility, it looks like this:

mappings.AutoMappings.Add(
	AutoMap
		.AssemblyOf<Invoice>()
		.Where(t => t.Namespace == "Dylan.Entities.CashDesk")
		.Conventions.Add<SchemaPrefixConvention>()
	);

mappings.AutoMappings.Add(
	AutoMap
		.AssemblyOf<Customer>()
		.Where(t => t.Namespace == "Dylan.Entities.DylanCrm")
		.Conventions.Add<SchemaPrefixConvention>()
	);

mappings.AutoMappings.Add(
	AutoMap
		.AssemblyOf<WebUser>()
		.Where(t => t.Namespace == "Dylan.Entities.WebStuff")
		.Conventions.Add<SchemaPrefixConvention>()
	);

Fluent NH will run your Apply() method to each mapped class in each of these three mappings, which means the resulting configuration will qualify each table name with a schema name derived from the mapped class’ namespace – and once that’s in place, you can query, retrieve, update, join and generally hack your objects about at will, and completely ignore the fact that under the hood they're actually being persisted across multiple data stores.

I think that's quite neat.