Musings on null objects, schemas and upgrades
My WTF of the day
The day started with a form crashing on one of our sites.
It's not an Umbraco Form, it's a form from an external marketing automation tool.
(Who's name I shall not mention)
A collection we test with .Any(x => x.Something)
had suddenly become null
overnight.
I hastily added a null check at the beginning of the predicate and got on with my day.
It had to be some messup on their part of course, and I couldn't be bothered.
The form worked again.
Later in the day, some other peeps at the office started panicking. Turns out all of the forms on several sites had broken down. They kept seeing the dreaded "macro failed to render" exception in Umbraco. We rolled up our sleeves and hacked in the extra null check on the rest of our sites. I actually noticed when I fixed the first one that it lost its nice layout, but for some reason I repressed it.
Null objects would've saved the day
The first thing I thought was that the third party had messed up by starting to return null. As long as the array was empty it would've worked. So I blamed them for not using a null object.
Thinking constructively, I figured I should as well blame myself. I should've translated the deserialized object to something where I had put in a null object.
In any case, the form would've rendered without columns if the array would have been empty. It defines groups of fields, or fieldsets if you will. And I figured none of our forms used that. (It's actually more like bootstrap columns, but that's beside the point)
If you're not familiar with the concept of null objects,
I highly recommend reading up about it:
https://en.wikipedia.org/wiki/NullObjectpattern
It'll make you more happy if you hate writing if (something != null)
in half of your codebase.
The real reason
I'd complained about the array being null on the forum for the tool. When I went down to my cave preparing to write a nice article about null objects, I notice someone from the company had answered me. He'd checked the API and couldn't find any forms that returned null for that property.
Of course they hadn't changed from returning empty arrays to null. But they had done something. Instead of checking the deserialized object in my unit tests, I started examining the actual response from the server. The real reason was of course that Newtonsoft JSON doesn't deserialize properties it doesn't know of. The property has changed its name overnight. The schema was all new. A plural "s" had been removed from the array property, and the properties of the collection object had also changed.
So I followed up with a new post where I referenced the documentation that clearly shows that the schema we follow is right. However, that was for a different method. There was another completely different schema for the one I was calling. After complaining about completely incoherent documentation, I discovered I was calling the first version of the API. The docs I referenced were for version 2. Digging my way to the v1 docs, I found that they didn't even mention said part of the schema. I'd found it because it was returned two years ago when I wrote the code.
What I learned
For one, I'll be even more adamant myself adding null objects to my business logic and services. Especially endpoints that someone might end up calling.
I also learned that if I ever notice something being deprecated, I should run off and upgrade ASAP. Even if you can trust people to keep an old version around until traffic disappears, you obviously can't expect them to let the schema stay stable for the that version. Although I'm guessing we're the last ones to leave v1 of the API. There was only me making noise on the forum tonight.
Still, my wish for today is that everyone starts using null objects and keep their public schemas intact.