Quantcast
Channel: Udi Dahan - The Software Simplist » CQRS
Viewing all articles
Browse latest Browse all 17

A CQRS Journey – with and without Microsoft

$
0
0

Update – clarification post here.

circlesI was on a call recently with the Advisory Board for the Microsoft Patterns & Practices (P&P) CQRS Journey project where they were showing the current state of their development. Towards the middle of the call, I mentioned that I found there to be too many concerns in one place and that I had expected there to be a division into multiple sub-domains/bounded contexts/business components (BCs). The answer was that they hadn’t gotten to the other areas yet and that’s why at that point in time there was only one BC.

The conversation got a bit derailed at that point, and I was asked how I would do it (though not quite as politely), ultimately leading to my tweeting this:

I think I got over 50 people who wanted in on this, while some of them urged me to work with P&P rather than separately. I think I’ll do both, hopefully resulting in two implementations that can be compared – one based on Azure (done by P&P) and the other based on NServiceBus (done by my guys). Who do you think is more worried 😉

But first things first

The fundamental flaw that I see happening with many software projects (including the P&P CQRS effort) is that not enough time is spent to understand the underlying business objectives – the thinking behind the use cases / user stories. Developers assume behavior is “like” that of another/similar domain – when the difference in the details matter a lot. That often leads to software boundaries that aren’t properly aligned with those of the business.

The effects of this lack of alignment may be felt only much later in the project, when we get a requirement that just doesn’t fit the architecture we’ve set up. I’ve blogged about the symptoms of this problem about 2 years ago in my post Non-functional architectural woes.

We need to get into the nitty-gritty of our problem domain to find out what makes it special.

Not all e-commerce is equal

Anytime somebody is going to make a purchase online, developers immediately create some kind of “order” entity with a bunch of “order lines”, just like they read about in all the blog posts and books. Then, all sorts of other behavior are shoe-horned around those entities and… voila, a working system.

The domain of conferences is different – we don’t actually ship products when people register so payment concerns are very different. If our company is purchasing 5 tickets to the conference, the number of people (and which specific people) that eventually go to the conference may be very different than the people we had originally registered – there doesn’t tend to be that kind of volatility in traditional B2C retail (like selling books to people online).

It’s also quite likely that if a company is sending many people to a conference that they wouldn’t be paying by credit card – invoicing and payment may happen much later. That is no reason to block registration from completing.

Not all registration systems are equal

I understand how people can look at systems like TicketMaster and use that as a model for this system but, once again, the differences in the domain matter.

First of all, most people don’t purchase movie tickets weeks in advance – conference tickets do go on sale that far in advance. Second, if the movie you want to go to is sold out this week, no big deal, you’ll see it next week – conferences are more of a one-time/yearly deal. Third, you usually go to the movies with family/friends – if you can’t get tickets for everyone, you’ll go next week. When it comes to conferences, there is no “next week”, so whoever can go, does. Also, attendees going to a conference together are usually coworkers, not family – there are less qualms about leaving someone behind.

This is already leading us to a model where we should not view a group registration as a single success or failure affair. This will have an impact on the commands, events, and transactions that flow through our system.

In any case where people are reserving something far in advance, there is a high likelihood of cancellations. This is similar to the domain of hotels/hospitality where you can cancel your reservation up to N days before your arrival at no charge. This also tends to influence the payment structure – we’d rather not have to return people’s money as there can be per-transaction charges for that, instead delaying payment can make sense.

Similar to how hotels overbook by a certain amount (to offset cancellations), our conference might look at doing something similar. The difference is that in the case of a hotel, the guest will likely just book a room in a different hotel in the case the first hotel was fully booked. This probably won’t happen with a conference.

For that reason, we want to remember who wanted to come to our conference even when we thought we were full. You see, our best chance of filling a seat that opened up due to a cancellation is by a person who wanted to register before. What we need here is a waiting list – something that doesn’t make the same kind of sense for hotels or airlines (although airlines do use waiting lists, just that that is usually exposed to travel agents and not to travelers booking online).

First-come, first-served – fairness

The traditional developer thinking about systems is rooted in synchronous and sequential processes. In attempting to give a good user experience, developers want to give the user final confirmation as quickly as possible – whether that’s success or failure.

This results in a first-come, first-served user interaction model – whichever user registers in our conference management system first, the better the chance they’ll get what they want. That sounds like a pretty fair system, the only thing is that fairness was not a requirement.

In the real world, if people are standing in line for tickets, they’d get really upset if the tellers decided somewhat arbitrarily to serve people in the back of the line before those in the front. The great thing about online systems is that nobody can see the “virtual line” – the system can be as unfair as we like and there isn’t a real way for the users to know that this is happening.

Why be unfair?

While conferences, theaters, and airlines all want to have all seats filled, the difference between the ongoing models of airlines and theaters and the once-a-year model of the conference influence how sales are done. Some companies send a lot of employees to our conference so we want to give them preference in registration. This is area that we have the most leverage over – when it comes to the masses who arrive in ones and twos, there’s not very much we can do. It makes sense to bend over backwards for a large group, but not for a small one. A commitment from a large company tends to mean more than that from a small one.

If Boeing has already registered 70 people to your conference and now wants to send 5 more, are you really going to tell them “sorry, we’re fully booked”, or are you going to do everything in your power to keep them happy so that next year they’ll want to keep working with you? Wouldn’t it be nice if you could “unregister” some people to make room for the Beoing guys.

Now, you can’t necessarily do this up until the last minute, but potentially 2 weeks (or whatever) before the event could be reasonable, leaving people the ability to cancel flights and hotels without charges (assuming we tell them during registration that they should buy refundable plane tickets).

The easiest way to “unregister” someone is to not tell them that their registration was confirmed. In short, 2 weeks before the start of the event we finalize all registrations deciding (based on our internal priority) who gets in and who doesn’t. We may have logic that decides to immediately finalize registration from Boeing (and other select customers) without waiting until 2 weeks before the event.

Just don’t look TOO unfair

Appearance is everything. Perception matters. You don’t want to get a reputation for being unfair.

So when we open registration, we can allow the first N people to bypass our waiting list and get accepted right away (payment still needing to be handled later). At that point, you can start moving new registrations through the waiting list.

The thing is, nobody knows that you aren’t actually full at that point :)

Influences on architecture

I hope you’re getting the impression that this collection of scenarios is going to have a big impact on the design. It indicates to us which parts of the business need to be 100% consistent with each other and which parts can be eventually consistent – ultimately defining where one bounded context stops and another begins. This has a direct impact on the events that we’d end up with – who would publish what, and how many others would subscribe to it.

I know some people will look at the above scenarios and say “but what if the requirements were different?”. The thing is that not all requirements are created equal. In working with our business stakeholders, we need to identify which elements are stable and which are potentially volatile and, yes, that’ll be different in each project. We want to align the main boundaries of our software with the stable business elements.

And don’t even try to create a system so flexible that it could handle any new requirement without any architectural changes – down that path lies madness. User-defined custom fields used in user-defined custom workflows, all of it appearing in reports with sorting, filtering, and grouping. You might as well give your users Visual Studio.

Back to P&P

I don’t know if P&P will adopt this set of requirements for their CQRS Journey. The thing here is that we can see the collaborative nature of the domain quite clearly – multiple actors working in parallel where the decisions of one affect the outcomes of another.

The requirements that I’ve seen being handled in the CQRS Journey so far don’t seem complicated enough to justify anything more than a 2-tier architecture – it’s feeling somewhat over-engineered right now. I know that people in the community see other benefits to CQRS but I’ll have to put up a separate blog post describing why there are other better solutions than CQRS most of the time.

Anyway, I’m willing to see how things progress and tweak these requirements (up to a point) so that both the NServiceBus solution and the Azure solution are addressing the same problem.

In closing

Occasionally I hear people still raising the agile mantra against Big Design/Requirements Up Front. The thing is that Agile Manifesto never said to intentionally bury your head in the sand with regards to the purpose of the system. It was a push-back against spending months in analysis without anything but documents coming out, but the goal was to reach a middle ground. Nobody ever said “no design up-front” or “no requirements up front”.

I’m going to try to work with both P&P and the alumni of my Advanced Distributed Systems Design course to come up with simplest possible solution that addresses the requirements (functional and non-functional).

Hope you’ll find this journey interesting.

Update – clarification post here.


Viewing all articles
Browse latest Browse all 17

Trending Articles