Transcript from the "Challenge 4: Solution" Lesson
>> So we had this big nasty error showing up for our particular user here, whenever they were loading the page. So we can punch in on this stack trace, and just see if we can understand it. So this first line of it is saying, cannot read property substr of null.
[00:00:38] And allows you to build interpolated strings. Well inside of this string, way down here, Chrome has even underlined, hey, this line right here is where the problem is. I couldn't find substring because rant.text was null for some reason. Let's see if we can attach a debugger, and see if we can understand.
[00:00:57] So, I'm gonna try and put a debugger here on line 8. But doesn't work. Every time I try and click on line 8, it keeps trying to attach a debugger on line 15. Now the problem here, is that this entire string template is considered a single statement. And the chrome debugger will not allow you to attach the debugger inside of a single statement.
[00:01:20] You can either attach it at the start of the statement, or at the end. So I can put a debugger on line 4, or I can put a debugger on line 15. But I can't put a debugger anywhere in between. So the debugger on line 4, because let's catch this thing before we actually blow up.
[00:01:40] Let's try this thing again, and we'll reload, So, when we start this, we get our template function was called with an object rant. And indeed, rant.text is null. So that's certainly why we can't call substar on it. You can't call the substar function on anything other than a string.
[00:02:01] So let's see if this was, is this our fault that random text is null, or is this bad data from the server? And we can figure that out by looking at the Network tab again. So we can look at it. This is data that is coming from rants, so we can pop open this API requests to rants.
[00:02:24] And using the preview tab here in the network, it will format the response so we can kind of decipher it a little bit easier. If we look at all the rants that we're pulling down, there's a lot of them coming. And if we pop open one of them, we see that the data actually coming from the server, contains the text null.
[00:02:44] So for whatever reason, our servers returning bad data for this user account, got some junk in its account. Maybe it was a bad restore. Maybe we weren't doing proper client side validation for a while, and we took some bad data. Or maybe this is a dev account and somebody just screwed something up.
[00:03:03] For whatever reason, our client needs to expect, that sometimes the server will return data that isn't quite the shape we expect. The server is a different application, and so we need to guard against it. So we need to add some validation to understand, can we render this thing before we attempt to?
[00:03:25] So I'm going to use the sources navigation to kind of go up. I don't think adding object validation is appropriate to go in a template function. So I'm gonna go up a little bit, and see where does this get called from. It gets called from this function here called render.
[00:03:41] And this seems like a fine enough place to add a validation step. So I'm gonna go ahead and stop execution. And let's just see if we can create a little, a simple validator here. So I want to get the rant object. The rant object was passed into template.
[00:04:00] And so it must be this thing right here, that this.model.toJSON. That must be how we create the rant. So now that we have the rant, we should see, all right, we only want to do this if it's valid. And if it's not valid, we wanna do something else.
[00:04:16] We should probably track some sort of analytics to know that we have bad data, and show the user something reasonable, so that we don't totally screw up their user experience. So, if there's no, or if rant.text, let's see what should we do, if type of rant.text is not a string, because that's what we expect it to be.
[00:04:42] Then, Let's send an error to our analytics, and our analytics happens to just attach to anything that gets sent to console. So we're gonna print a console error that says, Received invalid rant data, rant. And then let's do something for the user. Let's say their rant text is now, Sorry, an error occurred.
[00:05:14] We're on it. And then, rather than regenerating this, we'll just pant rant directly. So we injected a little, a simple validation routine here into render, it's probably not the right place for this long term in the architecture, we should probably create a better validation mechanism. But this will do for now to solve our bug.
[00:05:39] Let's reload and just make sure that that works. So, I left my breakpoint here, but that's fine, we can still check. At this point, we've called rant. And now the rant is valid even though that error occurred, we injected user friendly text into it. So let's go ahead and detach this and see what happens.
[00:06:02] So all the data came back for the user. The posts or the rant that I attempted to go in, plus a bunch of bad data sorry, an error occurred, sorry, an error occurred, sorry, an error occurred. This is a much a better user experience for the user, even though there's errors all over the place.
[00:06:17] At least we told them there's errors, at least we told them that we know that there is errors. And, we do in fact know that there is errors. Because we can go to a console and see, here's all of this bad data that got set up to our monitoring.
[00:06:30] So we can now see that this is happening and respond to it. So this was a data bug. Just like we need to validate our data before we send it to the server, we can't always trust the server either. And servers will often send us data in shapes that we don't expect.
[00:07:36] And finally, we'll wrap up the day with some thoughts on designing applications for easier debuggability.