Thứ Bảy, 10 tháng 10, 2009

Firsthand Frustration with Interface Inaccessiblity

Most of us in the software development business are probably at least aware of accessibility issues associated with software development (particularly user interface development). However, I find that I usually understand the need for something better when I experience the need myself. Although I have learned some lessons about the importance of accessibility from those around me with accessibility issues, I recently encountered a personal experience with an interface that was rendered largely inaccessible for me. It was a frustrating experience, but has provided me with new understanding and empathy for those who are forced to use interfaces that lack sufficiently accessible design. In this post, I look at the personal frustration I felt firsthand during this experience and review what I've learned from it.

Those who know me or have attended one of my technical presentations would probably agree with my statement that I have relatively deep voice. One of the disadvantages of having a relatively deeper voice than "the typical range" of voices is that careful enunciation is more important to convey what I'm trying to say. Years ago when my wife and I went to Disney World, I was impressed at the advancements in speech recognition demonstrated at the Epcot Center. Although these voice recognition systems worked well for everyone in our party, they did not even acknowledge that I was speaking. Since then, I've noticed that most voice recognition software has trouble handling my voice.

In this recent customer service fiasco, I needed to change some information on one of my accounts. The automated telephone system gave me the option of using telephone keys or voice recognition. Because I am all too familiar with the limitations in speech/voice recognition related to my deep voice, I chose the option of using the telephone keys. For most of the options, this worked well. Unfortunately, there were a couple of prompts during the process that required me to speak the selection. My guess is that the system was built this way because of the difficultly of differentiating between numerals and letters based on telephone keys pressed. Whatever the reason for this design and as no surprise to me, the voice recognition did not work well with my voice.

The voice recognition service kept misinterpreting at least one of the letters that I spoke. When I tried to enunciate them more clearly, any late emphasis in speaking a particular letter was interpreted as a second letter. It was bad enough that I had to keep repeating the same string of letters and numerals, but it was even more frustrating when the system would report automatic transfer to a customer service agent after three failed attempts. This would not have been so bad except for the fact that the "transfer" ended up in the call hanging up after about 15 seconds of various noises. After experiencing this twice, I really wished that I could continue trying to voice the letters in a way the system could understand rather than being "transferred" again.

In this case, the company I was working with has a virtual monopoly on the service that I purchase from them. This may be one reason that they get away with a system that "transfers" a customer by hanging up on that customer. It also made me realize that their telephone system was basically inaccessible to me and, if I had any alternatives or substitutions for their service, would drive me to that competitor. I asked myself why they didn't have an online presence where I could enter letters and numerals from my computer keyboard in such a way that they could easily differentiate between the two and I would not need to worry about inaccessibility due to the deepness of my voice.

From all this, I now appreciate more than ever the importance of building accessible software systems. Several years ago, I learned the importance of dealing with colors when one of the highest ranking officials representing my client had severe color blindness. I had built a Flex-based demonstration for this client that relied heavily on colors and contrasts for visual effect. This client representative could barely make out some of the features after significant effort. Although my color scheme enhanced the conveyance of information for the "typical" viewer, it made it worse for him. I experienced the same frustration with the telephone system: it probably works well for the "typical" user but was extremely frustrating and essentially inaccessible for me.

The Electronic and Information Technology Accessibility Standards (Section 508) states its purpose as follows:

The purpose of this part is to implement section 508 of the Rehabilitation Act of 1973, as amended (29 U.S.C. 794d). Section 508 requires that when Federal agencies develop, procure, maintain, or use electronic and information technology, Federal employees with disabilities have access to and use of information and data that is comparable to the access and use by Federal employees who are not individuals with disabilities, unless an undue burden would be imposed on the agency. Section 508 also requires that individuals with disabilities, who are members of the public seeking information or services from a Federal agency, have access to and use of information and data that is comparable to that provided to the public who are not individuals with disabilities, unless an undue burden would be imposed on the agency.


This requirement for federal systems (United States) to be accessible to public users is particularly important because there is usually no competition for these services. In other words, the users are captive customers and need to be able to access their services. In the competitive marketplace, it makes sense to provide accessible services so that potential customers will not move to the competition.

It is important to develop our services in an accessible way so that potential customers do not give up on us and leave in frustration. Popular programming languages, frameworks, and platforms often provide assistance in creating more accessible software. Examples of this include Java SE Desktop Availability (including the Java Accessibility API and the Java Accessibility Utilities), Flex Accessibility (including accessible components, tutorials, and best practices), and .NET accessibility features (such as the AccessibleObject class).


Accessibility Rule of Thumb

As a rule of thumb, it seems that an interface should always have at least two ways to convey and accept information. If the telephone system uses voice recognition, it should probably also be built for 100% support for pressed keys for those of us with "voice challenges." Similarly, the voice recognition is likely a nice alternative to pressed keys for those who have poor eyesight or otherwise have difficulty pressing the correct telephone keys. Our interfaces are more likely to be generally usable if they provide more than one way to accomplish each task. Some people hear better than they see and some people see better than they hear.


Conclusion

It can be an extremely frustrating experience to deal with an interface that likely works for "most people," but does not work for me because of assumptions made when designing the interface.


Additional Interface Usability/Accessibility References

Electronic and Information Technology Accessibility Standards (Section 508)

Usability Approach to Accessibility (focus on tip #17)

Understanding Web Accessibility

The Resolution Race: Perpetuating Inaccessible Computing

Clinton Pledges Funds for Net Accessibility Research

Thứ Năm, 8 tháng 10, 2009

More on the Future of JavaOne

Twice previously (April 2009 and June 2009), I publicly pondered the future of JavaOne given Oracle's announced acquiring of Sun Microsystems. Toward the end of the article "Sun management stumbled on EU Oracle probe", The Register now claims that "there will be no more JavaOne conferences under the new Oracle owner."

Until/unless Oracle officially announces the end of JavaOne, we still do not know for certain the future of JavaOne. However, for reasons that I outlined previously, it will not be all that surprising if Oracle does merge JavaOne with its Oracle OpenWorld conference.

In the DZone article JavaOne: Is the Party Over?, Mitch Pronschinske quotes several people in the industry regarding their opinions on the rumor that Oracle will drop JavaOne. There are also comments from other readers of the article. I have previously blogged on the observations about the future of JavaOne made by people attending 2009 JavaOne.

None of this confirms with certainty the future of JavaOne. It is doubtful that we'll know anything certain until after the current transaction between Oracle and Sun is completed. However, my feeling is that even if JavaOne continues on, it will be quite different in the future.

Thứ Hai, 5 tháng 10, 2009

RMOUG: Beware Triggers and DBA Code of Ethics

The Rocky Mountain Oracle Users Group (RMOUG) is well-known in the Oracle database administrator community. This is one of the most successful models I have seen of an effective user group and its annual Training Days conference is particularly well regarded. Although I am not a database administrator (DBA), I still found three DBA-centric articles in the current edition of the quarterly RMOUG newsletter (RMOUG SQL>UPDATE_RMOUG) to be worth the read and worth mentioning here.

The three articles in the Fall 2009 edition of SQL>UPDATE_RMOUG are "Beware..." (Another Look at Triggers), "Database Administrator's Code of Ethics", and "Using the PL/SQL Profiler." In this blog posting, I'll look briefly at the first two of these three articles.


Beware ... Triggers

Tom Kyte is one of the best-known experts in the Oracle community. He authors the askTom site and is a Senior Technical Architect at Oracle. His Blogger profile has been viewed approximately 87 thousand times. When I give a presentation during the same conference slot he is presenting in at a database-oriented conference, I can expect a very small audience at my presentation.

In his article "Beware...", Kyte writes, "At first, I thought triggers were the coolest thing ever ... something that I as a developer could use to perform 'magic.'" Kyte goes on to explain that the "forgotten trigger has bitten me many times in the past." Kyte also states, "If I could remove a few features from the database -- it would be triggers and when others then null."

After providing many examples of trigger abuse, Kyte concludes, "When used correctly and sparingly, triggers can be a positive thing. It is when they are used for every and anything that they become a really bad idea. ... Triggers should be used when there is no other way to achieve your goal. They should be the last resort."

I am not aware of this article being available online, but you can reference Kyte's The Trouble with Triggers for more information from Kyte on triggers.


DBA Code of Ethics

In the article Database Administrator's Code of Ethics, OracleGiants editor Brian Carr states that the purpose of this article is "to analyze the social and ethical responsibility of Database Administrators (DBAs)." In this article, Carr defines a DBA as "the person in charge of managing the relational database and its access rights" and references the Wikipedia article on database administration.

In explaining why DBAs should have a code of ethics, Carr points out that DBAs, like their systems administration cousins, "generally have high levels of access" in various powerful organizations with highly sensitive data. To support this position, Carr references the InfoSec News story The Data Security Weak Link.

Carr points out that physicians and certain types of engineers have their respective codes of ethics. He suggests that DBAs should "also be required to take an oath, or swear to practice by a strict Code of Ethics" because "people and organizations do trust extremely confidential and sometimes very personal information to a Database Administrator."

In this article, Carr first references Stephen Wynkoop's proposed SSWUG DBA Code of Ethics before outlining his (Carr's) own proposed code of ethics that adds fiduciary responsibility, limitation of data access to only that required to do the job, and "a more professional tone" to the SSWUG DBA Code of Ethics. In this article, Carr briefly describes six principles (prudence, justice, temperance, courage, responsibility, and trustworthiness) behind the proposed code of ethics.

As I read this article, I definitely saw some things that I liked, but I also wondered how realistically it would be followed. It would be interesting to know if there is any proven correlation between existing professions with codes of ethics and better behavior because of the existence of a code of ethics. I believe that a code of ethics could be a great educational tool to help younger people in a profession learn what is considered ethical and what is considered bad form. However, it is likely that a code of ethics provides very little deterrent to a person lacking concern for rules, laws, or ethical behavior.

Carr concludes his article with a realistic assessment of the potential advantages of a DBA code of ethics. He states, "The Code of Ethics would likely never be enforced, other than what is considered to be unlawful, however, the code is about striving to be a more cohesive profession when it comes to what we do and how we do it."

Personally, as a customer or patient whose records are at the mercy of DBAs out there, I would like to see some guidance related to what is considered ethical behavior. As a software developer, I cannot help ask myself questions like "Would a code of ethics benefit software developers?" and "Would software developers care about a code of ethics?" In other words, would having a code of ethics for software developers change anything?

This article "Database Administrator's Code of Ethics" is hosted online and this online version includes references at the end of the article. The print version of the article in SQL>UPDATE states that this article is a "collaboration between Burleson Consulting and Brian Carr." I bring this up because Burleson Consulting hosts a brief article called Ethics for the Oracle Professional.


Conclusion

Although I am not a DBA, I found these articles to be thought-provoking. Many of the reasons Kyte outlines for not using triggers can apply to similar "magic" and trickery we might employ in software development. I feel about aspect-oriented programming (and some other software development concepts) similarly to how Kyte feels about triggers: they can be very helpful when most appropriate, but can be a maintenance nightmare when used indiscriminately. Too much "magic" can be too difficult to read and maintain.

Like DBAs, software developers (especially those that maintain production software) have access to sensitive data. In addition, developers are in a position to introduce vulnerabilities in software's security (such as the back door popularized in War Games). There is no question we need software developers to rely ethically, but the question is whether a code of ethics would have any influence on that.

Groovy JDK (GDK): Object[] and T[]

The Groovy JDK (GDK) provides many convenience methods that can be invoked on arrays. The GDK includes specific support for many array types such as Byte[], byte[], boolean[], double[], float[], int[], and long[]. The GDK also supports String[], T[], and Object[]. I'll focus on the last two (Object[] and T[]) in this blog posting.

In this post, I'll have the some of the Groovy code reference a Java class called Person.java and the code listing for that class is shown next.

Person.java

package dustin.examples;

/**
* Simple class to be used in Groovy Object[] examples.
*/
public class Person
{
private final String lastName;
private final String firstName;

public Person(final String newLastName, final String newFirstName)
{
this.lastName = newLastName;
this.firstName = newFirstName;
}

@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Person other = (Person) obj;
if (this == null ? other != null : !this.lastName.equals(other.lastName))
{
return false;
}
if (this == null ? other != null : !this.firstName.equals(other.firstName))
{
return false;
}
return true;
}

@Override
public int hashCode()
{
int hash = 3;
hash = 97 * hash + (this.lastName != null ? this.lastName.hashCode() : 0);
hash = 97 * hash + (this.firstName != null ? this.firstName.hashCode() : 0);
return hash;
}

@Override
public String toString()
{
return this.firstName + " " + this.lastName;
}
}


In Java, there isn't much one can do directly with an array of the above objects. The next code sample demonstrates some of the limited functionality available with direct use of an array:

JavaArrays.java

package dustin.examples;

import static java.lang.System.out;

/**
* Simple example class that demonstrates functionality on Java arrays.
*/
public class JavaArrays
{
public static void main(final String[] arguments)
{
final Person[] objectArray =
{ new Person("Flintstone", "Fred"), new Person("Rubble", "Barney") };
out.println("Length of array is " + objectArray.length);
out.println("Array toString is " + objectArray.toString());
}
}


When the above code is executed, the output looks like that shown in the next screen snapshot:



The output of a toString call on an array is not very helpful. As I discussed in the blog post Java Arrays: Copying, String Representation, and Collections, the java.util.Arrays class provides some useful methods for dealing with arrays. In Groovy, many of these same convenient methods are available directly on the arrays themselves thanks to Object[] and T[]. In the remainder of this blog post, I will look at some of these direct Groovy array method support in detail.

In this first snippet from my Groovy script groovyObjectArray.groovy, the Object[].asType(Class)
method is demonstrated. This method allows an array of Objects to be treated as a Set of Objects or a List of Objects. The version that provides a SortedSet is commented out because the objects in the collection need to be Comparable for a SortedSet and our custom Person class is not Comparable.

groovyObjectArray.groovy (part 1)

import dustin.examples.Person

Object[] objectArray = [new Person("Flintstone", "Fred"), new Person("Rubble", "Barney")]
println "objectArray's class type: ${objectArray.getClass().name}"
objectSet = objectArray.asType(java.util.Set)
println "objectSet's class type: ${objectSet.getClass().name}"
objectList = objectArray.asType(java.util.List)
println "objectList's class type: ${objectList.getClass().name}"
// Running Object[].asType(java.util.SortedSet) requires elements in array of
// objects to implement the Comparable interface because that is a requirement
// of java.util.SortedSet. A ClassCastException is encountered if the objects
// do not implement Comparable: "cannot be cast to java.util.Comparable"
//objectSortedSet = objectArray.asType(java.lang.SortedSet)
//println "objectSortedSet's class type: ${objectSortedSet.getClass().name}"


The output for these first few lines of Groovy code is shown next.



Object[] provides several more useful and convenient methods for accessing array elements. Some of these (Object[].size(), Object[].toArrayString(), Object[].toString(), Object[].join(), and Object[].count()) are shown in the next code listing, the second part of the script groovyObjectArray.groovy.

groovyObjectArray.groovy (part 2)

println "objectArray #items (.length property): ${objectArray.length}"
println "objectArray #items (size() method): ${objectArray.size()}"
println "objectArray toArrayString: ${objectArray.toArrayString()}"
println "objectArray toString: ${objectArray.toString()}"
println "objectArray join with <--->: ${objectArray.join('<--->')}"

// The Object[].count method requires Groovy 1.6.4.
personToMatch = new Person("Flintstone", "Fred")
println "objectArray #contained items: ${objectArray.count(personToMatch)}"


The output from the above snippet of the script is shown next.



As the above code listing and its corresponding output indicate, the Object[].toString() and Object[].toArrayString() methods provide nice String representations of the array contents. The Object[].size() method is a method-based approach to get the size or length of the array. The Object[].join(String) method joins the String representations of the elements of the array to each other with the provided String-based separator joining them. The Object[].count(Object) method has only been available since Groovy 1.6.4 and provides the number of instances of the provided Object within that array.

The third and final part of the groovyObjectArray.groovy script demonstrates the useful methods on T[] that provide minimum and maximum values of the elements of the array. The elements need to be comparable for these to work and I use Strings, integers, and doubles respectively.

groovyObjectArray.groovy (part 3)

// Use methods on T[]
Object[] stringArray = ["One", "Two", "Three", "Four", "Five"]
Object[] integerArray = [1, 2, 3, 4 ,5]
Object[] doubleArray = [1.0, 2.5, 5.0, 7.5, 10.0]
println "stringArray.max(): ${stringArray.max()}"
println "stringArray.min(): ${stringArray.min()}"
println "integerArray.max(): ${integerArray.max()}"
println "integerArray.mix(): ${integerArray.min()}"
println "doubleArray.max(): ${doubleArray.max()}"
println "doubleArray.min(): ${doubleArray.min()}"


The output from the above is shown in the next screen snapshot.




This posting has demonstrated the useful convenience methods provided for array access and manipulation in Groovy GDK with Object[] and T[].

Thứ Sáu, 2 tháng 10, 2009

Groovy JDK (GDK): List Enhancements

In prior blog posts, I have discussed several highly useful classes and methods provided as part of the Groovy JDK (GDK). These posts have covered GDK-extended classes such as File, String, and Number. In this post, I cover GDK's extension of one of the most popular interfaces in the Java Collections Framework: the List.

The GDK List extension provides numerous convenient methods and includes methods that provide mathematical operator support for Lists. In this blog post, I look at several of these methods and operators provided by the Groovy extended List.

In my first code listing, I set up two Lists. The first is set up without any explicit specification of interface or implementation. The second is set up with explicit interface declared, but no specific implementation of that interface is specified.


println "====== SET UP TWO LISTS ====="

// Obtain a List implicitly (dynamic typing)
implicitList = ["Arizona", "New Mexico", "Colorado", "Massachusetts", "Utah", "Wyoming"]
println "Implicit: ${implicitList.getClass().name}"

// Explicitly specify List interface, but rely on implementation implicitly
List explicitList = ["Phoenix", "Santa Fe", "Denver", "Boston", "Salt Lake City", "Cheyenne"]
println "Explicit: ${explicitList.getClass().name}\n"


I included a println statement after each variable declaration that prints out the type of concrete class actually being used. As the output in the next screen snapshot indicates, an ArrayList is implicitly applied in both cases.



With two lists prepared, we can start using GDK's extended List functions to operate on these lists. I have blogged previously about using the Java Collections class to make provide a Collection that is immutable or a to provide a Collection that is synchronized. The GDK List class makes these Collections.unmodifiableList(List) and Collections.synchronizedList(List) methods even easier to use directly on the List with its List.asImmutable() and List.asSynchronized() methods. These are demonstrated in the next (second) code listing.


// Demonstrate easy access to immutable version of List
List immutableList = implicitList.asImmutable()
println "List.asImmutable: ${immutableList.getClass().name}"
println "Collections.unmodifiableList: ${Collections.unmodifiableList(implicitList).getClass().name}\n"

// Demonstrate easy access to synchronized version of List.
List synchronizedList = implicitList.asSynchronized();
println "List.asSynchronized: ${synchronizedList.getClass().name}"
println "Collections.synchronizedList: ${Collections.synchronizedList(implicitList).getClass().name}\n"


The output from the above code is shown in the next screen output. We see that the same type of objects returned from the respective Collections methods are returned here.



The GDK List class adds methods for accessing the first element, the last element, the head (first element), or the tail elements (all elements except the head element). These four methods are demonstrated in the next (third) code listing.


// Demonstrate List.first()/List.head() and List.last()/List.tail()
println "First state is ${implicitList.first()} and last state is ${implicitList.last()}"
println "Head state is ${implicitList.head()} and tail states are ${implicitList.tail()}\n"


The output corresponding to the code listing directly above is shown next.



Groovy makes it really easy to generate a List with entries in the reverse order of the original List via its GDK List.reverse() method. This is demonstrated in the next (fourth) code listing.


// Demonstrate List.reverse()
reverseList = implicitList.reverse();
println "Content of reverseList: $reverseList\n"


The output from running the above Groovy code is shown next.



During my transition from being primarily a C++ developer to being primarily a Java developer, I often found myself missing operator overloading. Groovy brings it back in the Java world. One example of this is the support for the + operator supported by Groovy's GDK List. The next example demonstrates adding an element to a List using the + operator and adding another List (in this case a single-element List) to the original List using the + operator.


// Demonstrate plus (+) operator
implicitList += "Montana"
println "Montana added with +: $implicitList"
explicitList += ["Helena"]
println "Helena added with +: $explicitList\n"


The GDK List supports LIFO stack semantics with its List.push(T) and List.pop() methods, demonstrated in the next code example.


// Demonstrate List.push()
implicitList.push "Idaho"
println "Implicit with push-ed Idaho: $implicitList"
explicitList.push "Boise"
println "Explicit with pushed-ed Boise: $explicitList\n"

// Demonstrate List.pop()
implicitList.pop()
println "Implicit after pop-ed: $implicitList"
explicitList.pop()
println "Explicit after pop-ed: $explicitList\n"


The following output demonstrates that these List.push(T) and List.pop() methods work as we would expect.



The Groovy GDK List class supports the - operator similarly to how it supports the + operator. The following code snippet demonstrates removing one List from another using List.minus(Collection) method (there is also an overloaded version for removing an individually provided object) and using the - operator.


// Demonstrate minus and "-"
rockyMountainStates = implicitList.minus("Massachusetts")
println "Rocky Mountain States (after 'minus'): $rockyMountainStates"
capitalsToRemove = ["Boston"]
rockyMountainCapitals = explicitList - capitalsToRemove
println "Rocky Mountain Capitals (after '-'): $rockyMountainCapitals\n";


This code's output is shown next with Massachusetts and Boston missing from their respective Lists.



As a potential preview of what is to come with Java SE 7, Groovy supports subscript notation for Lists. What this means is that individual elements of a GDK List can be accessed in an array-like fashion.


// Use subscript operator to replace Massachusets/Boston with Idaho/Boise
implicitList[3] = "Idaho"
println "Put implicitList[3]: $implicitList"
explicitList[3] = "Boise"
println "Put explicitList[3]: $explicitList\n"

// Demonstrate retrieving by subscript operator
println "Get implicitList[2]: ${implicitList[2]}"
println "Get explicitList[2]: ${explicitList[2]}\n"


The above Groovy code places "Idaho" and "Boise" back in the original Lists in place of "Massachusetts" and "Boston" respectively. Then, the elements for "Colorado" and "Denver" are extracted from the Lists. Both the setting and the getting of elements of the underlying List were accomplished using [index] syntax where index is a 0-based index value. The output is shown next.



The GDK List.reverseEach(Closure) method allows one to iterate in reverse order over the target List and invoke the provided closure on each item iterated over. The following code demonstrates this with a very simplistic closure that simply prints the currently iterated element's String contents.


// Demonstrate reverse iteration with simple closure
implicitList.reverseEach() {println it}


The output for the above code is shown next.



I previously blogged about the GDK String.execute() method that allows the String upon which that call is invoked to be executed against the underlying operating system. The GDK List class provides a similar List.execute() method that expects the first list item to be the actual command to be executed and the remaining list elements to be the parameters to that command. In other words, List.head() should provide the command in a List built to be used with execute() and List.tail() should provide the parameters to that command.

An example of this is shown in the next code listing (Windows-specific example):


// Demonstate List.process
commandList = ["cmd", "/C", "type", "groovyList.groovy"]
println "${commandList.execute().text}"


The output from the above is actually simply the entire Groovy script containing the code examples in this post. For brevity, I only show the bottom of that output here.



The GDK List adds several convenience methods and operator support to the standard JDK List. This makes List data structures easier than ever to use and gives us a taste of what may come in future versions of Java.

Thứ Năm, 1 tháng 10, 2009

Common Debugging Steps Articulated

In a relatively recent blog post, I discussed why I believe that more software developers should write blogs. In that post, I mentioned that I believe that some developers do not write blogs because they feel they have nothing new to add. A blog post I recently read illustrates how even a blog post on "old news" (debugging in this case) can be a useful addition to the blogosphere. In this (my) blog post, I will be referencing that blog post and adding my own thoughts about common effective practices used in debugging code.

Over the years I have been engaged in professional software development, I have observed definite improvement in my ability to debug problems. For me, there is no question that experience is a significant contributor to debugging efficiency. The recent posting on the Turnleaf Design: Ramblings of a Junior Developer blog called Six Steps for Fixing Any Bug does a nice job of succinctly describing key steps in debugging most software problems. This is a quick read and I recommend it for anyone, but especially for relatively less experienced developers. Although none of the steps or concepts discussed in that blog post are new to me, I like how they've been articulated and collected in one location. In my post here, I want to address each one of them and add some of my own thoughts.

Billy Korando, author of the Turnleaf Design blog, summarizes six steps in debugging and provides brief explanations of each.

The Bug is Probably Mine

Under Step #1 ("Take responsibility"), Billy guesses that around 95% of the time a defect is encountered, the error belongs to the developer. If we are talking about the development staff as a whole compared to the products they are using, I'd estimate an even higher percentage. If we are talking about "the other guy (or gal)" on the development team compared to me, then it depends on the person I am comparing to. Indeed, in The Practice of Programming, Kernighan and Pike write, "Beginners have a tendency to blame the compiler, the library, or anything other than their own code."

I have seen a few developers who are always quick to blame the compiler, the JDK or other library, the framework, the COTS product, or anything else besides their own code. These things are software themselves and so do have bugs of their own, but I have found that blaming such products should normally be the last resort. Looking for the bug first in the place it is actually least likely to be is inefficient at best.

If the product you're blaming for the defect is open source, you might look at the code to verify the defect is really there. With closed source software, you're limited to writing as simple demonstrative tests as possible to reproduce the suspected defect. One easy approach is to search that particular product's bug database and search forums and blogs for identification of that defect. However, I would not recommend performing any of these steps until after checking out one's own software because I agree that our own defects outnumber those of the products we use. The percentages are in favor of spending effort analyzing our own code first.

It also depends on the particular product. If I am using Java libraries, I definitely look long and hard at my own code and use (or possible misuse) of those libraries. If I'm using a well-used framework like the Spring Framework, I consider the possibility of a bug in that software only slightly sooner than I would have in the standard libraries. However, if I'm using a little-known tool or using a well-known tool in infrequently used ways, then the chances of the defect being part of the product I am using go up.

Loving the Stack Trace

It is easy to not like stack traces. They are not easy on the eyes and can seem formidable at first glance. However, I think anyone who has spent any significant time maintaining code or fixing defects has come to see their inner beauty. Stack traces are especially welcome to the bug fixer because they are such a tremendous asset in performing step #2 in the previously referenced blog post ("Narrow down where the bug occurs").

In Java, a stack trace is not limited to exception handling. One can always access the stack trace using Thread.getStackTrace().

When a stack trace is not available (either because the language/platform does not support it or because the type of error is such that a stack trace is not readily available or useful), there are other ways to narrow down when the problem occurs. These include logging (step #5 in the referenced blog post) and simply thinking through the way the code is supposed to work.

The Value of Unit Tests

One of the popular facets of Test-Driven Development is the idea of writing a unit test that reproduces the problem and then knowing the problem has been satisfactorily addressed when that unit test no longer fails. A nice side effect of this approach is that it makes for easier regression testing and a suite of such tests help reduce the chance of breaking one or more pieces of functionality while fixing a different piece. Unit tests can also be helpful in isolating cases where there actually is a problem in someone else's code. I have been known to write "unit tests" for third-party software to ensure that they are keeping their contract. They usually are, but not always. Unit tests satisfy what the authors of The Practice of Programming recommend: "Make the bug reproducible."

The Debugger

There are certain classes of problems and defects that seem to require a debugger. I have found this to be especially true in the case of weakly typed languages where silly typos or spelling errors have led to strange results that are difficult to understand and often result in hanging or nonresponsive applications rather than in obvious error messages. For example, I have encountered several errors in my Flex applications that I was only able to resolve via use of the Flex debugger.

Real Developers Ask for Help

It seems that we software developers are a proud lot. It can be difficult for us to admit our own mistakes (part of the reason why it is important to admit that our own code may be the culprit before blaming everything else) and can be difficult to admit we don't know something. However, we can save ourselves and our clients significant time in some cases if we simply are willing to talk out the problem with and ask questions of other software developers.

There are several reasons this is advantageous. First, no developer can have seen and experienced every single problem or defect that might come up. Some developers know languages better than us and some may know the domain or business logic better than us. Second, sometimes we just need a "second pair of eyes." There might be something obvious that 99 times out of 100 we'd have caught ourselves, but did not catch in this case because of fatigue, being too close to the problem, being lost in all the changes we have made, etc.

A third reason to bring in another developer on those particularly hard defects is that sometimes the simple act of explaining the situation, its symptoms, and what we've tried already helps us realize the answer to our own question. I have been on both ends of this. There have been times when I have responded to someone's plea for help only to find them resolving the issue before my eyes as they explain it to me. I have also done the same thing myself, realizing the problem as I take the time and effort to articulate the problem and logically think about my options. The authors of The Practice of Programming specifically recommend "Explain[ing] your code to someone else" for precisely this reason.


Another Perspective on Fixing Bugs

When I blogged that more software developers should write blogs, I specifically stated that one reason for this is that they might point out links that are helpful to them that I was not aware of previously and find helpful. Such was the case here. The blog post Six Steps for Fixing Any Bug references (and is in response to) another useful post: How to fix bugs, step by step. The latter entry recommends other practices that I have found useful in dealing with software defects and debugging such as tracking bugs (reduces chances of forgetting important details), searching for error messages, and taking a break when appropriate (because fatigue can reduce the chances of successfully solving the problem and increase chances of doing further damage).

Chapter 5 ("Debugging") of The Practice of Programming has many great recommendations related to debugging and I have quoted a few of them in this post. The "Sample Content" at http://www.informit.com/store/product.aspx?isbn=020161586X includes sections on debugging.


Conclusion

Debugging is an essential part of software development. At times it can be frustrating, but I have also found it to be exhilarating when I have successfully resolved a particularly nasty bug. Debugging is one of those steps in software development that seem to most directly benefit from experience. Because all of us have different experience, sometimes the best thing we can do is to seek help in resolving a particularly thorny issue. Not only can someone else help us debug the particular problem at hand, but if we're observant we can learn other tips and tricks in debugging to add to our debugging tool set.

Java API Documentation: A Software Development Community Contributor

For those of us who regularly write code in Java or a JVM-hosted language (Groovy, JRuby, Jython, etc.), the Java Platform API documentation is a very valuable resource. In fact, it is one of the resources I most frequently access in my Java development. However, the Java API documentation's value is not limited to JVM-based development. It can, in fact, be helpful for developers writing code in programming languages that have nothing to do with the JVM (Java Virtual Machine).

An example of the value of the Java API documentation even outside of the Java ecosystem is provided in the comments on a recent DZone link to a blog posting called URI vs URL vs URN. In the comments section for both the original blog post and the DZone link to that blog post, Shawn Hartsock points out that the Javadoc-based documentation for the java.net.URI class is a useful resource in understanding the relationship of the terms URI, URL, and URN.

The concepts of URL, URI, and URN are not unique to Java. However, the documentation for the Java URI class provides about as clear, lucid, and thorough coverage of these concepts as I would want, regardless of the language that I am developing in. Included in this class's excellent documentation are references and links to the authoritative original sources on the subject (Uniform Resource Identifiers (URI): Generic Syntax [RFC2396, August 1998] and Format for Literal IPv6 Addresses in URLs [RFC2732, December 1999]). The documentation for java.net.URI provides highly detailed and specific information based on these documents and then provides this concise explanation of the relationship of URI to URL and to URN:

A URI is a uniform resource identifier while a URL is a uniform resource locator. Hence every URL is a URI, abstractly speaking, but not every URI is a URL. This is because there is another subcategory of URIs, uniform resource names (URNs), which name resources but do not specify how to locate them. The mailto, news, and isbn URIs shown above are examples of URNs.


The documentation for java.net.URI also adds that "the conceptual distinction between URIs and URLs is reflected in the differences between this class and the URL class." In other words, the differences between the two JDK classes java.net.URI and java.net.URL reflect the differences in the concepts of URI and URL. For the Java developer, the differences are modeled directly. For the non-Java developer, the classes themselves might not be useful, but their documentation certainly is useful.

The value provided by Java documentation to the general software development community is not limited to the Java SE API documentation. The Java EE API documentation contains significant information on various aspects of HTTP and other web-related technologies.

I have found the Java API documentation to be extremely helpful in my Java development. The more surprising observation, though, has come when I have found information that I am looking for on topics more general to software development. The Java documentation contributes significant technical knowledge to the general software development community.