Pages

Wednesday, September 28, 2011

Apache Ant Code Katas: Learning A Build System In One Week

Introduction

Build systems are software packages which help software developers by automating project tasks that need to be done repeatedly, such as compiling source code, running compiled code, generating documentation, and packaging a system for distribution. All of these tasks do not take much time to do by hand for small projects, but for large academic or enterprise projects with hundreds or thousands of files, doing anything manually is virtually impossible. Apache Ant, a free build system commonly used in enterprise, carries out all of these tasks and more by using Java libraries to process instructions in user-created XML files. Users can extend Ant's functionality by writing their own libraries or by combining it with dependency-management tools like Ivy, which download whatever third-party libraries are needed to run a given piece of code, then save them locally. For this exercise, I completed several code katas designed to teach me some of the basic functionality of Ant 1.8.2. Each kata required me to create a specific filename.build.xml file, which would contain processing instructions for Ant.

Kata 1: "Hello World"

In the time-honored tradition of everything in computer science, I started here. The objective here was to teach use of the <echo> element to print informative text to the console. This did not take very long.

Kata 2: Properties Are Immutable

This kata was intended to teach procedures for defining properties, and to demonstrate that properties cannot be changed once defined within a build file. I defined a property, then attempted to define another property with the same name. As intended, this had no effect whatsoever, and the <target> which printed the property value printed the first value which was defined.

Kata 3: Dependencies

In Ant, the "depends" attribute of a <target> element specifies which targets must be completed before a target's instructions will be executed. This is used to make sure that any prerequisites for a target to run correctly (e.g., compiling code before trying to run it) can be carried out. This kata required us to print the name of the target as it was being executed, and I spent a few hours fruitlessly trying to print each target's "name" attribute before discovering that it might not be possible without Javascript workarounds. In the end, I defined properties with the same names and values as the targets they were defined within, and settled for <echo>ing those.

Kata 4: Calling the Java Compiler on HelloAnt

This exercise used a simple Java program which printed "Hello Ant" to the console. Here, within a "compile" target, I defined two properties: paths to a source directory (where the .java file was) and a build directory (where the .class files would be output to). I then used the <javac> element, which would tell Ant to run the javac compiler given the specified directories as parameters. This kata was still fairly easy. More importantly, running this script repeatedly was faster than having to specify the directories each time I ran javac from the command line.

Kata 5: Running HelloAnt

This exercise called for importing the .xml file from Kata 4 and using its "compile" target to compile the system before running it. As it turned out, defining the directory paths in Kata 4 meant I could easily reuse them here, as importing a file also imports all of its defined properties. Using the same principles outlined by the Dependencies kata, I made the "run" target dependent on "compile". The hardest part of this was guessing at how to write the <java> element's "classname" attribute for java files in a package, which I couldn't find an example of in the Apache documentation. At first, I tried to treat the class name as a series of nested folders (/edu/hawaii/ics314/filename.extension), which is how it appears in the file system. After several variations on this, I learned that ant requires that the classname be written using its Java format (edu.hawaii.ics314.filename, no file extension).

Kata 6: Making Documentation for HelloAnt

This kata demonstrated the use of the <javadoc> element, within a target that was dependent on the <compile> target, which was imported. This ensured that the Javadoc files would only be generated if the source code actually compiled. The <javadoc> element also allows you to control what information is included in the javadoc by setting attributes such as "author" or "overview" to "true". Generating documentation manually is always tedious, and the attribute options are less tedious to use than typing each option individually (every time you needed to revise the documentation) and running Javadoc from the command line.

Kata 7: Cleaning the Software Package

This exercise required me to modify the .xml file from Kata 4 to add a target which deleted the "build" directory generated by the "compile" target. This was intended to teach the use of the <delete> element, which instructs Ant to delete the directory specified in the "dir" attribute.

Kata 8: Package HelloAnt for Distribution

I had a recurring problem when I first tried to implement this kata: as required, it would delete the build directory, but it would mysteriously include the build directory in the .zip file it created for distribution. Eventually, I realized that because I had to create the build directory again to store the .zip file in build/dist, it was always saving the empty build directory into the .zip file. I fixed this problem by modifying some code from a class example to first save the .zip file to a temporary directory, copy it over to the desired directory, then delete the temporary directory. The main lesson here was to use the "excludes" attribute to exclude the build directory from the distribution. Regardless, manually excluding unnecessary files before creating the distribution directory would have been an annoyance for a small project like HelloAnt, but impossible for any enterprise project of moderate size.

The second requirement was to make sure that unzipping the directory from the command line would preserve the original directory structure. This was simpler and involved creating a directory with the same name as the current directory within the distribution directory. Removing the build files from the distribution not only reduces its file size, but makes sense in light of Prime Directive 2: forcing other developers or users to build the system using the build files you've provided is a good way to verify that others can install and use your system.

Ant / Ivy and the Three Prime Directives

As free software packages which work together, Ant and Ivy are fairly easy to install as long as one follows the site instructions (Prime Directive 2), and automating otherwise tedious tasks easily fulfills a useful task (Prime Directive 1). While I can't say that I have personally tried to extend the system, I was able to complete most of the katas without going outside Apache's documentation, which does go some of the way towards fulfilling the third prime directive as well. It is also worth noting that despite my initial problems on some of the later katas, all of the tasks I was trying to instruct Ant to perform would have taken just as long, if not longer, if they had to be performed by hand and/or directly from the command line over and over again. Build systems may take time to learn, but a little time invested up front here will always save more time in the end.

Final Thoughts

Though I wouldn't claim to understand everything about Ant at this point, the code katas did force me to learn enough to understand its basic capabilities and encourage me to look further into its other features. The extensive use of custom XML markup for interpretation by Ant and Ivy's Java libraries demonstrates to me that XML, as a user-defined markup language, is as useful as a developer wants it to be. Learning new software tools or APIs quickly is always a little like jumping into a pool; code katas won't get you into the deep end right away, but they can teach you enough to slowly move into deeper water and not drown.

Tuesday, September 20, 2011

The Robocode API: Rapid Learning With "Code Katas"

Introduction

Learning and practicing new computer skills (a programming language, an IDE, an operating system, etc.) is a task that is often frustrating at best and intimidating at worst, especially when one is having trouble learning the system at its most basic levels. The philosophy of code katas, a form of practice with a name borrowed from Japanese martial arts, seeks to break the learning process down into a series of repeated drills, each one slightly more complex than the last. As the developer completes each drill, he or she gains essential skills along the way. This kind of "effortful practice" produces results faster than unfocused practice because it is focused around specific tasks, ideally just beyond one's current level of competence.


With this in mind, I set out to complete thirteen code katas for the Robocode API:
  1. Position01: The minimal robot. Does absolutely nothing at all.
  2. Position02: Move forward a total of 100 pixels per turn. When you hit a wall, reverse direction.
  3. Position03: Each turn, move forward a total of N pixels per turn, then turn right. N is initialized to 15, and increases by 15 per turn.
  4. Position04: Move to the center of the playing field, spin around in a circle, and stop.
  5. Position05: Move to the upper right corner. Then move to the lower left corner. Then move to the upper left corner. Then move to the lower right corner.
  6. Position06: Move to the center, then move in a circle with a radius of approximately 100 pixels, ending up where you started.
  7. Follow01: Pick one enemy and follow them.
  8. Follow02: Pick one enemy and follow them, but stop if your robot gets within 50 pixels of them.
  9. Follow03: Each turn, Find the closest enemy, and move in the opposite direction by 100 pixels, then stop.
  10. Boom01: Sit still. Rotate gun. When it is pointing at an enemy, fire.
  11. Boom02: Sit still. Pick one enemy. Only fire your gun when it is pointing at the chosen enemy.
  12. Boom03: Sit still. Rotate gun. When it is pointing at an enemy, use bullet power proportional to the distance of the enemy from you. The farther away the enemy, the less power your bullet should use (since far targets increase the odds that the bullet will miss).
  13. Boom04: Sit still. Pick one enemy and attempt to track it with your gun. In other words, try to have your gun always pointing at that enemy. Don't fire (you don't want to kill it).

The Robocode project, once managed by IBM and now an open-source, community-driven effort, provides a way to program armed virtual robots and pit them against each other. Robocode robots are controlled by programming three types of behavior: movement, radar scanning, and firing. Though the core concepts are simple, the API is versatile enough that in the hands of experienced developers, Robocode battles can become a serious business indeed.

Look at this genetic algorithm, now look back at mine. Sadly, my code lacks complex algorithms. But the idea behind the code katas is that, with practice, that code is what my code could look like. Each group of katas emphasized a specific skill, whether finding specific points on a map, circling a particular area, tracking and picking targets from among multiple enemies, or controlling the power of the robot's shots based on information acquired about enemy robots.

The first three position methods were easy to implement. The fourth took a little more work, but finding the center was fairly easy after writing methods to calculate the angle between the robot and the center, and the distance of the straightest path to the center, and the sixth was just a variation of the fourth. The fifth method was the hardest of the group for me, and it took a while before I realized that it was returning the wrong angles because the robot was not accounting for its own previous turning when calculating the turn angle. I made heavy use of the Math.atan2 method here, as it was easy to retrieve the x- and y-distances between two points for use in calculating the angle.

The Follow robots were easier to write, since most of the data needed to match the headings of enemy robots could be obtained from pre-made methods, especially the method which retrieves a scanned robot's name for easy tracking. Follow03 was easily implemented by causing the robot to scan continuously for enemies, store their data, and compare the results after each scan.

Most of the Boom robots were also quickly written; Boom01 and 03 only needed to fire automatically. Boom02 was also easily handled using the getName() function. I am still not sure whether or not I implemented Boom04 correctly; it lost its "lock" on the target frequently,
and occasionally aimed in the opposite direction of its target's motion. The problem was probably related to correcting for differences between the gun angle and the robot's heading, something I did not quite get the hang of; since each exercise in a group was based on previous ones, Boom05 could be the exercise where sloppily designed but still previously workable methods finally became unusable.

Overall, the "code katas" were easy ways to pick up basic programming skills, and even some of the errors along the way pointed the way to competitive strategies I might be able to use in the future.