Tuesday, October 25, 2011

Not so trivial pursuit - Software engineering edition

Hello readers. Today, I present to you 5 quickie questions for budding software engineers to chew on. Some of these are more specific to my development experiences so I don't expect you to know the answers, but you are reading this on the internet after all, so feel free to embrace the power of infinite shared knowledge.

1. Subversion is a version control system. Name another and briefly describe how it differs from Subversion. (Hint: Linus Torvalds insists you don't use Subversion)

RCS: Doesn't allow for concurrent changes, each developer must obtain a lock to edit a file. Developers must access the same file system to access files.

CVS: Versions are file-based as opposed to repository-wide. Back-end repository is composed of files rather than a database.

Git: Every developer has their own local copy of the whole repository. Rather than managing commit access, you choose other developers' repositories to merge with your own.

2. Briefly describe the difference between exhaustive and practical testing. Which test would you choose? (Answer correctness is based on your justification of your choice, rather than the choice itself)

Exhaustive testing can be more thorough and thus come closer to proving the correctness of a program where as practical testing tries to uncover errors by testing samples. Exhaustive testing, if possible to execute, can produce more reliable results. However, in most non-trivial programs, exhaustive testing is near-impossible if not impossible and thus impractical.

3. Name two ways that a robot can be scanned other than explicitly saying calling the scan() method.

Here are three other ways: 1) When your robot turns, assuming its gun and radar are not set to turn independently. 2) When your robot's gun turns, assuming its radar is not set to turn independently. 3) When your robot's radar turns.

4. When defining an equality relation, name at least two properties that must be upheld.

Here are four: 1) An object must equal itself. 2) An object must never equal null. 3) If two objects are equal, then their hash codes must be the same as well. 4) If object A equals B, and B equals C, then A must also equal C.

5. Given the following Ant code, what would you expect to happen? The default target is bubbles.


Ant prints out everything nice, then spice and finally sugar.

Friday, October 21, 2011

Alone we can do so little

An obligatory irrelevantly relative introduction spiel
If the pyramids were worked on by a single person, Tutankhamun's tomb would probably have a pretty big sunroof. Let's not argue over the details behind that statement or how King Tut existed after the age of pyramids and was buried in the Valley of Kings instead. The point being made is that the pyramids were built on the backs of a huge labor force working together to accomplish a single objective. Now if we can only apply this wonderful concept of collaboration to the world of software development, imagine all the virtual pyramids we could build together!

Let us collaborate...
Helen Keller once said, "Alone we can do so little; together we can do so much." The power of collaboration ought to be intuitively obvious to anyone. To illustrate, if we had 8 slices of pizza, it would be much faster for 4 people to eat 2 slices each as opposed to 1 person eating all 8 by themselves provided, of course, that each person eats at a relatively similar pace. Likewise, if a piece of software had to be developed, it seems obvious that if the work was divided amongst several developers, the overall efficiency of the development process would increase as well.

Pitfalls of working together
There are several downsides to group development of course:

1. The balance of work is not always fair. We've all been there before, a teacher assigns group work and you're forced to divvy up the work amongst the group members. But the day before the project is due, one of your group members have yet to even bother to communicate a single thought to the rest of you, not to mention put in any work effort. That's when you grit your teeth, shout some obscenities in your head and suck it up and do their work for them. By the way, if you have never gone through this before, you're the person that's slacking off.

2. Incompatibility of styles may exist. Sure, we can all pick up The Elements of Java Style, read it cover and cover and try to adhere to the standards at all cost. But there is always going to be a slip-up here or there. This really becomes a problem if you have a team member that's brilliant at coding but you can never figure out how their code works because it is simply unreadable and the documentation basically says, "trust me, it works."

3. Working concurrently is difficult. If the goal of a project was to serve a plate of faux-Chinese food to a hungry customer, a plausible solution would be to implement the Panda Express assembly line of food scooping. But when dealing with software development, working on a project sequentially becomes highly inefficient. Why must developer A wait for developer B to finish working on the Apple class of their Fruits project when he's in charge of handling the Orange class? But if they're each handed a copy of the Fruits project, it's entirely possible that the changes developer A makes to the Fruits project conflicts with with the changes developer B made.

Navigating the pitfalls
For dealing with the first two pitfalls, a large portion of the solution is communication. If there is an imbalance of duties, it really is up to every member to correct the situation. All too often you'll find that the person picking up the slack doesn't ever voice their dissatisfaction. Likewise, some of the solution to the second issue is to simply communicate and decide on a coding standard that will suit every project member involved. Then, as I've discussed previously, use a project builder like Ant! Using Ant in conjunction with automatic assurance tools like PMD or FindBugs and especially CheckStyle in this case will eliminate a big headache for any collaborative software development effort.

Enter SubVersion
Obviously, the problem of multiple developers working on a piece of software existed the very first time two programmers got together, modified the same piece of code, and realized they overwrote one another's alterations. If I had to guess, this probably took place a long time ago...

Not necessarily drawn to scale

But, I digress. With the advent of version control software, developers were able to successfully resolve the issue of concurrent development by requiring the source file to be checked out for revisions. While the source is checked out, no one else could make changes to it, but it made it possible for multiple developers to work on the same project without destroying one another's progress. However, the check-out system meant inefficient development, since a file could not be worked on simultaneously by another developer as long as it was checked out. The resolution was optimistic locking. Rather than actually locking the file from modifications and requiring that a file be checked in before it can be checked out again, a file could be "checked out" by any developer at any time and when they check the file back in and commit their changes, the changes are merged with other developers' changes. If a conflict arises, the developers can then work among themselves to resolve it. Subversion is one such version control system which utilizes optimistic locking and allows concurrent development.

Experiencing the multi-developer environment
To really grasp how useful Subversion can be, the best way is to experience it first hand. Downloading a project file from Google Project Hosting (which we will dive into a bit later) on which you are collaborating with 20+ people on is an interesting experience, to say the least. When I first downloaded the project just to get a feel for Subversion, I was able to immediately see the minor tweaks that my fellow developers had made previously. After settling on the revisions I wanted to make, I downloaded the latest project file again and, already, I saw additions to the project file that I weren't there just minutes ago. Conveniently enough for me, the changes did not interfere with the additions I had in mind, and I went ahead with my revisions, and committed the new file without a hitch. It was very interesting to see the updates being made in almost real time as multiple developers made their tweaks and committed their own changes. It was easy enough to simply download the project, make changes, and upload the changes but ultimately, the process had to be applicable to my own projects somehow! Subversion works by having contributors work from a central repository, but where could one host a repository that is easily accessible to all team members? One solution to this question came in the form of internet giant Google's own project hosting.

Hosting your very own software development project
Getting started with Google Project Hosting is simple, you just log in to your Google account, head over to the project hosting site and create a new project. To find out more, head over to their Getting Started wiki. Once again, I was able to host my very own project without too much problems. The only minor bump in the road for hosting my Robocode robot and officially opening the little guy up for open source development was creating the user and developer guide wikis. For those of you that are new to wiki editing like I was, there is a special wiki syntax by which you must abide by to quickly construct your wiki pages. Not all of the syntax is extremely intuitive, but a helpful guide does leave you with enough information to work out what you need to do to get your wiki looking how you want it to look. One interesting quirk about WikiSyntax is that words with multiple capitalization is automatically regarded as a link to another wiki page. Unfortunately, as it turns out, if you are hosting a Java project like I was, a lot of your references to your own project is regarded by the wiki as a link to a non-existent wiki page. This is a bit of a hassle, but ultimately, something that I could live with considering some of the other more useful features. For example, putting in a heading automatically generates an anchor to which you can then reference directly from a link. This was very helpful in creating a wiki with multiple headings and a Table of Contents that allowed the viewer to quickly jump to a specific heading. In fact, see it for yourself at my project home page.

Final thoughts
Not only is collaboration a good idea in software development, it is crucial to the success of larger projects. Albeit, I have thus far only barely scratched the surface of the potentials of hosting a project online and using version controlling systems to manage a collaborative project. But even with my brief swim in the vast ocean that is open source development, I can quickly already see the advantages to having a project hosted in a centrally accessible location and allowing multiple developers to access and modify the code concurrently. I'm hoping I was able to convey why I am so excited about the possibilities that these tools open up for me as a developer and that you, my faithful audience, will have some of the excitement rub off on you as well. After all, if you're reading this, you are likely interested in software engineering and if you're interested in software engineering, your proverbial mouths should be watering with anticipation of how you, too, can start collaborating with others right now!

Links to check out:
Apache Subversion
Getting started with your own Google Hosted Project
My Google Hosting Project Home Page

Tuesday, October 11, 2011

Coward: One who, in a perilous emergency, thinks with [its wheels] - Ambrose Bierce

A few weeks ago, I wrote about the marvelous little virtual minions that I created through the wonder that is Robocode. Now, one might have presumed that my robots were mere results of simple exercises no more exemplary of a battle worthy digital tank than a twig is of a shady oak tree. However, if one were to have thought that, then one would have failed to overlook that when thirteen twigs are combined, they would most definitely create something greater! Such as a branch perhaps?

To be certain, the general goal of this new endeavor was to create a robot that would compete among its peers in the virtual arenas in all of their 40 by 40 pixels of glory. In my efforts to accomplish this goal, I forged together a chimera of my previous iterations of single-function robots to create a single entity armed with the three basic principles of a Robocode robot: Movement, Targeting and Firing. Additionally, as any good robot knows, its primary edict in life is the Three Laws of Robotics. Now, if you will all recall from our previous discussion of the Three Laws of Robotics, the first two laws don't really factor much into Robocode robots. Thus, the ThirdRobotLaw robot was conceived, with its utmost priority being the protection of its own life.

ThirdRobotLaw, or TRL as I've come to know the little bugger as, was designed with a focus on survival. As such, it was determined that the strategy for its movement would be to minimize opportunities to be hit by its opponents. What this entails is that first we had to reduce the potential angles of attack by enemies. Hugging a wall, as it turns out, was an obvious choice since it immediately reduced a fourth of the cardinal directions from which bullets could come from. Upon the battle starting, TRL picks either the West or East wall to run towards in a true coward's fashion by determining which wall is closer. Upon reaching a wall, TRL changes to one of two modes depending on the number of enemies left on the battlefield. The first mode, if there are more than one enemies remaining is to randomly choose a direction between North and South and glide towards it at a random interval. The idea behind this mode is that if the enemy of TRL's enemy is the enemy of that other guy. TRL deviously hides along the wall and shuffles along at random and hopes that its enemies kill each other off. However, when the battlefield participants dwindle down to but one opponent, TRL will then adopt the only strategy available to a coward in that situation: eat or be eaten. At this point, TRL goes into turret mode and ceases to randomly glide around in a desperate effort to not die. It is also important to note that even in turret mode, if TRL is hit by bullets multiple times, it will try to glide away at random again in an effort to avoid bullets again. Conversely, if TRL is missing too often, it will try to move away from its current wall in an effort to get more aggressive.

Prior to reaching turret mode, TRL does not really engage in any sort of robot targetting. When it finally does begin to track enemies, there should only be one enemy left and thus, no real illusion of choice as far as who to prioritize. Using a modified version of the TrackFire sample robot's tracking mechanism, TRL sits in place and tracks the closest enemy. The closest enemy, in this case, also happens to be the only enemy.

When in turret mode, whenever TRL scans a robot and its guns are ready to fire, it will do so. However, based upon how far its enemy is, TRL will scaled back the bullet power in order to conserve energy since greater distances usually means a higher likelihood of missing. Yet, in order to compensate for robots who also act as stationary turrets, if TRL is able to connect on several consecutive shots, it was switch its guns to fire maximum power bullets under the assumption that either the other robot is stationary or our tracking is doing a decent enough job of keeping our gun lined up.

Here are the results of TRL's 1v1 attempts against the sample Robocode robots:

Vs. Walls: 0 wins, 10 losses (an absolute massacre)
Vs. RamFire: 0 wins, 10 losses (yet another massacre)
Vs. SpinBot: 1 win, 9 losses (slight improvement, but otherwise utter defeat)
Vs. Fire: 2 wins, 8 losses (still yet a bit better)
Vs. Crazy: 5 wins, 5 losses (two random robots producing 50/50 results)
Vs. Tracker: 7 wins, 3 losses (a bit more positive news)
Vs. Corners: 10 wins, 0 losses (unfortunately this was TRL's primary sparring partner)
Vs. SittingDuck: 10 wins, 0 losses (anything less here would be unacceptable)

On a whole, versus sample robots, TRL does not fare well in 1v1 situations, winning only 35 out of its 80 battles, 10 of which were against SittingDuck. While it would be most gratifying for me to report that in group battles, for which TRL was designed for, it performed admirably and conquered the field of battle by watching others die in front of its radar that was simply not the case. In fact, depending on the types of robots it faced in battle, it was often the first robot to die, especially when the other robot specialized in wall movements as well, forcing TRL to leave its sanctuary. The silver lining is that in the absence of these types of robots, TRL was rarely the first robot to die, and occasionally nabbed the first place in a round by virtues of janitorial prowess (i.e. finishing off the last enemy who has already no doubt sustained heavy damages). In retrospect, it might have been prudent for TRL's random wall sanctuary to include the North and South walls to avoid being pigeonholed by certain wall riding robots. Additionally, rather than turning its body to glide up and down, it may have been simpler and faster to simply make use of the back() functions available to all Robocode robots.

In testing TRL, I knew that its 1v1 prowess would be limited at best and so its acceptance tests consisted of generally weaker sample robots like SittingDuck and Corners. I also made the decision that I did not particularly care if TRL could beat non-SittingDuck opponents 100% of the time and that a better-than-half average was sufficient. In testing its movements, I made sure that its two primary controlled movements were implemented correctly. That is to say that TRL always necessarily arrived at either the East or West wall in each round without fail, and that against a stationary target, it too was stationary. Finally, I tested that TRL's bullet power was indeed scaling based upon its intended algorithm and that upon successfully hitting a target consecutively, it would then increase its bullet power to maximum.

If nothing else, this project has taught me one thing: an idea might sound good but until it manifests and is tested, there truly no way to know. Even in hindsight, I feel like the design of the strategy to evade at random until everyone else is dead is a sound one. Albeit there are kinks and unexpected behaviors that were unforeseen in the design of the robot, but overall the tactic still seems good, even if the execution in practice yields poor results. However, rather than focusing on the weaknesses and shortcomings of the robot, the most important thing that I took away from creating ThirdRobotLaw was actually the development process. From the Java coding standards to the automatic quality assurance tools, I learned more about the process than robocode development. It was simply nothing short of amazing how much more polished my project appeared in the end when I made use of Ant in conjunction with Checkstyle, PMD and FindBugs. Certainly, having more tools at my disposal as a developer now and having gained familiarity with how to take advantage of said tools, I would probably have approached this project a little differently. In particular, I would have been testing my robot along side JUnit from start to finish, making sure that each behavior was working as intended before moving on and tacking on more features. One of the biggest mistakes I made in this project is a mistake that often extends to students and possibly developers all over the world in that I started to write my robot as soon as I had a design in mind. I then proceeded to write big portions of functionality that intertwined with one another all at once rather than keeping them as separate modules which can then be tested on a per module basis as well. Ultimately, the failures led to a disappointing survival rate for a robot whose namesake is, in and of itself, an instruction for absolute survival. As a TRL's designer, I express my regrets here and now, and apologize to my loyal fans for TRL's many flaws. However, as a more seasoned Robocode developer now, I can promise you without a guilty conscience that version 2.0 of our robots will better than ever! Maybe by then it will be able to win 36 out of 80 rounds...