CompSci 307
Fall 2022
Software Design and Implementation

As soon as we started programming, we found to our surprise that it wasn’t as easy to get programs right as we had thought. We had to discover debugging. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs. — Maurice Wilkes, 1949

Lab Exercise: Debugging

This exercise is intended for you to practice using IntelliJ's Debugger to find bugs in your code, rather than println() statements, because it is a powerful time saving tool if you learn to use it well.

Submission

There will not be an official submission for this exercise, instead show your progress to a UTA during lab when you think you are finished to get feedback.

Resources

Pair Programming

Labs in this course expect you to work either in pairs or with your project team.

Professionally, this practice is called Pair Programming: working closely with another programmer, sharing a "single computer" that we will simulate using a shared computer, shared repository or use IntelliJ's new Code With Me feature. To ensure both people do some coding, you will switch which person actually writes the code every 10-15 minutes (in industry this switch happens only 1-3 times per day). The person who is not actively coding can be advising, suggesting better names, looking up documentation, or searching the Internet for solutions to small problems you are likely to face, but not multi-tasking (i.e., doing their own work or socializing).

Specifications

No matter how skilled a programmer is, no one always programs perfectly the first time, so a systematic approach and patience are vital when facing buggy code. Consider how NASA engineers deal with a ‘data glitch’ on Voyager 1 or what Tesla engineers are going through right now based on bugs in their autopilot feature.

Finding and fixing errors is as much a part of the programming process as typing in the program to start with. If you believe that you are the exception and that you rarely create bugs in your code, it may be that you are failing to adequately test your code! If you believe debugging is harder than programming, you may be right. The programming process and the debugging process require two separate (but overlapping) skill sets, and some will be naturally better at one part than the other. However, just like programming skills, debugging skills can be honed with some training and practice. So let's don our deerstalker hat and chew on a pipe as we attempt to play the role of detective. In order to solve the mystery, we will need to define the crime, victim, and suspects. Then we will follow the clues and collect evidence until we have located the problem and applied a fix.

No matter how you typically debug programs, practice using the Debugger by following these steps:

For each bug you find:

Again, even if you think you know what a bug is, take some time to explore the tools provided by the Debugger.

Buggy Programs

In pairs, complete the debug the following programs using your forked version of the lab_debugging project. After each, add, commit, and push your changes to the code before continuing on to the next.

Detecting Leap Years

Examine the code in the class LeapYearValidator which attempts to determine whether or not a given year is a leap year using the following definition:

A year is a leap year when it has 366 days instead of 365 days. In the international Gregorian calendar a year is a leap year according to the following, correct but perhaps poorly worded, rules as obtained from timeanddate.com:

  1. Every year divisible by 4 is a leap year
  2. But every year divisible by 100 is NOT a leap year
  3. Unless the year is also divisible by 400, then it is still a leap year

 

Validating Credit Cards

Examine the code in the class CreditCardValidator which attempts to implement the following algorithm to validate a credit card number:

A credit card number is validated based on a checksum algorithm. The algorithm works as follows: accumulate a sum by adding a value obtained from each digit moving from left to right, where each kth digit is examined starting with k=0 for the left-most digit.

  • If k is even, add the kth digit to the sum.
  • If k is odd, multiply the kth digit by two. If the result is greater than or equal to 10, subtract 9. Add this computed value to the sum.

If the resulting sum is divisible by 10, the credit card number passes the checksum test, otherwise it is not valid.

 

Binary Search

Examine the code in the class BinarySearcher that implements Binary search, a very efficient search algorithm that finds the position of a target value within a sorted list by repeatedly comparing the target value to the middle element of some part or all of the list and then only continuing to search half of the remaining elements. If the search ends with an "empty" half, then the target is not in the list.

It is also considered by many to be one of the hardest algorithms to code correctly because, while the first binary search was published in 1946, the first binary search to work correctly for all values did not appear until 1962 and some argue that we still do not have a guaranteed correct algorithm.