The franken-systems we often find ourselves immersed in are a product of a hundred bad decisions, compounded like interest until they yield a wealth of dysfunction. Such is the case in this example.
First, some background. I'm working on a system to do some event scheduling. At the beginning of the project, my team learned that we'd also be implementing a web service for a name and address system, since we needed some of that data, and the client kind of wanted a web service for that other system anyway. We could take as much time to build it as we needed, up to two weeks. A couple other guys on the team built this web service under the direction of a designer. This train of thought contains several bad decisions, for those keeping score at home.
Fast-forward to today. I'm working on updating address information in the scheduling system. What should have been a pretty simple effort had proven ridiculously difficult. The root of the current set of problems is the design of the aforementioned web service. Specifically, I'm beating my head on the wall over the state and county components of the address.
These are not, in fact, textual representations of the state and county, respectively. They're objects. Now, don't get me wrong - I'm a big fan of objects, and I can appreciate the elegance of a wide and deep hierarchy. It's a great way to explore a problem domain you may not be familiar with. Invoices have headers and detail lines, and a detail line has an item and a quantity and a description, right?
But is that really what you need for a state?
Let me run through some of the places where the choice of an object for the state has caused problems.
- ASP.Net DataGrid data binding. It turns out that the DataGrid doesn't handle complex objects well, so it just couldn't cope with State as a whole object within an Address. There are multiple workarounds for this, of course, including replacing the grid, I'd expect. The direction I went on this was to craft a UIAddress object that flattened an Address the way I needed it. This resulted in extra code - not just to define the object, but to translate to and from the new, different address forms, but it worked for the UI.
- Updates. It turns out that when you update the state value for an address, not only do you need to reach down in to the object (address.State.StateAbbreviation) -- no, that's not quite enough. Try to update that, and you'll get an error -- a key violation error -- because you haven't set the StateID to a valid value. That's right. You can't set an address to a different state unless you happen to know the database key of that state. Upon further examination, this made a bit more sense to me. After all, if we happen to grant statehood to Puerto Rico or maybe annex Canada or something, and we choose to abbreviate Puerto Rico as
"TX" or "AB", well, then, we'd just have a mess on our hands, wouldn't we? So you can't just send in the state abbreviation -- that won't work at all. Sigh.
- New objects. You can't just create a new Address() now. If you do that, you won't have initialized the corresponding State and County objects. Again, not the end of the world, but it's just a little bit more code you have to write whenever you use these objects.
The moral of this story is clear - consider the users of your APIs before they show up at the gates with pitchforks and torches.