I’ll See Your Two Heads And Will Raise You Seven

Posted on Friday, October 24, 2008
0 commentsAdd comments

One of the issues with the development of great code is the limited perspective of its developers. Not every programmer knows the ins and outs of a language, is able to harness every nuance of the language, or realized the ultimate potential (or weaknesses residing within) the code they have written. This is where peer reviews, hopefully, strengthen a project.
An old axiom says “two heads are better than one,” which definitely allowed my partner and I for the DueDates-Silver project to accomplish a very nice implementation. In my blog last week, I discussed how we used a carpenter’s approach of ‘measure twice, cut once’ in our design process.
If two heads are great, then nine heads would surely trump that old axiom. That’s what happened this week. Two weeks ago, my software engineering peers and I were split up into nine teams each working on their implementation of the DueDates project. This week, each team member was asked to review three peer projects and provide constructive feedback to that team of developers. This provided each project group the opportunity to see six implementations of DueDates, in addition to their design. Most projects were reviewed by six peers, while DueDates-Silver was lucky enough to have seven peers reviewing it.

Meting Assignments
Which projects to be reviewed and who would be reviewing them was predetermined by our professor, what capacity each reviewer would be asked to perform within the project review was determined by the project owners.

My review assignments were:

Peer ProjectTeam Members
DueDates-PurpleJohn Ancheta, Daniel Arakaki, Mari-Lee Flestado
DueDates-RedPhillip Lau, Creighton Okada
DueDates-VioletAnthony Du, Vincent Leung


Those assigned to review DueDates-Silver were:

Review CompletedPeer ReviewerDueDates Team
YesJohn AnchetaDueDates-Purple
YesAnthony DuDueDates-Violet
YesJung JehoDueDates-Green
YesPhillip LauDueDates-Red
NoScheller SanchezDueDates-Gold
YesAric WestDueDates-Orange
YesJohn ZhouDueDates-Yellow


The documentation, classes, and design reviews assigned to each reviewer for the DueDates-Silver project were:

• Documentation – Anthony Du, Jung Jeho
• DueDates.java, UserLibraryInfo.java – Phillip Lau, Aric West
• Library.java, User.java, Book.java - John Zhou
• Testing Suite – John Ancheta
• General Conceptualization/Implementation Structure – Scheller Sanchez

Meeting Assignments
I really enjoyed reviewing the DueDates implementations created by my peers. Many of them had great ideas. For example, Anthony Du had created an ErrorLogger class that parsed the command line arguments that I thought would be very useful in future iterations of our DueDates-Silver project. Other projects did various forms of testing that were interesting, and seeing uses of Java API elements that I was not familiar with was enlightening as well.

Additionally, the comments gained from our reviewers will definitely strengthen the design of DueDates-Silver in version 2.0. For the most part, the recommendations are in regards to minor improvements to the design, such as altering toString() method returns. Others were more beneficial, such as suggestions for improving our testing suite and using String.format() for output to the console window. And then there’s always the comments for improvements to the design that you already know need to be improved, perhaps, even scheduled for version 2.0, but still, someone just has to point it out!

DueDates v1.0: The Personal Library Checkout Management Tool

Posted on Monday, October 20, 2008
0 commentsAdd comments

In Code Complete 2 author Steve McConnell continually advocates a ‘measure twice, cut once’ philosophy to software engineering. He believes in this philosophy so much that he devotes an entire 37-page chapter explaining the concept and its practice. At its crux ‘measure twice, cut once’ stresses planning and preparing your implementation prior to the actual implementation of it. I really tried embracing this practice in this project.

DueDates 1.0 is a console application allowing a user to access both the University of Hawaii Library (UH) and Hawaii State Library (HSL) systems. By accepting the necessary user credentials from the command line (user id and password), DueDates accesses the user’s account retrieving the checked out items and presents them in the console window.

I was once again joined in this project by my previous partner for the CodeRuler project, Robin Raqueno. (Check out his DueDates blog entry.)

Knowing that this is not the final iteration of DueDates, I wanted the implementation decided upon to be thought out with the future of DueDates in mind. In fact, this was a formal requirement of our implementation. In ‘measuring’ our implementation, while it had to satisfy our current objective—retrieving checked out items data from UH, it need to be robust enough to support migration to a GUI web-based application with a strong potential for added features.

Peer Programming Feedback Loop
Peer programming is supposed to make development on a project faster, higher quality, and more fun. But, peer programming suffers from a feedback loop causing projects to become more robust, thus requiring additional development time and more stressful if you care to be responsible to your peer programmer.

Being paired with Robin, who I had worked with previously, really alleviated the stress and time involved in getting to know a new partner and how to work with that partner on a project. It would be nice to think that a pair of programmers could just get together and hack out a program without needing to become acquainted with a peer’s personality, work habits, realm of experience, etc. Robin and I had already gone through this process during the CodeRuler project, so we were able to jump right into our DueDates project.

Another great benefit to being paired with Robin is that we both work extensively with databases, so this allowed us to take a very data-centric approach to our design process. In some ways, I think this added to the robustness and complexity of the implementation of DueDates we decided upon, but we strongly believe this effort of ‘measuring twice’ will pay off in future versions of DueDates. We identified five classes that DueDates would need to support our implementation:

  • DueDates - The main application responsible for process flow and execution of the program.

  • Library - Represents a library with associated attributes to acquire checked out information from its public web site.

  • User - Represents a user with associated attributes to log in to a library’s web site.

  • UserLibraryInfo - Aquires the checked out data for a specific user from the associated library.

  • Book - Represents a book with associated attributes.

Robin and I met daily, 5/7 days face-to-face and 2/7 days over Skype, for at least an hour, typically longer. We spent 3-4 days discussing our implementation and what we expected it to do and be capable of in future versions. We spent 2 days implementing, followed by 2 days testing, creating user and developer documentation, and reviewing our code. Putting the effort up front to ‘measure twice’ allowed us to manage the tasks during the implementation and testing with decreased stress and few ‘tweaks’ to our original class designs.

We split our tasks evenly and equally, both working on all classes and committing updates regularly. I think Robin and I work well together, and I appreciate where he complements my programming weaknesses. Often when I would get stuck or had other responsibilities to deal with (i.e., work), I would let Robin know where I was at, then the next time we’d speak he would have resolved any issue allowing the work flow to continue uninterrupted.

Logistic and Implementation Issues
We suffered several logistical issues during the first several days of working together. These were issues related to working with TortoiseSVN, being in the proper Eclipse workspace, having the proper Eclipse setting in place, and being able to update and commit files. Many of the issues were minor, but just time consuming and frustrating to deal with multiple times over those first days. Once we sorted through these issues, which thankfully Robin was able to resolve, we had no logistical issues during the remainder of the development process.

The same cannot be said for implementation issues, which we encountered a few. Many issues were trivial, such as those flagged by CheckStyle. Others were more difficult to resolve, such as needing to make DueDates into a singleton class and several suggestions by PMD that, in my opinion, degraded the code quality.

Probably, the biggest area that could be improved would be testing of our implementation. We were unable to achieve 100% coverage using Emma due to private and void methods, which are not accessible and have no testable returns to test against using JUnit.

DueDates v2.0
So with all this up-front planning we did, will there be a DueDates v2.0? If so, what will it look like?
Robin and I really envision DueDates as a web application providing a robust GUI interface that allows a user to enter library and user information from an interface, add new libraries to retrieve data from, and provide downloadable library repositories allowing users to connect to libraries from additional locations. DueDates v2.0 may include options for notification via email, Twitter, and cellular at a frequency determined by the user. The implementation we decided upon really supports a migration to this format.

Now that you’ve heard about DueDates v1.0, check it out at DueDates-Silver. You will find a User’s Guide, a Developer’s Guide, and JavaDocs for it there. Users may download the executable file from the site, while developers will find the source code available. If you extend DueDates, please let us know; we’d like to know how the process went.

The Pseudo-Realistic Subversion Experience

Posted on Wednesday, October 08, 2008
0 commentsAdd comments

This week provided me the opportunity to get the feel of a true configuration management experience, and the introduction to a new peer programmer, Anthony Du.

The objective here was to experience working on someone else’s project, and also, having someone else work on your project, but with the understanding that we are both team members on each project responsible for the improvement and advancement of the project. I call this a pseudo-realistic experience because the projects both Anthony and I collaborated on are our trivial stack implementations.

Getting Started
Anthony and I had a rough start when we paired up. I had not worked much with Google Code or TortoiseSVN at that point during the week. I had been focusing my attentions to the assigned configuration management readings for the week, and had foregone any testing or experimentation with actual process of subversion control prior to class. Anthony on the other hand had been experimenting with trying to host his project remotely. We spent the majority of our lab getting to know each other and experimenting with hosting my project, since we were limited to using my laptop.

I think this actually paid off for us in hindsight, as we met later on Wednesday evening and both seemed much more confident having progressed further with our understanding of the hosting of our projects.

Working Our Projects
Once we both got our projects hosted, I did not encounter any additional obstacles. I made minor changes to Anthony’s build, which failed to pass the verify check due to some tabs in the code which broke the CheckStyle quality assurance test. Anthony added the bin directory to my project, and I was able to check it out and sync my local copy with the changes he had checked in to the remote repository.

Growing as a Developer
I’m confident in my skills as a developer. I’m not saying I’m a great developer, and definitely not a perfect developer. But, I don’t get intimidated by code or put off when approaching a new project. I think I try to approach code objectively and with a sense that whatever I want to attempt should be possible, even if at first not elegant. For many years my personal mantra has been “If there’s a will, there’s a way!” So, why then does my heart beat faster, my adrenaline start pumping, or perhaps I even give a slight cringe at the thought of others working on or reading my code?

I think this is because as a developer putting my code out there for others to see is tantamount to flaying my chest open to expose my beating heart. I would rather have a paper I have written critiqued than have my code criticized. But, I need to become accustomed to this to grow and improve as a developer.

I think this is the most valuable lesson I will learn, having just started the journey, in leaving the single-developer lifestyle behind and joining the world of team project development.

Working with TortoiseSVN and Google Code Projects

Posted on Wednesday, October 08, 2008
2 commentsAdd comments

This week I began working with TortoiseSVN, “The coolest Interface to (Sub)Version Control” according to its web site. TortoiseSVN provides remote access to code files for the management of the collaborative efforts by a developer group working on a project.

The project used to familiarize myself with TortoiseSVN usage was stack-johnson. This project is remotely hosted at Google Code. Stack-Johnson is a basic stack implementation developed by my software engineering professor Philip Johnson at the University of Hawaii at Manoa.

Learning the Ropes
TortoiseSVN simplifies the tasks of subversion control to a great extent versus using command line arguments, so I appreciated not having to work from the MS-DOS shell. After setting up a C:\svn-google directory from which to work with the code repository files for the stack-johnson project, it was a simple task of checking out the project files. Since TortoiseSVN is a GUI application that is accessed directly from the Microsoft Explorer short-cut menu, it was just a matter of selecting SVN Checkout... from the menu. To complete the checking out of the files requires the user to enter his username and password needed, which is provided by Google Code from the user’s Profile > Settings tab.

The first step any contributing developer wants to take after checking out project files is a check of the build status. In this case, I ran Ant against the verify.build.xml file to ensure the build was still viable from the updates other developers have been contributing to the project.

To understand the edit and checking in aspect of subversion control, I made a minor change to the project by restating the getIterator() method declaration in class ClearStack. It was a trivial change, but this allowed me to see some of TortoiseSVN’s visual cues it provides to developers. Upon checking out of project files, TortoiseSVN flags the files with a green checkmark icon in Microsoft Explorer. Once a file has been edited by a developer that icon gets changed to a red exclamation point. This visually identifies the files or directories the developer needs to check in to the repository.

Checking files back in becomes a simple task as well in TortoiseSVN. Again from the short-cut menu provided by Microsoft Explorer, I selected SVN Commit... to upload the changed ClearStack.java file to the stack-johnson remote repository. Again this process will prompt the user to provide his username and password, however, the user has the option of having his password retained by TortoiseSVN eliminating the task of needing to retrieve the unique and random password assigned by Google Code.

On My Own
With a comfortable feel from the successful use of TortoiseSVN’s basic operations and familiarity with Google Code’s remote project hosting site, I decided to embark on my own. If you’ve been keeping up with my blogs, you should know that I have been working on a similar project to stack-johnson. That project is my stack-reeves project which I have been working on over the past few weeks as I have journeyed through the exploration of coverage testing and manual and automated quality assurance methodologies.

Setting up a remotely hosted project on Google Code in itself is not a difficult task, however, there are some pitfalls to watch out for. I had initially gone through the steps of setting up my stack-reeves project. This had gone smoothly until I decided to reset my project from the Source tab. This caused all the subdirectories to be deleted from the project. I had not uploaded my project files yet, but it caused the branches, tags, and trunk subdirectories to be deleted. There was no direct way to recreate the subdirectories or undo the operation, so I only had an svn directory.

This wasn’t at all what I had wanted, and not knowing for certain if just recreating the accidentally deleted subdirectories in the local repository that I would be uploading to Google Code would be adequate, I decided to delete the project and start anew. Well, this only maked matters worse. First, projects are only flagged to be deleted, and that deletion is scheduled for some undetermined future date and time. This meant that even if I had wanted to recreate the stack-reeves project that I’d need to wait for the personnel at Google Code to drop the project first.

I decided to do some quick searches in the help function provided by Google Code only to discover that even once a project is deleted (by Google Code personnel) that the project name would still be unavailable. I found this completely frustrating that not only was I unable to delete the project as the project owner, but I wouldn’t be able to reuse the project name once it actually gets dropped from the hosting site.

I went through the process of creating another new project, stack-ronnreeves and ensured I made none of the mistakes that led to my befuddlement in my first attempt. The stack-ronnreeves project can be accessed here.

Conclusion
Overall, there were no major challenges to using TortoiseSVN or Google Code. The GUI interface and integration of TortoiseSVN in Microsoft Explorer makes it a trivial learning task for experienced users of the Microsoft Windows OS. Google Code is adequate for a free, open source project hosting site, but it appears to me that one of the main challenges it faces is resolving the issue of providing project owner’s true administrative rights.

The Downside of Coverage Testing

Posted on Wednesday, October 01, 2008
0 commentsAdd comments

This is part two of a two part discussion on Coverage Testing. The complement to this discussion is The Upside of Coverage Testing. These discussions are follow-ups from my blog Stable Builds: Using Ant and QA Tools.

Coverage tools are good, but they aren’t perfect. Just like no one tool can be used for every job, so too it can be said of coverage testing tools. Coverage testing ensures that every class, method, block, and line of code has been reached, but that does not guarantee that each one of these has been tested appropriately or adequately.

Sometimes You Have to Break Code to Fix Code
To prove the point, I decided to introduce a bug into the complete coverage tested Stack implementation. The bug I introduce isn’t one that would typically go unnoticed in the process of a normal development cycle, but none-the-less, it demonstrates that coverage testing has some serious weaknesses to it.

The bug I introduced was the addition of a popAll() method to clear an existing stack of all objects that had been placed on to it. Since this implementation of a stack uses a List as its underlying implementation, a properly functioning popAll() method would look like:
   1:  public void popAll() {
2: this.elements.clear();
3: }

The one I added to the Stack implementation looked like:
   1:  public void popAll() {
2: this.elements.remove(0);
3: }

Not only does the new implementation make the mistake of not clearing all the objects from the stack, it compounds the problem by accessing the first object placed on the stack. The latter violation is the worse of the two, because stack by definition is a first in/last out abstract data type. Whimsically removing the first item placed onto the stack changes the definition of what a stack is.

Resetting Splints
Okay, so at this point you should be asking yourself, but won’t your coverage tool just indicate that there is an error with this erroneous implementation. Well, that answer depends on how well your test cases are written.

For example, I can maintain 100% coverage testing of this code by adding just three new lines to my test suite method testNormalOperation():
   1:  stack.push(one);
2: stack.popAll();
3: assertEquals("Testing stack popAll is clear", 0, stack.toArray().length);

Yet, the addition of a new test testPopAll() to the test suite clearly demonstrates that the JUnit build process will fail:
   1:  public void testPopAll() throws EmptyStackException {
2: Stack stack = new Stack();
3: stack.push(one);
4: stack.push(two);
5: stack.push(three);
6: stack.popAll();
7: assertEquals("Testing stack popAll is clear", 0, stack.toArray().length);
8: }

Aftermath
Probably the worst aspect of encountering an unexpected or difficult to resolve bug in your code, is believing you have tested for just an event to later find out that just such a bug exists in your project. As I stated in my earlier blog, any testing is better than none. But, testing, especially coverage testing has its weaknesses. Coverage testing assists a developer in reaching every line of code in an attempt to assure him that all of his code has been tested. However, there are many problems with believing that just reaching a line is an adequate test of the line. In my example, it obviously fails, but worse it redefines what a stack is, which is most certainly not what a developer would want to do. Other places where coverage testing fails are reaching lines that contain multiple statements (e.g., x++; y = x;), or branching statements where not all conditions are tested (e.g., if ((x == 1) || (y != x))). A coverage tool is part of a developer’s first aid kit in code triage, but the developer has to maintain that it’s not the entire kit.

My Stack implementation with full coverage testing, plus introduced bug: Stack-JUnit-Lab-Reeves-6.0.630.zip

The Upside of Coverage Testing

Posted on Wednesday, October 01, 2008
0 commentsAdd comments

This is part one of a two part discussion on Coverage Testing. The complement to this discussion is The Downside of Coverage Testing. These discussions are follow-ups from my blog Stable Builds: Using Ant and QA Tools.

Coverage testing tools, such as Emma, provide a developer the means to test all lines, conditional branching, and routine entry of a unit of code. Unit here denotes a chunk of code that is exercised as a unit—a method, a class, a component, or a system. The goal is to obtain 100% coverage of the targeted unit’s code. The benefit to coverage testing is in the assurance that every line of the unit has been tested and has passed that testing. As the complexity of a project increases, especially in regards to the development of an entire system, coverage plays a vital role in managing the development lifecycle by ensuring that integration of new units are thoroughly tested and that their integration do not break the existing build.

To wet my feet, so-to-speak, I decided to do coverage testing of the Stack implementation from one of my earlier blogs (noted above). The coverage tool being used is Emma, which according to its User Guide “is essential for detecting dead code and verifying which parts of your application are actually exercised by your test suite and interactive use.” While the Stack implementation is a trivial unit for testing, it should suffice in demonstrating the upside of coverage testing.

Baseline
One must first assess where he stands, get a baseline, when testing, performing maintenance, or instituting a repair. A run of Emma against the existing Stack implementation indicates that it does not have complete coverage. While all of the classes in the implementation had been tested, not every method (73%), code block (69%), or line (75%) had been.

First Aid
A coverage tool, and all Quality Assurance tools for that matter, is part of a developer’s first aid kit in code triage. So, I set about trying to bandage the Stack implementation to reach full coverage of its methods, code blocks, and lines. Emma provides a summary level html page that displays the code, highlighting the untested portions. For the Stack implementation, only the EmptyStackException class had complete coverage, while the Stack and ClearStack classes each lacked or had deficient coverage testing of two of their methods. The Stack required further testing of its top() and toSting() methods, while ClearStack had no testing of its isEmpty() and getTop() methods.

Setting Splints
To achieve 100% coverage required the addition of some test cases within the Stack implementation. Since Emma had indicated where to focus my attention, it was an easy task to go about setting splints to mend the broken coverage. Tackling the ClearStack methods, I added the new tests testTopObject(), testEmptyStack(), and testNonEmptyStack. These tests covered reaching the getTop() method and its lines of code, while the other two tests reached the isEmpty() method and tested it for both true and false returns.

Covering the untested Stack methods were just as easy to resolve. I added testIllegalTop() to test for the throw of an EmptyStackException when calling top() on an empty stack. The remaining coverage was provide with the creation of a testToString() test.

Coding-After or Bug Control Pills
However you swallow it, coverage testing is helpful in obtaining stable code. Testing of any type is better protection against unplanned bugs, than no testing at all. Coverage testing ensures that code doesn’t lay fallow within an implementation—all code is shallow—and that it has at a minimal been looked at least once beyond the act of hacking it out. Coverage tools are simple to use, once incorporated into a developer’s routine, and become insurance policies allaying concerns of integrating new code with old code. While the Stack implementation may have been trivial, there was an extensive amount of it that wasn’t being tested. Had this been a critical (life-or-death) system, untested code could very well be a law-suit waiting to happen. Testing may not be able to guarantee that code is 100% error free, it is, however, due diligence on the part of the developer in aspiring to that end.

My Stack implementation with full coverage testing: Stack-Reeves-6.0.630.zip

Subscribe to: Posts (Atom)