Monday, October 22, 2007

MyIsern-1.2

Today's assignment is MyISERN-1.2.


All tasks completed.

Group Process

My partner Kevin English really got into the text interface on this assignment. We had already divided it up on a previous assignment so that he was doing the interface, but on this one he really seemed to have a vision of how it should work. He volunteered to do all the data inputting, so he was writing code for himself to use.

I tried it out a little, and it is a nice interface. It's actually menu-driven rather than command-driven and pretty intuitive1.

As far as working together, we mostly did what we've done on past assignments: meet as often as we can, kick some ideas around, and then decide what we'll do until the next meeting. Since I'm writing the model, a lot of the group interaction has been about what methods my partner needed me to implement.

Difficulties

The main difficulty we had was with JAXB and Java. Every time we've used it, we've thought about wrapping JAXB somehow, but we never did. The problem is that we couldn't find a way of wrapping it that would solve the problems we were having without being more work than the problems themselves.

For me, working on the model, the problem manifests as doing things three times. For Kevin, it was probably different.

When we first started using JAXB, I thought maybe we could just wrap or convert the three JAXB objects into things that formed an inheritance tree. But there was really only one method they had in common. The problem was that they had many repeated methods which were analogous but not identical in type or number.

Kevin has his own take on the problem, but I look at it this way:

Java doesn't let you merge, or even blur the line between, object structure and metadata. Objects can't easily inspect each other's structure and interact based on what they discover. It's also very rigid about types. JAXB, on the other hand, converts XML entities with children to classes with fields. The sum is that you lose the ability to treat the structure of the data as data that can direct the code. Instead, it's an invisible (to the objects) structure that you must hard-code the objects to synchronize with.

To really get around that, as far as I can see, the wrapper would have to be a sort of reverse-JAXB that turns the JAXB objects back into some type of self-describing data structure like a DOM tree or nested maps of strings.

That never seemed worth the effort, so we would always sort of daydream about having a solution and then keep going without it2.

I'm interested to see what other groups have to say about JAXB. I keep going back and forth between thinking there must be wonderful way around it that I just haven't figured out yet and thinking that Java and JAXB are just hopeless.

Another minor thing is that our code coverage suddenly dropped right near the end. From the reports, it looks like everything has pretty good coverage except for some enums and our old command-line interface, which is coming in at under 60%. I knew that my partner was still using parts of the command-line interface to work with the new interface, so I figured he had merged or moved the test code in some way that caused it to only test the things we're actually still using.

In any case, the sudden drop didn't seem to be caused by a whole bunch of new, untested code. I also didn't notice it till my parter was asleep, so I didn't hold up the release for it.

Next Time

Next time, we might want to do a little more of the "skeleton" of the project earlier: things like issues, unit test, and wiki pages. We sort of lost track of where we were and what was left to do, and I think that would've helped.


  1. It has a little bit of old code that I wrote in the first iteration for displaying tables. Right at the last minute, that old code started choking on nulls.

  2. We didn't realize it until the very tail end of this assignment, but there's also a problem with JAXB and null. JAXB uses null in a lot of places where an empty collection would make more sense. If I'd known how pervasive that was, I might have gone ahead and written a wrapper even if that was the only thing it fixed.

Use Case Specification

Today's assignment is UseCaseSpecification. Our use cases are here.


Our team drew up a list of the use cases we wanted, then divided them up to work on them. I expected that would lead to two different styles of use case at the end, but I was surprised at how different they turned out to be. My partner, Kevin English, took a much more formal approach. For example, his alternates always go back to the beginning and start from scratch, while mine often fork off in the middle of the typical case. Also, my mock-ups look like napkin doodles.

We actually cut out a lot of use cases because there were so many. Finding, adding, and editing each of the three types of things (collaboration, organization, and researcher) would already be nine and our target was six to twelve. We ended up not having separate use cases for finding things, and just including that as a step in editing. We also combined all the analysis into one use case.

We mostly followed the tips on how to write good use cases, but I think mine might have been a little on the terse side. It's very easy to come up with use cases, but it's hard to remember all the rules and it's easy to do too many.

Wednesday, October 17, 2007

MyISERN Review 1.1

Today's assignment is MyIsernReview-1.1. I'm reviewing the code of Marcius Bagwan (team blue). The team blue code is here.


Installation

The project downloaded and unpacked fine, but when I tried to build the jar file, I got an error message:

BUILD FAILED
/tmp/myisern-xml-1.1.1015/build.xml:45: This package requires SWT_HOME
to be defined and /tmp/myisern-xml-1.1.1015/${env.SWT_HOME}/swt.jar
available

I didn't know what SWT stood for. The acronym wasn't expanded in any of the build.xml comments, and there was nothing in the developer guide about it. It turned out to be a graphical interface toolkit called Standard Widget Toolkit. I downloaded it and set SWT_HOME, and the jar built.

But then it didn't run:

$ java -jar myisern-1-blue.jar -describe -all Researchers
Exception in thread "main" java.lang.NoSuchMethodError: main

I fixed build.xml to look for "main" in a class that actually had it, but it still wouldn't run:

$ java -jar myisern-1-blue.jar -describe -all Researchers
Exception in thread "main" java.lang.NoClassDefFoundError:
org/eclipse/swt/graphics/Drawable

And it didn't verify either:

[checkstyle]
/tmp/myisern-xml-1.1.1015/src/edu/hawaii/myisern/example/TestMyIsernXmlLoader.java:7:1:
Redundant import from the same package -
edu.hawaii.myisern.example.MyIsernXmlLoader.

BUILD FAILED
/tmp/myisern-xml-1.1.1015/checkstyle.build.xml:30: Got 1 errors and 0
warnings.

Coding Conventions

After all that, I didn't look very hard for coding violations. One thing I noticed is that a lot of code is commented out using // instead of /* */ (EJS-36).

Test Cases

Black Box

Nearly all the tests are black box tests of the checkArguments method, which accepts the command-line arguments and prints out the results. It also returns a boolean flag that is true if the arguments are valid and false if they are not. With a few exceptions, the tests are all of this flag.

Some tests that could be added:

  • query for an object that isn't there (and verify that the program handles not finding it, not just that the arguments were well-formed)
  • invalid xml (blank name, out-of-range year, dangling reference)
  • check correctness of output (before printing)

White Box

There were only two tests that seemed to be white box: One reaches into the XML loader and checks that the Collaborations XML tag is present, and the other tests an isLinkValid method (for URLs) that doesn't seem to be called outside the object itself.

The code is hard to follow, and I don't think I understand it well enough to recommend many white box tests. I can recommend:

  • test whatever it's doing with SWT
  • test the main method

Breaking

It's already broken. Running it, with any arguments, is a test that causes it to crash.

Summary

Right after I posted this and sent the email, I realized I forgot this section. It's not actually due yet, so I'll add it now.

In summary, the program doesn't run.

The lesson I learned is how hard it is to evaluate a program that doesn't work at all. (By "evaluate," I mean that it's hard to examine. It's very easy to form an opinion.)

Monday, October 15, 2007

MyISERN-1.1

Today's assignment is MyISERN-1.1.


All assigned tasks completed.

Difficulties

The main difficulty was figuring out how to design the program and organize ourselves. My parter Kevin English has a lot of experience with MVC using Ruby on Rails, so we decided to use an MVC design. Kevin worked on the controller and the view, and I worked on the model.

We were also a little unsure about how the model should look. We started writing out method calls showing how it would be used, and then we though maybe we should try test-driven design. So, for the model at least, I was using TDD.

I came up with a technique of commenting out the @Test annotation (as //TODO @Test) and using Eclipse to generate stub implementations so that I could check in the unit tests before the "real" code without breaking verify. It worked fairly well -- writing the code seemed to go a lot faster with the tests in place1.

The biggest problem as far as organizing the group was the model interface. I think we spent most of two meetings talking about what the method signatures would be. Finally, it was all settled. Then right after the last meeting before release, I got an email from my partner telling me I had done it wrong.

Next Time

Next time, I'd like to nail down all the interfaces between code that will be written by different people before anything else is done. It might help to print out the Javadoc HTML and bring it to the meetings.

We seemed to be meeting more as time went on. I guess it helps more than we expected.

I wouldn't mind using TDD again, but I really think it's time to add a web interface and a database. It gets harder and harder to add those as the project gets on. I don't care how agile you think you are, this is a huge risk. It's like we're deliberately simulating the type of insane requirements flux that kills projects2.

I wrote our current data model, and I know that it will have to be thrown away when we go from JAXB objects to a database. Obviously, the same is true for my partner's command-line and text table code when we go to the web.

Why didn't we write an abstraction layer so that we can easily switch? Doing that so it actually works is a lot harder than it sounds. I doubt anyone has had enough time to even come close.

(I just saw Kevin's entry. I agree, it's also time to ditch Java.)

Wednesday, October 10, 2007

MyIsernReview

Today's assignment is MyIsernReview. I'm reviewing the code of Andrew Wong (team silver). The team silver code is here.


Installation

Downloading, unpacking, verifying, and building the distribution all went fine. When I ran the jarfile, it printed out a nice help message, telling me to use -tabs or -console to choose the type of output. Both ways worked as advertised.

Code Format and Conventions

Per our instructions, I spent only a few minutes looking for violations, and none leapt out at me.

Test Cases

Black Box

The unit tests included these black box tests:

  • Test that the number of records printed is the same as the number of records given.
  • Check that no records are printed when no records exist.
  • Test that the program runs.

The box couldn't be completely black because a lot of the methods being tested print their results. The tests mostly went by status flags in the return values. (For example, the method that prints out records returns the number of records printed and the test checks that return value.)

The problem of testing printed output doesn't have any perfect solution (that I know of) but it might be better to have methods that return the complete output and test that. It would also be good to test the contents of the output and the number of columns.

White Box

Emma reports 100% coverage.

The white box test were geared toward testing the column formatting in console mode. There's a method called getColumnSize that takes an array of strings representing a column and figures out what the width of the column should be. The method actually takes the length of the longest string in the column and uses the next multiple of ten after that, so there are several white box tests using string lengths chosen to test the rounding logic.

There are also tests that the program runs in the right "mode" based on the command-line arguments.

The table structure is basically hard-coded, so a lot of the code is a bunch of method calls that have to be in the right order to put things in the right column. It would be good to test that things are actually going in the right columns.

Breaking

With the XML input given in the specs, there are really only two cases for the program to cover, and it basically goes straight through and does them. The only way I can see to break the program is to drop the assumption in the spec and give it other data, which I think doesn't count.

There is one thing I noticed. It's not technically "incorrect output" but some of the columns in console mode are much wider than they need to be. The data is trimmed of whitespace before it's put in the table, but the getColumnSize method is passed an array of the untrimmed data. That's pretty easy to fix.

Lessons Learned

The main thing I learned is that System.out has a format method that's good for printing columns.

Testing a program like this is a little odd. The input is fixed, so you could just have a test that does a giant string comparison on a string that's printed out as the entire output. In fact, you could have a program that just prints out a hard-coded string.

It's kind of silly, but now that I think of it, I wish I had done that. It would have been a lot easier.

Monday, October 8, 2007

15.MyISERN-1.0

Today's assignment is MyISERN-1.0.


Lessons Learned

Group Work

My partner on this project was Kevin English. He had to be on the mainland from Friday until Monday, so we probably did things a little differently than other groups.

Kevin set up the project on Google and did as much of the code as he could before he left. While he was gone, he could get email and a web browser, but didn't have his development environment. So from that point on, he worked on the wiki and I worked on the code.

We ended up not really using the "discuss" Google group and just sending each other email directly. With more people that might have been bad, but with just two it was not a problem.

The main lesson for me was that if you can divide up the work very clearly, by area or time or both, it helps lessen the effect of physical separation.

JAXB and XML

I didn't really learn anything about JAXB or XML, except some basic background on what JAXB is for. We only used it a little, and the method calls were already in place by the time I started working on it.

The Code

When I started, the first thing I was going to do was add unit tests for the code that Kevin had written. I immediately ran into that same problem we've had before with unit testing code that prints out its results. That really seems like a flaw in Java because it gives you an easy, obvious way to write your program and then makes that way impossible to test.

I'm still not completely satisfied with the output. It prints out a table, but the "description" fields are so long that they often wrap around and mess up the display of the table on the screen. It looks okay in the Eclipse console, which doesn't wrap, but when you run it from the command line, it looks messy.

In the end, I figured it was better to have the output literally be a table than a non-table that looks nice when you wrap it.

Tuesday, October 2, 2007

14 CM Practice

Today's assignment is CM Practice, where we practice setting up a project on Google according to the class conventions.


All three tasks accomplished successfully.

Subversion Client

I already had the command-line client installed, so I decided to use that. One benefit is that I can just paste my command lines into this entry.

Improving Stack-Johnson

Every time I use svn with a new server, there are a few rough spots. No two servers are set up in quite the same way, and I always seem to want to use some feature of svn that I haven't needed in a while, like reading only the log message of the change I just committed. It took a little reading of the docs, but went fairly well:

$ svn --username brian.jaress checkout \
https://stack-johnson.googlecode.com/svn/trunk stack-johnson
$ cd stack-johnson
$ ant -f verify.build.xml

(At this point, I made my change.)

$ svn diff
Index: src/edu/hawaii/stack/EmptyStackException.java
===================================================================
--- src/edu/hawaii/stack/EmptyStackException.java       (revision 34)
+++ src/edu/hawaii/stack/EmptyStackException.java       (working copy)
@@ -1,7 +1,8 @@
package edu.hawaii.stack;

/**
- * EmptyStackException is thrown when an attempt is made to pop an empty stack.
+ * EmptyStackException is thrown when an attempt is made to pop an empty
+ * stack or check its top element.
 *
 * @author Philip M. Johnson
 */

$ ant -f verify.build.xml
$ svn commit

(Filled in the log message.)

$ svn update
$ svn log -r HEAD
------------------------------------------------------------------------
r35 | brian.jaress | 2007-10-02 09:19:18 -1000 (Tue, 02 Oct 2007) | 4 lines

Expanded EmptyStackException class comment to mention that it's thrown
when checking the top of an empty stack.

------------------------------------------------------------------------

Creating a New Project

This task was mostly about setting up a Google project in exactly the class-approved way. The biggest difficulty was that the instructions were in the form of a slide show full of screenshots that I couldn't really make out. I spent a lot of time squinting at pictures that were either tiny or blurry, depending on how much I zoomed in.

Once the Google side was all set up, I just had to bring the files in:

$ svn --username brian.jaress checkout \
https://webspider-jaress.googlecode.com/svn/trunk
$ cp -R webspider-jaress/* trunk
$ cd trunk
$ svn add *
$ ant -f verify.build.xml
$ svn commit

Then I checked my email and confirmed that I had gotten a message containing the change.

Lessons Learned

I learned a few quirks of Google Code and Google Groups and puzzled out our class conventions for how they should be used. I also discovered a few quirks of Subversion that I hadn't known about, like having to do an update before you can see your own commit in the log.