How to Debug Programs and Life

For several reasons related to WWDC2016, I’m breaking up the sequence I’m doing on XML. We’ll continue that next week, but this week I’m giving you the article I wrote from this week’s Slice Of App Pie podcast on debugging. I’ve had several questions on the issue. this is the first of several responses. Look for this fall a whole series on Debugging.

If you’d like to hear me talk about debugging, listen to the podcast here or click here for the episode web page.

Let me tell you two stories. The first is a story about Rear Admiral Grace Hopper. She was one of the first people to program what we think of as a modern computer, and wrote the first compiler, and the Language COBOL. On September 9, 1947, there was an error in the computation on the Harvard Mark II computer she was working with. Some of the staff found a moth had gotten caught in a relay, causing the error. She taped the moth to her notes for the day.


By Courtesy of the Naval Surface Warfare Center, Dahlgren, VA., 1988. – U.S. Naval Historical Center Online Library Photograph NH 96566-KN, Public Domain, https://commons.wikimedia.org/w/index.php?curid=165211
While a moth is not a bug, and others used the term before her, for years afterwards she would tell this story, and is credited with popularizing the term  bug first in the computer industry, and eventually the world.

My second story is one I get often. Over on my MakeAppPie.com website, the most frequent communication I get is “your code doesn’t work.” I go and look at the code, and find it does. What I rarely get is, “I was having problems with your code, and found that on line 6 of the function printSomething in class ViewController needs to be  let a:[String:AnyObject]! = nil not a:[String:String]! = nil.

The difference between those two comment is the second case debugged the code. The first did not. Over at MakeAppPie.com it does happen that Apple switches versions of Swift or an API on me, and the code fails. But the first commenter did not bother to look, or even bother to get specific about why it didn’t work. The second did some work.

Not enough people do that work from what I can tell.From the questions I ask them after that first comment, I think they don’t know how to. Not enough people learn about debugging. I’d like to do some explaining about debugging.

I find there are two kinds of bugs:my bugs and not my bugs. My bugs are the things that I did wrong. I like these bugs. I have control over them. If I can do something wrong, I can fix it. I have control of the situation.

There are three bugs that I can do something about: syntax errors, logical Errors and Design Errors. Syntax errors are bugs where I typed code wrong. For example in JavaScript I could have this function:

function myFunction(p1, p2) {
var p = p1 * p2
return p;
}

Because I forgot a semicolon after the calculation of p1*p2, I have a syntax error and the application will not run. One of the most frustrating things about JavavScript is it won’t tell you when there is a syntax error. Fortunately most languages are a lot more explicit about syntax errors. If you did this in Swift

func whatIsX(x:Int!) {
if x = nil {
print(“No Value for X”)
}
var result = String(format”X is %i”,x)
Print (result)
}

Xcode would light up in errors and warnings.  From the IBM Sandbox (you can try this here: http://swiftlang.ng.bluemix.net/#/repl/575eaa89d4c6c057192c0ba4) I got this:
ERROR at line 9, col 27: expected ‘,’ separator
var result = String(format”X is %i”,x)
^
,
ERROR at line 6, col 10: cannot assign to value: ‘x’ is a ‘let’ constant
if x = nil {
~ ^
ERROR at line 9, col 21: use of unresolved identifier ‘format’
var result = String(format”X is %i”,x)
^~~~~~
ERROR at line 10, col 1: use of unresolved identifier ‘Print’
Print (result)
^~~~~

Sometimes syntax errors are hard to understand. The first error says I’m trying to assign a constant with nil, wich I can’t do. You sometime have to do a little interpreting. I want to compare x and nil. I used the assignment operator = when I should have used a comparison operator  != or ==.  I also forgot a : after format to make it a parameter. Swift is case sensitive and Print should be print. If I changed my code to this I’d get rid of the errors..almost: IBM sandbox

func whatIsX(x:Int!) {
if x != nil {
print(“No Value for X”)
}
var result = String(format:”X is %i”,x)
print (result)
}

I get one more warning to change var to let.

/swift-execution/Sources/main.swift:6:9: warning: variable 'result' was never mutated; consider changing to 'let' constant
    var result = String(format:"X is %i",x)
    ~~~ ^
    let

So I change it to this:
func whatIsX(x:Int!) {
if x != nil {
print(“No Value for X”)
}
let result = String(format:”X is %i”,x)
print (result)
}

And then I get no errors. (IBM Sandbox)

Syntax errors of the fatal kind like x=nil don’t get too far. Your program will not compile. Warnings like changing var to let, will let the program work, but often they might cause problems later on as the second kind of bug, a logical bug.

Logical bugs will give you wrong answers or wrong functionality. Since  most compilers catch all the syntax errors, this is the most common like of bug. The program can run but it doesn’t do what we want. In the same function, there is no errors or warnings, but is has two bugs. If you called the function wahtIsX(x:nil) you’d crash with an unwrapping error.(IBM SandBox)

fatal error: unexpectedly found nil while unwrapping an Optional value

If you called whatIsX(x:5) you’d get(IBM Sandbox)

No Value for X
X is 5

We have two bugs. the first is the logical operator in the if statement. It should be equals  == instead of not equals !=.  Secondly,  we have a flow of execution problem. The if statement executes, then continues down the code. With X having a value of nil, it cannot unwrap that in the String function. There’s two solutions for this. We could use an else clause for the second print, or we can return after encountering a nil. I used the second

func whatIsX(x:Int!) {
if x == nil {
print(“No Value for X”)
return
}
let result = String(format:”X is %i”,x)
print (result)
}

Now we run with both function calls and the function works. (IBM Sandbox)
whatIsX(x:nil)

No Value for X

whatIsX(x:5)
X is 5

The third kind of error is a design error. I tend to break these into two categories, code design and user experience(UX) design. Let’s look at UX design first. Apple has an entire set of design guidelines (https://developer.apple.com/design/), including the Human interface guides and a webpage (https://developer.apple.com/design/tips/ )summarizing good design. Android does too. (https://developer.android.com/design/get-started/principles.html) If your user has a problem using your app, they wont use it. Let’s take one simple design principle that works with phones. Compare these two layouts:

One has the button on the top, one on the bottom. People hold their phones  one-handed so they can do most functions with their thumbs. Most thumbs don’t reach the top of the phone, while all reach the bottom. It’s better design to put a frequently pressed button on the bottom. If you want one that requires bit more effort, and possibly a bit of reflection, place it on the top.

There is serious research in this topic. The master on this topic is Donald Norman,who at one time worked for Apple on this subject.  His book the Design of everyday things is a classic in understanding Human Centered design. These design issues are found everywhere, not only user interfaces. For a simple example here’s a video of  Don Norman talking about doors

The other design error is code design. We can get rid of many logical bugs by designing them out. For example suppose you have a 1GB database based on a web server somewhere. You could load the entire database into you phone and then find the few record you want, but that is not good design. It takes up lots of memory, maybe enough to blow out the application. Instead you design the program to ask for only the records you need, not all the ones you don’t.

Code design bridges my bugs and not my bugs. The not my bugs category has  the errors that aren’t your fault. At best, you can assume they are going to happen in your application and design your application to deal with them. For example look at these two phones:

The one of the left is designed to constrain your answer to Yes or No. The one on the right might have yes, Yes, Yah, maybe, no, No, What, are you crazy, NO!!!!, or  a 5-paragraph essay on Don Norman’s design principles. Which is easier to code for and get expected results? Which would be near impossible to do any analysis on? That’s design at work.

Let go back to the web database for another example. I can’t assume anything about the data I’m getting from that server. It may give me the right data. It might give the wrong data, corrupted data, take forever for data to reach me, not make a connection with the server, or have a interrupted connection with the server. My design accounts for each of those possibilities, since any one of them might crash my app as a bug. This is where error handlers and validators come into design. Prevent the bug by adding code that deals with it happening.

The last bug that isn’t my fault is the one written by somebody else’s code. If you are reading this close to when I published it, there’s a perfect example you’re probably going to be battling. Consider this code, which is the WhatIsX function but adds one to x before printing:

func whatIsX(x:Int!) {
if x == nil {
print(“No Value for X”)
return
}
var y = x!
y++
let result = String(format:”X is %i”,y)
print (result)
}

That worked fine last week in Xcode(you might get a warning about the bug though), but if you use the IBM Sandbox and I’m guessing the new Xcode available after WWDC2016, things will not be so nice. Both  are Swift 3.0 implementations,  you’ll get this error:(IBM Sandbox)

ERROR at line 8, col 6: '++' is unavailable: it has been removed in Swift 3
    y++
     ^~
      += 1

Swift 3.0 has some syntax changes. Removing ++ or is one of them. You have to write this code with y +=1:
(IBM Sandbox)
func whatIsX(x:Int!) {
if x == nil {
print(“No Value for X”)
return
}
var y = x!
y += 1
let result = String(format:”X is %i”,y)
print (result)
}

Updates to the language, APIs or third party libraries are all subject to this kind of thing regularly. You have to fix syntax changes to the language and changes in implementations of APIs as they happen.  We’re stuck with the compiler, but this is one reason I minimize my use of 3rd party libraries. Some might think I reinvent the wheel, but I’m paranoid: how do I know it is a wheel?. How to I know this code is secure? The amount of testing and validation I have to do to prove it (and in medical devices It’s mandatory to do such testing)  means I might as well write and test my own code. .

Bugs mean the application doesn’t, work, doesn’t do what I want it to and it could do one more thing: It doesn’t do what I want in an acceptable way. Blowing out my memory by loading an entire data is an example. So is a memory leak, where something is gobbling storage and taking up a lot more memory than it should need.

So how do I find bugs? I test for them. Testing can become a complex thing, but I’ll go through a few of the most simple ways I look for and find bugs.  Testing means testing the entire application at different levels. It is testing individual methods to make sure they work. It is also testing the classes to make sure they work, and testing the whole application. It is testing the user interface by giving a copy to a few users and seeing what they think. For each of these I find the bugs, I find the failures in the code.

Finding them is sometimes easy, sometimes hard. Your two simplest tools for debugging is printing to the console and breakpoints. Printing to the console which we do with  print/write/NSLog depending on the language you are using gives us a value of a variable while the application runs. It can tell us two things: that the values for this variable are correct and that the application reached the point where the print is.

Sometimes I want to know that execution happened, but I don’t need to watch a value change. That’s where breakpoints are useful. With most development environments  that allow breakpoints you can also explore  the current values of all your variables and instances. Using those two I find most of the logical errors.

Other times you need stronger tools. Breakpoints and print statements don’t  work alone for memory leaks.  For those you’ll need some monitoring applications. Xcode of course includes Instruments, but other development environments have similar tools.

Once I know what’s wrong I fix it. Very often I’ll find it is a simple mistake. Sometimes it may need a more extensive change.

One I fix it, I I test again. And fix the bugs I might have introduced in the fix, until I’m happy I have no bugs.

This has been quite technical, but somewhere in that technical stuff is a lot you can take away that is about life and any situation. Let’s summarize the above with a few observations that true anywhere.
Be Sherlock Holmes – When problems or failures arise, don’t fret. Instead start the detective work to find out what is wrong. Dig and dig deep to find the problem. use whatever tools will help you find the causes. Most people hate problem solving. Be like Sherlock — seriously enjoy the hunt for the culprit.
Own your mistakes — You’ll often find you either caused the failure or contributed to the failure. Own the mistake. What you own you have control over. That means you fix it, and move forward. If you blame Apple for every bug you get, you will never get a finished product.  If you blame someone else for every problem you have  in life, you will be stuck doing nothing forever.
Laugh at your mistakes -While there are exceptions, most stuff is the small stuff, such as using plus instead of minus somewhere.  These knuckle-headed  mistakes deserves only one response: you laugh at your silliness, and then you fix it.
If it’s not your mistake, work around it the best way possible– Sometimes it is not your fault, and you have no control over the situation. There are always workarounds. Find a workaround to fix it. Get guidance about the workaround from other with the same problem. Sometime the ones at fault might give you a workaround.  If the situation changes and there is a more direct solution than your workaround, its a great idea to use the more direct solution. Workarounds and hacks have a bad habit of attracting bugs.
Design so there are no mistakes– Start your project with a clear vision of what your want. Find all the things you can that might cause problems before you make anything. Play with the system a bit to see if there are any bugs you missed. Only then plan out your design so you avoid as many of those bugs as possible.
Think like a user, not an engineer or artist: Donald Norman and Bruce Tognazzini , Another  former Apple exec who wrote the first Human Interface guide,  wrote a rather long post on how Apple lost its way on design. . While rather long and a very good read, the point is clear: Apple has stopped thinking about how people use their devices and instead spend too much time making it pretty. My book  Practical Auto Layout is of course my favorite example of one of Apples big mistakes. Apple describes an actually simple layout system as quadratic equations between views in stead of pinning and aligning views, losing all the developers in the process. Aple didn’t think of how most developers think. Think of your audience first. Immerse yourself in that audience. Find what they do and think like them. If you don’t, people won’t like your product and won’t use it, nor will they recommend it to their friends.
The always one more bug paradox. You cant get rid of every bug. Some bugs are bugs  because some of your users think one way and others another way. You can’t satisfy both. You can sit there getting pixel perfect and not shipping. This is Resistance doing its worst. Perfect is not the goal, getting a minimum viable product is. Get it working without any additions to your plan, or major revisions. If anyone is fails at this rule constantly at this it is me. I have to kick myself frequently to just get it done and ship. This lesson is an example. It was supposed to be a quick summary of a podcast and became a major article. I get stuck in a paradox. You want to wow your audience, but you also want to ship the minimum viable product. The only advice I can give (I’ll talk more about this in next weeks podcast) is get the product out, and do a lot of revisions after you do. Unless you are major-league recognized brand, a few mistakes will not kill you. Even for large brands a few mistakes didn’t kill them. Apple shipped Apple Maps before it was ready. At first it was a disaster, but it didn’t kill the company, and I like using MapKit far more then Google maps when I code map. Just fix your mistakes, apologize for the inconvenience, make it better and keep going.

There’s this emphasis on coding these days. That’s only a third of good programming. The other two thirds, design and debugging are as important. As life skills they may be more important. I hoped I’ve given those of you who haven’t thought too much about debugging some help and advice about how to think about those other two thirds.

2 thoughts on “How to Debug Programs and Life”

  1. Great topic – one thing I have struggled with is using breakpoints and the debug navigator effectively. I would love an expanded discussion about those tools. I really appreciate your detailed explanations!

    1. After what I saw last night on the state of the platform presentation at WWDC, you will be definitely getting that, and a lot more there are some new tools that are really cool for a variety of bugs. I really need to cover the full debugging system. However Apple dropped a ton of bricks on everyone on the syntax department with Swift 3.0, (that was the biggest awkward silence I’ve ever heard there) so I have have lot of updating to do first. That said, I’m also thinking that I might get bored with updating in late June/July and this would be a good topic to cover.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s