Null's hidden cost0:07
One of my other passions is investing. With any investment you wanna see a reasonable rate of return. This is because with any investment, you're putting your money at risk. So the higher the risk, the more return you wanna see. Bringing that to programming, the creator of Noel calls it his billion dollar mistake. Now, this quote's actually 15 years old. I'm sure at this point it's a trillion dollar mistake.
Now, this quote's actually 15 years old. I'm sure at this point it's a trillion dollar mistake. This is not only from all of the null related to errors, but also the additional code we have to write to handle null. The combination of the two has resulted in a large time investment or cost, which he estimates to be billions of dollars. So when I'm talking about reasonable returns, I'm often talking about avoiding null.
Running the PHP script0:50
So when I'm talking about reasonable returns, I'm often talking about avoiding null. Let's jump into some code. This is a simple little php script. It's only about 30 lines, and it outputs the vows for any given argument. So let's see it in action. On the command line, I'll just do php vows, and let's put in layer casts. So we see that it says layer cast has three.
and let's put in casts. So we see that it says casts has three A's that's interesting. I guess it doesn't have any in their vows. Just a's, let's do my name, php Vows, and we'll say Jason McCreary. So we have some a's some E's, some o's. That's also interesting. I guess Y is not considered a vowel by php. Anyway, getting back to the code.
Tracing null returns1:33
I guess Y is not considered a vowel by php. Anyway, getting back to the code. If we dig a little deeper into vowel histogram, we see that this returns a string or null, and that's if vows is null. Where's vows come from? If we dig a little deeper, this comes from the vows function. And in this function, we can also return nulls when vows is empty.
And in this function, we can also return null when $vows is empty. Oh, look at that. I'm actually in control of what's considered a vow anyway, getting back to null, because we're returning null at a low level, look at the additional code that we have to write to now handle null all the way up the stack. And because $valHistogram returns null, that means anything calling it would also need to handle null.
that means anything calling. It would also need to handle null. Now in this case, echo doesn't seem to care about null. It just prints out an empty string. But if we were passing this to other string functions available in PHP, they would complain about null, and we would have to coalesce this into an empty string. So we see, even in this 30 line program, all of the additional code written to handle null,
Refactoring to reasonable returns2:41
So we see, even in this 30 line program, all of the additional code written to handle null, we could probably reduce this code base by 30% by using a more reasonable return. So let's do that. As we've seen with returning null, it's always best to start at the lowest level possible. That way we can prevent bubbling it up into higher levels of the application that have more and more null checks. So instead of returning null at this low level, what could be a more reasonable return value?
So instead of returning null at this low level, what could be a more reasonable return value? What we know our primary action is to return an array. That's the result of string split. So if vows are empty instead of returning null, we could just return an empty array. That would be a more reasonable return value. If no vowels were found, we can also update our method signature. Moving on to vow histogram.
we can also update our method signature. Moving on to vow histogram. We can see phpstorm is already highlighting that the null check is no longer necessary. Instead, we can just check to see if vows is an empty array. We could do something like count($vows) is equal to zero and instead return an empty string. That'll allow us to update the signature to remove the null check, and ultimately our null coalesce. We added at the highest level.
to remove the null check, and ultimately our null coalesce. We added at the highest level. But we can take this a bit further because we pass an array. Now we can actually remove this code completely. It's not really a guard clause, it's more of an optimization. That's because array count values is just gonna receive an empty array. That's okay. Sorting an empty array is okay as well.
an empty array. That's okay. Sorting an empty array is okay as well. And finally, the buildQuery function will return an empty string for an empty histogram. So we have the opportunity to remove this code completely and allowing us to remain focused on the primary action of this method. Let's just go back to the command line and manually test this by running our script again. And we'll see here that LayerCast still outputs three.
Keeping necessary null guards4:50
and manually test this by running our script again. And we'll see here that layer cast still outputs three and Jason McCreary still outputs the proper values going to our lowest level of code. You might think we could streamline this if statement as well, and on the surface it seems as though we could. But if you look at preg_replace, it can actually return null in the case of an error. So while this empty check is probably meant to focus on an empty string, it actually works on null.
So while this empty check is probably meant to focus on an empty string, it actually works on null as well, which saves us in the case that preg_replace throws an error. So whether it was intended or not, this if statement actually has some built-in error checking. If we remove it, we introduce a potential null error and contribute to that billion dollar mistake. Now, this code sample focused on null,
Reasonable returns and null object5:37
and contribute to that billion dollar mistake. Now, this code sample focused on null, but we should always try to provide the most reasonable return type and value to prevent writing additional code at a higher level. Remember, more code often means more complexity, but at the least it means more we have to read. Finally, the practice of reasonable returns pairs nicely with using objects. In fact, the combination of the two is the null object,
with using objects. In fact, the combination of the two is the null object, which I'll demonstrate in a future refactor.
