Wednesday, December 14, 2011

Hale Aloha CLI version 2.0

Team project page: http://code.google.com/p/hale-aloha-cli-tiger/

It was not long ago since our review of "tiger" team's code base when we were invited to join the team and add some new enhancements:

set-baseline [tower | lounge] [date]
This command defines [date] as the "baseline" day for [tower | lounge].  [date] is an optional argument in YYYY-MM-DD format and defaults to yesterday.  When this command is executed, the system should obtain and save the amount of energy used during each of the 24 hours of that day for the given tower or lounge.  These 24 values define the baseline power for that tower or lounge for that one hour time interval.  For example, if lounge Ilima-A used 100 kWh of energy during the hour 6am-7am, then the baseline power during the interval 6am - 7am for Ilima-A is 100 kW.

monitor-power [tower | lounge] [interval]
This command prints out a timestamp and the current power for [tower | lounge] every [interval] seconds.  [interval] is an optional integer greater than 0 and defaults to 10 seconds. Entering any character (such as a carriage return) stops this monitoring process and returns the user to the command loop.

monitor-goal [tower | lounge] goal [interval]
This command prints out a timestamp, the current power being consumed by the [tower | lounge], and whether or not the lounge is meeting its power conservation goal.   [goal] is an integer between 1 and 99.  It defines the percentage reduction from the baseline for this [tower | lounge] at this point in time.  [interval] is an integer greater than 0, and defaults to 10 seconds.
For example, assume the user has previously defined the baseline power for  Ilima-A as 100 kW for the time interval between 6am and 7am, and the current time is 6:30am.   If the goal is set as 5, then Ilima-A's current power must be 5% less than its baseline in order to make the goal.  At the current time, that means that Ilima-A should be using less than 95 kW of power in order to make its goal.
It is an error if the monitor-goal command is invoked without a prior set-baseline command for that [tower | lounge].  Entering any character (such as a carriage return) stops this monitoring process and returns the user to the command loop.

From these specifications, we identified two technical areas which needed to be implemented to support these commands:
1. Persistent storage and retrieval of baseline data for set-baseline and monitor-goal
2. Timer-based monitor loop for both monitor-power and monitor-goal
I decided to tackle #1, while Ted decided to tackle #2.  Ted implemented the monitor loop with a Timer.  Our design for persistent storage across command executions is to store the baseline data in XML files, each named in the pattern "[tower | lounge].xml".  To support modular design, I decided to create a separate class to hold the baseline data as well as the XML file storage, parsing, and retrieval.  See the file, Baseline.java, for implementation detail.  The XML file handling codes were based off of this tutorial: http://totheriver.com/learn/xml/xmltutorial.html

Another technical challenge we encountered was the need to simulate user interactions in automated JUnit tests.  We accomplished this by using connected pipes (PipedInputStream and PipedOutputStream) and System.setIn() to re-route the System.in stream.  The test codes is then set to execute on a separate thread by wrapping it in a FutureTask object.  Interactive user interactions are then simulated with timed writes to the pipe.  See TestMonitorPower.java for a sample implementation.  This approach was suggested in this message thread: http://www.codeguru.com/forum/showthread.php?t=453798

With these new testing methods, we were able to increase test code coverage from the initial ~30% to 70% coverage.  Yet, the possibility for automated code testing that it open is now quite endless!

Friday, December 2, 2011

Hale Aloha CLI Technical Review for the Tiger team



Today, we are conducting a peer technical review, taking on three different perspectives:
User's perspective: Does the system accomplish a useful task?
Installer's perspective: Can an external user successfully install and use the system?
Developer's perspective: Can an external developer successfully understand and enhance the system?

First, it should be understood that all software projects are never completed.  Rather, they are continuously being enhanced and enriched.  Thus, the issues pointed out here are relevant only up to revision 67 of the project.

User's Perspective:
$ java -jar build/jar/hale-aloha-cli-tiger.jar
Successfully connected to the Hale Aloha Wattdepot Server
> current-power Ilima-A
Current power for Ilima-A as of 2011-12-02 06:49:59 is 3.91 kilowatts.
> daily-energy Mokihana 2011-11-05
Date must be before today.
> daily-energy Mokihana 2011-12-01
2011-12-01T00:00:00.000-10:00
2011-12-01T23:59:59.999-10:00
Mokihana's energy consumption for 2011-12-01 was: 659 kWh.
> daily-energy Mokihana 2011-11-01
Exception in thread "main" org.wattdepot.client.BadXmlException: 400: Range extends beyond sensor data, startTime 2011-11-01T00:00:00.000-10:00, endTime 2011-11-01T23:59:59.999-10:00: Request: GET http://server.wattdepot.org:8190/wattdepot/sources/Mokihana/energy/?startTime=2011-11-01T00:00:00.000-10:00&endTime=2011-11-01T23:59:59.999-10:00
at org.wattdepot.client.WattDepotClient.getEnergy(WattDepotClient.java:762)
at org.wattdepot.client.WattDepotClient.getEnergyValue(WattDepotClient.java:810)
at org.wattdepot.client.WattDepotClient.getEnergyConsumed(WattDepotClient.java:857)
at edu.hawaii.halealohacli.command.DailyEnergy.run(DailyEnergy.java:85)
at edu.hawaii.halealohacli.processor.CommandProcessor.chooseModule(CommandProcessor.java:45)
at edu.hawaii.halealohacli.processor.CommandProcessor.run(CommandProcessor.java:71)
at edu.hawaii.halealohacli.Main.main(Main.java:38)
> energy-since Lehua-E 2011-11-01
org.wattdepot.client.BadXmlException: 400: Range extends beyond sensor data, startTime 2011-11-01T00:00:00.000-10:00, endTime 2011-12-02T06:57:14.561-10:00: Request: GET http://server.wattdepot.org:8190/wattdepot/sources/Lehua-E/energy/?startTime=2011-11-01T00:00:00-10:00&endTime=2011-12-02T06:57:14.561-10:00
at org.wattdepot.client.WattDepotClient.getEnergy(WattDepotClient.java:762)
at org.wattdepot.client.WattDepotClient.getEnergyValue(WattDepotClient.java:810)
at org.wattdepot.client.WattDepotClient.getEnergyConsumed(WattDepotClient.java:857)
at edu.hawaii.halealohacli.command.EnergySince.getEnergyConsumed(EnergySince.java:100)
at edu.hawaii.halealohacli.command.EnergySince.run(EnergySince.java:72)
at edu.hawaii.halealohacli.processor.CommandProcessor.chooseModule(CommandProcessor.java:49)
at edu.hawaii.halealohacli.processor.CommandProcessor.run(CommandProcessor.java:71)
at edu.hawaii.halealohacli.Main.main(Main.java:38)
Total energy consumption by Lehua-E from 2011-11-01 00:00:00 to 2011-12-02 06:57:14 is: 0.0 kWh.
> energy-since Lehua-E 2011-12-01
Total energy consumption by Lehua-E from 2011-12-01 00:00:00 to 2011-12-02 06:57:14 is: 158.4 kWh.
> rank-towers 2011-11-01 2011-11-09
Date must be before today.
> rank-towers 2011-11-01 2011-12-01
Exception in thread "main" org.wattdepot.client.BadXmlException: 400: Range extends beyond sensor data, startTime 2011-11-01T00:00:00.000-10:00, endTime 2011-12-01T23:59:59.999-10:00: Request: GET http://server.wattdepot.org:8190/wattdepot/sources/Ilima/energy/?startTime=2011-11-01T00:00:00.000-10:00&endTime=2011-12-01T23:59:59.999-10:00
at org.wattdepot.client.WattDepotClient.getEnergy(WattDepotClient.java:762)
at org.wattdepot.client.WattDepotClient.getEnergyValue(WattDepotClient.java:810)
at org.wattdepot.client.WattDepotClient.getEnergyConsumed(WattDepotClient.java:857)
at edu.hawaii.halealohacli.command.RankTowers.run(RankTowers.java:106)
at edu.hawaii.halealohacli.processor.CommandProcessor.chooseModule(CommandProcessor.java:53)
at edu.hawaii.halealohacli.processor.CommandProcessor.run(CommandProcessor.java:71)
at edu.hawaii.halealohacli.Main.main(Main.java:38)
> rank-towers 2011-11-23 2011-12-01
For the interval 2011-11-23 to 2011-12-01, energy consumption by tower was:
Mokihana 5289 kWh
Lehua 5290 kWh
Ilima 5426 kWh
Lokelani 6219 kWh
> quit
From the user's point of view (see sample executions above) the program could use a bit of polishing on its command handling and error reporting.  For example, the command "current-power" works correctly, while the other three commands, "daily-energy", "energy-since", and "rank-towers", suffers from date handling problems.  Computational-wise, they worked correctly.  However, the date handler code suffers from a "single-month view" problem for date comparison, and couldn't handle out-of-range date gracefully.

Installer's Perspective:
From the installer's perspective, the project site has the basic description and user's guide needed to successfully install the system.  However, the user's guide could include more usage description rather than depending on the user to discover the "help" command within the program's execution.  The download page contains a copy of the project for distribution, with the correct version number and release date.  The distribution contains a ready-made "hale-aloha-cli-tiger.jar" file that can directly be used without a compile and build system.  From the installer's perspective, the system was well-described and packaged.  Again, based on the sample executions given above, the system can be improved in its date and error handling.

Developer's Perspective:
From the developer's perspective, the most useful starting point is the Developer's Guide.  The guide fully covers the command-line based approach to automated testing and build, and provide a succinct set of guidelines with regard to new improvement development.  It does not, however, enforce any project management process.  It does, however, covers JavaDoc and Continuous Integration using Jenkins CI server.

Next, we take a look at the source code.  From the source code, the JavaDoc documentation is generated, from which the system's design can be examined.  The documentation is well written, and the system was designed well to support information hiding.  However, we also notice that this particular design does not implement a CommandManager class, as suggested in the design specification.

With the Ant build system, it is easy to run the included tests and gain insight into its coverage.  It should be noted here that two of the four commands are not tested by default: "energy-since" and "rank-towers".  This is due to the fact that the developers named the JUnit tests incorrectly, and thus the tests are never invoked by junit.build.xml.  This mistakes led to the poor total coverage of only 21%.  Furthermore, the JUnit tests only exercises the "isValid()" command, while the main "run()" routine is never exercised in the tests.  The testing part of this project can substantially be improved.

The source code is properly documented and easy to understand.  However, it seems requirement capture was not rigorously exercised.  The suggested modular design in the specification is not followed, and the commands are glued together in a very inefficient manner: requiring re-instantiation of every modules for each user input.

Next, we examine the team participation.  Having prior knowledge that the team is following the "Issue-Driven Project Management" process, each members' contribution can be easily traced on the project's Issues page.  There are two incomplete issues: "Issue 36: Improve JUnit Tests" and "Issue 19: Provide error checking in Command Processor."  Thus, the developers are aware that their JUnit tests are incomprehensive.  The issues page suggest approximately equal distribution of contributions.

The Continuous Integration page for this project also tells a part of the development story.  The project is consistently worked on, and problems are promptly corrected.  It appears there was a major issue with their build system from build #13 to #35, during which they struggled over two days trying to find and correct the cause.  About 8 out of 10 commits were associated with an appropriate issue.

As a potential external developer, I can see many areas that can be improved upon.  The build system seems to have been a major stumbling block, thus one should examine it and make it rock solid prior to starting the actual code development.  Further, because some design specifications were not followed (i.e. modular design) new enhancements needs to change parts of the original code-base to be incorporated.  Furthermore, with the inefficient instantiation, one might have to replace the Main glue codes completely.

It is understandable that "requirement capture" was not strictly stressed in the "Issue-Driven" development approach.  But it surfaces eventually as a major issue in the validation process.  Remember, design the system before you implement it!