4

Been given an awkward design challenge, and I'm not sure how best to handle it.

The scenario is this: in the system there's a concept of "Client". Each client has various bits of supporting metadata such as contact name, business sector and so on.

The system does two things. It takes bookings against each client, and it reports on the business in those bookings.

One client, however, is different. It has a bunch of regional offices - over 100 in all, which is about five times the number of other clients in the system. For the purposes of bookings, we have to treat each office as a separate client. For the purposes of reporting, we have to treat them as a single client.

Of course, if necessary I can deal with this by putting a different if/else each and every time a client is mentioned. But that's going to be ugly as hell and hard to maintain. Some of this sort of logic is inevitable but I'd like to minimise it.

Some of it can get pushed into the Client object itself, which at least keeps it in one place. But it made me wonder: this can't be a rare scenario. Are there any pre-existing architectures or design patterns that might help?

  • Would it be considered an error if the report contains both the regional offices as well as the clients that the offices belong to? – Bart van Ingen Schenau Mar 10 '17 at 13:24
  • @BartvanIngenSchenau Yes, that would be considered a fault – Matt Thrower Mar 10 '17 at 13:29
7

There is a pattern for your case, and it is called Separation of Concerns.

You should split the Client class into two separate entities. One that the bookings are made with/against and a separate one for the reporting. For the purpose of this answer, I will call them Venue and Client.

Each Client would own one or more Venue objects. It just happens to be that you currently have only one Client that owns multiple Venue objects, while all the others own just one.

4

I dealt with exactly this problem when I worked as an MIS application developer for a market segmentation analyst. We were accustomed to working with mom and pop stores and then our VP of sales decided to start targeting large commercial chain operations, which have multiple stores.

The simple and obvious answer is to add a new domain entity to your model. Using your terminology, let's call it Office.

Every Client has one or more Offices. Sounds like the bulk of your Clients have exactly one Office, which is completely fine; for these folks, you still want to maintain a separation between Office and Client because (a) any client might add a secondary Office at any time, and (b) Client and Office entities have different attributes. A Client may have a corporate address while only an Office will have a shipping address, for example. This distinction may become important in ways you're can't foresee, e.g. if there are tax implications that are different per location, or if your sales force comes up with a commission structure that differentiates between Clients and Offices, that sort of thing.

Avoid the temptation to merge the stuff together, or to treat them as parent/child in some sort of hierarchical structure. They are not parent and children Clients, they are distinct business entities in their own right with different attributes and behavior.

If you use this approach you should be able to use identical logic to work with a Client that has one Office, two Offices, or 100 Offices.

1

To be honest, it's kind of worrying that you think of if/else statements when "confronted" with such a scenario.

Luckily, you realize it is the wrong way to go.

There is not so much a pattern that fits your solution, as an entire paradigm: it's called Domain Driven Design or DDD for short and what it basically says is that your system should be modelled according to reality.

It's already clear to me that you are dealing with two entities that have a one-to-many relationship between them, but the system currently knows about only one entity (which you call Client).

The first thing you should do is dig into which entities you are dealing with exactly. Client seems pretty vague. You might end up with ClientCompany and ClientOffice, for example. Then, ClientCompany is what you do reporting against, and Bookings are attached to ClientOffices. But without further information on your system and use cases it's hard to tell what your Domain should look like.

If this means a rather big design change, the standard reaction will be

"But... that's way too much work! We need to support it next week!"

Just realise, if you choose any other route than this to make it less work... You will have to do double/triple/... to fix whatever mistake you are about to make.

Good luck!

  • Haha, this is still at the prototype stage, so there's no such concerns. And I had already worked out for myself I needed separate objects for Client, ClientOffice and Booking - they're all in there. But I'm curious about your implication that this can be done without any control flow logic at all: surely if one Client needs treating differently to other Clients (i.e. here, we need to let users select a ClientOffice, otherwise don't) it needs an if/else? My question is about how to minimise it while maximizing maintainability. – Matt Thrower Mar 10 '17 at 16:44
  • 1
    @MattThrower: You can get out of that by not showing Cients at all to a user who wants to make a Booking, but only a list of ClientOffices. And if that doesn't fit your requirements for some reason, you can make the case of a Client with a single ClientOffice the special case (normally, the user needs to select an office, but if there is only one then the selection is made automatically). – Bart van Ingen Schenau Mar 11 '17 at 7:38
0

The simple solution is to allow clients to have child clients.

Then each regional office is its own client, while you can still combine everything as a total for the large client.

The other clients are just clients with no child clients.

This will also allow for the regional offices being grouped together if that need later arrives.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.