My job involves a project that has a lot of different pieces that all need to communicate via XML messages. There are two schools of thought on how these messages should be organized.
In reality these messages can contain hundreds of fields and lots of nesting, but I'll try to simplify. So let's say the project is for a mechanic that works on various vehicles. The messages are requests for things like painting a car, changing the oil, and replacing the brakes.
Option One: Use different types for each message.
With this setup, each request has its own top-level type, and each type has its own members:
So we'd get a request that looks like this:
<PaintRequest> <vin>123</vin> <color>red</color> </PaintRequest>
<OilChange> <vin>123</vin> <oilType>synthetic</oilType> </OilChange>
<BrakeReplacement> <vin>123</vin> <brakeType>cheap</brakeType> </BrakeReplacement>
The argument for these messages is that you know exactly what to expect from each message based on its type. A
BrakeReplacement is guaranteed to have a
brakeType member that you can then use to take some action.
Option Two: Use one type for every message.
With this approach, there is only one top-level type, and that type will contain different members depending on what type of request is being made. So you'd have requests that look like this:
<Vehicle> <vin>123</vin> <color>red</color> <oilType>null</oilType> <brakeType>null</brakeType> </Vehicle>
<Vehicle> <vin>123</vin> <color>null</color> <oilType>synthetic</oilType> <brakeType>null</brakeType> </Vehicle>
<Vehicle> <vin>123</vin> <color>null</color> <oilType>null</oilType> <brakeType>cheap</brakeType> </Vehicle>
These messages can contain every field, but in reality most fields will be null, and only the fields pertinent to that specific request will be filled out. You'll know which fields should be in the message based on which endpoint the request came through.
The argument for this approach is that you only have to deal with one type, and in theory a request can contain multiple types of actions (although in our specific case, that's never the case).
My question is: Do either of these approaches fulfill or violate any software engineering / design / OOP principles?
I understand both arguments, and I see pros and cons for each approach. But I'm trying to find a more "official" source than my humble opinion.
The only thing I can think of is Liskov's Substitution Principle, in that the second approach uses the same types for different requests, so you can't substitute one instance in for another. So if somebody sends an OilChange request in to the PaintRequest endpoint, we won't know that's wrong until pretty late in the process.
But I think that's a stretch, as the LSP applies to type inheritance, not instances.
For what it's worth, these requests are coming in over REST endpoints and then get sent to a backend Java process. That Java process uses JAXB to convert the XML into Java classes.