 Good afternoon. Good afternoon, everybody. Thank you all for coming. This started out because I went to a new client and I looked at their code base and all I wanted to do was rant. This is wrong. That's wrong. And I thought the best therapy for getting the rent out of my system was to turn it on its side and say I am not going to say what's wrong and try to try and say what you should be doing and what is right. And so this talk was born as a result of that. First I'm going to say a few words about my background and then comes the meat in the sandwich and the message there is good error messages are useful error messages and finally a little framework that I put together that puts all these ideas into practice. Although I have to say don't have great expectations. It's actually too big to be it's not big enough to be a framework even a little one And it's not abstract enough to be a design pattern, but I didn't know what else to call it. Okay, first of all Me I'm Paul Keating. I've been programming in Python. Oh lord. I've been programming in Python for a living for well since Python 1.5.2 And I've been attending Europe Python for nearly all of that time. My first Europe Python was in Charlewine Belgium in 2003 that wasn't the first European Python that was the previous year, but that was my first Europe Python. I Support an application that has embedded programming languages Python one of the most prominent and I write tools for programmers applications for end users and practically everything in between and It's one thing to be angry about The bad error messages you see but it's much more important to say what is a good error message And this is what this this talk became good error messages are useful error messages So the first question is useful for who? And this is just another way of saying that as a writer to get through to your reader You have to know who your audience is Look at what you're writing. Is it understandable to that audience? Now if your audience is if it's an interactive application then your audience is probably an end user If it's a batch program then your error message is being written to a log so that's going to be a support person or a programmer and If you're writing a library or an API then your support person you know the person your audience is a programmer and you have to speak to that programmer as a programmer and Pop-ups are not helpful there Sometimes you do have two audiences If you're writing a library module, then one audience is the programmer who is calling into your library module and The other audience is the end users of The application that that programmer is writing But for the present just let's consider the fact that let's consider the situation where you'll you have just one One audience because two audiences hard. There'll be more about that later on Consider first of all is your quest is your message understandable Now this is an over the top example As far as I know it says error file not found in Punjabi It's an over the top example, but there's no getting away from the fact that if you show a stack trace To an end user It means no more than that if a stack trace leaks out to your end user. That's a failure Stack trace is indispensable to a programmer. It may or may not be a value to a super user depending on their background It's gobbledygook to everybody else and even if someone can read a stack trace if they don't have access to the source code It's still not very useful. I Don't know if any of you here answer questions on stack overflow anyone Over and over in a comment you have to tell use the people who ask questions on stack overflow Please post your stack trace. I think I have to do that Two or three or four times out of ten for every question I try to answer and that is because People don't actually know how to read stack traces without learning how to do it and these are beginners usually they're very very very close to being end users and If the person who sees your stack trace doesn't understand it then you're going to have to do some translation Now this came from a tutorial Student called me over and said I don't understand this message. It says dict. Isn't callable He said I know a dick isn't callable who said anything about calling anything and His problem was really a syntax error He should have used square brackets instead of round ones and he lacked the he lacked the background to make sense of What the error message it was telling him the error message was telling him you think you have a callable in that variable But you don't you have a dick But he knew he had a dick and it wasn't any help to him to say that he That he was trying to he was trying to call it Now fixing this is not a question of fixing the error message The interpreter and the people who write the error messages in the interpreter have to assume that the programmer has at least grasped the basics of the language and That's really what training courses are for. Oh, Lord but Even if the interpreter can assume that the programmer has grasped upon fundamentals of language if you're writing a library You should not assume that the programmer who is using your library is an expert Most programmers use libraries on a casual basis. They can't be all be experts in every library module There are dozens of of There are dozens of things There are dozens of libraries in the standard library that doesn't in the standard library and there are Thousands on by PI you can't know them all nobody can so To show you what I mean. I was using beautiful soup And I made a beginner error and the library would have been entitled to issue this error message Results that has no attribute prefix, but it didn't what it actually said was this This not only told me what was wrong with my code. It made a shrewd guess at the concept. I had failed to grasp That shows concern for supporting a beginner for seasoned programmers fixing such an error is quick You got the error because you wrote food up prefix So you go to where food was last assigned and You see it was assigned by a call to find all and you look up find all to see what it actually returns And there's your problem solved that four-step process for a seasoned programmer is so automatic You don't even notice you're doing it But it's hard to appreciate sometimes that for a beginner They don't even know what start Now when I was writing this actually went to read the code in beautiful suit that issue that error message and there it is It's a simple subclass of list All it has is one dunder method The only reason this subclass exists is to give that nice error message That was why it was put there I Think that's really great because it shows real concern for the needs of the user who may well be a novice The next question is is it explicit? This code is from an end-of-day batch process It writes its message to a log that log will be read if at all the next morning Now the thing about back batch processes is they can't just raise an exception toss their toys out of the Out of the cart and stop Because in a batch process there is some client system downstream disease expecting the output from this program It can't just stop in midstream. It has to Deal with the error as best it can and carry on Now the question here is why is anybody reading this log? Well It's because the manager of a downstream system put in a ticket or sent an email saying look I was expecting 5,002 rows in my interface file and I only got five thousand and the person who actually reported the error can probably even tell you The numbers of the trades that he didn't get that he was expecting So your application supports person already knows that something is wrong And he already may already even know what what trade was giving the trouble and then he reads an error message that says Something went wrong with trade one two three four five Yeah, thanks a lot guy. I knew that already If an error message is a call to action Well, the only action this makes me want to do is put my fists through the screen. Sorry about this In this situation trace back is your friend trace back allows you To put all of the information that would have been in the exception that stopped the program and then carry on So because this is being read by an application support person It's trace backs are allowed just write out the trace back and carry on It's a very very simple thing to do and it's so easy You only have to like add two lines to your program import trace back and print and trace black dot print exe And that's it. So The thing there is that if you don't have a sufficiently explicit error message Then the person who's reading it doesn't know what to do The next thing is is it unambiguous? Now we have a situation where the message is going to an end user The user is being told they're using the wrong payment type if they don't understand Why they're getting the message they'll not want an explanation and it's really helpful in that situation to know Which validation rule they have broken? Now in this particular case you see an exception being raised But that is actually being tracked by the application the application puts a pop-up and says you can't do that So they don't see a stack trace or they get is the message the trouble with this is That there are two identical texts in the message in the program if your programmer he's all he's got to go on is The text of the message and if he searches through the source guess what he's going to be pointed at two different places in the code So the rule is don't put two identical text into error messages Because the error message there the text of the error message is performing the same role as a line number would in a stack trace At the very least put in an extra full stop on the end or put one and two or a and B or something So that when the person who's trying to follow up this problem knows what could go for it to find out what But what it is he knows where to look if you point them at two different places in the code It's likely going to double the time to resolve the issue. I Will talk more about this issue of later on and the next question Now I'll leave you to read this for a bit If I can get the thing to stay on This try accept look at what it's doing It calls a function It traps the error it changes the exception type and it says the error happened in that line and Furthermore the error message that it gives you Error occurred in call to that function tells you nothing that you couldn't have to learn from the stack trace It is doing absolutely no good whatsoever So in this situation don't point the user at this point in the code because that's not where the problem is the real thing to do here is that Just call it If you're going to raise an exception anyway, well raise the proper exception So substituting your own error message here just misleads the person trying to find the problem and the final question is Does it work? The difficulty about exception handling is that it very often doesn't get well tested It doesn't get well tested look at that code and let's assume That the exception is deep and far inside that first call If that happens then the assignment to curve name doesn't take place and So the print call at the bottom will fail now. This is showing Variable reference before assignment because you mentioned the variable in the print statement But it hadn't been assigned yet There are other possibilities very often you'll see an attribute error because something wasn't initialized or you'll get formatting errors But all told this is actually pretty good It shows you what originally went wrong the original exception and it also tells you there's something wrong with your acceptors That's terrific. The only thing that bothers me about this is that it is pointing me To two different errors at two different places in the code and that text tends to make me go a bit cross-eyed but This is in Python 3 as it happens The code where this is taken from is actually running in Python 2 and in Python 2 there are no exception chains And so all you get is the x that all you get is the error in the exception and The only way to find out what's really wrong is to go fix your error in your exception and then rerun it to get the real thing That went wrong in the first place Sorry about this So you have code like there and you want to make sure that your acceptors really works Well, one thing you can do is just force it a zero a zero divide at the top of your try clause And that will force the exception and then you will know whether you have all the information in your Acceptors that you want to print to the screen. I Thought everybody knew this dodge, but apparently not so that's why I'm mentioning now This little framework that I'd like to introduce to you I'm going to have to talk a fair about about my working environment And the challenge was to apply these principles in an easy way that could be mastered by people who are Super users and not professional coded I'm going to talk about a little about the software environment and the people who write the error messages and what sort of validation rules They are our application vendor defines hooks. These are points at which the application will call your code In GUI programming, they would be called invent handlers or callbacks in your callback You get Your function callback function gets called and you and there are three things you can do you can silently return You say I think this data is cool. You may save it in the database The second thing you can do is fix the data You don't like and then silently return and the save will get saved in the database And the third thing you can do is raise an exception if you raise an exception Then the application will see the exception trap the exception and give the user a pop-up to say you can't do that because of this validation error The trick here is that if you raise an exception because there's a validation problem You'll get the pop-up, but if there is an unexpected exception that you weren't expecting and you didn't trap for Then the user will also get a pop-up and That's something you really really don't want it very often happens when you move a new validation rule live that There's a regression error in it that wasn't properly tested And so you get a new exception in that has got nothing to do with the validation rule necessarily But stops the save from happening and that can bring the system to a grinding halt and you can't do that You're in a situation where you're validating a trade and somebody presses the save button and now he can't save a trade any trade You really want to avoid a situation like that because it's extremely embarrassing if it does this is what the Application does if it's if it gets an exception it doesn't give a stack trace It just takes the exception text and puts it up on the screen And this is something I deliberately did in order to get that pop-up to put on this screen I just named a module in a way that the validation rule didn't like and That's what that's what the result is, but it doesn't have to be a Python module Of course, it could be anything now secondly a little bit about the people who write the error messages They may be professional coders, but they frequently are not they may be back-off of super users. They may be risk managers They may be accountants Why aren't programmers writing these well because it works better if the people who know what they're doing write the code directly Python permits that that's why it was a really really good decision to put Python in as the embedded programming language Now that would be fairly an obvious thing to do today But the vendor did it in 1997 that was false-sighted and also rather courageous so we get complicated corner case validation and The end users very often don't understand why they save as being rejected They're often regarded as a bug and the validation problem may be so subtle that the developers don't understand it either So developers responding to a bug report may need to get a subject expert to go to the user to explain to them what they did wrong and that means you have to identify the rule that was broken and Maybe you have to run a blame on the code to find out who wrote the rule And then you go to that person or his department and you say hey explain to me this Actually better than explaining to me. You just go to him and explain to him what he was doing wrong So the requirements were it had to be simple cut-and-paste coding that non programmers can use quickly and accurately It must be possible to identify the rule where the problem took place even if even if there are duplicate messages and Finally unintended exceptions mustn't bring the system to a halt Now super users very often do attach the same message to two different situations They may do it accidentally or they may even do it deliberately because they don't understand why it's a bad idea and the solution consists of one simple class and Also a way to distinguish between the exceptions that we want to propagate to a pop-up and the exceptions We want to do something else about because we don't want to bring the system to a halt now This validation error class is really really simple its sole purpose really is to Identify the exception as a validation error and not some other error and secondly to Identify the point at which the exception was raised That function underline on there over there all it does is pretty well the same thing as the Thunder line macro and C it tells you what line number the problem was at and there are two backs in there because it has to Go back one stage out of the function and burr one stage out of the exception call to get back to the line where the actual exception was raised and When you when you do accept raise that exception the validation exception that is the thing you see if you look there you'll see the Validate text object is the name of the validation function and the 977 is the line number it with the raise statement Then you can say to your programmer Well go and look in this function It's on that line and he knows exactly where to where to find the problem And then he will very soon know who to go and talk to to find out what the error is What's really important here is that we raise a validation error So that the application rejects the save and suppress we suppress all the other ones You see accept exception the rule say never do that well We do because if there's an unintended exception that we weren't prepared to trap We cannot allow that to lead back up to the application level because it will stop the save And you really don't want that to happen now it gets written to a log on the screen Not all users will see it and some of them won't report it even if they do But super users will see it and you'll find out about it eventually now This is one case where I haven't been true to the source I did this in the interest of getting it all on to one slide There's about 15 lines to determine which validation function you call when And that depends on what object it is you're trying to validate So it isn't really called my validation function Now I mentioned earlier that it can be difficult to have to handle messages that have two audiences And this little example here illustrates two things you can do Firstly have different channels for different levels of messages So an end user message comes in a pop-up But the stack trace gets written to a log And the second thing you can do is raise different kinds of exceptions for different things if someone's calling into your library Then it may be an error on the programmers part So that's one kind of exception It may be things that you expect the application programmer to anticipate and do something about And the third kind of exception is things that neither of you can really do anything about unless the user actually gets involved Suppose for example that your library needs a resource A web page and network connection enough disk space If the user's lost his internet connection or has not enough disk space There's not anything very much that your application writer can do to fix that But you can make the application writers life easier by having different classes of exceptions for the different things that can happen and the different things that can go wrong So To sum up An error message is a call to action What do you expect the reader of the message to do with it? And the first question is is it understandable? Does he understand what is wrong? That's why you mustn't give stack places to end users Secondly, is it explicit? Does he know enough about what was wrong to actually go and do something about it? Something went wrong with trade one two three four five Doesn't tell you enough to fix it Third thing is is it unambiguous? Does he know exactly where to look? And the fourth thing is does it point in the right direction? Do not tell the person who's trying to solve the problem that was an attribute over here Attribute error over here when actually it was a key error down there now While i've been saying this i'm sure a lot of you have been saying to yourselves. Yeah, I knew that Okay, but that's just common sense And pretty well all of what i've been saying in here has been just common sense But I didn't make up these examples to put them on slides and then throw stones at them These examples are real messages taken from production systems that were written by professional coders So although what i've been saying is mostly common sense Well, I won't be the first person to remark that common sense isn't nearly as common as one might like but The good side of that is that the answer actually is simple. There's good news Writing error messages is common sense. It equates just to thinking about your users needs Think about the people who are reading your messages And what you expected them to do with them And if you do that and you do it well Then you really really can't go all that far wrong now I'm afraid my pacing here has been a little bit Put out by the fact that I've been had the projector go off on me a lot So a lot of the sort of intervening intervening chit chat between the slides I'm afraid was lost in the lost in the frantic clicking And so I've come to this rather at the end of this rather earlier than I had planned or rehearsed So at this point, um, I think I can call for questions because um, I've run out of things to say Raise hands for a question. Can I go back to one of your throwaway comments? Yeah, that uh, 10 people's divide by zero that you thought everyone knew but I don't know Can you go back to that? Oh Because surely it raises an exception. Yes, that's a whole point. Yeah, but therefore you crash at that point Yes, but you will if you get a zero divide exception Then that's fine, but if you get another exception because what you're printing in your accept clause fails That's what that's what it's meant to test um I may not understand Exception handling properly here. So the thing is that That is a bad That that print statement is a bad print statement because it can actually it can actually itself throw an exception If curve name isn't defined at the point where you do the print You're going to get an exception in the accept clause Okay, yes But you don't want an exception of the accept clause You don't want your you don't want your your stack trace to be muddled up with two exceptions One that was the real problem source of the problem and one that was the exception the accept clause The accept clause must actually print out the problem without failing Okay, okay So the idea of putting the divide in there is you force an exception and then you can that will allow you to see Did I did my accept clause tell me I had a zero divide? Or did my accept clause tell me I had Uh an undefined variable in my print state Okay, so it's giving you Something in the log file to find just to give you an index. It's temporary It's only there to test the accept clause to make sure that you haven't your coverage is good Right. Okay. Okay. Thank you Any more questions? Raise hands Okay, everything seems clear Okay, one more Thanks very much. Uh, just quick question like Do you have a vague idea of like the longest Message you should ever give because I've seen some huge ones very descriptive, but Well explicit better than implicit um I can tell you that In in this particular environment if your error message is more than 512 characters instead of getting a pop-up You get a scrollable window Um, I've never got that far Um, but uh If you know you're going to get a pop-up You don't want the pop-up the message to extend off the edge of the screen and so on So that really more depends more on the situation I think though that if it's really complicated what we do here is we put line numbers in and that will That will go to a subject expert who will explain The maybe then a URL or something that will give a give a help message would be an appropriate Way of keeping the message within reasonable bounds Okay, any more questions, okay, it appears it all was just common sense I'm sorry like thank you for the applause, but I think we still had one more question somewhere. Was it you? Sure. All right, thanks In the case you mentioned of the dict Example would you propose to change this error message saying You try to call a dictionary, but maybe you should use the square brackets No, I don't think we should change the error message and the reason why is because you have to You have to take account of the fact that the real error from the point of view of the of the interpreter is that You thought there was a callable in that variable and there wasn't now To the beginner he knows it's a dict and he expects the interpreter to know it's a dict And he doesn't understand that it could in the meantime have been reassigned to something else Very often beginners don't understand the pitfalls of dynamic languages And the fact that he knows it's a dict doesn't mean that the compiler knows it's a dict And and so I don't believe that it would be possible for the compiler interpreter To actually give him a message saying you've got your syntax wrong And in actual fact, you only have to explain that to a beginner once or twice and after that they don't have the problem anymore So that's what training courses are for Okay, thank you Did all Okay, thank you so much