Friday, March 11, 2011

Just what kind of sort are you?

More fun with sorting...

In the last post I discussed how an incorrect type of sort (alphabetic vs. numeric) led to bad data. A more common concern related to sorting is performance, either from coding inefficiency of an inappropriate choice of algorithm for the application. This is a surprisingly complex subject, which I will just scrape the surface of here.

The key characteristics of a sort algorithm are:
  • typical number of operations for various data sets (fully random to already sorted)
  • typical amount of data access (a swap is more expensive than a compare)
  • amount of memory usage (some algorithms work within the original array space, while others expand into additional, potentially large, work areas)
And so the things to consider when evaluating a sort algorithm for your application are:
  • the size of your data
  • whether your data is always random, or partially ordered
  • your available memory
Let's consider some popular algorithms. First the simple classics.

Bubble sort
Popular in introductory programming courses, probably because it is easy to understand and very easy to code. The basic method involves continually looping through the list comparing adjacent members and swapping places if the second is ever greater than the first, until a complete loop yields no swaps.

swap = 1;
while (swap) {
    swap = 0;
    for ( i = 0; i < max; i++ )
        if ( A[i] < A[i+1] )  {
            swap( A[i], A[i+1]);
            swap = 1; }
}

Memory efficient. Speed is not so bad for a small, mostly ordered list. Bad for everything else. Performance can be estimated with O(n^2), i.e., relative to the square of the number of elements in the list. For the novice only.

Selection Sort
Here, an outer loop through the list contains an inner loop which finds the maximum value amongst the remaining members, swapping it with the value in the outer loop location.

for ( i = 0; i < max-1; i++ )
    for ( j = i+1; j < max; j++ )
        if ( A[j] > A[i] )
            swap( A[j], A[i])

Logical, consistent, memory efficient - but still O(n^2). For large data, you can do better.

Insertion Sort
Creates a new list from the original by taking members from the first and inserting them in their sorted order in the second. Simple, uses some extra memory, but not efficient for large data.


Now let's move on to the serious contenders.


Quicksort
Clever programmers love the Quick Sort algorithm, which uses a divide and conquer type approach. It's probably your fastest choice for a large random dataset, with the average case O(n*log(n)). So what's the catch? Worst case for this algorithm is a dataset that is already sorted, where performance creeps back to O(n^2).

But, hey, how often does that happen? And how bad can it be? Well, pretty often, and pretty bad. It's a common occurrence to have a small amount of new data added to a large ordered set, requiring a reshuffle to fix the order. This also brings to mind a situation I ran into some years back, working on a pretty compute-intensive circuit analysis program that implemented an NP-complete algorithm. (That means it could not be guaranteed to complete in a reasonable time.) A new analysis routine was introduced that we estimated could add maybe 10% additional processing.

Run-time doubled.

We eventually determined the reason was back-to-back sorts in the code.The new analysis required the data to be in order, so the developer began the new function with a sort - not realizing that the preceding function had modified the data and so ended with a sort to restore the order. The first sort was very fast. The second sort was more than 100X slower. Ironically, this same developer had implemented the quick sort function some months earlier recognizing that performance would be crucial given our large datasets. The fix was a single comment symbol to remove the redundant sort. Now sensitized to the issue, we went on to remove another unnecessary sort, further improving performance.


Continuing on our survey...


Merge sort
Does a recursive divide-and-conquer sort and merge. While Quicksort may be a little faster on large random lists, Merge sort has no Achilles heel. Performance is O(n log n) for average and worst case, approaching O(n) for nearly sorted lists. Does use some extra memory (2n). All-in-all, a pretty darn good choice for most applications, and is the algorithm used in the standard library sort routine for a number of modern programming languages.

Heapsort
Combines a selection sort with a type of binary tree called a heap. Competitive with Quicksort and Merge sort for speed (performance is O(n log n) for average and worst case), it is a good choice when memory is tight.

Shell sort
An evolved combination of bubble and insertion sort, it's generally quite efficient, but does have some gotchas. Easy to code, it's a good choice for many applications.


Some endnotes:

  • This vulnerability to presorted data is sometimes used in Denial of Service attacks, given the popularity of Quicksort.
  • Many versions (especially early ones) of the C library function qsort() exhibit this behavior as well. The function qsort() is not required to be implemented as a Quicksort, though it often is.
  • Some variations to the textbook algorithm can alleviate Quicksort's vulnerability to the presorted data worstcase.

References:

There are a lot of great resources out there. A variety of sort and other algorithms are covered in detail in these books:

  • Robert Sedgewick, "Algorithms in C"
  • Mark Allen Weiss, "Data Structures and Algorithm Analysis"
  • Tenenbaum, Langsam, Augenstein, "Data Structures Using C" 
A couple of really good overviews, with links to explore further:


The next two links provide some fascinating comparative visualizations of the algorithms, while the last provides some of the best critical analysis:




Monday, March 7, 2011

Sordid sorting

Here's a quick testing tip based on something I ran into this week. If you are testing an application that uses ordinal numbers, make sure your dataset:
  • crosses a decade boundary (e.g., 7, 8, 9, 10, 11, 12)
  • includes a 9, or numbers that have 9 as a digit
  • but the last / highest number should not include 9
Why? A common programming error is to use an ASCII sort when a numerical sort was intended. If you have the numbers 1 through 12, you want a sort to produce
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}

A numerical sort will give that. But an ASCII or alphabetical sort will produce
{ 1, 10, 11, 12, 2, 3, 4, 5, 6, 7, 8, 9}

If your dataset was 1 through 9, or 4203 through 4207, you would not notice a problem. In my case the data was sufficient to trigger the problem, which was especially apparent because a developer had put a sanity check in the code.

if ( current_version > highest_version )
    print ("ERROR: current_version > highest_version")

We had to track down what created the condition, which turned out to be the bad sort. But if not for the error message, who knows what odd behavior this erroneous data would have caused - and whether I would have caught it. Everybody makes mistakes; good developers work to catch them.

There is a lot that could be said about datasets for testing ... but there are a couple of interesting points on sorting, test, and performance issues that I would like to cover next time.

Tuesday, January 18, 2011

Man's capacity for error

In my first job at a software company, I worked with a senior engineer named Leon. A PhD in Physics, Leon was known to toss out nuggets of wisdom with the laid-back intellectualism of a college professor. Here is one of my favorites, that became more meaningful to me over the years. I am paraphrasing here, but I think it conveys the gist.
I used to be a staunch supporter of Nuclear Energy. But it wasn't until I started working in software that I came to realize man's capacity for error. Intelligent people, well-educated people, people who cared about their work - made lots of mistakes! And that includes me! So even though I understand the protocols under which nuclear material can be handled safely, I have no faith in a human's ability to reliably follow those protocols.
My message here has nothing to do with nuclear energy. The point is that when humans are involved, errors occur. We call them bugs, and our job is to find them, or reduce their occurrence. Without anger or recrimination. We work to improve the quality of the things we test. That is the service we provide. That is our mission.

Sunday, November 28, 2010

Social Networking for Test Professionals follow-up

In the last entry I formulated my ideas on what social networking means to us test professionals. Soon after I read a column by Thomas Friedman on the professional use of social networks. Here is the link, and a relevant excerpt:

"...today’s knowledge industries are all being built on social networks that enable open collaboration, the free sharing of ideas and the formation of productive relationships — both within companies and around the globe. The logic is that all of us are smarter than one of us, and the unique feature of today’s flat world is that you can actually tap the brains and skills of all of us, or at least more people in more places. Companies and countries that enable that will thrive more than those that don’t."

Clearly Tom reads my blog. :)  

Then I stumble on a blog by Rick Nelson in Test & Measurement World magazine (here) quoting that same Thomas Friedman column. Rick also references an interview EDN managing editor for news Suzanne Deffree did with Deirdre Walsh, social-media and community manager at National Instruments.

Walsh listed five reasons why engineers should use social networks (paraphrasing): 
1. technical support from peers
2. staying abreast of the industry for career reasons
3. be heard, by your peers and your vendors
4. professional networking with like-minded peers
5. become "famous" in a free-form venue not restricted by their job description


So look around, change your perspective, find your voice, get involved. Here are a couple of forums I frequent, and a couple where I am a member and occasionally drop by:


www.softwaretestingclub.com
www.qualitytesting.info
groups within LinkedIn:
Software Testing & Quality Assurance
Software Testing and Quality Assurance (yes, they are different)
Bug Free: Discussions in Software Testing
DFT Experts  (Design For Test - a hardware thing)
First Fault Problem Solving





Wednesday, November 17, 2010

Social Networking and the Test Industry

Recently my friend and colleague Paul, who happens to be the VP of Technology at a major aerospace and telecommunications company, sent me the following query.

 "I would be interested in getting your views on the use & impact of social networking on software & hardware testing."

That is an interesting question. Three areas come to mind. 

1. Social networks devoted to the subject of testing.

Test is generally not taught in school, and doesn't receive the same respect in a company as design or development. Participation in a social network focused on the subject gives testers the opportunity to ask questions or discuss ideas, keep up with the state of the industry, or just receive encouragement in the importance of the discipline. It can be a very useful tool for professional development. I have recently started participating in the LinkedIn Group Software Testing & Quality Assurance, and a really excellent independent organization called The Software Testing Club (www.softwaretestingclub.com). 

2. A good bug tracking tool has built in social networking type features (IMHO).

Any serious test effort, in hardware or software, should involve the use of a tool to document and track bugs or defects. This would include the details of the problem and the test that uncovered it. It would track the state of the bug as it progresses through its lifecycle toward fix and verification - or whatever might be its final disposition. The tracking packages can also have some very useful extra features that seem to fall into the domain of a social network, like the ability to host threaded discussions attached to the defect, and notify interested subscribers of updates in the discussion or state, or subscribe to new filings in a particular area. The tool is assumed to be running internal to a company, perhaps on their intranet. 

3. Crowdsourcing.

There is a relatively new type of testing going on today that involves a large group of testers, often geographically dispersed, working independently, but organized and managed over a social network. This is somewhat reminiscent of the way open source software development works. A prime example is a company called UTest (www.utest.com) that is worth checking out. They have >10,000 people signed up, non-employees, with varied levels of education and experience, who have an interest in participating in software testing. A company will contract UTest to have their software exercised, and UTest will assign a group (50? 100? 200?) to the task. Testers are compensated based on unique bugs filed or test plans supplied. This has been called crowdsourcing.

The Software Testing Club (mentioned in point 1.) is building a crowd-sourcing type organization called (strangely enough) The Crowd. Expect that to be a more focused, perhaps closer to a contractor source.

Due to their large and actively interested user bases, Microsoft and Google get to accomplish a fair semblance of crowdsourcing with a Beta test of a new product or version.

It's a little harder to imagine the applicability of crowdsourcing to hardware test. I imagine you could run a test effort against a released product, or send out samples to a large group.

So those are my initial thoughts on the subject. I would love to hear yours. Comments welcome.

Thursday, October 7, 2010

Should you hire from your customers?

In the last two posts I discussed how you should look at your customers to help determine the necessary technical qualifications of your testers, as well as what level of industry experience would be useful. This raised the question of whether you should ever hire from your customers. My answer would be yes - but only with the consent of their management.

Full disclosure: Probably half my group, including myself and my boss, at one time worked for electronics or semiconductor companies, using or supporting internally the kinds of tools that we now develop and test. Certain tools in this industry are very technical, with very specific usage, and industry experience is very useful in developing, testing, and supporting them. For this reason cross migration between vendor and customer is a common occurrence. We have had particular success in recent years hiring field application engineers from our customers ranks.

But be warned! You do not want to get into the situation where your customer thinks that you are recruiting from his fold. You risk losing that customer, potential legal action, or worse - a negative reputation. So if you are considering a candidate who is actively employed by one of your customers, your best approach is to clear it with her management first (with the candidate's consent, of course). Companies can be surprisingly open to this for a couple of reasons:
  • They expect turnover.
  • They may recognize that this employee has career aspirations they cannot satisfy.
  • And they may expect significantly improved support if they have a man on the inside. (and they'd be right!)

So, you have successfully vetted the technical qualifications of your candidate. Great! But don't forget that you are hiring for a QE role. Do they have the right temperament for test? Do they have any background in it? If your candidate shows real potential otherwise than go ahead and hire them, but provide them with formal training in software test once they start.

Monday, September 13, 2010

Clarifications

In the previous post I discussed how you should consider the technical skill level and domain knowledge of your customers when considering prospective testers for your software tools. I would like to add a couple of clarifications.
  1. This doesn't mean that all your testers have to fit the same mold. On the contrary, I am a fan of diversity on multiple levels. Having a team from diverse backgrounds tends to increase the size of your group's technical arsenal
  2. That discussion totally ignored skill and experience in the discipline of software test. An experienced user of specific tools is not necessarily a good tester, and could likely benefit from education in the subject. Similarly, a tester with no industry-specific experience - but who has been working in the field of software test for a decade or two - can bring a lot to the table regardless, and tends to raise the professionalism of the group.
  3. Can someone learn either the domain knowledge or the software test skills? Abso-freakin-lutely. My pet peeve is when a company will only consider someone for a function if they are currently performing that exact function in their current job. I believe one of the most important considerations should be the demonstrated ability for a person to learn and produce.
  4. What if your tool has multiple levels of users? Perhaps you provide enterprise software, where administrators set it up and keep it running, analysts customize the tools to the company's needs, and then the typical user of the front end belongs to an industry specific demographic, whether they be engineers, accountants, or clerical. In a case like that you need to determine which skills should be in every member's toolbox, and which merely need to be represented in the group, or at least accessible to it. For example, you may only need one Oracle DBA, while everyone in the group knows how to drop and add a user in order to reset the test data. Or everyone familiar with the technical lingo and basic use flows, but a couple with enough experience to develop datasets and map out more complex usage scenarios.

The general subject of what makes a good tester has been covered in many places, so I won't get into that here. You can find a useful discourse on the subject - and on most things test related - in
Testing Computer Software, by Kaner, Falk, and Nguyen.