Let's talk
product

Billboard booking system said three of four were free

A booking system checked clashes on one site, not all four faces of the campaign. How to test yours for the same gap, and what we changed to close it.

· · updated

Several hoardings in a group, only one of them checked

If your billboard booking system tells a salesperson that boards are free when they are already booked on a campaign, the usual cause is that clashes are checked against one site per booking, not against every face in the campaign. The first thing to check is what your system treats as the thing being sold. It should be a face and its dates, not a location and not a booking header.

Here is how that looked at one business, and what fixing it took.

A client books a campaign across four of your hoardings for the same month. Your system records it. A week later a second salesperson checks whether one of those four is free for the same dates, and the system says yes. As far as the clash check was concerned, three of the four surfaces on that campaign were still available to sell.

The cost of that is not a software defect. It is the phone call to a client whose campaign has to move, or the client who turns up to find someone else’s artwork on the site they paid for, and the credit note that follows. A media owner runs on being able to say “that face is taken” and be right. This system could not.

What was actually going on

The system had two different records that were both called a booking. One was a booking header: one client, one date window, one rate, and a single site. The other was a set of per-site booking lines, one for each surface on the campaign, which existed and were plainly meant to be the way a campaign covering several hoardings was recorded.

New bookings were written to the header. The lines were filled in by import and by conversion, and read by the calendar and the availability screens, but the code that decided whether one booking clashed with another never looked at them. It compared header against header, on that single site. A campaign on four hoardings had one header naming one site, and four lines. The clash check saw one.

The unit of sale is the face and the window

The correction is a way of thinking about the business, and it reaches well past outdoor media. The thing you draw on a map is not the thing you sell. A location has an address, a photograph, coordinates, an owner, a lighting type. None of those is what a client buys. A client buys a surface, for a window, at a rate, and one location can carry more than one surface, so each is its own record with its own dates.

Once that is said out loud, several problems that felt separate become one. The clash check belongs on the line, by surface and date window, because that is the record that says something is committed. Availability is a property of a surface over a window, not of a location. The rate belongs on the line too, because that is where a price meets a specific surface and can know whether it is lit. And a campaign on four surfaces produces four jobs for the field team and four sets of proof photographs, which is what operations needed anyway.

Every one of those had been attempted on the header at some point, and every one had a qualifier attached to make it work: take the first site, take the header rate, assume one photo set. When a system needs “take the first” to function, it is recording the wrong thing.

What we changed, and the order we did it in

The first assumption was that the lines were the newer, correct mechanism and the header’s site was a leftover, so the plan was to move the clash rule onto the lines and stop reading the header. That was backwards in the way that matters. The lines were the better record and the unused one for new bookings. The header was the leftover and it was live. Putting the correct rule on the dormant record would have produced a clash check that never ran, on a system whose users had just been told double-booking was now prevented.

So the order became: put the rule where bookings are actually written, mirror the fields onto the lines at the same time so the two cannot drift, then move the writing onto the lines, then remove the header’s site. Three steps instead of one. A rule that is known to be wrong gets worked around by the people using it. A rule that silently does not run gets trusted.

What it did not fix

On the version that shipped, the header’s site field is still present and populated, and one report still reads it. It is correct today because conversion writes both. It stays correct only for as long as nobody adds a third way of creating a booking.

The mechanism, and the symptom that gave it away

The way this surfaced was not a double-booking. It was a booking calendar that came up empty. Not wrong, empty. The calendar drew its bars from the per-site lines, and the screen that listed those lines had been trimmed to return only each line’s identifier and its site, because that was all its first caller needed. Every line arrived without a start or end date, the calendar skipped every line with no dates, and drew nothing. A two-line fix.

That is the shape most modelling mistakes take when they finally show themselves. Nothing failed loudly. A screen drew its frame, its filters, its legend and its headline figures, and the area where the data goes was blank. The header knows about a site; the lines know about surfaces and dates; and any code that reconciles the two does it with an assumption that is silent when wrong.

How to check your own system

  1. Book one campaign across three or four of your own faces for the same month.
  2. Ask a colleague to check each of those faces for the same dates. Every one should say taken.
  3. Ask your supplier whether the clash check runs on the face and its dates, or on the booking.
  4. Look at a two-sided structure. Each side should be its own record with its own dates.
  5. Open the calendar for that month. It should show one bar per face, not an empty screen.

Decide what a single sellable unit is before writing the first rule, and put every date, rate and clash check on that record. If the answer to “which record means this is committed?” is “it depends which screen you ask”, double-booking is already possible and you have not seen it yet.

That is the record Sazinga AdBoard keeps: a face and its dates, so that when the system says a surface is taken, it is.

This came out of building Sazinga AdBoard

Every site, every booking, every invoice — in one place. The problem above is one we met while building it, and what we did about it is in the product.

If you run something like this, there is one thing you can do without a call: tell us your board count.