But that is probably a… suboptimal way to handle this. Let us go over the type of entities that we have here:

Customers / Passengers

Flights

Planes

Booking

The key point in here is that each of those is pretty independent. Note that for simplicity’s sake, I’m assuming that the customer is also the passenger (not true in many cases, a company may pay for your flight, so you the company in the customer and you the passenger).

The actual problem the customer is dealing with is that they have thousands of flights, tens or hundreds of thousands of seats and millions of customers competing for those seats.

Let us see if we can breaking it down to a model that can work for this scenario. Customers deserve its own document, but I wouldn’t store the bookings directly in the customer document. There are many customers that fly a lot, and they are going to have a lot of booking there. At the same time, there are many bookings that are made for a lot of people at the same time (an entire family flying).

That leaves the Customer’s document with data about the customer (name, email, phone, passport #, etc) as well as details such as # of miles traveled, the frequent flyer status, etc.

Now, we have the notion of flights and bookings. A flight is a (from, to, time, plane), which contains the available seats number. Note that we need to explicitly allow for over booking, since that is a common practice for airlines.

There are several places were we have contention here:

When ordering, we want to over book up to a certain limit.

When seating (usually 24 – 48 hours before the flight) we want to reserve seats.

The good thing about it is that we actually have a relatively small contention on a particular flight. And the way the airline industry works, we don’t actually need a transaction between creating the booking and taking a seat on the flight.

The usual workflows goes something like this:

A “reservation” is made for a particular itinerary.

That itinerary is held for 24 – 48 hours.

That itinerary is sent to the customer for approval.

Customer approve and a booking is made, flight reservations are turned into actual booked seats.

The good thing about this is that because a flight can have up to ~600 seats in it, we don’t really have to worry about contention on a single flight. We can just use normal optimistic concurrency and avoid more complex models. That means that we can just retry on concurrency errors and see where that leads us. The breaking of the actual order into reservation and booking also helps, since we don’t have to coordinate between the actual charge and the reservation on the flight.

Overbooking is handled by setting a limit of how much we allow overbooking, and managing the number of booked seats vs. reserved seats. When we look at the customer data, we show the customer document, along with the most recent orders and the stats. When we look at a particular flight, we can get pretty much all of its state from the flight document itself.

And the plane’s stats are usually just handled via a map/reduce index on all the flights for that plane.

Now, in the real world, the situation is a bit more complex. We might give out 10 economy seats and 3 business seats to Expedia for a 2 months period, so they manage that, and we have partnership agreements with other airlines, and… but I think that this is a good foundation to start building this on.

Comments

Interesting case of document database normalization (i mean flattening the document structure by separating nested entities and promoting them to independent documents).
IMHO there's still something that could be improved: there's no seat information in the booking document - so in order to know your seat you have to load a flight document and perform a manual search for a seat with matching booking ID, and database is not going to help you with that.

What I find really clever about your approach here is you aren't trying to just denormalize what was given from the domain and make it work as a data model.

You are actually diving deeper into the domain much than the presented data model and actually going up to the use-case and asking:

"Well, a customer does have bookings, and yes aflight does have seats ... but when does a customer need to know what seat they have? If they book a flight a year in advance, do they choose their seat?"

And from experience, NO!. You only know about 2 days in advance where you are going to sit, as you check-in online and pick it then.

So "a customer booking a seat" is actually an incorrectly defined use-case from the business perspective. You've just clarified the process of the business and built your model from that; in essence, you book a reservation on a flight, and at some later time, the check-in process allocates you a seat.

Dominic,
That is why it is usually very hard to actually do sample domain modeling. Because the actual model really depends on the kind of business rules you deal with.
I like to always ask what kind of paper forms they are using, because a lot of the time, that really reflects the real business process communication lines.
And people come and try to do things in software and impose their own view on the business processes.

"And people come and try to do things in software and impose their own view on the business processes"

As awkward as it might sound, this is not always a bad thing. Depends. As always. There are number of small companies, who somehow operate successfully on a daily basis and yet, when you look at them closely, there are no defined processes, just individual habits (even among people with same set of obligations) with loose coupling on the points where people need to interact. In these companies a software can be a boot that kicks them into more defined and organized operating mode.

Urmo,
The problem is that many times, the software's idea of what needs to be done is very far from the current (informal) processes. That can create one of several options, sometimes is leads to well defined process that works well.
Other times, it leads to jumping through hops to get the system working so people can just do their jobs.

I was not referring to the cases, where software is introduced/developed just by throwing it at the customer users face. It mostly on the cases, where software is either developed specifically for the company or heavily customized. In both cases, customer has to start answering question "how do you do X" in more formal way. And that can lead to many good things.