Pages

Showing posts with label Three Prime Directives. Show all posts
Showing posts with label Three Prime Directives. Show all posts

Friday, December 2, 2011

Looking At The Big Picture: Software Review of a WattDepot Project

In my last post, I discussed my experiences in designing a WattDepot team project maintained under continuous integration. The follow-up project involves switching to another team's open-source WattDepot project, updating their documentation, and adding additional functionality to their code base. As a prelude to this, we evaluated their project (and they evaluated ours) according to the Three Prime Directives of Open Source Software Engineering.

The Three Prime Directives are a set of three guiding principles for open source software development that, when followed, make a system built on an open-source API like WattDepot useful, easy to use, easy to maintain, and easy to extend. WattDepot, as an API which provides users with "infrastructure for experimentation and development of "Smart Grid" applications," allows users to retrieve stored data on power and energy generation and consumption from a remote server. It was designed with the Three Prime Directives in mind, and it stands to reason that any project based on its tools should reflect the application of those same directives.

Prime Directive #1: "The system successfully accomplishes a useful task."

Any software system must do something which end users will find useful. In the first phase of our WattDepot projects, all systems needed to implement four commands: CurrentPower (the current power being used by a tower or floor lounge in the Hale Aloha residential complex), DailyEnergy (the energy consumed by a tower or lounge on a given day), EnergySince (the energy consumed by a tower or lounge from a given day up to the present), and RankTowers (the four towers' energy consumption from a given start date to a given end date, sorted in ascending order). The project also needed to provide a help function (to tell the user how to use each command) and a quit function to close the program.

The implemented commands.
The functions were all implemented, and when given input in the expected format, for the most part they returned the expected results. At this stage of the review, though, a few bugs were already apparent:
  • current-power should return a value in kW, not kWh.
  • rank-towers cannot handle having the same start date and end date; it returns what seems to be a default value for Lokelani and then does not print information for any of the other towers.
  • The help command fails to display its message when the .jar file is executed outside of the original distribution directory. This seems to indicate that its file path does not point to a file within the jar (which should be self-contained) but to an external file instead.

This software system fulfills most of the First Prime Directive by implementing most of the useful tasks specified in the original assignment, but its help function is not properly configured to reference other files relative to itself within the jar. Though the .jar works as long as their instructions are followed and the .jar is never removed from the distribution folder, it is not good that the .jar is not self-contained. In case of internal problems like this, a user should have some external documentation, whether stored locally or on the developer site.


Prime Directive #2: "An external user can successfully install and use the system."

Logically, the user of a software system must be able to set up and begin running a system in order to take advantage of the useful task it accomplishes. If the help function does not provide enough information for a user, the next place to go for helpful documentation would be the team's project hosting site and its wiki subsection.

*Note to any future readers of this entry: The versions of the wiki pages referenced are as of November 29, 2011. With the exception of the home page (the screenshot of which appears below), the page code for these versions will be available here:

The Home Page

home page

The home page gives a brief introduction to the project's relation to WattDepot and to the Hale Aloha Residential Complex. This is fine, but tells prospective users and developers little about what a WattDepot server does, and nothing about the specific energy consumption information the system is capable of requesting. There is no sample input or output provided on this page; instead, site viewers are referred to the User Guide. The home page's introduction is fine, but it tells viewers very little about what the system is capable of.


The User Guide

The user guide starts by telling the user to "navigate into the directory of the distribution jar." It doesn't tell the user where to download the distribution, or that it needs to be unzipped. A link to the Downloads page is clearly visible in the Google Code website template, but a user guide should not always assume the user knows where on a site the relevant files are stored.

The guide then provides instructions for running the .jar file from the command line, and a useful table of example command syntax. This part of the page is quite accurate. The problem comes in the next table, which provides a list of acceptable names to enter as sources. As I discovered when testing the distribution, the system does not support queries for data from the sub-sources at the [TOWER_NAME]-[FLOOR_NUMBER]-lounge and [TOWER_NAME]-[FLOOR_NUMBER]-telco level; only tower and floor-level lounge names are supported. Thus, "Ilima" and "Ilima-A" through "Ilima-E" will work, but "Ilima-XX-lounge" and "Ilima-XX-telco" (where XX is a two-digit number representing the floor where the lounge is located) will not. While there was no requirement that lounge- and telco- level subsource data requests be supported, the user guide should not misdirect users by saying that the software supports this when it does not.


Distribution

The distribution (version 1.0.2011.11.29.12.22) is clearly numbered according to major release number and date of packaging, and it does contain an executable .jar file, so no issues were present here.

Input Testing

As a general rule, the program handles bad date inputs and incorrect tower and lounge names well, though as mentioned earlier, it does not support querying for lounge- and telco- level subsources as the user guide suggests. Dates that are not in yyyy-mm-dd format are rejected, and dates that are outside calendar ranges (e.g, 2011-13-01, or 2011-02-29) are rejected, and source names that are not the names of towers or floor-level lounges are rejected. (The implementation of this - matching inputs against a hard-coded array of string names - has to be manually edited and is not very extensible, but it works.) The quit function works as well.

However, the system does not do any range-checking for dates in the future.
Enter in a command:energy-since Ilima 2011-12-28 
server provided bad xml:org.wattdepot.client.BadXmlException: 400: Range extends beyond sensor data, startTime 2011-12-28T00:00:00.000-10:00, endTime 2011-12-02T04:07:04.920-10:00: Request: GET http://server.wattdepot.org:8190/wattdepot/sources/Ilima/energy/?startTime=2011-12-28T00:00:00.000-10:00&endTime=2011-12-02T04:07:04.920-10:00
Unable to retrieve energy consumption data
Total energy consumption by Ilima from 2011-12-28 to 2011-12-02 was 0.0 kWh
To its credit, it does give an appropriate error message and returns a default value in addition to the default BadXmlException thrown by the WattDepot server.

A similar problem occurs when requesting daily-energy data for the current date:
Enter in a command:daily-energy Ilima 2011-12-02
server provided bad xml:org.wattdepot.client.BadXmlException: 400: Range extends beyond sensor data, startTime 2011-12-02T00:00:00.000-10:00, endTime 2011-12-03T00:00:00.000-10:00: Request: GET http://server.wattdepot.org:8190/wattdepot/sources/Ilima/energy/?startTime=2011-12-02T00:00:00.000-10:00&endTime=2011-12-03T00:00:00.000-10:00
Unable to retrieve energy consumption data
Total energy consumption by Ilima on 2011-12-02 was 0.0 kWh
It seems to be the case that the start and end timestamps used to make the data request are hard-coded to extend from 12:00:00.000 AM midnight on the specified date to 12:00:000.000 AM midnight on the next day. When data requests are made for the present day, the system fails because it requests data outside the available range. This is not a problem for any of the other commands, only for daily-energy.

There was another bug in rank-towers, which gives incomplete output when the start date and the end date are the same:
Enter in a command:rank-towers 2011-12-01 2011-12-01
For the interval 2011-12-1 to 2011-12-1, energy consumption by tower was:
Lokelani             0 kWh
Note that this bug occurs only when the start date and end date are the same, regardless of whether any of the specified dates are the present day or not.

Finally, the program does not do out-of-range checking for dates beyond the server's range of data in the past. This is the case for all of the commands.
Enter in a command:rank-towers 2000-12-01 2011-12-02
Error: Unable to query sources for energy consumption.
Error: Unable to query sources for energy consumption.
Error: Unable to query sources for energy consumption.
Error: Unable to query sources for energy consumption.
For the interval 2000-12-1 to 2011-12-2, energy consumption by tower was:
Lokelani             0 kWh
In all fairness, though, it is impossible to know the start date for any particular server, especially since a server can crash and be restarted without warning. What matters here is that the error is handled with an appropriate message and some kind of default value being returned, and in this respect the handling of this error is correct.

This system partially fulfills the second prime directive by providing error-checking and some wiki documentation for users; however, the wiki documentation is incomplete and sometimes misleading.


Prime Directive #3: "An external developer can successfully understand and enhance the system."

As part of our project requirements, each team's wiki section was supposed to contain a Developer Guide which explained how to build the system from the source code provided in the distribution. The Developer Guide should tell users how to develop for the project, both in a technical and philosophical sense, by specifying environments, console commands, development philosophies, testing requirements, and any other information necessary. Regardless of what it is called, all open source projects should provide information on how to integrate one's system enhancements with the main project by following the same methodology.


Developer Guide

The Developer Guide tells the user to set up Apache Ant, but does not specify a version number (all of our projects were developed under 1.8.2). It then tells the user to run "ant -f verify.build.xml" in the project's root directory. Automated quality assurance through Checkstyle, PMD, and FindBugs is specified as being part of the verify process. However, no coding standards are specified, and the development philosophy is only specified as "issue-driven" without specifically being described as issue-driven project management (which is the only method so far discussed in class). The project's continuous integration server is specified.

The instructions for extending the commands available to the system is quite vague, only telling the user to modify existing files without specifying what parts of the code need to be modified:

"To add additional commands, create a class with the desired functionality that implements the Command interface. Then, modify the CommandParser class to recognize the new command and correctly create in instance of the new class when the appropriate command is entered.

Each Command class and its tests are considered black boxes. The only part of the existing program that should need to be modified (and then, only slightly) when a new Command is added is the CommandParcer class. This modularity should be maintained, as it keeps the system relatively easy to extend."
As far as my teammates and I have been able to work out, commands are added by adding the name used for the command to an array in CommandParser, then instantiating an instance of the command's class within a later set of switch cases, then finally adding a method to call functions from the command's class and pass the appropriate arguments. Normally, even if the external documentation were missing some information, developers should be able to fall back on Javadocs; however, this was not the case.

Javadocs

Javadocs, generated with Java's built-in tool for automatically generating system documentation at compile-time, are a useful source of specific information about methods and instance variables. This system is missing most of its documentation. Methods and classes are tersely documented (e.g., a constructor documented only as "Constructor") and most instance variables are not documented at all. All of the classes that implemented Command also inherited the Javadoc specified in the Command interface, which misspelled "Command" as "Comman." Finally and most obviously, the Index page of the Javadocs says "Implements a Robocode Robot called DaCruzer," a holdover from the Robocode template project on which our Ant configuration files are based.

Information Hiding

Information hiding is the practice of designing a software system such that the specific implementation of design decisions are hidden from external code which references it as much as possible, so that the code can be changed later without affecting the operation of other code. This system has no information hiding of any kind; all instance variables are package-private (Java's default setting) because no public, protected, or private designation was specified, and all the classes are in the same top-level package.

Building The System From Sources

The system builds correctly when "ant -f verify.build.xml" is invoked. and passes Checkstyle, FindBugs, and PMD. It also passes the lone JUnit test for RankTowers, which only has 24% instruction coverage according to Jacoco (which the Developers Guide also does not mention). The other classes have no tests implemented for them, except in the form of text files which import no JUnit assertions and have no @Test methods - and thus would not work as JUnit tests if their extensions were changed to .java. Overall coverage of the project is about 20%, which is usually too low to indicate adequate test coverage of the system.

Source Code

The source code is very sparsely commented as a whole, which did not help when our group was trying to figure out how a developer would go about adding new Commands. In addition, there are many signs of half-finished code, including "//TODO:" comments, missing @parameter Javadoc tags, and commented-out, unused instance variable fields. The strangest thing, as mentioned earlier, are the .txt files labeled TestEnergySince, TestDailyEnergy, and TestCurrentPower. Their names and comments suggest that they were supposed to be unit tests, but including them as text files keeps them from being compiled and run, so it must be concluded that they were not finished in time to make the distribution.

Issues

According to the philosophy of issue-driven project management, a project should be clearly divided into a series of smaller tasks divided evenly among group members, with each task being small enough to be finished in time for the next meeting. The Issues page for this group is misleading; despite the issues with test cases mentioned earlier, all test case-related issues are listed as completed. Each of the three team members (Jesse, Richard, and Micah) was responsible for about a third of the project, with Jesse designing energy-since and current-power, Richard designing the command-parsing class, daily-energy, and help, and Micah designing rank-towers, the Command interface, the command-line interface itself, and quit. Micah seems to have done a little more work than the other team members, and has the only functioning test case.

Continuous Integration

All of the WattDepot projects are verified and re-compiled when the class's continuous integration server, which runs Jenkins. Continuous integration is the idea that a system stored in a repository should continuously be in a verified state, in which all quality assurance and unit tests are passed. Most continuous integration tools provide for automated compilation (either at regular intervals, manually, and/or when changes are made) and testing, as well as notification when a repository commit "breaks" the build by failing a test.


number of commits by date
Commits to the hale-aloha-cli-kmj project by date. Dates marked in red are dates for which
one of the projects' required services were down: the Jenkins server was down from November 18
to November 19, and the WattDepot server was down from November 21 to November 24.

If a group is working diligently, commits should occur on a daily basis, and any broken builds should be fixed promptly. If a group is following issue-driven project management, then commit messages should list the issues which a commit addresses, and around 90% of the commits should be non-trivial fixes directly tied to an issue.

The kmj team had no commits for five days (November 10-15), and a look at the Jenkins site reveals that their project remained in a broken state for almost 24 hours after the WattDepot server resumed operation on the November 24, finally experiencing a successful build on November 26. In addition, only 16 of their 26 commits (about 61.5%) are directly tied to an issue; the rest are not.

This team missed most of the requirements for the Third Prime Directive by having low test case coverage, missing Javadocs, a sometimes erratic work schedule, occasionally long times between build fixes, and not labeling commits in accordance with issue-driven project management. As a result of all of these things, it would be difficult for a new developer to understand the system and their development methodology by examining their previous work, and difficult to gauge whether their new code might break the functionality of an untested method.

Conclusion

The hale-aloha-cli-kmj project provides most of the basic functionality required to satisfy the first Prime Directive, and most of the error checking needed to satisfy the second Prime Directive, though some missing information in the wiki keeps it from completely satisfying the second Prime Directive. It is in relation to the third Prime Directive that the state of the project fails to hold up under scrutiny. This is not a criticism of the code itself - which mostly works as expected - so much as it is a criticism of how little it is documented and how much of it is untested. And ultimately, all else being equal, it is reliability, ease of use, and ease of development that will separate an open-source project from others of its kind.

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.

Saturday, August 27, 2011

The Three Prime Directives of Open Source Software: PDF Split and Merge

Introduction

In the world of open-source software, the "Three Prime Directives" define the characteristics of a true open-source project. To fulfill the first directive, "the system must successfully accomplish a useful task." To fulfill the second prime directive, it must be true that "an external user can successfully install and use the system." The third directive is fulfilled when "an external developer can successfully understand and enhance the system." Fulfilling the three prime directives is important for an open-source project because it ensures that users and other developers can contribute bug reports, feature requests, and their own add-ons to the project, thus enabling the developers to better understand the needs of their customers and improve their system.

Sourceforge

Sourceforge is a well-known source code repository for open-source software, offering hosting and version-control services and providing a means for end users to directly contact development teams with bug reports and other feedback. ICS 314 is a Java-oriented class, so we were asked to find and review a Java-based project.

PDF Split and Merge

PDF Split and Merge's homepage describes itself as "... an open source tool (GPL license) designed to handle pdf files." Its GUI is written in Java Swing, and the command line interface is also based on Java.

The Windows installer for PDF Split and Merge can be found at http://sourceforge.net/projects/pdfsam/, and the other installers can be found at http://www.pdfsam.org/?page_id=32.

Prime Directive 1

PDF Split and Merge (referred to as PDFSam from here on) provides a wide suite of tasks related to the manipulation of PDF files. These include splitting and merging the pages of existing PDF files, rotating PDF pages, and combining multiple sections extracted from PDFs into a single new document. Most other programs which provide these functions are proprietary (e.g., Adobe Acrobat or Adolix Split Merge PDF), so consumer demand does exist for the useful task which PDFSam accomplishes.

Prime Directive 2

Ease of Installation

PDFSam was easy to install, and though there were problems with the installation, they were quickly fixed. The Downloads page features "basic" versions for Windows, Mac OS X, and a .zip file, which contains all the files that the .exe installer creates. The program requires Java SE 2 version 1.6 or higher to run. The site also offers an "enhanced" version that is free (if you compile the code yourself) or available as a regular installer for "a single donation of any amount." I installed the basic version.

Installing From A .zip File

Once the files are extracted, the program is easily run from the pdfsam-2.2.1.jar file. For some reason, the folder still contains a useless "pdfsam-starter.exe" file, exactly like the folder created by the .exe installer. The .exe installer had its own set of problems, which are covered in the next section.

Using the Windows Installer

The .exe installer ran with no problems on my Windows 7 machine, but the application failed to launch from the startup menu. I ran a compatibility check, which recommended running it using Windows XP SP2 settings. This caused the program to open and crash, saying it had failed to find "pdfsam-2.2.1.jar." The installer had created pdfsam-2.2.1.jar in the installation directory, but for whatever reason pdfsam-starter.exe couldn't detect it.

The readme.txt file included with the installation stated the following:

"Installation: Unzip the archive into a directory. Double click pdfsam-2.2.1.jar or open a console a type the command "java -jar /pathwhereyouunzipped/pdfsam-2.2.1.jar"".

Following this instruction successfully launched the program. Though the program runs from the .jar file, and readme.txt does tell the user to run the .jar file and not the nonfunctioning launcher "pdfsam-starter.exe," there are problems with this approach. Any user who used the .exe installer would not be able to easily access the program from the start menu, which only provides a link to the broken "pdfsam-starter.exe" file and no link to the .jar file that actually runs the program.
The program isn't unusable by any means, but the need to read documentation to get around a broken launcher implies that the problem is known but still not addressed, and doesn't satisfy the first prime directive's requirement for ease of installation.

Ease of Use

I was able to use most of PDFSam's PDF manipulation features without consulting the included instruction manual. It has five basic functions: "Alternate mix" (which can reverse the order of a document's pages or mix pages from documents at specified intervals), "Merge/Extract" (which lets you merge specific parts of PDFs), "Rotate" (which rotates all pages in a document in increments of 90 degrees), "Split" (which divides a document into pieces), "Visual document composer" (which lets you take individual pages of multiple documents and merge them into a single document) and Visual reorder (which lets you change the order of pages in one document). I tested PDFSam's basic functions with multi-page PDFs of lorem ipsum text and found the features easy to use.


The PDFSam GUI.

The command-line features are less easy to use, but still usable by following the instructions in the tutorial PDF or its wiki (command line instructions shown):

The mistake to avoid making here is to assume that "options" and "required" mean the "options" and "required" arguments that apply to "command." Actually, "required" covers all the arguments exclusive to "command," whether the arguments are specified as optional or not. After an hour or so of working through my confusion, I successfully did this:


The command line output produced by merging two PDFs.

To be fair, my mistake was a careless one, and command-line tools aren't usually intended for casual users (who will mostly use the GUI), so any difficulty on the part of the command-line tools doesn't detract much from the program's overall usability. PDFSam still mostly fulfills the second Prime Directive as it relates to ease of use.

PDFSam does a mixed job of fulfilling the second Prime Directive, and is easier to use than it is to fix it after it installs.

Prime Directive 3

PDFSam does a good job of fulfilling the third Prime Directive. Source code and developer-level documentation is easy to find on the project's official (non-Sourceforge) site. The source code is available on the Downloads page. Each Java source code file begins by making developers aware of their modification rights under the GPL, and each file includes cross-references to other Java files. This is demonstrated by the code excerpt below:

Developer-level documentation is provided on the Resources page. Java documentation is provided for both the basic and enhanced version's APIs, and changelogs and software requirements are also available. The Resources page also provides links to request features and access its SVN repository. Bugs are reported in the forums. Developer documentation is easy to find, the source code is readily available, and changes are publicly proposed and discussed, fulfilling the Third Prime Directive.

Conclusion

Despite my problems with PDFSam's Windows installer, its GUI is easy to understand and provides many useful ways of manipulating PDFs. Developer documentation, source code, and forums for communicating with developers are easily accessed. Overall, PDFSam fulfills many of the requirements of the Three Prime Directives.