Why Debugging?
Although App Inventor does a good job of eliminating many programming concepts, making it easier for programmers to build mobile applications, it has very few tools for debugging. When problems arise, users are mostly helpless in trying to deduce what an error is, track it down, and determine what the correct solution is. There needs to be a way to help users in debugging. The visual environment of App Inventor also requires us to consider how we present debugging information to users. We must keep with the over-arching goal of giving users meaningful information that can be interacted with intuitively.
What debugging tools DO Exist?
Take a look at the following blocks.
Here you can see we are attempting to use the addition block to add the string, "abc", with the number, 123. In App Inventor the addition block limits us to only adding numbers. One good thing App Inventor will do is actually prohibit us from ever plugging the "abc" block into the addition block. The block is immediately rejected.
![]() Unfortunately, there is a way to get around this. If we plug the "abc" block into a global variable, called string, and then plug the get global string block into the addition block we can illegally attempt to add "abc" and 123. As you might imagine, this will not work. In the example on the right, you will notice two addition blocks with get global string and 123, as well as multiple get global string blocks throughout the program. Now, if we try to execute this code, we will be presented with a rather useless pop-up error message.
The error message tells us that there is an issue between adding "abc" and 123. As I said, there are two blocks performing this function, as well as multiple blocks referring to "abc". This pop-up message gives no information about which block the error originated from. Imagine we have a very large and complex program with hundreds of blocks. Finding this block is only going to be more difficult. This can be even more irritating if the error is quick-fire error (an error that occurs very often and very quickly, such as one produced by a timer that goes off every second). You'll notice the second message on the block says the pop-up will occur every 5 seconds, such that the error is firing. If you have to scroll through hundreds of blocks looking for an error that is firing every second, you'll probably find that these pop-ups will make you want to chuck your computer right out the window.
Sometimes we can run a program and the computer will not recognize that there are any errors, yet the program is not behaving the way we want it to. Perhaps a string is not printed the way we anticipate, or we are getting the wrong calculation of a number. These are called logic errors. They are errors that do not hinder the execution of a program, but causes the program to operate incorrectly. Debugging this type of error can be incredibly difficult because not only to you have to infer what the error is, but you have to search for the source. App Inventor has this tool called Do It that will quickly allow you to evaluate an isolated block from the editor without having to execute it on the device. Putting a Do It on a block looks something like this:
![]() In this example we called a Do It on the procedure call of Increment. Increment, takes the global variable, count, adds one to it, and returns its new value. The Do It message appears in a comment box connected to the block you called a Do It on. So, if the current count is 0, the procedure will add 1 and print the value in the comment box. If you have a variable that is frequently changing, you can call a Do It, multiple times at different stages of execution. The next Do It would return 2 and so forth. Do It gives programmers the power to track specific changes during execution. Unfortunately, Do It only tells us what a value will be between executions. If we are changing count in other places, a Do It will not take that into consideration on this particular block. What we need is a better way to isolate blocks and track them over time. We also need to improve the layout for Do It and comments. Having comments and Do It messages intermingled in one comment box is unclear and unnecessary.
What I've Done!
First off, it should be noted that part my work has been branching off and improving work that Johanna Okerlund '14 did for her thesis. The goal of my work was to minimize the amount of time users spend searching and agonizing over bugs, as well as to give users better tools to determine the best solutions to bugs. Johanna and I have implemented various tools to help users in the troublesome process of debugging.
Errors on Blocks
As I mentioned above, the error messages produced by App Inventor are less than useful and mildly annoying, at best. There are two particular issues with the current messages. First, they give you absolutely no clues to where the offending blocks are located. Second, they are a terrible way to present recurring information. Our solution is to put the error message directly on the error inducing block.
Putting the error directly block immediately eliminates the need to spend time searching for the error inducing block. There is absolutely no confusion as to which block is causing the error. If an error is occurring multiple times, rather than have a recurring pop-up message, there is simply a running total of how many times the error has occurred, providing more information about the error.
JSON Format for Lists
Currently, lists in App Inventor are displayed in an awful parenthesized format you can see on the left-hand picture below. This format originates from the way the Scheme Programming language, which is where the blocks are evaluated, formats lists. In Scheme, strings are not quoted and no commas or other separators are used. Although this makes sense in Scheme, it makes absolutely no sense to a typical App Inventor user, especially those completely new to programming. In this notation you cannot infer that "cat" and "fish dog" are two separate strings. Users can tell no difference between string "true" and boolean true. The same goes for string "6" and number 6. This is the format used in the blocks editor for building the application as well as on components themselves in the application. Users have defaulted to writing complicated parsing methods to display lists in a way that is appropriate for their application.
The solution was to reformat lists into JSON format for the user. JSON wraps strings in quotes, leaves booleans as true or false, and leaves integers as themselves. Each element is separated by a comma and the whole list is wrapped in brackets. All of these features overcome the ambiguous nature of the parenthesized notation. It is also the case that perhaps a user wants to format the lists in a particular way for their application. I have created a block that allows a programmer to parse a list into a string with each element separated by the specified separator. In the following example we parse a list of animal strings into a single string, with each animal separated by a single line.
This tool negates the need for users to write messy, possibly inefficient parsing methods. In terms of debugging, using JSON format presents more meaningful information to programmers. A pleasing format can be extremely powerful. As a goal, App Inventor hopes to make the system completely JSON compatible. There is a strong desire to be able to parse directly from JSON styled files and pages.
Watch and Icons for Watch, Do It, and Comments
![]() I mentioned that the current display for comments and Do It is cluttered and confusing. My solution was to put these functions into separate textbubbles, each with a personalized icon and various features particular to each bubble's purpose. By clicking on the icons, you can hide and reveal each accompanying bubble. The left bubble is for comments, for which you can clear, hide, and remove. The middle is for the Do It function, which has the same functions as comments, but also the option to call multiple Do Its. The right bubble is for Watch. Watch is much like an extended Do It. If you put a Watch on a block, while the block is called, in this case due to Button1 being clicked on the device, the value of the block will be printed in the bubble. This is possible more powerful than Do It because it allows the user to see the exact value of something during execution, rather than between. It is useful in watching for an unexpected value, or to see how many times a loop executes. Also, it is much simpler to just put a Watch on something instead of calling multiple Do Its, which may or may not be giving you the precision of information you need. For Watch, you may have the desire to turn Watch off. Without removing the bubble, you can continue executing on the device. When you turn Watch back on, it will pick up wherever the device is. The user can also choose if they want values printed top-bottom or bottom-top.
Future: Trace and Deterministic Replay Debugger
My next project is to finish up a feature called Trace. Like Watch is much like an extended Do It, Trace is like an extended Watch. When a user puts a "trace" on a certain part of the program, a single bubble is put on the starting block of the trace that contains all values of all blocks executed over that time. This provides valuable information about how values change, overlap, or affect each other. The design will include a way to click on the name of a particular block so that it centers over and highlights the block so that you can quickly identify and fix any issues with it. I also hope to move the trace out of the bubble, and into a free-standing bubble so that it is mobile over the entire workspace.
Next I would like to implement a Deterministic Replay Debugger. I do not have a detailed plan for this, but the general concept will be to give users a way to replay an exact execution of a program. This will be a good way to debug something that doesn't occur every time or occurs only under very specific circumstances. Some constraints will be finding a way to save all that was executed without slowing down the program and also implementing a way to pause and start a replay. The replay debugger will be a very powerful debugging tool, combining the concepts of Do It, Watch, and Trace with visual cues.
|
App Inventor >