Monday, December 8, 2008

Final showdown: DueDates 2.0 vs. Akala Group

It's time we ended this
Finally, it's come time for DueDates 2.0, the final battle in our quest for programming glory. It was a tough beast indeed, requiring us to conquer both XML parsing and Wicket webapp coding. Though we suffered some bruises, in the end we dominated the monumental challenge put ahead of us!

Putting fantasy aside, our final project for ICS 413 was to turn our console-based DueDates application into a full-blown web application using Wicket. Aside from converting everything DueDates 1.2 could do into a webapp, we also had to add in XML parsing using JAXB in order to get user information without relying on a database backend. In order to help us accomplish this significant upgrade to the system, our professor divided us up into groups of 4 instead of 2. This made the logistics of meeting up with each other harder, but had the benefit of more man hours being put into the project. My partners were Arthur Shum, Daniel Arakaki, and Jeho Jung. We decided to start with DueDates-Blue as the base to work off of since Arthur started working on DueDates 2.0 before it was officially assigned and already finished 2 of the 7 requirements by himself on the first day the project was officially assigned.

It's not your fault, CSS, it's Internet Explorer's
My role was to write the CSS code to format the HTML pages, and it definitely took some work to get a design that not only looked nice but would work properly across the three browsers I used: Mozilla Firefox 3, Internet Explorer 7, and Safari 3.2. I originally started off using Eclipse but it soon became obvious that it was inadequate because it lacked syntax coloring and brace matching. I even tried a CSS plugin for Eclipse, but it paled in comparison to my favorite text editor, Notepad++, so I ended up using that for the majority of the time that I was coding. As a result though, this time was not sent to the Hackystat server, so it looks like I barely put any time into the project. I found that this was one of the disadvantages of the Hackystat system, where you're forced to use only the IDE's that the Hackystat sensors support, even though you might be better at using another unsupported IDE/editor.

In order to get to the current design of the webapp, I had to go through several redesigns and color scheme changes. Originally I wanted a fixed-width design with a dark gray color scheme, but when I created the mock-up in Photoshop, it looked boring and too dreary. Then I tried several different color schemes and layouts in CSS to get a better feel for how it would look in an actual browser. At one point I even tried a pink color scheme since akala means pink in Hawaiian, but having your project page look like the Barbie Fun House is not exactly the idea I had in mind.

Eventually, after several failed designs, I settled on a red scheme that made the page look professional and lively. This is where I ran into my next problem with CSS. Although most, if not all browsers support the CSS standard, the way they render it to the screen is completely different. In particular, Internet Explorer 7 has a drastically different way of rendering CSS elements than Firefox and Safari do. For example, when specifying a fixed width, Firefox and Safari do not count the borders with the width, but Internet Explorer does. This means that if you create a box with a 300-pixel width and a 1-pixel border, Firefox will create a 300-pixel wide box and tack on the 1-pixel border to it, whereas Internet Explorer will create a 298-pixel wide box with a 1-pixel border on either side to add up to 300 pixels. There are other differences too, such as how IE interprets padding and margins, but I won't go into detail about them. Needless to say, I spent a great deal of time just making sure the CSS was compatible across all three browsers I tested the webapp with. In the end, after scouring the web, I found a very helpful CSS tip:
* { padding: 0; margin: 0; }
This code will explicitly set the padding and margin to all elements on the page to 0, which solves a lot of the positioning issues with Internet Explorer. I still had to implement some hacks here and there but for the most part it kept the layout looking the same across all three browsers.

Final webpage layout, taken from Arthur Shum's blog

Boy, you are outta time!
Unfortunately, I was only able to meet with my group members once throughout the entire project, but we figured out how to read the values parsed from the XML file by JAXB, which was a huge step forward. Strangely, although Daniel Arakaki said that Arthur and he met up 6 times throughout the project, they did not inform me about these meetings and I had no idea they were getting together. To be honest, I feel as if they were purposely excluding me. I also sent out an e-mail asking them to give me feedback on one of the CSS layouts I made but received no responses. Regrettably, Arthur did ask me to implement certain features into the CSS at one point but I became very busy around that time and was unable to get to it, and by the time I did take a look at it, someone else had already implemented it. I had another project for another ICS class that I had to work on so I couldn't put in as much time as I wanted to, but I'm surprised Arthur had enough free time to work on it for an average of 5 hours per day. I didn't have the luxury of time on my side, but it's still very impressive that he was able to stay motivated and work on it for so long every day.

Monday, November 24, 2008

Implementing a stack in Wicket - a simple example that leads to frustration

Wicket good
Now that we've been working on the DueDates project for the past few weeks, the next step is to design a web interface for it. Unfortunately, many of us don't know the difference between a CSS tag and a kangaroo, so our professor gave us a very simple assignment to help us 'jump start' our way into using Wicket.

What is Wicket?
So what is Wicket? According to Wikipedia, it's a "lightweight component-based web application framework for the Java programming language." In simpler words, it's a tool that allows Java developers to write Java programs to display web pages. This is different from Java applets that run inside a web page; Wicket allows developers to take advantage of Java to generate web pages for them. This means that all the features of Java can be used, such as inheritance and encapsulation, and dynamic websites can be created much like writing a normal Java program.

Stacks of Wicket
Our assignment this time was to implement a stack in a web page using Wicket. Three buttons are available to push, pop, and clear the stack, and a text box was provided to push new strings onto the stack. This program seems deceptively simple, but it proved to be a challenge to do in Wicket, even with the professor's ample examples and bootstrap code for us to use. Coupled with the poorly-written Javadocs for Wicket, I found it hard to make progress while writing the code. In the end I did finish the assignment, but I don't feel like I can do it if asked to write it from scratch.



My Wicket stack project

One problem that I did run into and could not resolve was how to write a JUnit test case for Wicket. The JUnit assert classes that Wicket provides have very lacking Javadocs and I couldn't figure out how to use most of the methods in the classes. I attempted to write some tests based on what I could figure out, but in the end a coverage report showed that the tests were not working. A specific example would be the submit button; I have three submit buttons and I overrided each one's onSubmit method to do what it's supposed to do. However, I couldn't figure out how to 'press' a specific button in the unit test because the FormTester class (provided by Wicket) only has a submit() and submit(string) method, and the submit(string) method doesn't work when I give it the name of the button. The Javadoc comment for that method is also close to non-existent, only listing it as an alternative method to...something else that it fails to mention.

Although it's easy to see how powerful a tool Wicket can be, it's also disappointing that the Javadocs are poorly written and how it's significantly harder to turn a normally simple program such as a stack into a web application. I was expecting the transition to be easier than this but perhaps this is because I'm still unfamiliar with how to use all the classes. Hopefully by the time DueDates 2.0 rolls around, I'll be able to master the art of Wicket-fu.

You can find a copy of my Wicket stack implementation by clicking here.

Monday, November 17, 2008

DueDates 1.2, with more features anew

Scotty, I need more features!
Continuing our DueDates project, we've brought the version number up to 1.2 with some new nifty features. In addition to querying the library websites and printing a list of borrowed books to the console, the program can now send e-mail too. It also supports a wakeup function that keeps the program running in the background and wakes up every so often to check for borrowed books. If there are any books due, it sends out an e-mail.

Agree to disagree
Implementing these new features was quite simple so my lab partner and I did not need to meet face-to-face this week to get them done. However, another problem did arise. We both had an idea of how we wanted to structure the program, but unfortunately our two ideas were complete opposite of each other and could not be reasonably combined. Aric wanted to have a DueDates class that processed the user input and formatted the output, and each UI class, for example a GUI or the console, would simply take the user input and pass it to DueDates, and DueDates will give the UI an output to print. So the flow goes something like this:
DueDates entry point creates Console class -> Console reads user input and passes to DueDates-> DueDates processes user input, gets output, and calls print method in Console -> Console class prints output based on information it receives from DueDates
I really don't like this way because it means that adding any methods in the UI classes meant adding additional code into DueDates to call those methods, and you can't just create an instance of the UI classes and expect it to work how you'd expect it to because it expects the calling class to be DueDates. In other words, the UI classes -only- work as user interfaces and expects another class, in this case DueDates, to handle all the processing. This seems like a very circular relationship to me, where DueDates expects to receive information from a UI class and the UI class requires DueDates to handle processing.

What I want to do is have the DueDates class be nothing more than an entry point into the application. The UI classes themselves will use another class, for example LenderHolder, with all the necessary methods to create, login, and query the libraries. The flow goes something like this:
DueDates entry point creates instance of Console -> Console reads user input and calls methods in LenderHolder -> LenderHolder creates, logs in, and queries the libraries -> Console gets the borrowed books from LenderHolder and prints out the data
I believe this is a much more elegant solution because each class can be instantiated and used on its own. DueDates is the entry point and is used if the person is simply trying to use the program. The Console class can be used by outside developers if they want to use the console to read in user input and do what the DueDates project does, and if they want to develop their own UI, they can use the LenderHolder class. In this case, there is no circular relationship and each class serves a useful function that would be usable by another developer working on another project.

We've yet to work out this disagreement, but I hope to resolve things before the next version is out. As for the overall software development process, I only ran into one other problem: my internet connection was really slow one day so whenever the Eclipse Hackystat sensor plugin tried to send DevTime data to the Hackystat server, it would take a really long time and freeze up Eclipse in the meantime. This was frustrating to say the least and made me quit developing that day because every 5 minutes, Eclipse would freeze for 1 minute while waiting for the sensor plugin to upload the data.

Look forward to more updates in the future!

Friday, November 7, 2008

Software ICU - making sure your code doesn't go blue

Code blue, code blue! We need an ICU!
In a hospital, some patients are put in an Intensive Care Unit (ICU) which monitors all their vitals and ensures that they don't end up with something like cardiac arrest, prompting doctors to come running down the hallway yelling "Code blue!" while pushing along a defibrillator machine. Likewise, for software development, we can also put our projects into a software ICU that monitors its 'health', preventing us from running down the halls yelling "Code red!" when we see all the compiler errors and unhandled exceptions.

Hackystat, it's in your project, hacking your stats
The software ICU we're using for our project is called Hackystat, written and maintained by our professor for this course. It records the data generated from several Java development tools and graph it over time:

Hackystat server screenshot showing our project's health

In the screenshot, you can see several columns:

Coverage: code coverage measured using Emma, higher is better.
Complexity: cyclomatic complexity measured using JavaNCSS, a measure of how many branches and loops the code has, lower is better.
Coupling: how dependent a class is on other classes (such as how many imports it uses), measured using DependencyFinder, lower is better.
Churn: the number of lines that are modified in a SVN commit, measured using the SVN changelogs, lower is better (commit early, commit often).
CodeIssue: the number of issues that the QA tools reported, in our case Checkstyle, FindBugs, and PMD, ideally this should be zero.
Size: size of the project in lines of code measured using SCLC.
DevTime: amount of time spent developing the project, measured using an Eclipse plug-in provided by Hackystat, it records whether there was any work done in 5-minute increments.
Commit: number of SVN commits made, measured using the SVN changelogs.
Build: number of builds made, measured using Ant.
Test: number of unit tests done on the project, measured using JUnit.

As you can see, some of the columns are colored (green for good, red for bad) and some aren't. The columns that aren't colored are the ones that are hard to use as metrics for evaluating a project's health. For example, how do you determine how healthy a project is based on the number of lines of code it has? A simple program will obviously have less lines than a large project, but that's no indicator of how healthy either of them are.

As for our project, you can see that the complexity is steadily falling and churn is going down too, indicating that we're simplifying the code and committing it more often. Unfortunately, our coverage has taken quite a huge drop, from around 80% to 50%. This is because I had to disable a unit test that was failing half the time. It was querying the same web page three times in a row and it would occasionally fail to download the page, resulting in a failure. This made me realize that I had to redesign that class because the unit tests for it are clunky and hard to write. Apart from this issue though, our project is quite healthy - lots of greens, and as long as we get those unit tests written the project status is looking good.

I want me a piece of that Hackystat too
So now you've seen what Hackystat can do, and you might be thinking that you want to use it for your projects too. But how do you set it up? Fortunately, the Hackystat website provides a detailed tutorial on how to set up your development environment correctly. Unfortunately, you have to set up each sensor manually by writing several configuration files, installing the necessary tools you want to gather data from, and then setting up the Ant build files to report the sensor data to the Hackystat server. I myself didn't run into any significant problems while setting up my system but several of my classmates did. If you're going to do it yourself, especially if you want to set up all the sensors that Hackystat supports, be prepared to spend a good deal of time getting everything to work. You only have to do it once for each computer you want to use the Hackystat system for, so it's better to just bite the bullet now and reap the benefits of having a software ICU automatically monitor your project.

So why use Hackystat?
So why use Hackystat if it's difficult to set up? After all, the tools that Hackystat monitors can all be run manually without any significant difficulties. Well, as with any tool, it's only effective if it's being used. To expect the developers (or even yourself!) to manually run each tool every day is practically asking them to forget to do it. Also, running the tools manually can only tell you the status of the project at that given moment. Hackystat can display the trend of the project over time, which can reveal information that would be hidden otherwise. Perhaps the coverage of the project is slowly dropping over time, indicating that more unit tests need to be written. Seeing a graph of the coverage over the period of a week can instantly reveal this, but it might not be obvious if the coverage percentage is still high. All in all, having another tool to monitor a project with is always a good thing.

Monday, November 3, 2008

One small step for man, one giant leap for DueDates

Finally, version 1.1
As I've posted previously, we are now adding shiny new features to our DueDates project! In addition to displaying borrowed books from either the Hawaii State Public Library System or the University of Hawaii at Manoa Library System, our project now supports sorting by either library name or by earliest due date, and also displaying only the books that are due within a certain number of days. We managed to implement everything that our professor wanted for this milestone, but it was a hard battle to get there.

It's as easy as quantum physics!
Implementing the new features was easy enough because our code is was written with modularity in mind so all we had to do was drop in the new classes and modify a few things here and there. However, as I've learned over the years of programming, it's the error checking and testing that really makes people wonder why anyone would choose computer science as their major. In DueDates 1.0, we didn't implement any error checking or error reporting, so this time around I wanted to put all of that in there in droves. At least that was the plan, until I realized that up until now I've only learned the theory behind exception handling but haven't had any practical experience implementing them. After spending several days reading up on proper ways of working with them, I think I've finally grasped the concept of throwing and catching exceptions and I put them into our project. That was the easy part.

Then came the test cases. Oh boy, this is where improper project planning really came back to bite us in the rear. Rather than writing the test cases first and then doing the implementation based on them, we decided to first write the classes and then the test cases to verify them. This doesn't sound like a bad idea in theory, but in practice it's like a visit through hell. First of all, although JUnit supports 'command-line variables' (actually, they're VM environment variables you set at runtime, but let's not be a Java Nazi), I couldn't figure out how to modify our custom Ant buildfile to use them. I could use them when I ran JUnit by itself though in Eclipse. In the end, I had to temporarily hardwire the variables into the code. The next version of DueDates will definitely resolve this issue.

The next problem was testing private methods and getting access to private fields. There are various guides floating around the internet that say if you need to test a private method, you should probably reconsider why it's private in the first place, but sometimes it just doesn't make sense to make it public or when making it package-private doesn't help because your test cases are in a different package. We had a situation like that where our entry point, the main method in the DueDates class, was calling a private method in the same class and the test case was in a different package. In order to get around this problem, I had to use reflection, a way to access private methods and fields by 'unlocking' them.

This is when the third and biggest problem cropped up. While I was writing the test cases for the DueDates class, I soon realized that I was creating a new instance of the DueDates class over and over again because I had no other way to set certain variables or perform certain operations. In turn, this bumped the JUnit run time up to more than 3 minutes! It got to the point where I didn't even want to run the tests anymore because they took so long. This made me realize that I need to break up the DueDates class into more methods to make JUnit testing easier and bring down the run time. If I had written the test cases first, I probably would've realized this early on and wouldn't have to redesign the DueDates class.

When coders collide
Once again I worked with my partner Aric, and because of how complex our code has gotten, there were multiple times where we had collisions when one of us tried to SVN commit our changes. I learned just how important it is to assign tasks that don't overlap with each other since it can take quite some time to work out the collisions. Sometimes it was really obvious whose changes to use, but other times it was a mental struggle to figure out whose code was 'superior'. Either way it is a colossal waste of time. The diff tool that comes with TortoiseSVN is pretty junky too, not only is the interface reminiscent of the MS-DOS days, but sometimes me and Aric edited the same line with the same exact text and it screamed "collision!" (why would you NOT merge two changes that are exactly the same?).

We found even less time to meet up this time around due to the differences in our schedules, but we still communicated online and as much as possible. Every time I made any sort of major change to the system, I shot him an e-mail letting him know what I did. In the future, if we can't meet up very often, it becomes even more important that we split up the project correctly to minimize overlaps.

Hudson, the best friend you've never had
Hudson provides 'continuous integration', which is just a fancy way of saying "it automatically does things you want it to." The 'things' that it does can be very helpful though, such as periodically compiling your code or automatically running QA tools. In our case, we set up Hudson to periodically check for any SVN updates, and if there is one, it will compile the code and run the JUnit tests, Checkstyle, PMD, and FindBugs. If it encounters any errors, it will set the project status to 'fail' and automatically send out an e-mail to all the group members. It's a very nice tool in this regard since it provides an extra 'set of eyes' for our code. The only problem I can foresee, which doesn't apply to us, is if Hudson is set up incorrectly. Since all it does is automatically do what a human would do, the development environment in Hudson must be set up the same way as the developers have it. Our professor gave us strict outlines on how to set up our environment, so we've had no problems compiling and verifying our code with Hudson. Although this version of DueDates was harder to work on than the 1.0 release because of all the extra features and error checking that we added in, Hudson helped alleviate some of the burden by automatically telling us when we screwed up.

Lessons learned through pain and misery
So what lessons have I learned this week, now that I've had even more experience with the DueDates project? Well...

1. WRITE YOUR TEST CASES FIRST. I can't stress this point enough. They are almost in a sense an interface for your classes. By designing a test case, you're also designing how you want your methods and variables to be accessed. That's not to say that the test cases are immutable and that the classes should conform to them absolutely. On the contrary, the test cases should be improved upon and rewritten if there are any problems with them. However, by designing them first, you can save yourself a lot of hassle later on when you realize that you can't access the methods or data members that you need.

2. Delegate out tasks to minimize overlap. Object-oriented programming tries to teach the concept of modularity, that classes should be written so that the individual pieces can be assembled together into the complete system. Likewise, developers should try to 'modularize' their work by having different people assigned to different tasks. This way you maximize everybody's time instead of butting heads trying to figure out whose version of the same source code is the 'superior' one. You don't want to start an impromptu Mortal Code Kombat, trust me.

3. Focus on one thing at a time. One thing that I've noticed is that when I come across a bug or something that needs improving but I'm not quite sure how to do it, I'd rather work on something that I do know how to do and save the other issue for later. That's what I did for the 1.0 version of the project, but for 1.1 I tried to force myself to address the problem instead of putting it off. What I realized is that although it's more frustrating to have to do the research and put in the time to trace down the problems, in the long run it's much, much better for development because you solve the problems that are affecting the system -now- instead of writing new code that can potentially introduce even more problems. As a good friend of mine once told me, "You gotta do what you gotta do." So do what you gotta do now or else you'll end up with more do's on your hand than you know what to do with and we all know what that leads to: a big pile of do-do.

Look forward to more posts as we round the corner to DueDates 1.2!

Saturday, November 1, 2008

Code review revisited: something old, something new

It's (code) hammer time!
Now that we've gotten further on our DueDates project, our professor asked us to do a code review again for a (hopefully) new and improved version. Last week we reviewed three other projects by our classmates, but due to the added functionality and length of the code, we only reviewed one project this week, DueDates-Gold.

Something new
So what's new this time around? We added another library the user could get their borrowed book info from, the Hawaii Public State Library system. We also added in sorting by due date and by library name, and also a -within flag to show only the books due within a certain number of days. Finally, we tried out a new feature of Google Project Hosting that makes code review easier by tying in the review to the specific branch of code rather than the revision number.

Something old
Unfortunately, this code review has seen a bunch of old problems crop up. The DueDates-Gold project is, simply put, not modular at all. It only has three classes excluding JUnit test cases and exceptions, and one class performs almost all of the functionality of the program. The second class is simply an ADT, and the last one contains only one method. Just like the last code review, some people in the class seem to lack a fundamental understanding of how object-oriented programming works.

One thing I did learn from reviewing their project though was that it's important to make your classes modular, but it's also important to make your project settings modular too. Everyone in the class is using the Eclipse IDE, and our projects come with settings for it so anyone using Eclipse doesn't have to manually set up things such as external libraries and build paths. When I imported the DueDates-Gold project, there were a number of problems that I had to fix before I could even compile and test it, mostly having to do with missing jar files. Also, their JUnit test cases relied on reading environment variables that the user has to set up themselves, which I believe is a very bad practice. It helped to illustrate just how important it is to set up your project so that other developers can easily download your source code and work on it without having to spend hours just trying to get their development environment the same as yours.

Bad GPH, bad boy
Google Project Hosting, you're up to your old tricks again. You tempt us with the allure of a new feature that cures cancer and eliminates hunger, but really it's just the same old crap in a new box. In my last code review, I complained about how annoying the code review process is in GPH. Any comments that people make are tied into the revision number they made them on, but you can't tell if a revision has any comments when looking at the revision changelog. This means that it's not only difficult for the reviewers to find their own comments after submitting them, but it's doubly difficult for the developer to find them in the first place. Our professor had us try a new technique this time by creating a branch of our code and reviewing the code in the branch, but there is no difference in how the code review works. In the end I had to write a guide on how to keep all the comments in one revision number so that it's easy to find for us. You can view the guide here. This also illustrates yet another problem with GPH; when you create an issue, you can't edit the description of the issue, you can only add comments or change the issue title.

Strangely, we were supposed to receive a code review from the DueDates-Green group, but we didn't get any comments from them. When I looked at their project, it seems like they haven't set up their own project for this code review either.

I'll get you next time
Although we had a better idea of what we wanted our reviewers to scrutinize this time around, our review request is still pretty general. There are problems with the code that we're already well-aware of already, for example we don't have enough error checking, so asking the reviewers to take a look at that would be a waste of their time and ours. Next time we do a code review, I want to pinpoint more specific problems that I want them to look at, such as whether the project is portable enough for them to download and compile right away, which is something that is hard to test on our own systems since they're already set up correctly. Unfortunately, because we didn't receive a code review, this question will have to remain unanswered until the next code review.

One more thing: until the GPH code review problem gets resolved, it's probably a good idea to write explicit instructions for the reviewers on how to keep their reviews in one revision, unless you enjoy doing a scavenger hunt through your revision log.

Thursday, October 23, 2008

Code reviewing - a coder's litmus test

I'd like a second opinion, doc
Unless your entire coding career has consisted of nothing more than "Hello world" programs, chances are you've looked over your code to see if there are any areas that can be improved and optimized. However, since you wrote it yourself, chances are you also think it's the bomb diggity when it's actually more along the lines of what your dog did on your front yard this morning. This is where having a second opinion comes in really handy, and to give us some practice in code reviewing, our professor had us review three other DueDates projects done by the other groups in our class. If you're unfamiliar with the DueDates project, refer to this post. I was assigned the following projects to review:

DueDates-Purple
DueDates-Violet
DueDates-Red

DueDates-Purple
This project, in my opinion, could use a lot of work. All of their methods are in one class file which to me seems like they either rushed to get it done or don't really understand what objected-oriented programming is. For example, their command line parser is very easily broken; it assumes that the ID number will always be 9 characters long and that the dash will always be the 6th character. The parser also only checks to see if there are 3 or 4 command-line arguments, and if it's 4, it expects '-verbose' to be the first argument. This will become a problem once we start to use multiple login credentials in one command where we'll be using multiple flags. I realize this is only the first revision of the project but to me it seems like they'll just have to end up rewriting everything anyway because in its current form it's not modular at all.

DueDates-Violet
This project was the best of the three that I reviewed. I was asked to only look at the JUnit test cases class for the ErrorLogger class, a class that keeps track of which errors occurred and then outputs them to the console. Strangely, I was not asked to look at the ErrorLogger class itself, which may have been helpful in figuring out if the test cases were good or not. Fortunately, the test cases were very well-written and I was only able to bring up some minor cases that they could've added. Also, I didn't look at the other classes, but the file names makes me feel like they understand the concept of object-oriented programming and are striving to make their code modular.

DueDates-Red
This project, like DueDates-Purple, put all of their methods into one class. I was asked to only look at their getHawaiiStateInfo method, which logs the user into the Hawaii State Library system, gets the user's borrowed items, and prints them out to the console. Apart from the fact that this one method is doing too many things by itself, it should also be put into a new class by itself and the return type should be changed to something more modular rather than outputting directly to the console. This project will also require significant rewrites.

DueDates-Orange, our own project
Likewise, we also received code reviews from everyone that was assigned to look over our project. The reviews generally pointed out one thing: that we didn't spend enough time on error reporting. Other than that, most of the comments were for minor issues, but nobody pointed out any major faults. We even received some high praises for making the system easily expandable! You can view our project here.

Some interesting observations
Throughout the reviews, I've noticed some interesting trends. First of all, people actually wrote nice comments such as "I like how you did this" or "This is what I wanted to do too". I was surprised by this because I thought a code review was supposed to point out only the bad parts of the code, although I suppose some words of encouragement would be nice to hear for the code writers. However, I think this leads to another problem that I've noticed, which is that people generally left only a few comments here and there and a good number of them were 'nice' comments. In my opinion, a code review is a critical examination of the code and any problems should be pointed out. By being nice and holding back potentially 'hurtful' comments, it pretty much renders the review useless because it sidesteps the entire point of doing a code review in the first place. The reviewers need to be brutal and say what needs to be said instead of dancing around the point.

It also seems like some people don't really grasp the concept of object-oriented programming. When we started this project, we were told that we'll be expanding it as we go along, adding more and more features over time. Therefore, it was to our best interest to make the project as modular as possible from the get-go so we don't have to end up rewriting big portions of it. Unfortunately, 2 out of the 3 projects I reviewed wrote all of the code in one class, and it was written to specifically perform only what the requirements wanted but had no future expandability in mind. I hope this is because they rushed to get the project done by the due date, but I have to say it's sort of shameful to see code still written like this in a 400-level course.

Google Project Hosting, I love to hate you
In order to do our code review, we used Google Project Hosting. In my previous blog post, I praised how GPH was a good all-in-one package for programmers who were looking for all the tools they needed to manage their projects. After this code review experience, I'm going to have to retract that statement. For reviewers, commenting on code is easy enough; you open up the source file in GPH, double-click on the line you want to edit, then type in your comments and save them. What GPH doesn't tell you, however, is that your comments don't get posted until you tell GPH to publish them, but the kicker is that there's no 'Publish comments' link anywhere to be found! To get to it, you need to click on the revision number in the changelog that your comment was for and then publish it from there, but this is completely non-obvious and no instructions are provided. I lost and entire project's worth of comments because I didn't know this.

Where's the "Publish comments" button/link?


Here it is! (on the right side)

The second issue is for people trying to look at code review comments. The comments themselves are assigned to a revision number and by default, all comments submitted are associated with the most recent revision. Since you can only view one revision at a time, this presents a problem if the comments are spread across multiple revisions. To make matters worse, the revision browser doesn't show which revisions have comments and which ones don't.

Can you tell which revisions have comments?

In our case, what happened was that some people reviewed our code and submitted comments, then we made some more revisions and some other people reviewed our code after that. Because by default GPH submits the comments to the most recent revision, the comments were split across two different revisions and it made reading through them a pain.

Bruises licked and lessons learned
So what are some of the lessons that I got out of this code review? First of all, make sure you tell your reviewers to look at the right classes. I was asked to only look at a JUnit test class, but was not asked to look at the class that it tests! Obviously I can't really evaluate a test case class very well if I'm not to look at the class it tests too. Secondly, if you're doing a code review, be as brutally honest as possible. It does you and the reviewer no good to play 'nice' and beat around the bush when there are glaring problems with the code. If the code sucks, just say it and save everybody a lot of time. Lastly, write all of your comments for a single revision, and the code writers need to tell the reviewers which revision number to write their comments for. Otherwise it makes it hard for the code writers to view the comments and a super helpful comment might go by unread, lost forever in the internet void. If these tips are followed, it should make the review process much easier for both the coders and the reviewers and prevent you from pulling out your hair in sheer frustration. Now if you'll excuse me, I need to get a haircut...

Monday, October 20, 2008

DueDates project, a first taste in multi-developer coding

Coders don't play nice with each another
From the moment we started taking ICS courses, we were told by our professors that if we use someone else's code for our assignments, it constitutes as plagiarism. As a result, the easiest way for us to prevent against this is to not share our code with others in the first place. Maybe this is the reason why so many ICS students seem so anti-social, it's all because they want to keep their code to themselves!

Luckily, our ICS 413 class aims to break this viciously bad habit because, in the real world, not sharing code pretty much means not receiving a paycheck. To help us learn that sharing code and collaborating with one another is a -good- thing, we were assigned to implement a simple program. All it had to do was check to see if we had any borrowed books from the UH library system and print it out to the console.

Every beginning...already has another beginning
To facilitate this process, our professor provided us with a Java class that uses the HttpUnit library. This library (and supporting libraries, since it relies on other stuff too) allows developers to use 'screen scraping', which is a shorter and smarter-sounding way of saying "parse HTML, automatically fill out form fields, and submit it". The Java class he gave us started us off by providing methods to log into the UH library system and pull the borrowed books data from a table. All we had to do was program it so it could be run from a console using arguments.

I'd like to order Subversion for two, please
Previously we played around with Subversion by ourselves, but this is the first assignment where more than one person had to actively work on a single project. I worked with Aric West on this project, and it was definitely a much different experience than coding individually.

We managed to implement the requirements, but not without some significant difficulties. All the lessons learned about creating test cases and planning out your project before you even begin to code really hit home. At first we decided to do a quick-and-dirty implementation to test the code that our professor gave us, but after that we decided to just expand on it since it was already written and working. This is where we should've done things differently. Although we tried to write it initially with modularity in mind, we should have first planned it out thoroughly because some parts of it required almost a complete rewrite. For example, I was tasked with creating a command line parser class. Although the class itself was pretty easy to write, the hardest part was making it play nice with everything else and I had to modify every other class to support error checking for the parser class. This problem could have been mollified if we planned out our project structure before we started coding, and although it was small enough to handle for a small program with only two developers, it's easy to see how it can become a HUGE problem when you have to tell a big group of coders "Hey guys, I need to update 20 classes to support mine because we didn't design things properly." Not exactly an efficient way of establishing good co-worker relations...

Also, just like there are different literary styles when writing a book, there are also different styles that people use when they code. Aric wrote some code that got the job done, but I wasn't a big fan of how it was written, even though there was nothing wrong with it. The control freak in me wanted to change everything around to how I wanted it to look, but I had to suppress that urge and just accept it as an alternate road leading to the same destination.

Don't call me, I'll call you
Our professor stressed that we should meet up for at least 30 minutes each day to work on the project. This is easy to do in an office environment; walk over to the other guy's cubicle and strike up a conversation with him. As students though, it was much harder to do because of conflicting schedules, difficulties in transportation, or even something as simple as finding a place to meet up at. As a result, we were only able to meet up for the first two days of the project, and we made the most progress in those two days. After the first day we already finished the quick-and-dirty implementation, and after the second we managed to modularize a big part of it. However, after that things kinda fell apart and we lost communications. Neither of us worked on the project again until the day before it was due and we could only collaborate online. Even then, that was a much different experience than in person. There's just something about working with someone else next to you that really motivates you to get the work done and avoid all distractions. Since I'm assuming that this project will continue on in the future, I'd definitely try to meet up with my group members more often, though it might become harder as the number of people increases. Still, the advantages far outweigh the hassle of synchronizing everyone's schedules, and after this project I'm sure everyone else will value it highly too.

You can read me like an open-source project
Open source development is an interesting way of working on a project. Normally people who are working on a project also see each other in person or are in the same company, but when an open-source project gets put online, there could be any number of developers from various locations, and there isn't so much a development team as there are just contributors. Hence, there need to be tools so that people can keep track of the project's progress. Luckily these tools do exist, and Google Project Hosting does a pretty good job of providing these tools in one consolidated package. It offers SVN access for both visitors and developers, a wiki to store relevant information, file hosting, and an issue tracker to delegate out tasks. However, it's not perfect and lacks in certain features that I'd personally want to see. One thing in particular is that I'm not a big fan of how you can't edit anything once it's been committed, and a history of all the changes is always kept. Nice if someone comes in and destroys all your data, but not so nice if you made a huge spelling error or posted something stupid. A feature to be able to edit or remove your changes within 15 minutes of committing them would have been nice. Overall though, Google Project Hosting is pretty awesome given that it's free and offers pretty much everything someone needs to maintain an open-source project.

Thursday, October 9, 2008

Configuration Management, Part 2

Be nice to your neighbors, now
Rarely in the real world will you be working on a programming assignment by yourself. Usually you'll have to collaborate with several people and the end result is a compilation of everybody's efforts. In part 1 of configuration management, we created and modified two Java stack projects, and we're going to do the same again, this time for a classmate. I was partnered up with Creighton Okada, who created his stack project here. Just as with the last exercise, I checked out the source code, made a slight modification, then committed the changes back to the SVN server.

SVN changelog for stack-okada project

Creighton did an excellent job on his stack project. There were no bugs or errors that Ant could find, and unlike me, he remembered to add in descriptions for all his SVN commits. All I made was a simple Javadoc comment change to his project. Although in this case, Creighton and I were not doing edits at the same time, I can see how being able to do so is a great convenience. When I was working on the CodeRuler project with Tyler, I programmed a certain block of code while he did another. We had a slight clash when we tried to merge the code because I edited some of his loops and function calls to make them more efficient, but he changed his functions so that my calls wouldn't work on his code anymore. In the end we decided to go with my changes, but this problem could've been altogether avoided if we used SVN to keep each other up to date on what the other was coding. If a small issue like this can happen between just two programmers, imagine how much more complex it will get when more people are involved. Even when there's only one developer, SVN can be helpful by keeping revision histories for every file, and it's a cinch to bring a new developer into the project. I know I'll be SVN for my projects in the future since I'm notorious for making big changes to some code that ends up breaking the system, and only then do I realize I forgot to make a backup...

Google Project Hosting, what will they think of next?
Google Project Hosting (GPH) is an interesting beast. The basic premise of the site is to host people's projects and allow anyone to use SVN to manage their projects. There is also a mailing list to automatically e-mail people any time the project is updated, though it would have been nice if GPH itself had a built-in mailer rather than having to create a separate Google Groups mailer and configuring GPH to use it. GPH is very friendly and very open-source; anyone with a Google account can create a project, and anyone can browse and download the source code for any project. They even offer different open-source licenses that your project can fall under. Although not quite the beast as SourceForge is, it offers a simple way for people to use SVN for their projects without having to set up the server themselves. And who knows, putting the project online can even attract new developers, and since it's already on a SVN server and set up, all you need to do is add them as a member into the project and they're good to go!

Wednesday, October 8, 2008

Configuration Management, Part 1

What is configuration management?
Let's suppose that I just started working at a small firm with 10 employees, and we're working on a programming project. Bob and I became fast friends and we get along great. But Bob and I have also been assigned to work on the same piece of code in the same source file. This obviously creates a problem. Just last week, Bob made the mistake of working on the file when I was also working on it, and the 2 hours I spent writing that nifty function was lost forever when Bob overwrote my changes with his. Now Bob e-mails me whenever he starts to work on the file and when he stops working on it so we don't come across this problem again. However, Bob sent me an e-mail today telling me he's going to work on the file, and it's been 4 hours since then...oh look, here comes Bob now. He just told me that he forgot to e-mail me 3 hours ago telling me he was done with the file. What did I do with my 4 hours? Twiddle my thumbs, re-arrange my desktop, change my wallpaper, and take a quick nap. Now I get to work on the file, and Bob gets to take a paid mini-vacation thanks to me.

As you can see, this is a very big problem. What if Bob and I need to work on the same file, but on different parts of it that don't overlap? What happens if Bob accidentally overwrites my changes? Is there any way of handling overlaps when they do happen? This is exactly what configuration management aims to control automatically so that the programmers can do their job rather than send out "are you done yet?" e-mails. In this case we will be using Subversion, abbreviated as SVN, to get the job done.

Subversion? Sounds scary!
A secret agent, clad in an expensive tuxedo and armed with nothing more than a small pistol, somehow manages to infiltrate a top secret enemy base and subvert the computers that are aiming nuclear warheads at a friendly country. Cue the explosions and the dashing escape, and complete the mission successfully while getting the girl to boot. Fortunately (or maybe unfortunately), this is not what happens when we use Subversion to maintain our source code. So what is Subversion? At its core, it's nothing more than a file server that allows people to upload and download files. However, it's the additional features that differentiates Subversion from other file servers. It does three things that the others don't do:

1. Revision history - SVN tracks all changes made on files so that it's possible to get any previous versions of the file. It's like a little time machine that allows you to go back to any point in the file's lifetime.
2. File edit merging - SVN allows multiple users to be working on the same file at the same time. Users 'check out' a local copy of the file, make their edits, and then upload them to the server. If two people check out a file at the same time but one of them uploads it first, the second person won't overwrite the first person's changes when he uploads his copy; the two files will be merged together with both of the edits - unless there's a overlap.
3. Merge overlap handling - if two people try to upload a file and there is an overlap in the edits, SVN will notify the user and let him handle it. This way one user cannot overwrite another user's work without his knowledge. So as we can see, SVN solves the issues mentioned earlier quite well, allowing more than one person to work on a file at once, merging their changes, and dealing with overlaps. Now that we know what SVN can do, we can move on to the practical part - actually using SVN to manage a project.

Step 1. Install an SVN client
Our assignment for this week begins off with us installing an SVN client, TortoiseSVN in this case. Don't let the name fool you, TortoiseSVN is not only free, but quite powerful. It integrates into the shell, allowing you to right click on a folder and instantly turn it into a SVN-managed folder. I ran into no problems installing and running this SVN client and I highly recommend it if you don't already have a favorite SVN client that you use.


TortoiseSVN right-click shell menu

Step 2. Modify an existing Google project
To start off simple, we're going to take an existing Google project, modify it, and then upload it to the SVN server. A nice, simple project has been provided for us by our professor, the same stack project we've worked on before. I created a folder and 'checked out' all the project files into that folder, then modified a Javadoc comment slightly and then uploaded my changes to the SVN server. The process is quite simple, and the only cumbersome part was having to use the command-line-only Ant to verify the project before and after the modifications to make sure it wasn't broken to begin with and it isn't broken after the changes were made.

SVN changelog for stack-johnson project

Step 3. Create a new Google Hosting Project
Now that we've modified an existing project and have learned how to use SVN, we're going to create our own project and upload it to Google Project Hosting so that it's SVN-managed. After creating the project page on Google Code, all we need to do is create a folder on our computer, use SVN to check out the files from the SVN server (which should contain only 3 empty folders), and then add in our source code and commit it to the server. The process is pretty straightforward, but remember to check the project settings to see which directory SVN checks out by default. Mine was set to the trunk directory, and when I uploaded my files, I put them in a folder called trunk, resulting in all my files being put into the trunk/trunk folder. Also, it's very easy to forget to add a description of what was changed, and after you finish committing it I don't think there's any way you can modify it, so don't forget to add in a description of what you modified each time.

SVN changelog for my own stack project, notice how I forgot the description the first two times

Hurray for SVN!
Although the exercises in this post don't really show off the true usefulness of SVN, it's easy to see how this tool is crucial when there are multiple people working on one project. Even when there's only one developer, it can be used to keep track of file changes, which might come in especially handy when a big part of the code is modified and the entire program breaks but there are no backups of the older versions, a situation I've been in before. SVN is much more than just a simple file server, so take advantage of all the features that it offers!

Tuesday, September 30, 2008

Is coverage really enough?

What is coverage?
In this week's assignment, our professor assigned a plethora of reading material relating to coverage. Yet, after reading through all the articles, none of them really explained what coverage is in a simple and concise way that's easy for an undergraduate student to understand. Finally, I figured it out myself, and this is my definition: coverage is the percent of code that is being executed when the program is run. Now, this seems like a very simple definition, but it's actually quite accurate, and the reason why it is will become obvious soon.

How to test coverage?
For this exercise, we were given a Java project that implements a stack using an ArrayList. The project also came with some JUnit test cases. Using Ant and Emma to generate a nicely-formatted HTML file, we can not only see the coverage percentage but also which code is being executed and which ones are not. You can see a sample Emma report here: sample report

How to improve coverage?
Our first task was to write additional code so that the coverage increases to 100% from the default 80% for the stack project. Going back to our earlier definition, coverage is defined as what percentage of code is being executed at runtime. This means that methods need to be called and each line needs to be executed, including any branch conditions. So what's the easiest way to increase coverage? Write code to run what wasn't executed! For this exercise, the most sensible way of doing this is to write additional JUnit tests. By adding some tests that call the unused methods and throw the exceptions in the catch blocks, the code was easily brought up to 100%.

Screenshot of some of the JUnit test cases used

How does coverage help?
So how does coverage help a developer? It helps him to see which parts of his program are untouched, and therefore untested. Also, if the code is covered and there were no errors during runtime, that means that there is nothing wrong with the execution of the program for that particular trial. So does this mean that if the code coverage is 100% and there is no problem during runtime, then there is nothing wrong with the code? This is the most misleading part and as we'll see shortly, code coverage is not the same thing as code robustness.

Why should we not rely solely on coverage?
In the previous scenario, we raised the coverage to 100% and the code ran fine with no problems. It's easy to just assume that because the code ran fine with 100% coverage, then there is no problem with the code. To disprove this, we'll now purposely introduce a bug into the code that doesn't break the 100% coverage, but will blatantly cause problems. The easiest way to do this is to impose a cap on the number of elements the stack can hold. We'll do this by modifying the push method in the Stack class from:
public void push(Object obj) {
this.elements.add(obj);
}
to:
public void push(Object obj) {
if(this.elements.size() <= 4 { this.elements.add(obj); } }
As you can see, this makes it so that only a maximum of 5 items can be added to the stack. Because the JUnit tests only adds 3 elements at most to the stack, the JUnit tests pass, and Emma shows 100% coverage in the code. However, if we create a new JUnit test that tries to push more than 5 items and then pop them off, the elements will obviously be wrong. This goes to show that just because code coverage is high, that does not mean that there are no problems with the code.

Why is it not good to solely rely on coverage?
Going back to our earlier definition once more, coverage ONLY tells us which code is executed during runtime and which ones are not. Just because a line of code is executed successfully, that doesn't mean it's robust and can handle any situation. That job is left to the developer to write good test cases that tests not only the expected parameters but also the out-of-boundary situations too. Coverage is only one of the tools that developers can use to debug their code, but it should never be the sole means of determining the quality of code. Where is coverage comes in handy is showing the developer which pieces of code have not been debugged yet, but it is in no way a replacement for creating good, robust test cases.

You can get the source code for both versions here:
Stack project without bug
Stack project with bug

Wednesday, September 24, 2008

Automated vs. Manual QA

Bugs, bugs, bugs, every programmer's nightmare. A program may take a month to write, but several months to debug. Even if all the bugs are caught, more are bound to pop up in the most unexpected of places. Fortunately for us, just as in real life, there are tools that we can use to kill those pesky critters once and for all.

Exercise
In this exercise, we used three quality assurance tools, Checkstyle, FindBugs, and PMD. Each one has a different focus, which will be described in more detail later on in this post. Our professor provided a test project for us to try these tools on and we used the Ant build system to run each QA tool on it. Then we are supposed to fix up the code as much as possible, then upload the final build, which I've provided here:

http://finalranma.imap.cc/stack-danielftian-6.0.924.zip

Checkstyle
Checkstyle mainly checks the formatting of the source code to insure that it follows code formatting guidelines. Of course, the guidelines can vary from organization to organization but the important thing is for everybody to use the same one so that they don't have to spend hours trying to read other people's code and can spend the time fixing it instead. In the provided project, there were a few formatting errors that were easily fixed once they were pointed out, such as the position of the curly braces. Checkstyle generates a HTML report that lists all the places where a formatting error has occurred. It will even find problems with Javadoc comments, such as missing parameters and incorrect sentence formatting. However, it obviously won't catch things such as method names and variables that are ambiguous, and these tasks are still better left to real people to verify.

FindBugs
FindBugs specializes in finding bugs that normally won't be flagged during compile time, but might become issues during runtime. The one example that was brought up in the test project was that Integer one = new Integer(1); is much less efficient during runtime as Integer one = Integer.valueOf(1);. FindBugs generates a HTML report that includes detailed descriptions of the problem and the solution in plain English that even beginner programmers can understand. This is a great QA tool that can find problems veteran programmers know about, but less-experienced ones would be unaware of.

PMD
PMD, like FindBugs, focuses on finding bugs that show up during runtime, but I find that it uses a much more robust, but stricter ruleset for finding errors. This can be both a good and a bad thing. For example, when I ran PMD on the test project, it reported that there was an empty catch block and even managed to detect that a method was creating a variable and then returning it immediately when it could have just returned the variable's value instead. It also suggested that certain variables could be made final since they are only initialized in the declaration or constructor. However, one particular error confused me. The description said "Avoid using implementation types like 'ArrayList'; use the interface instead" for the code ArrayList list = new ArrayList;. Because of this one lingering error (I fixed all the Checkstyle and FindBugs errors), I was unable to use Ant to verify the build. Just like FindBugs, PMD will generates a HTML report and provides detailed descriptions for the problems it found, but unfortunately the description pages all link to PMD's website, which is a problem if the computer doesn't have internet access. Also, the description pages provide examples, but they are examples of what the wrong code looks like and doesn't show any examples of what the correct code should be, which became very troublesome in this case since I couldn't find a solution elsewhere.

CodeRuler and QA tools
Our professor also asked us to run the QA tools on our prior CodeRuler assignment to see how well our code held up to conventions. Checkstyle reported a bunch of Javadoc errors, along with several lines being longer than 100 characters. All of the errors that Checkstyle caught were also acknowledged by a peer review of our code by one of our classmates. FindBugs reported that there were no errors, but PMD showed up several, illustrating the differences between their philosophies. PMD reported that one of the methods we had was empty and also to avoid using if (x != y) in order to keep the code consistent with the "if same, else different" philosophy. This problem was obviously not caught in the peer review because it's more of a semantic problem than a potential source for bugs.

Automated vs. Manual QA
So in the end, which one is better? Automated or manual QA? I'd have to say both. Manual QA can catch things that only a human can notice, such as badly-named variables and methods and incorrect formatting for comments. Automated QA, on the other hand, can use the knowledge gained from veteran programmers and catch bad programming practices that would otherwise go unnoticed, but even so, a human being needs to review the errors to deem whether a fix is necessary or not. In the end, by combining the two methods, a programmer can not only write code that works, but also code that is well-formatted and, when compiled, is efficient and better than it could have been without any QA tools.

Monday, September 8, 2008

Lessons learned from Code Ruler

Our instructor provided us with an assignment to implement an AI script for CodeRuler, a game that was created by IBM. You can find the official site here:

CodeRuler: http://www.alphaworks.ibm.com/tech/coderuler

The Premise
You are a ruler who has been given a castle, 10 peasants, and 10 knights. Peasants can capture land, garnering you points and faster reinforcements from your castle, but die to one swift blow from a knight. Knights can kill opposing peasants and knights and capture castles, and castles themselves will provide provide a new peasant or knight every few seconds, faster if you own more land. Points are gathered from killing the enemy and capturing their castles, as well as claiming land and having surviving units at the end of the game. Of course, the player with the highest number of points wins. The twist to this game, however, is that the player has no direct control over the units and must write an AI script in Java that will be used to control them.

The Implementation
For this assignment, we were assigned partners to work with and I had the pleasure of working with Tyler Wolff. The strategy that we decided to implement was to have the peasants capture land in a 'fill' fashion by moving up and down until it encounters a square already captured, then moving left and right one block and repeating the same process. The implementation for the peasants is actually quite simple since they can't do anything except this one function.

CodeRuler showing our 'fill' implementation for peasants

The meat of where the coding is, at least in my opinion, is writing an effective AI for the knights. Because the knights are the ones that have the biggest impact on the outcome of the game, we decided to focus most of our efforts on writing an effective strategy for them. What we ultimately decided on was to eliminate the biggest threat first - the enemy knights, and then take care of the other units only when there are no knights to oppose ours. To that end, we try to 'gang up' on a single knight by picking one that's closest to one of our knights and then sending all of our knights to kill that single one. Unlike peasants, knights have health and it takes several attacks to bring one down, so focusing the attacks should prove more effective than randomly selecting targets.

However, there are some other factors to consider. Since only one unit can occupy any given space at any time, a situation can occur where all the knights try to go towards one enemy unit but get stuck behind each other, forming a line that's easily defeated. This is because when the knights try to move to a square already occupied by a friendly knight, they can't do so and therefore stop in their tracks, essentially wasting a turn. The fix for that was to make them turn 45 degrees to the left or right and attempt to head in that direction instead, moving around the knight rather than bumping into him repeatedly. This code worked quite well and improved our results drastically. We even took it one step further and added an additional check to see if there is an enemy in the new direction and to attack it if there is. However, the code only performs 2 checks and if both spaces are occupied by friendly units, the knight will not move or attack.

If all the enemy knights are dead or if a castle happens to be closer than the closest enemy knight, the knights will attempt to capture the castle. The process of capturing a castle is the same as capturing land, except only a knight can do it. After all the enemy knights and castles are killed and captured, the knights will then go after the closest peasant. Our code is written so that if there is already a knight chasing after a peasant, another knight will not join the chase and will instead pick a random direction to move in until it finds a peasant that is not being pursued by another knight. This strategy works best if the knights are spread out, as each knight can chase down a different peasant, but does not work so well if they are bunched together because they will all see one peasant as the closest one, but only one knight will chase after it while the rest move in random directions. However, at this point the enemy has no castles and no knights, so the player has essentially won and killing the peasants slowly or quickly has little bearing on the final outcome.

Playtesting
So all this is good in theory, but how does it hold up against other AIs? Although we couldn't test our AI against the other groups that also worked on this assignment, we did manage to test it with the built-in AIs and the results were impressive:

Our AI vs. Migrant Ruler
Trial 1: 864 vs. 0
Trial 2: 812 vs. 0
Trial 3: 639 vs. 0

Our AI vs. Gang Up Ruler
Trial 1: 712 vs. 84
Trial 2: 739 vs. 133
Trial 3: 809 vs. 60

Our AI vs. Smart Split Up Ruler
Trial 1: 788 vs. 70
Trial 2: 797 vs. 86
Trial 3: 801 vs. 58

Our strategy was very effective in eliminating the enemy knights and our AI can easily win any one-on-one match. We even tried it with a 6-player free-for-all and our AI can win up to 70% of the games. There is only one potential problem; CodeRuler imposes a time limit on how long it takes code to run, a mere 0.5 seconds every turn. Because our code contains a large amount of loops and checks, it can reach this limit, especially when the knights are going after the peasants. When this limit is exceeded, CodeRuler will stop the AI script from running, although all the other AIs will continue to run, leading to a situation where your units sit there and don't do anything at all while the enemy wipes out your forces with impunity. This would be a good way to impose a cap on the amount of logic that people can program in and would strike a good balance between complexity and optimizations, except for one problem: it is completely dependent on how fast the computer is that CodeRuler is being run on. Someone with a faster system will be able to implement more complex code than someone with a slower computer. In my opinion, there needs to be a better way to impose this limit because even amongst our small class of 20 students, there is a big variance between computer speeds.

Lessons Learned
Through this experience, I feel like I've learned a great deal about programming itself. Eclipse surprised me a number of times, especially when it pointed out which variables I haven't used, and going from using a text editor (albeit with syntax coloring) to an IDE has been an enlightening experience. CodeRuler is, I believe, a really great alternative to writing simple Java programs because it presents a clear and fun goal that can be constantly improved upon. If the processor speed issue is fixed, it has the potential to be the next "Hello world" program. Lastly, working with Tyler has been a very good experience. Usually when I get into groups, I tend to try and do everything by myself because my partner almost always ends up being incompetent or lazy and I find it much more reassuring to finish everything by myself so I'm not placing my grades in the hands of something I don't trust. Tyler, on the other hand, has shown me that if people do get together and pull their weight, they can yield a product that is more than the sum of its parts.

You can obtain a copy of our code and our Javadoc from here:

http://www2.hawaii.edu/~wolfft/tylerwolff-daniel.f.tian.zip

Sunday, August 31, 2008

The Open Source Software Experience

There are three 'prime directives' that developers should strive for when writing open-source applications. To better describe the directives, I will be evaluating a Java-based project called Vuze that I found on sourceforge.net.

Overview
The project that I will be examining is a Java-based bittorrent client formerly known as Azureus and is now known as Vuze. The difference between Azureus and Vuze is that Azureus is strictly a bittorrent program, whereas Vuze combines Azureus' functionality with a Youtube-like portal of digital content such as movies and games that users can download using the bittorrent protocol. The older versions of Azureus are still available for download, but the company has discontinued support for it and are now focusing their efforts on Vuze.

According to their homepage, Vuze's goal is to create a bittorrent community where independent people and companies can share their videos, music, and games with a large audience and, if they choose to do so, charge them on a for-rent or to-own basis. This is an attractive proposition for anybody who has something they wish to share but don't necessarily have the bandwidth to distribute it to the general public. Allowing companies to charge for their content also provides an avenue for digital distribution, which has significant advantages over buying a physical medium at a retail store. Essentially, their goal is to create a one-stop shop for digitally-distributed media, using the bittorrent protocol as a means to alleviate bandwidth issues.

Vuze homepage: http://www.vuze.com/app
Sourceforge page: http://sourceforge.net/projects/azureus/

Prime Directive 1 - The system successfully accomplishes a useful task.
In order to fulfill Prime Directive 1, a program must provide some sort of useful functionality for the user. Vuze definitely fulfills this criteria. It provides a working bittorrent client that can not only download torrents from its own portal but also take any torrents found on the web. The portal also provides tools for content creators so that they can add their files to the network and share it with others. A system is also in place for purchasing content, although this mostly applies to games from what I've seen, as almost all the videos are trailers rather than full-length movies. Also, based on the number of comments and how fast videos download, there seems to be a sizable active community, so Vuze looks like it's definitely progressing towards its goal.

Prime Directive 2 - An external user can successfully install and use the system.
In order to fulfill Prime Directive 2, a user must be able to download, install, and run the program without running into any roadblocks. Vuze satisfies this directive by providing a very clear link to the downloadable executable on their homepage. They also have Linux and OS X versions available in addition to the Windows version. On a Windows machine, an installer automatically installs the program and the process is very straightforward because it uses the standard Windows installer. Vuze itself is easy to use thanks to its well-designed interface. Documentation is provided but is hardly necessary because of how simple the program is to download, install, and use.


Prime Directive 3 - An external developer can successfully understand and enhance the system.
In order to fulfill this prime directive, the source code for the application must not only be available, but it must also be formatted and commented in a way that makes it easy for anyone to edit it and add or change features without having to spend an extraneous amount of time figuring out the existing code. The source code for Vuze was provided on their sourceforge page, and I downloaded it and took a look at it. Unfortunately, the program is split between very many Java source files, but apart from the folders that the files were found in, there is no indication of how it all ties together or even how to compile it. Also, only a small number of files contain any comments at all, and those that did were woefully lacking in details, often only providing simple comments that don't explain things well enough to get a good grasp of what a method or code block is doing. No documentation was provided either apart from a change log. Vuze fails the third prime directive because it would be hard for anyone to understand the source code, let alone make any modifications to it.

The lesson in this exercise is that, to write an open-source program, a developer needs to keep in mind three principles that will help his or her program to thrive. If the program does not serve a purpose, nobody will want to use it. If it is hard to install or work with, nobody will want to use it. And finally, if other developers cannot easily understand or modify the source code, nobody will know how to improve it.

Wednesday, August 27, 2008

FizzBuzz programming exercise

This is the first blog post of many to come, so it may be a little rough around the edges. I'm currently attending a course called ICS 413 - Software Engineering, and this class teaches what I hope to be efficient programming practices that I can apply in real life, a stark contrast to my other courses which I feel are more like intellectual exercises rather than practical examples.

The Exercise
A simple exercise to start us off, this one has us refreshing our Java skills by programming something relatively simple. The output has to be a count from 1 to 100, one number per line, except that if the number is a multiple of 3, the output is "Fizz", when it's a multiple of 5, it's "Buzz", and when it's a multiple of 3 and 5, it's "FizzBuzz". This program, though deceptively simple, was a good measure to see how our Java knowledge has stood the test of time, since for most of us, the last Java programming assignment we've had was in ICS 211 almost two years ago.

The Process
Of course, the foundation of any good programmer is a good IDE, and Eclipse is the IDE we're using for the course. I've used Eclipse before back in the introductory Java courses, and the developers have made some huge improvements to both the speed and the interface of the program. Unfortunately, they also made it display a welcome screen that blocks the windows behind it, and it's not immediately obvious that you have to close this window to see anything behind it. When I tried to create a new project and a new class, I thought something was wrong when the welcome screen didn't change until I realized that I had to close it first. Not exactly very intuitive if you ask me, and a slight issue where HCI is concerned.

Fortunately, the actual programming itself went quite smoothly except for one problem where I forgot how to declare a method with no return value. At first I was trying to use public static null FizzBuzz(), which didn't work. A quick Google search reminded me that it's supposed to be void, not null. For the past few years, I've been programming mostly in Visual Basic for an Access database so I'm a little rusty at Java, but I have to say, forgetting something as simple as this is pretty shameful for me. The entire program from beginning to end took 8 minutes and 2 seconds to write and it served as a nice reminder that I need to brush up on my Java syntax, something I'm sure I'll be getting a lot of practice with from this course.

Code
public class ClassFizzBuzz {
public static void FizzBuzz() {
for(int i = 1; i <= 100; i++)
{
if((i % 5 == 0) && (i % 3 == 0)) {
System.out.println("FizzBuzz");
}
else if (i % 5 == 0) {
System.out.println("Buzz");
}
else if (i % 3 == 0) {
System.out.println("Fizz");
}
else
{
System.out.println(String.valueOf(i));
}
}
}

public static void main(String[] args) {
FizzBuzz();
}
}