Pages

Tuesday, November 29, 2011

Putting It All Together: Software Tools and Issue-Driven Project Management

In this semester, I have been completing various skill-learning exercises called "katas" to quickly learn the basics of some software tools designed to make Java development easier, faster, and more error-free. Likewise, through my own struggles, successes, and failures, I have learned that these tools are only as good as the people who use them. Ultimately, any organization is only as good as its people, and no class on software engineering would be complete without at least one project that needed to be organized through a project team.

Over the last two weeks, I have been working with Christopher Foo and Eldon Visitacion to design a console application using the WattDepot API. Throughout the duration of the project, in addition to the Subversion, Ant, Eclipse, and JUnit tools discussed in past entries, we began using a class Jenkins server as a continuous integration tool. Configuring Jenkins to automatically build and test the project after each repository change helped us to pinpoint which Subversion commits introduced faulty code into the system and which developers were responsible, making us more careful about verifying our code in the first place. We used Google Project Hosting to manage our repository and a small wiki.

Our work and school schedules prevented us from meeting in person very often, so we designated issues and set intermediate deadlines mostly through email. Each group member was responsible for posting and closing their own issues and notifying the member assigned to a certain part of the project of any bugs they found while examining or testing each others' code, and all group members were responsible for testing the final .jar executable.

The Hale Aloha CLI

The console application's purpose was to retrieve data from the WattDepot server for the University of Hawaii at Manoa's Hale Aloha freshman residential complex, consisting of four towers where energy consumption and power data were being logged for the Kukui Cup. It needed to display the current levels of power being used, the amount of energy consumed on a given day, the energy consumed since a given day, and the rankings in energy consumption of the four towers from a given start date to a given end date.

The Command Line Interface

Command-line interface.
The command-line interface was designed by Christopher Foo. The Control class passes commands to the CommandProcessor class, which stores a TreeMap of classes which implement the Command interface. The Command interface specifies two methods. The first is an execute method, which constructs the object that carries out the command, initializes its fields, and prints the data retrieved from the server as a string. The second is a getHelpString method, which prints the correct syntax to use the command if the command "help" is issued. Typing "quit" exits the program. The available commands can be extended by adding the new Command-implementing class to the TreeMap.

Our team's implementation does not use Java's Reflect class.

Current Power

>current-power [tower | lounge]
current-power
The Current Power command was designed by Eldon Visitacion. It retrieves the newest available power consumption data recorded by a tower or lounge source's sensor on the current day. Data is in kilowatts.

Daily Energy

>daily-energy [tower | lounge] [date]
energy-since
The Daily Energy command was designed by Eldon Visitacion. It retrieves the newest available total energy consumption recorded by a tower or lounge source's sensor on a given date, in yyyy-mm-dd format. Data is in kilowatt-hours.

Energy Since

>energy-since [tower | lounge] [date]
energy-since
The Energy Since command was designed by me. It retrieves the total energy consumed by a tower or lounge source on a given date, in yyyy-mm-dd format. Data is in kilowatt-hours.

Rank Towers

>rank-towers [start] [end]
rank-towers
The Rank Towers command was designed by me. It retrieves the total energy consumed by each of the four Hale Aloha towers from a given start date to a given end date, both in yyyy-mm-dd format. Data is in kilowatt-hours.

JUnit Tests

JUnit tests were incorporated into our system fairly early on. The first draft tests for EnergySince were running by November 12 (continuous integration build 15). The first tests for Control, CommandProcessor, and Quit were posted by November 15 (build 25). CurrentPower and DailyEnergy tests first appear on November 16 (build 27), a test for Help was posted on November 17 (build 38), and the first version of TestRankTowers was also committed on November 17 (build 39). JUnit tests had mostly reached their final states by Build 54 on November 24, and the system stayed at a consistent level of at least eighty percent instruction coverage afterwards.

Since parts of our command implementations were dependent on the time reported by the server, there were some pieces of my code - mostly those that converted time information to strings or to some other format based on the current date - which could not be tested. Despite this, I was able to test most of the methods used in my classes, especially the utility methods responsible for creating the XMLGregorianTimestamp objects used to retrieve energy consumption data. As I had chosen to make all of my setter and utility methods private, I had to learn to use Java's Reflect class to invoke them in tests. Oracle's tutorial and Lasse Koskela's exception testing examples were very useful here.

Another odd problem I had was using Reflection to invoke a method with a parameter that was a non-primitive-type array. If the parameter is just declared as foo[].class, Java interprets it as a varargs parameter instead of an array. In this case, I was trying to test the setter method for an array of XMLGregorianCalendar timestamps.

The correct way to do this, described at Your Mitra here, is to declare the array as a new class which contains the array:

Method testSetEnd = testClass.getDeclaredMethod("setEndTimestamps", new
Class[]{XMLGregorianCalendar[].class});

Then, in the method invocation, the array being passed as a parameter needs to be cast to a new class as well:

XMLGregorianCalendar sampleTimestamp =
Tstamp.makeTimestamp("2011-11-11T11:11:11.111-11:00");
XMLGregorianCalendar[] holdTimestamps = new XMLGregorianCalendar[]{sampleTimestamp,
sampleTimestamp};
// Cast the array to an object, otherwise it will be treated as varargs.
testSetEnd.invoke(testObject, new Object[]{holdTimestamps});

The large number of date-processing utility methods in my classes made it difficult to test all possible branches of the code, especially those which executed based on times retrieved from the WattDepot server. We also did not implement tests for the main method in the Control package, which we tested manually. JUnit’s policy of factoring in what percentage of test case code was executed greatly decreased the branch coverage score: the test which branched based on the time returned from the server executed only a few of their branches in the average unit testing. In the end, we achieved roughly 85% instruction coverage and 80% branch coverage.

Our software system is thoroughly documented and contains input-checking code that ensures that the right number of command-line arguments are given, dates do not overlap with each other or exceed the current date, and that source names match with an existing source's name, and most or all of these input checks are intentionally triggered in each class's Junit tests by passing bad input to the each Command's execute method. In addition, all of the Commands which take date parameters are capable of collecting data for the current day up to the most recent data reading from the requested source. Though it has its flaws, I consider it to be fairly high-quality in its error checking, operation, and test case coverage.


Server Issues

Though it had been difficult and at times annoying to get used to continuous integration practices, it was harder to coordinate system changes when the Jenkins server briefly crashed, or when it began automatically failing builds when the WattDepot server crashed and our Junit tests failed automatically after being unable to establish server connections. As the cliche goes, "You don't know what you got till it's gone." For all the annoyance of having a Jenkins build fail over some minor formatting error, it was still preferable to having that error remain in the code because the committer forgot to verify it beforehand.

In the end, Jenkins forced me to adopt better development practices by encouraging me to obsessively run Checkstyle, PMD, FindBugs, and JUnit tests - both in order to commit workable code, and to avoid having my usually careless errors broadcast to my team members. This makes continuous integration an effective tool for pinpointing which committers are responsible for errors and encouraging better practices (though maybe not quite as effective as a foam rocket to the head).


Debugging A Time Problem

The other server-related issue I experienced was in retrieving energy consumption data from the server at midnight. The WattDepotClient.getEnergyConsumed method retrieves data given a source name, two XMLGregorianCalendar objects representing the start and end times for data collection, and an integer representing the sampling interval in minutes. The original versions of my code had the interval set to 15 minutes (or 96 data points per 24-hour period). I noticed that JUnit tests would always fail mysteriously for current-day data requests made within about twenty minutes of midnight, throwing BadXMLExceptions which stated that my time range requested data beyond the available range of data on the server. Since my ending time was always based on the timestamp of each source's most recent sensor data on the server, my start time was hard-coded to midnight of the starting day, and I was in the same time zone as the server, I knew I was not experiencing synchronization issues between local time and the server. Further testing on November 24 revealed that the problem disappeared at about 12:17 AM, which was suspiciously close to my sampling interval. When I reported my problem to the class mailing list, Professor Johnson confirmed that the bug was the result of my sampling interval exceeding the range of available data. The solution was to set the sampling interval to 0 minutes, which allowed it to make data requests even when the starting time and the ending time were exactly the same.


Conclusion

Learning about the proper use of the tools of automated quality assurance and continuous integration has helped me reduce the number of syntactical errors I make in the first place, while making sure that most of my worst development mistakes are eliminated by automated quality assurance before entering the repository. Having team members with whom communication was easy made it faster and less confrontational to diagnose issues and suggest solutions, and enabled our group to proceed at a steady rate. Incorporating unit testing into our builds early on helped us get test coverage up to a reasonably high level by the end of the project, even if it was not possible to test some parts of the code. Ultimately, the combination of good time management and industry-standard quality-assurance tools helped us work around server crashes, data-request bugs, and test coverage problems and see the project to its completion. A good team can compensate for occasionally dysfunctional technology, but even good technology usually cannot save a project from a truly dysfunctional team.

Tuesday, November 8, 2011

The WattDepot Katas Project: Thoughts on an Open Source API

This week, I worked on a series of code katas for the WattDepot API, an open-source interface used to retrieve data on daily power and energy generation and use from remote sensors. The WattDepot API is intended to give users the tools to process technical, obtuse, automatically generated energy data and put it into a form that means something to the people who will use it.

I was able to complete the first Kata, SourceListing, in one or two hours; it asked for an alphabetical listing of all the Sources on the WattDepot server and their descriptions. Most of the code for this can be attributed to the SimpleApplication.java example program included in the distribution, as a Source object includes a name and a description.

The second Kata, SourceLatency, which required a program that calculated latency for each Source and printed the sources in ascending order based on latency, took two days. I had somehow managed to finish ICS 211 without learning how to use Hashtable, or else I had just forgotten that it existed. As a result, I spend the next two days trying to figure out how to sort one array according to the ordering of another array, without any success whatsoever. The solution I eventually found, and the way in which I found it, demonstrate why it is better to work on complex projects in groups. The reason I finally gave up on my insane attempt to sort two arrays simultaneously was because one of my classmates suggested during peer-programming exercises that I use a Hashtable. It turned out that a Hashtable with array-list values to store Sources with the same latency values worked just fine using the latencies as keys. As in some of my other projects, I have found that solving programming problems is a strange mix of happiness that something works, and frustration that it took me several sleep-deprived hours to figure out a simple mistake.

The third Kata, SourceHierarchy, required a program which printed Sources and their SubSources with increasing indentation for each level of sub-source. This kata also took two days, mostly because I sought clarification on how to parse the SubSources. The major issue I had at first, which turned out to be a non-issue when I figured out the actual format of the assignment, was that the SubSources returned by Source.getSubSources are not a recursive data structure (that is, a SubSource does not contain the Source data for its SubSources, only their URIs), and it was not possible to construct the hierarchy recursively. The trick, as Professor Johnson said, was to make a single pass through the list to figure out which sources were SubSources, and then use that to create the hierarchy. The solution I eventually implemented parsed the URIs to retrieve the SubSource names and did not print any Source which was listed as another source's SubSource.

The fourth Kata, EnergyYesterday, required a program which totaled up the energy used by each source on the previous day and printed each Source and its energy use in ascending order by energy use. This was similar in design to SourceLatency; in both cases, I used Hashtables to store Lists of Sources with identical energy or latency values, using the energy or latency values as the keys to retrieve them, then iterating through the lists and printing each Source with its associated key. Once I had fixed my SourceLatency issues, it did not take much editing to create EnergyYesterday; the main additional problem was the simple task of creating a timestamp which was rolled back by one day.

The fifth Kata, HighestRecordedPowerYesterday, required a program to print the highest recorded power for each source for the previous day, sorted in ascending order. It took up almost all of Monday, and several hours of Tuesday morning; this blog entry is being written at 6:00 AM on Tuesday morning, November 8, and the last kata still isn't finished. I had to write several utility methods for this class, mostly to generate the timestamps for power data requests and to parse the timestamps back into AM/PM format. The kata appears to be working correctly, except for one thing: I was never able to figure out whether it was a bug, or just a reflection of college study habits, but the peak power measured for every single sensor was at 12:00 AM midnight:

// My output for Kata 5 is reproduced below:
Connected successfully to: http://server.wattdepot.org:8190/wattdepot/
Server: http://server.wattdepot.org:8190/wattdepot/

Source              Highest recorded power in watts ( 07-Nov-2011 )
Lokelani-12-telco   1,203  12:00am
Lehua-10-telco      1,263  12:00am
Mokihana-08-telco   1,390  12:00am
Mokihana-04-telco   1,612  12:00am
Ilima-12-telco      1,818  12:00am
Lehua-04-telco      1,868  12:00am
Ilima-10-telco      2,227  12:00am
Lokelani-04-telco   2,432  12:00am
Mokihana-10-telco   2,662  12:00am
Lokelani-06-telco   2,890  12:00am
Ilima-08-telco      3,276  12:00am
Ilima-08-lounge     4,036  12:00am
Lokelani-10-lounge  4,204  12:00am
Ilima-10-lounge     4,285  12:00am
Lokelani-06-lounge  4,667  12:00am
Ilima-06-lounge     5,208  12:00am
Ilima-A             5,237  12:00am
Lokelani-04-lounge  5,458  12:00am
Mokihana-12-lounge  5,665  12:00am
Lokelani-D          5,845  12:00am
Mokihana-A          5,862  12:00am
Lehua-08-lounge     6,233  12:00am
Ilima-D             6,512  12:00am
Mokihana-10-lounge  6,612  12:00am
Mokihana-C          6,877  12:00am
Lehua-B             7,258  12:00am
Mokihana-E          7,484  12:00am
Lehua-C             7,760  12:00am
Ilima-B             8,022  12:00am
Lokelani-08-lounge  9,564  12:00am
Ilima               33,961  12:00am
Mokihana            35,322  12:00am

The sixth kata, MondayAverageEnergy, required me to write out the average energy consumed by a Source over the previous two Mondays. It is probable that I did not finish this kata in the hours remaining before the deadline. The main problem is in figuring out if today is Monday, then subtracting the number of days since the last Monday (to generate the first data set), then rolling back the date seven days to the previous Monday (to generate the second data set), and if I had had more time I would most likely have been able to reuse some of the code from EnergyYesterday to do this. I would have to put most of the blame for my poor scheduling on the two days of time I used to try to sort two arrays simultaneously for the second and fourth katas.

Though I may have frequently been frustrated with my own lack of knowledge or the difficulties of certain parts of the assignment, the WattDepot katas generally served as another example of how code katas can force developers to learn about a language or API's capabilities very quickly. Parsing WattDepot energy data into human-readable form is mostly a matter of timestamp generation, sorting among multiple sets of data elements, and parsing strings, and I was forced to learn new capabilities of the Java language and the WattDepot API for all of these tasks. The difficulties of making energy conservation relevant to consumers and enterprise users begin with putting information about their energy use into a form they can understand, and the WattDepot API provides a flexible platform for this purpose.

Tuesday, November 1, 2011

Hawaii's Alternative Energy Future

The marketing image of Hawaii as a carefree, distant paradise masks the higher cost of living and vulnerability to supply disruptions that such distance brings. My home state in the middle of the ocean has no locally available fossil fuels and little alternative energy generation. As a result, it generates 89.8 percent of its power by importing oil - 75% of it from foreign countries - at a cost of $7 billion per year. As a result, Hawaii pays twice the U.S. average for electricity. The costs don't stop there: ever-rising gas prices are passed on to consumers directly at the pump and indirectly at the store, a result of having to import most food and other goods by plane or container ship.

Recognizing the difficulties ahead, Hawaii's state government passed the Hawaii Clean Energy Initiative, a set of clean energy goals for providing 70% of Hawaii's energy from renewable sources by 2030: 30% by increasing energy efficiency, and 40% from increased use of renewable energy. The plan asserts that Hawaii's temperate climate, wind conditions, large coastline, and geological activity allow its islands to take greater advantage of geothermal, wind, solar, and other alternative energy sources than other parts of the United States. It also acknowledges that the plan depends on public support for its policy goals and public participation in efforts to reduce personal energy use.

One of the challenges of the HCEI is the integration of new types of power generation, such as wind and solar, which do not generate power as consistently as fossil fuel power plants. Since wind speed and sunlight should vary based on weather patterns, it is necessary to collect enough data to determine what those patterns are, limit electricity usage when less power is available, and alert customers when excess power is available - in effect, to create a "smart grid" of sensors to collect information about power generation and use. As explored in a Maui residential testbed by the Hawaii Natural Energy Institute, the smart grid would rely on a network of gauges which communicate wirelessly with a central "smart meter," which sends information to the utility. Future software could allow the utility to control certain devices through this network and remotely deactivate them to avoid blackouts. This type of energy control, called "demand response technology", is intended to reduce energy use by high-energy-use devices such as air conditioners during peak hours. Demand response technology, according to the HNEI's Jay Griffin, should be transparent - customers should know why their devices are being shut off, and when supply is in excess of demand, customers should be told and billed at a reduced rate for using electricity during hours which are less stressful for the grid.

The other challenge of the HCEI is convincing people that energy efficiency is something they control and that there is a financial benefit to their doing so. Regardless of utility customers' personal views on environmental issues, anyone is likely to try to reduce energy use if they can be convinced that it will save them money and that the causes of high energy use can be isolated. The Sea Grant institute at the University of Hawaii is currently conducting energy audits (logging of individual devices and circuits' energy use) of military housing. The ultimate goal of an energy audit is to help the audited person or organization to recognize points of high energy use, change their behavior, and ultimately save money. Sea Grant's current auditing procedure requires that its researchers manually graph and check the data gathered by the power-use sensors. Sea Grant uses the comprehensive data, which includes times, device model numbers, and temperature readings, to draw conclusions about residential energy use and provide efficiency advice to the audited family. Sea Grant's eventual goal is to automate data collection and organization in order to get the data into a human readable state in less time.

Hawaii has a long way to go to achieve its 2030 goals for renewable energy production. However, the research efforts now under way promise to make it possible to easily add renewable energy generators onto the power grid and to account for their unpredictability. They also promise to empower the public with new tools and services to track and take control of their energy use, a key part of achieving the increased efficiency goals. In all of these developments, software developers have a key role to play in solving the problems of implementing and analyzing the "smart grid" that is ultimately the backbone of any future system of energy generation.