1

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>

Or this:

<OilChange>
   <vin>123</vin>
   <oilType>synthetic</oilType>
</OilChange>

Or this:

<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>

Or this:

<Vehicle>
   <vin>123</vin>
   <color>null</color>
   <oilType>synthetic</oilType>
   <brakeType>null</brakeType>
</Vehicle>

Or this:

<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.

  • Your first choice uses verbs for the message types (paint, change oil, etc). Your second looks like a noun (vehicle). What happens if you have 2 verbs (paint the outside, replace the interior) that have name collisions on the fields (e.g., color)? Can you change/add vehicle fields without touching all of your endpoints? – Dan Pichelman May 12 '16 at 15:22
  • @DanPichelman There aren't any name collisions in the second approach. All of the fields are unique enough, or made to be unique enough, so that's avoided. And I'm not sure I understand your second question, so sorry if this is blabbering: each endpoint corresponds to one type of request, which only changes one thing. The messages support having one endpoint that updates multiple things, but that's not how the software works. – Kevin Workman May 12 '16 at 15:26
3

I would foster the first approach for 2 reasons:

  • As far as I understand, painting a vehicle, changing its brakes or replacing oil are 3 distincts operations that are made separately (in time, in space). Therefore it's not the concern of the endpoint managing the brush to know that the brakes must be replaced by cheap ones (or even worse, by null ones).
  • If your company evolves and decides to also put seats in its cars, existing endpoints remain unchanged, only a new one is created along with a new message type (maintenance is easier as you don't have to redeploy a whole new version to every endpoint).
1

This

Use one type for every message

seems counterintuitive and potentially problematic to me. I would much rather specify different messages for different scenarios and send these to different endpoints.

Your endpoints will have to reject messages they don't expect, but as they should reject badly formed messages anyway, I don't think there's much of an issue there.

The big gain will be that if you amend the structure of a OilChange message, it's reasonable to only have to worry about the code that parses and uses the OilChange message and the corresponding object. If you have one global message, any change to that could potentially affect every code path. A good test suite will cover this scenario, granted, but restricting the scope of your messages will reduce the number of potential issues you face.

0

Why not try something like this:

<Vehicle>    
</OilChange>    
</PaintRequest>    
<BrakeReplacement>
      <vin>123</vin>
      <brakeType>cheap</brakeType>    
</BrakeReplacement> 
</Vehicle>

It is Easy to Maintain such xml. You have only one XML file with No HOTCH POTCH in your file. If sometime in future, requirement changes and you feel that you can provide more than one services at once, no change is needed in your file type.

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.