Chapter 18

Recovering from Mistakes

IN THIS CHAPTER

check Understanding error messages

check Considering the uses of quick alerts

check Managing both common and custom error messages

check Embracing good coding practices

A lot of people associate mistakes with failure. Actually, everyone makes mistakes, and they’re all learning opportunities. Some of the greatest minds the world has ever seen thrived quite nicely on mistakes. (Consider how many tries it took Edison to get the light bulb right; also, see my blog post at http://blog.johnmuellerbooks.com/2013/04/26/defining-the-benefits-of-failure/ on the benefits of failure.) The point is that mistakes are normal, common, and even advantageous at times, as long as you get over them and recover. That’s what this chapter is all about — helping you recover from mistakes.

MATLAB can’t talk to you directly, so it communicates through error messages. Part of the problem is that MATLAB and humans speak two different languages, so sometimes the error messages aren’t quite as helpful as they could be. This chapter helps you understand the error messages so that you can do something about them. You can even find sources for common fixes to these error messages, so the work of overcoming any issues may have already been done by someone. All you’ll have to do is go to the right source.

When you write your own applications, sometimes you have to tell other people that they have made a mistake. Unfortunately, you can’t record your voice saying, “Oops, I think you meant to type a number instead of some text here” and expect MATLAB to play it for someone using your application. Therefore, you need to create your own custom error messages so that you can communicate with others using your applications.

Of course, the best way to handle error messages is to not make mistakes. Even though some mistakes are unavoidable (and others have had positive benefits, such as the making of the glue found on the back of sticky notes), you can work in ways that tend to reduce errors of all sorts. The final section of this chapter discusses good coding practices to use to avoid trouble. No, this section can’t prevent you from ever seeing an error message, but by following its advice, you can see fewer of them.

Remember You don’t have to type the source code for this chapter; using the downloadable source is a lot easier. You can find the source for this chapter in the \MATLAB2\Chapter18 folder of the downloadable source. When using the downloadable source, you may not be able to work through some of the hands-on examples because the example files will already exist on your system. In this case, you can create an alternative folder, Chapter18a, to hold the results of the hands-on exercises. See the Introduction for details on how to obtain the downloadable source.

Working with Error Messages

Error messages are designed to tell you that something has gone wrong. It seems like an obvious thing to say, but some people actually view error messages as the computer’s way of telling them it dislikes them. Computers don’t actually hate anyone — they simply like things done a certain way because they really don’t understand any other way.

Error messages come in two levels:

· Error: When an actual error occurs, processing stops because the MATLAB application can’t continue doing useful work. You can tell an error message because it appears in dark-red type and the system makes a sound. However, the most important aspect of an error is that the application stops running, and you need to fix the problem before it can proceed.

· Warning: When a warning condition occurs, the computer tells you about it but continues processing the application as long as doing so is safe. The message type shows up in a lighter red in this case, and you don’t hear any sort of system sound. In addition, the error message is preceded by the word Warning. In fact, you might not know that a warning has happened until you look at the Command Window. Fixing a warning is still important because warnings have a habit of becoming errors over time.

Remember The most important thing to remember about error and warning messages is that someone created them based on what that person thought would happen, rather than what is happening. You sometimes see an error or warning message that doesn’t quite make sense in the situation, or is possibly completely wrong. Of course, first you try reacting to the error message, but if you can’t find a cause for the error, it’s time to start looking in other places. The error or warning message is designed to provide you with help after something has gone wrong — and sometimes the help is absolutely perfect but at other times it isn’t, and you need to work a little harder to resolve the situation.

Responding to error messages

Until now, every time an error has happened, it has simply displayed in the Command Window without much comment. However, you can do more about errors than simply wait for them to announce themselves. MATLAB lets you intercept errors and handle them in various ways using a special try…catch structure. Listing 18-1 shows how to create such a structure in a function. You can also find this function in the Broken.m file supplied with the downloadable source code.

LISTING 18-1 Using the try…catch Structure

function [ ] = Broken( )

%BROKEN A broken piece of code.

% This example is designed to generate an error.



try

Handle = fopen('DoesNotExist.txt');

Data = fread(Handle);

disp(Data);

catch exc

disp('Oops, an error has occurred!');

disp(exc)

end

end

First, look at the source of the error. The call to fopen() uses a file that doesn’t exist. Using this call isn’t a problem; in fact, some calls to fopen() are expected to fail. When this failure happens, fopen() returns a handle with a value of –1. The problem with this code occurs in the next call. Because Handle doesn’t contain a valid handle, the fread() call fails. Reading data from a file that doesn’t exist isn’t possible.

Remember The try…catch block contains the code that you want to execute between try and catch. When an exception (something other than what was expected) does occur, the information is placed in exc, where you can use it in whatever way is necessary. In this case, the error-handling code (error handler) — the code between catch and end — displays a human-readable message and a more specific MATLAB error message. The first is meant for the user; the second is meant for the developer.

To try this code, type Broken() and press Enter in the Command Window. You see the following output:

Oops, an error has occurred!

MException with properties:



identifier: 'MATLAB:FileIO:InvalidFid'

message: 'Invalid file identifier. Use fopen to

generate a valid file identifier.'

cause: {}

stack: [1×1 struct]

Correction: []

Tip The exception information starts with the second line. It tells you that the exception is a member of the MException class and has certain properties. Because these properties are standardized, you can often search the Internet for help in fixing a problem, in addition to the help that the MATLAB product provides. Here’s the additional information you receive:

· identifier: A short, specific description of the error. An identifier provides a category of errors, and you can use it to find additional information about the error as a whole.

· message: A longer message that provides details about the problem in this particular instance. The message is generally easier for humans to understand than is the other information.

· cause: When establishing a cause for the problem is possible, this property contains a list of causal sources.

· stack: The path that the application has followed to get to this point. By tracing the application path, you can often find a source for an error in some other function — the caller of the current function (or one of its callers all the way up to the main application in the call hierarchy).

· Correction: Contains a suggested fix for the error when MATLAB can guess at one. This fix isn’t guaranteed to work, but you do find that the fixes do work a high proportion of the time.

Understanding the MException class

The MException class is the basis for the exception information that you receive from MATLAB. It provides you with the properties and functions needed to work with exceptions; you then use the exceptions to overcome, or at least reduce, the effect of errors on the user. The previous section of the chapter, “Responding to error messages,” acquaints you with the five properties that the MException class provides. Here’s a list of the functions that you use most often:

· addCause(): Appends the cause that you provide to the list of causes already provided with the exception. You can use this feature to provide ancillary information about an exception.

· getReport(): Outputs a formatted report of the exception information in a form that matches the output that MATLAB provides.

· last(): Obtains the last exception that the application threw. Note that this is a static function, so you use it as MException.last() any time you need the previous error.

· rethrow(): Sends an exception to the next higher level of the application hierarchy when handling the error at the current level isn’t possible. (After an exception is accepted by an application, it’s no longer active, and you must rethrow it to get another part of the application to act on it.)

· throw(): Creates an exception that either displays an error message or is handled by another part of the application.

· throwAsCaller(): Creates an exception using the caller’s identifier that either displays an error message or is handled by another part of the application. (When one part of an application accesses a function, the part that performs the access is named the caller, so this function makes the exception appear as it if were created by the caller rather than the current function.)

One of the more interesting functions provided by the MException class is getReport(). Listing 18-2 shows how to use this function to obtain formatted output for your application. You can also find this function in the Broken2.m file supplied with the downloadable source code.

LISTING 18-2 Creating an Error Report

function [ ] = Broken2( )

%BROKEN2 A broken piece of code.

% This example is designed to generate an error

% and display a report about it.



try

Handle = fopen('DoesNotExist.txt');

Data = fread(Handle);

disp(Data);

catch exc

disp('Oops, an error has occurred!');

disp(exc.getReport());

end

end

Remember Notice that you must still use the disp() function to actually output the formatted string to screen. The getReport() output is nicely formatted, if rather inflexible, because you don’t have access to the individual MException properties. However, the output works fine for most uses. Here’s the output of this example:

Oops, an error has occurred!

Error using fread

Invalid file identifier. Use fopen to generate a valid file identifier.



Error in Broken2 (line 8)

Data = fread(Handle);

The output includes three of the properties. However, the cause isn’t used in this case because the cause can’t be identified by MATLAB. You need to use the addCause() function to add a cause when desired. In addition, MATLAB doesn’t have a handy correction for this problem.

Creating error and warning messages

As previously mentioned, MATLAB supports both error and warning messages. You have a number of ways to create exceptions based on application conditions. The easiest way is to use the error() and warning() functions. The first creates an error condition, while the second creates a lesser, warning condition.

The example shown in Listing 18-3 presents a basic method of issuing an error or warning resulting from user input. However, you can use the same technique whenever an error or warning condition arises and you can’t handle it locally. You can also find this function in the ErrorAndWarning.m file supplied with the downloadable source code.

LISTING 18-3 Creating Errors and Warnings

function [ ] = ErrorAndWarning( )

%ERRORANDWARNING Create Error and Warning Messages

% This example shows how to create error and warning messages.



NotDone = true;



while NotDone

try



Value = input('Type something: ', 's');



switch Value

case 'error'

error('Input Error');

case 'warning'

warning('Input Warning');

case 'done'

NotDone = false;

otherwise

disp(['You typed: ', Value]);

end

catch Exception

disp('An exception occurred!');

disp(Exception.getReport());

end

end



end

The example begins by creating a loop. It then asks the user to type something. If that something happens to be error or warning, the appropriate error or warning message is issued. When the user types done, the application exits. Otherwise, the user sees a simple output message. The example looks simple, and it is, but it has a couple of interesting features. The following steps help you work with the example:

1. Type ErrorAndWarning() and then presses the Enter key, all in the Command window.

The application asks you to type something.

2. Type Hello World! and press Enter.

You see the following output:

You typed: Hello World!

The application asks the user to type something else.

3. Type warning and press Enter.

You see the following output (which may differ slightly from that shown):

Warning: Input Warning

> In ErrorAndWarning at 16

Notice that the message doesn’t say anything about an exception. A warning is simply an indicator that something could be wrong, not that something is wrong. As a result, you see the message, but the application doesn’t actually generate an exception. The application asks the user to type something else.

4. Type error and press Enter.

You see the following output:

An exception occurred!

Error using ErrorAndWarning (line 14)

Input Error

This time, an exception is generated. If the exception handler weren’t in place, the application would end at this point. However, because an exception handler is in place, the application can ask the user to type something else. Adding exception handlers makes recovering from exceptions possible, as happens in this case. Of course, your exception handler must actually fix the problem that caused the exception.

5. Type done and press Enter.

The application ends.

The example application uses the simple form of the error() and warning() functions. Both the error() and warning() functions can accept an identifier as the first argument, followed by the message as the second. You can also add the cause, stack trace, and correction elements as arguments. The point is, all you really need in most cases is a simple message.

Setting warning message modes

Error messages always provide you with any details that the application provides. Warning messages are different — you can tell MATLAB to provide only certain details as needed. You can set the configuration globally or base it on the message identifier (so that warnings with some identifiers provide more information than others do). To set the global configuration, you provide two arguments. The first is the warning state:

· on: Sets the configuration element on.

· off: Turns the configuration element off.

· query: Determines whether the configuration element is currently on or off.

At a global level, you have access to two settings, which are provided as the second argument to the warning() function:

· backtrace: Determines whether the output includes stack trace information.

· verbose: Determines whether the output includes a short message or one with all the details as well.

To see how this works, type warning('query', 'backtrace') and press Enter. You should see an output message telling you the current status of the backtrace configuration element. (The default setting turns it on so that you can see the stack trace as part of the warning message when a stack trace is provided.)

The message identifier-specific form of the warning() function starts with a state. However, in this case, the second argument is a message identifier. For example, if you type warning('query', 'MATLAB:FileIO:InvalidFid') and press Enter, you see the current state of the MATLAB:FileIO:InvalidFid identifier.

Tip To suppress a warning, you use the warning() function with 'off' as the first argument. You supply the name of the warning as the second argument. For example, to suppress all warnings, you use warning('off', 'all'), but to suppress only warning messages associated with the attempted removal of a nonexistent path, you use warning('off', 'MATLAB:rmpath:DirNotFound'). You can obtain warning identifiers a number of ways, but the easiest method is to create the condition in which the warning occurs and then query it using warning('query', 'last'). To turn warnings back on, you simply use 'on' as the first argument.

Warning Setting warnings for particular message identifiers to off is usually a bad idea because the system can’t inform you about problems. This is especially true for MATLAB-specific messages (rather than custom messages that you create, as described in the “Making Your Own Error Messages” section, later in the chapter). However, setting them to off during troubleshooting can help you avoid the headache of seeing the message all the time.

Understanding Quick Alerts

Errors can happen at any time. In fact, there seems to be an unwritten law that errors must happen at the most inconvenient time possible, and only when anyone who can possibly help is out of the building. When you face this problem, at least you have the assurance that every other person to ever write an application has faced the same problem. Waiting by your phone for a call to support your application that you don’t want to hear (because it’s always bad news) is one approach, but probably not the best because the person on the other end of the line is unlikely to have the information you so desperately need to resolve the issue.

When you’re stuck with an error, sending yourself a note is probably a better option than waiting for a call from someone. Fortunately, MATLAB provides the sendmail() function for this purpose. It’s possible for you to make one of the responses in your error-handling code be to send an email that you can pick up on your smartphone. That way, you get information directly from the application, which enables you to fix the problem right where you are, rather than have to go into work. The sendmail() function accepts these arguments:

· Recipients: Provides a list of one or more recipients for the message. Each entry is separated from the other with a semicolon.

· Subject: Contains the message topic. If the problem is short enough, you can actually present the error message in the subject line.

· Message (optional): Details the error information.

· Attachments (optional): Specifies the path and full filename of any attachment you want to send with the message.

Remember Before you can send an email, you must configure MATLAB to recognize your Simple Mail Transfer Protocol (SMTP) server and provide a From address. To do this, you must use a special setpref() function. For example, if your server is smtp.mycompany.com, you type setpref('Internet', 'SMTP_Server', 'smtp.mycompany.com') in the Command Window and press Enter. After you set the SMTP address, you set the From address by providing your email address as input to the setpref() function, as in setpref('Internet', 'E_mail', 'myaddress@mycompany.com'). You can also verify your settings using the getpref() function. Use rmpref() to remove preferences that you don’t need, and use addpref() to add more preferences.

Listing 18-4 shows a technique for sending an email. The code used to create the error is similar to the Broken example used earlier in the chapter (see the “Responding to error messages” section). However, this time the example outputs an email message rather than a message onscreen. You can also find this function in the Broken3.m file supplied with the downloadable source code. (For this example to work, you must use setpref() to set the address of a real email server, as well as change the email address found in the sendmail() call in the code.)

LISTING 18-4 Sending an Email Alert

function [ ] = Broken3( )

%BROKEN3 A broken piece of code.

% This example is designed to generate an error

% and send an e-mail about it.



try

Handle = fopen('DoesNotExist.txt');

Data = fread(Handle);

disp(Data);

catch exc

disp('Sending for help!');

sendmail('myaddress@mycompany.com',…

'Broken3',…

['Identifier: ', exc.identifier,10,…

'Message: ', exc.message]);

end

end

Notice how the example uses the sendmail() function. The address and subject appear much as you might think from creating any other email message. The message is a concatenation of strings. The first line is the error identifier, and the second is the error message. Notice the number 10 between the two lines. This value actually creates a new line so that the information appears on separate lines in the output message. Figure 18-1 shows a typical example of the message (displayed using Outlook in this case).

Snapshot of a typical email message containing MATLAB error information.

FIGURE 18-1: A typical email message containing MATLAB error information.

Warning Working with email can be tricky because different email servers handle message requests in different ways, and modern email systems have multiple levels of security in many cases. Consequently, you may need to employ some specialized code to make the Broken3 example work with your particular server. For example, if you use Google Mail, you may need to take the helpful information at https://support.google.com/accounts/answer/185833?hl=en into account when putting this example together.

Relying on Common Fixes for MATLAB’s Error Messages

MATLAB does try to inform you about errors whenever it finds them. Of course, your first line of defense in fixing those errors is to rely on MATLAB itself. Previous chapters of the book outline a number of these automatic fixes. For example, when you make a coding error, MATLAB usually asks whether you meant to use some alternative form of the command, and it’s right quite often about the choice it provides.

The editor also highlights potential errors in orange. When you hover the mouse over these errors, you see a small dialog box telling you about the problem and offering to fix it for you. The article at https://www.mathworks.com/help/matlab/matlab_prog/check-code-for-errors-and-warnings.html discusses a number of other kinds of automatic fixes that you should consider using.

Remember Sometimes an automatic fix doesn’t make sense, but the combination of the error message and the automatic fix provides you with enough information to fix the problem on your own. The most important things to do are to read both the error message and the fix carefully. Humans and computers speak different languages, so there is a lot of room for misunderstanding. After you read the information carefully, look for typos or missing information. For example, MATLAB does understand A*(B+C) but doesn’t understand A(B+C). Even though a human would know that the A should be multiplied by the result of B+C, MATLAB can’t make that determination. Small bits of missing text have a big impact on your application, as do seemingly small typos, such as typing Vara instead of VarA.

Don’t give up immediately, but at some point you need to start consulting other resources rather than getting bogged down with an error that you can’t quite fix. The MATLAB documentation can also be a good source of help, but knowing where to look (when you can barely voice the question) is a challenge. That’s where MATLAB Answers (https://www.mathworks.com/matlabcentral/answers/) comes into play. You can use this resource to obtain answers from MATLAB professionals, in addition to the usual peer support. If you can’t find someone to help you on MATLAB Answers, you can usually get script and function help on Code Project (https://www.codeproject.com/script/Answers/List.aspx?tab=active&tags=922) and other third-party answer sites.

Tip Fortunately, there are other documentation alternatives when the MATLAB documentation can’t help. For example, the MATLAB Programming/Error Messages article at https://en.wikibooks.org/wiki/MATLAB_Programming/Error_Messages describes a number of common errors and how to fix them. Another good place to look for helpful fixes to common problems is MATLAB Tips (https://www3.nd.edu/~nancy/Math20550/Matlab/tips/matlab_tips.html). In short, you have many good places to look online for third-party assistance if your first line of help fails.

Warning Although you can find a lot of MATLAB information online, be aware that not all of it is current. Old information may work fine with a previous version of MATLAB, but it may not work at all well with the version installed on your system. When looking for help online, make sure that the help you obtain is for the version of MATLAB that you actually have installed on your machine, or test the solution with extreme care to ensure that it does work.

Making Your Own Error Messages

At some point, the standard error messages that MATLAB provides will fall short, and you’ll want to create custom error messages of your own. For example, MATLAB has no idea how your custom function is put together, so the standard messages can’t accommodate a situation in which a user needs to provide a specific kind of input. The only way you can tell someone that the input is incorrect is to provide a custom error message.

Fortunately, MATLAB provides the means for creating custom error messages. The following sections describe how to create the custom error messages first, and then how to ensure that your custom error messages are as useful as possible. The most important task of an error message is to inform others about the problem at hand in a manner that allows them to fix it. So creating custom error messages that really do communicate well is essential.

Developing the custom error message

The example in this section is a little more complex than earlier examples in this book. When you develop something like custom error messages, you want to create the code itself, followed by a means to test that code. Developers use a fancy term, testing harness, to describe the code used to test other code. The odd name isn’t necessary, though. One file contains the code that you use to check for a condition, and another file contains the test code. The following sections describe the two files used for this example.

Creating the exception code

Testing user inputs is usually a good idea because you never know what a user will provide. In Listing 18-5, the code performs a typical set of checks to ensure that the input is completely correct before using it to perform a task — in this case, displaying the value onscreen. The technique used in this example is a good way to ensure that no one can send you data that isn’t appropriate for a particular application need. You can also find this function in the CustomException.m file supplied with the downloadable source code.

LISTING 18-5 Checking for Exceptional Conditions

function [ ] = CustomException( Value )

%CUSTOMEXCEPTION Demonstrates custom exceptions.

% This example shows how to put a custom exception

% together.



if nargin < 1

NoInput = MException('MyCompany:NoInput',…

'Not enough input arguments!');

NoInput.throw();

end



if not(isnumeric(Value))

NotNumeric = MException('MyCompany:NotNumeric',…

'Input argument is type %s number needed!',…

class(Value));

NotNumeric.throw();

end



if (Value < 1) || (Value > 10)

NotInRange = MException('MyCompany:NotInRange',…

'Input argument not between %d and %d!',…

1, 10);

NotInRange.throw();

end

fprintf('Successfully entered the value: %d.\r',…

Value);



end

The code begins by checking the number of arguments. This example contains no default value, so not supplying a value is an error, and the code tells the caller about it. The NoInput variable contains an MException object that has an identifier for MyCompany:NoInput. This is a custom identifier, the sort you should use when creating your own exceptions. An identifier is a string, such as your company name, separated by a colon from the exception type, which is NoInput in this case.

The message following the identifier provides additional detail. It spells out that the input doesn’t provide enough arguments in this case. If you wanted, you could provide additional information, such as the actual input requirements for the application.

After NoInput is created, the code uses the throw() method to cause an exception. If the caller hasn’t placed the function call in a try…catch block, the exception causes the application to fail. The exception does cause the current code to end right after the call to throw().

Tip The second exception works much the same as the first. In this case, the code checks to ensure that the input argument (now that it knows there is one) is a numeric value. If Value isn’t numeric, another exception is thrown. However, notice that this exception detects the kind of input actually provided and returns it as part of the message. The messages you create can use the same placeholders, such as %d and %s, as the sprintf() and fprintf() functions used in earlier chapters.

Remember Note the order of the exceptions. The code tests to ensure that there is an argument before it tests the argument type. The order in which you test for conditions that will stop the application from running properly is essential. Each step of testing should build on the step before it.

The third exception tests the range of the input number (now that the code knows that it is indeed a number). When the range is outside the required range, the code throws an exception.

When everything works as it should, the code ends by displaying Value. In this case, the application uses fprintf() to make displaying the information easier than it would be when using disp(), because disp() can’t handle numeric input.

Creating the testing code

Testing your code before using it in a full-fledged application is essential. This is especially true for error-checking code, such as that found in CustomException(), because you rely on such code to tell you when other errors occur. Any code that generates exceptions based on errant input must be held to a higher standard of testing, which is why you need to create the testing harness shown in Listing 18-6. You can also find this function in the TestCustomException.m file supplied with the downloadable source code.

LISTING 18-6 Testing the Exception Code

function [ ] = TestCustomException( )

%TESTCUSTOMEXCEPTION Tests the CustomException() function.

% Performs detailed testing of the CustomException() function

% by checking for input type and ranges.



% Check for no input.

try

disp('Testing no input.');

CustomException();

catch Exc

disp(Exc.getReport());

end

% Check for logical input.

try

disp('Testing logical input.');

CustomException(true);

catch Exc

disp(Exc.getReport());

end

% Check for string input.

try

disp('Testing string input.');

CustomException('Hello');

catch Exc

disp(Exc.getReport());

end

% Check for number out of range.

try

disp('Testing input too low.');

CustomException(-1);

catch Exc

disp(Exc.getReport());

end

try

disp('Testing input too high.');

CustomException(12);

catch Exc

disp(Exc.getReport());

end

% Check for good input.

try

disp('Testing input just right.');

CustomException(5);

catch Exc

disp(Exc.getReport());

end

end

This code purposely creates exceptions and then outputs the messages generated. By running this code, you can ensure that CustomException() works precisely as you thought it would. Notice that the test order follows the same logical progression as the code in the CustomException.m file. Each test step builds on the one before it. Here’s the output you see when you run TestCustomException():

Testing no input.

Error using CustomException (line 9)

Not enough input arguments!

Error in TestCustomException (line 9)

CustomException();



Testing logical input.

Error using CustomException (line 16)

Input argument is type logical number needed!

Error in TestCustomException (line 17)

CustomException(true);



Testing string input.

Error using CustomException (line 16)

Input argument is type char number needed!

Error in TestCustomException (line 25)

CustomException('Hello');



Testing input too low.

Error using CustomException (line 23)

Input argument not between 1 and 10!

Error in TestCustomException (line 33)

CustomException(-1);



Testing input too high.

Error using CustomException (line 23)

Input argument not between 1 and 10!

Error in TestCustomException (line 39)

CustomException(12);



Testing input just right.

Successfully entered the value: 5.

The output shows that each phase of testing ends precisely as it should. Only the final output provides the desired result. Notice how the incorrect input types generate a custom output message that defines how the input is incorrect.

Creating useful error messages

Creating useful error messages can be hard. When you find yourself scratching your head, trying to figure out just what’s wrong with your input, you’re experiencing a communication problem. The error message doesn’t provide enough information in the right form to communicate the problem to you. However, creating good error messages really is an art, and it takes a bit of practice. Here are some tips to make your error-message writing easier:

· Keep your messages as short as possible, because long messages tend to become difficult to understand.

· Focus on the problem at hand, rather than what you think the problem might be. For example, if the error message says that the file is missing, focus on the missing file, rather than on something like a broken network connection. It’s more likely that the user mistyped the filename than it is that the network is down. If the filename turns out to be correct, it could have been erased on disk. You do need to eventually check out the network connection, but focus on the problem at hand first and then move out from there so that your error trapping is both procedural and logical.

· Provide specific information whenever possible by returning the errant information as part of the error message.

· Ask others to try your testing harness, read the messages, and provide feedback.

· Make the error message a more detailed version of the message identifier and ensure that the message identifier is unique.

· Verify that every message is unique so that users don’t see the same message for different conditions. If you can’t create unique wording, perhaps you need to create a broader version of the message that works for both situations.

· Ensure that each message is formatted in a similar way so that users can focus on the content rather than the format.

· Avoid humorous or irritating language in your messages — make sure that you focus on simple language that everyone will understand and that won’t tend to cause upset rather than be helpful.

Using Good Coding Practices

A lot of places online tell you about good coding practice. In fact, if you ask five developers about their five best coding practices, you get five different answers, partly because everyone is different. The following list represents the best coding practices from a number of sources (including personal experience) that have stood the test of time.

· Get a second opinion: Many developers are afraid to admit that they make mistakes, so they keep looking at the same script or function until they’re bleary-eyed, and they usually end up making more mistakes as a result. Having someone else look at the problem could save you time and effort, and will most definitely help you discover new coding practices more quickly than if you go it alone.

· Write applications for humans, not machines: As people spend more time writing code, they start to enjoy what they do and start engaging in writing code that looks really cool but is truly horrible to maintain. In addition, the code is buggy and not very friendly to the people using it. Humans use applications. No one uses cool code — people use applications that are nearly invisible and that help them get work done quickly, without a lot of fuss.

· Test often and make small changes: A few people actually try to write an entire application without ever testing it, even once, and then they’re surprised when it doesn’t work. The best application developers work carefully and test often. Making small changes means that you can find errors faster and fix them faster still. When you write a whole bunch of code without testing it, you really don’t have any way to know where to start looking for problems.

· Don’t reinvent the wheel: Take the opportunity to use someone else’s fully tested and bug-free code whenever you can (as long as you don’t have to steal the code to do so). In fact, actively look for opportunities to reuse code. Using code that already works in another application saves you time in writing your application.

· Modularize your application: Writing and debugging a piece of coding takes time and effort. Maintaining that code takes even longer. If you have to make the same changes in a whole bunch of places every time you discover a problem with your code, you waste time and energy that you could use to do something else. Write the code just one time, place it in a function, and then access that piece of code everywhere you need it.

· Plan for mistakes: Make sure your code contains plenty of error trapping. It’s easier to catch a mistake and allow your application to fail gracefully than it is to have the application crash and lose data that you must recover at some later time. When you do add error-trapping code, make sure to write it in such a manner as to actually trap the sorts of errors that you expect, and then add some general-purpose error trapping for the mistakes you didn’t expect.

· Create documentation for your application: Every application requires documentation. Even if you plan to use the application to meet just your own needs, you need documentation, because all developers eventually forget how their code works. Professionals know from experience that good documentation is essential. When you do create the documentation, make sure that you discuss why you designed the software in a certain manner, what you were trying to achieve by creating it, problems you encountered making the software work, and fixes you employed in the past. In some cases, you want to also document how something works, but keep the documentation of code mechanics (how it works) to a minimum.

· Remember Ensure that you include documentation within your application as comments: Comments within applications help at several different levels, the most important of which is jogging your memory when you try to figure out how the application works. However, it’s also important to remember that typing help('ApplicationName') and pressing Enter will display the comments as help information to people using your application.

· Code for performance after you make the application work: Performance consists of three elements: reliability, security, and speed. A reliable application works consistently and checks for errors before committing changes to data. A secure application keeps data safe and ensures that user mistakes are caught. A fast application performs tasks quickly. However, before you can do any of these things, the application has to work in the first place. (Remember that you can use the profile() command to measure application performance and determine whether changes you implement actually work as intended.)

· Make the application invisible: If a user has to spend a lot of time acknowledging the presence of your application, your application will eventually end up collecting dust. For example, the most annoying application in the world is the one that displays those “Are you sure?” messages. If the user wasn’t sure, there would be no reason to perform the act. Instead, make a backup of the change automatically so that the user can reverse the change later. Users don’t even want to see your application — it should be invisible, for the most part. When a user can focus on the task at hand, your application becomes a favorite tool and garners support for things like upgrades later.

· Force the computer to do as much work as possible: Anytime you can make something easier for the user, you reduce the chance that the user will make a mistake that you hadn’t considered as part of the application design. Easy doesn’t mean fancy. For example, many applications that try to guess what the user is going to type next usually get it wrong and only end up annoying everyone. Let the user type whatever is needed, but then you can check the input for typos and ensure that the input won’t cause the application to fail. In fact, rather than try to guess what the user will type next, create an interface that doesn’t actually require any typing. For example, instead of asking the user to enter a city and state in a form, have the user type a zip code and obtain the city and state from the zip code information.

If you find an error or have any questions, please email us at admin@erenow.org. Thank you!