<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Basil Vandegriend: Professional Software Development &#187; tools</title>
	<atom:link href="http://www.basilv.com/psd/blog/tag/tools/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.basilv.com/psd</link>
	<description></description>
	<lastBuildDate>Thu, 17 May 2012 14:31:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Visualizing Java Package Dependencies</title>
		<link>http://www.basilv.com/psd/blog/2012/visualizing-java-package-dependencies</link>
		<comments>http://www.basilv.com/psd/blog/2012/visualizing-java-package-dependencies#comments</comments>
		<pubDate>Wed, 07 Mar 2012 13:16:42 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[architecture]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=781</guid>
		<description><![CDATA[I have recently been examining the overall package structure of a Java enterprise application. I discovered an easy way to visualize the dependencies between packages using two open source tools JDepend and Graphviz and a little glue code. JDepend analyzes compiled Java bytecode and determines dependencies and metrics between Java packages. These analysis results can [...]]]></description>
			<content:encoded><![CDATA[<p>I have recently been examining the overall package structure of a Java enterprise application. I discovered an easy way to visualize the dependencies between packages using two open source tools <a href="http://clarkware.com/software/JDepend.html">JDepend</a> and <a href="http://www.graphviz.org/">Graphviz</a> and a little glue code. JDepend analyzes compiled Java bytecode and determines dependencies and metrics between Java packages. These analysis results can be used to generate a graph with packages as nodes and dependencies as edges. Graphviz can then be used to layout and draw the graph as an image. Sample code is provided at the end of this article to show how to do this.</p>
<p>Visualizing package dependencies can be useful for a number of reasons:</p>
<ul>
<li>Reverse engineering the architecture of an application when documentation is limited, out-of-date, or non-existent.</li>
<li>Automatically generating diagrams, saving the time required to draw them manually.</li>
<li>To understand impacts when doing large-scale refactorings or changing implementations of components.</li>
<li>To determine how to extract functionality for reuse.</li>
<li>To support good architecture / design as espoused by Robert C. Martin in his book <a href="http://www.amazon.ca/gp/product/0135974445/ref=as_li_tf_tl?ie=UTF8&#038;tag=basilvandegri-20&#038;linkCode=as2&#038;camp=15121&#038;creative=330641&#038;creativeASIN=0135974445">Agile Software Development, Principles, Patterns, and Practices</a><img src="http://www.assoc-amazon.ca/e/ir?t=basilvandegri-20&#038;l=as2&#038;o=15&#038;a=0135974445" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, such as by eliminating cyclical dependencies or unwanted dependencies.</li>
</ul>
<p>Here is an example package dependency diagram generated by Graphviz:<br />
<a href="http://www.basilv.com/psd/wp-content/uploads/2012/03/packages.png"><img src="http://www.basilv.com/psd/wp-content/uploads/2012/03/packages.png" alt="Example Java Package Dependencies Diagram" title="Example Java Package Dependencies Diagram" width="507" height="251" class="alignnone size-full wp-image-782" /></a></p>
<p>The source code provided below that was used to generate this example diagram is available from my <a href="https://github.com/basilv/Java-Examples">Java Examples</a> project on GitHub or as a <a href="http://www.basilv.com/psd/software#JavaExamples">packaged bundle on my Software page</a>. The code can easily be reused: change the directory of compiled code scanned by JDepend ("dist/classes"), and change the root package used to limit the scope of the diagram ("com.basilv.examples.packagediagram").</p>
<pre class="prettyprint">
package com.basilv.examples.packagediagram;
import java.io.*;
import java.util.*;
import jdepend.framework.*;

public class PackageDiagramCreatorApp {

  public static void main(String[] args) {
    createPackageDependencyDiagram();
    System.exit(0);
  }

  public static void createPackageDependencyDiagram() {
    Collection<JavaPackage> packages = analyzePackages();
    StringBuilder builder = generateGraph(packages);
    generateImage("packages", builder.toString());
  }

  @SuppressWarnings("unchecked")
  private static Collection<JavaPackage> analyzePackages() {
    JDepend jdepend = new JDepend();
    try {
      jdepend.addDirectory("dist/classes");
    } catch (IOException e) {
      throw new RuntimeException("Error adding directory for JDepend to analyze.", e);
    }
    Collection<JavaPackage> packages = jdepend.analyze();
    return packages;
  }

  private static StringBuilder generateGraph(
    Collection<JavaPackage> packages) {
    StringBuilder builder = new StringBuilder();
    builder.append("digraph packages {").append("\n");
    builder.append("node [shape=box];").append("\n");
    builder.append("rankdir=BT;").append("\n");
    Set<String> drawnDependencies = new HashSet<String>();
    for (JavaPackage javaPackage : packages) {
      String packageNodeName = getGraphVizNodeForPackage(javaPackage);
      if (packageNodeName == null) {
        continue;
      }
      builder.append(packageNodeName).append("\n");

      @SuppressWarnings("unchecked")
      Collection<JavaPackage> dependencies = javaPackage.getEfferents();

      for (JavaPackage dependency : dependencies) {
        String dependencyNodeName = getGraphVizNodeForPackage(dependency);
        if (dependencyNodeName == null
          || packageNodeName.equals(dependencyNodeName)) {
          continue;
        }
        String dependencyKey = packageNodeName + "->"
          + dependencyNodeName;
        if (drawnDependencies.contains(dependencyKey)) {
          continue;
        }
        builder.append(packageNodeName).append(" -> ").append(
          dependencyNodeName).append(" [weight=4]").append("\n");
        drawnDependencies.add(dependencyKey);
      }
    }
    builder.append("}\n");
    return builder;
  }

  private static String getGraphVizNodeForPackage(
    JavaPackage javaPackage) {

    String rootPackage = "com.basilv.examples.packagediagram";
    String packageName = javaPackage.getName();
    if (!packageName.startsWith(rootPackage)) {
      return null;
    }

    return packageName.replace(".", "_");
  }

  private static void generateImage(String fileName,
    String graphVizDotFormattedGraph) {
    try {
      File graphFile = createFileWithContents(fileName
        + ".txt", graphVizDotFormattedGraph);

      // This requires the Graphviz software to be installed -
      // see http://graphviz.org/
      String imageFileLocation = fileName + ".png";
      Runtime.getRuntime().exec(
        "dot -v -Tpng " + graphFile.getName() + " -o "
          + imageFileLocation);

      System.out.println("Image file available at "
        + new File(imageFileLocation).getAbsolutePath());
    } catch (IOException e) {
      throw new RuntimeException("Error generating image " + fileName, e);
    }
  }

  private static File createFileWithContents(
    String fileName, String graphVizDotFormattedGraph)
    throws IOException {
    File graphFile = new File(fileName);
    FileWriter writer = new FileWriter(graphFile, false);
    try {
      writer.append(graphVizDotFormattedGraph);
    } finally {
      writer.close();
    }
    return graphFile;
  }

}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2012/visualizing-java-package-dependencies/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Software Documentation Templates</title>
		<link>http://www.basilv.com/psd/blog/2011/software-documentation-templates</link>
		<comments>http://www.basilv.com/psd/blog/2011/software-documentation-templates#comments</comments>
		<pubDate>Mon, 18 Jul 2011 13:03:36 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[documentation]]></category>
		<category><![CDATA[quality]]></category>
		<category><![CDATA[software development]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=686</guid>
		<description><![CDATA[I am a believer in minimizing software documentation that lives outside the code. This does not, however, mean no documentation. There are a number of reasons why documentation can be useful, especially for larger organizations: Documentation is more effective than code at communicating high-level or cross-cutting design and operational concerns. Larger organizations or distributed organizations [...]]]></description>
			<content:encoded><![CDATA[<p>I am a believer in minimizing software documentation that lives outside the code. This does not, however, mean no documentation. There are a number of reasons why documentation can be useful, especially for larger organizations:</p>
<ul>
<li>Documentation is more effective than code at communicating high-level or cross-cutting design and operational concerns.</li>
<li>Larger organizations or distributed organizations cannot rely on face-to-face communications or having everyone co-located in one room so documentation has a role to play in knowledge transfer and communication.</li>
<li>Documentation can target a non-developer audience, such as business representatives.</li>
<li>Documentation helps protect against team turnover, which while a bad practice is not uncommon when using a vendor for development or maintenance or using separate development and maintenance teams.</li>
<li>The act of creating documentation helps clarify thinking and identify gaps, thus functioning as a form of quality control.</li>
</ul>
<p>This last reason is actually quite significant as it is often under-appreciated. In my experience it has happened quite often when I am working on design documentation for a body of code that I identify things that are sub-optimal, such as a badly named class or an unwanted dependency between components. This form of quality control is most valuable, however, when it uncovers gaps such as missing functionality or flawed design. Such gaps are very difficult for most other forms of quality control like testing or reviews to find. </p>
<p>The use of documentation templates makes it much easier to find these gaps by acting essentially as checklists of items to consider. I recently came across a great <a href="http://7d6a11fowa9p0ndghc221ih49r.hop.clickbank.net/">set of comprehensive templates covering all aspects of software development by Klariti</a> . For a team or organization the price of these templates is ridiculously low - the full set of software development templates costs far less than a day's salary - and there are an assortment of free templates as well. </p>
<p>There are some potential drawbacks to avoid when using documentation templates. Some people have a tendency to want to fill in every section of a template or to use all available templates. This can waste a lot of time and effort. Focusing on identifying what is relevant and useful to document and doing only that is much more effective. Another drawback is that while the templates are in Office format (Word or Excel), you might be better served using a different medium such as a Wiki or a <a href="http://www.basilv.com/psd/blog/2007/development-tools-should-use-text-files">text-based format</a> that is more friendly to version control. In these cases I would convert the templates to the desired medium. </p>
<p>Even if your team or organization has some templates, I think it would be beneficial to check out Klariti's templates and use them as a checklist to see if there is anything missing or needing revision within your own. That link again is: <a href="http://7d6a11fowa9p0ndghc221ih49r.hop.clickbank.net/" target="_top">Klariti's software development templates</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2011/software-documentation-templates/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stop Staring at the Spreadsheet</title>
		<link>http://www.basilv.com/psd/blog/2011/stop-staring-at-the-spreadsheet</link>
		<comments>http://www.basilv.com/psd/blog/2011/stop-staring-at-the-spreadsheet#comments</comments>
		<pubDate>Fri, 11 Mar 2011 15:38:40 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[management]]></category>
		<category><![CDATA[project management]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=616</guid>
		<description><![CDATA[As a scrum master or technical lead do you find yourself frittering away your time staring at the spreadsheet (or other tool) you use to track progress of the team? Do you keep studying the velocity and burndown or keep tweaking the numbers or formulas? I have heard of this becoming a chronic problem for [...]]]></description>
			<content:encoded><![CDATA[<p>As a scrum master or technical lead do you find yourself frittering away your time staring at the spreadsheet (or other tool) you use to track progress of the team? Do you keep studying the velocity and burndown or keep tweaking the numbers or formulas? I have heard of this becoming a chronic problem for a few scrum masters, and I find myself faced with a constant temptation to do this.</p>
<p>What is it about the spreadsheet that is so alluring? There is some value to studying it - I think of it as uploading the numbers into my subconscious to get an intuitive feel for where there might be obstacles or challenges that the team is facing now or will face shortly in the future. But the value of doing so quickly drops off and yet we keep staring. Part of the temptation I feel is to find ways to bump that daily or weekly burndown just a little higher by finding that task that is actually complete or is over-estimated. This is especially true if progress has not been good. </p>
<p>So what can we do to stop starting at the spreadsheet? </p>
<ol>
<li>Remember that identifying obstacles is no good unless they are dealt with. Focus on removing or mitigating the obstacles instead.
</li>
<li>Ask yourself what activity you can do that will best accelerate the team's progress. This might be helping a developer that is stuck on a technical issue, freeing up the time from a tester who has become a bottleneck, or clarifying requirements for upcoming work. More studying of the spreadsheet is never the answer. This is especially useful when the team's progress has been lower than expected.
</li>
<li>Remember that minor errors in the spreadsheet are inconsequential in the grand scheme of things. Forgetting to burn down a task or two is dwarfed by the innate inaccuracies of the estimates you are using to track progress. If you miss updating a task this week, you will likely catch it next week.
</li>
<li>Remind yourself that the spreadsheet is merely a tool, and that you are the master of the tool - not the other way around.
</li>
<li>Throw away the spreadsheet and use a simpler approach - perhaps a paper burndown chart on the team wall. Just ensure you do not then start staring at the wall.
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2011/stop-staring-at-the-spreadsheet/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Five Commandments of Version Control</title>
		<link>http://www.basilv.com/psd/blog/2009/the-five-commandments-of-version-control</link>
		<comments>http://www.basilv.com/psd/blog/2009/the-five-commandments-of-version-control#comments</comments>
		<pubDate>Wed, 23 Sep 2009 03:49:15 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[process]]></category>
		<category><![CDATA[software development]]></category>
		<category><![CDATA[version control]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=436</guid>
		<description><![CDATA[Effective use of version control is a fundamental development practice, especially if there is more than one person working on the same code base. Below are the standard rules I use for the proper use of version control in the style of biblical old testament commandments. I like imagining an authoritative voice booming these commandments [...]]]></description>
			<content:encoded><![CDATA[<p>Effective use of version control is a fundamental development practice, especially if there is more than one person working on the same code base. Below are the standard rules I use for the proper use of version control in the style of biblical old testament commandments. I like imagining an authoritative voice booming these commandments from a mountain top. Fire and brimstone are optional :)</p>
<h3>1. Thou shalt not break the build</h3>
<p>This is the first commandment because breaking the build causes immediate problems for the rest of the team. Anyone updating from version control repository will have a non-functional local copy of the code and will be unable to continue with their work until the problem is fixed. A broken build also causes issues for others wanting to commit changes: they cannot verify that their changes do not break the code base. Doing an unrelated commit on top of a broken build risks introducing new breaks that compound the difficulty in getting the code base back to working order. (This exact problem happened quite recently on my project.)</p>
<p>The general principle is to not introduce problems in the code base that interfere with other development activities. Each team needs to have a specific, unambiguous definition. As a minimum standard I require code to always compile and pass 100% of the unit tests. While I prefer that automated integration and functional tests always pass, they are slower to run and depend on external systems, so pragmatically the occasional failure can happen. </p>
<p>An easy way to make your definition of a broken build explicit is to define an automated build process that performs this check. This build process can be executed by the developer prior to committing a change, and can also be configured to execute on a continuous integration server immediately after a change is committed to ensure the code base is not broken.  </p>
<p>I like having a penalty in place for those that break the build. It can be a small monetary fine (that goes into the team pot for the next social event), receiving a mascot of shame, or being assigned an unpleasant task.</p>
<h3>2. Thou shalt put everything in version control</h3>
<p>All code and all related files must be in the version control repository. A new developer or a new instance of a continuous integration server should be able to check out a copy of the software and build a complete release from it. </p>
<p>Too often I have encountered code bases where some key files are not included. I have seen a number of projects not include third-party libraries in version control. This might be deemed acceptable if an enterprise library repository is used (using a tool such as <a href="http://www.basilv.com/psd/blog/2009/using-ivy-to-manage-build-dependencies">Ivy</a>), but in the cases I have seen the code base required a directory of library files to exist on each developer's local workstation without even a definition of the required versions of the libraries being used. Other common omissions include build scripts, configuration files, and documentation.</p>
<h3>3. Thou shalt use the version control repository as the source of truth</h3>
<p>The version control repository is the official source of truth for all versions of the software. Source code distributions may be created and distributed via shared network drives or via the web, but the source of truth remains the repository. </p>
<p>If multiple branches are being used within the repository then the purpose of each branch must be clearly defined. The typical approach is to use the trunk (mainline) for ongoing development work, and create branches for releases. So the trunk is the source of truth for the software overall, while each release branch is the source of truth for a particular release, and in particular the fixes and/or patches made for a  release. Distributed version control systems such as Git, which in essence treat each local workspace as a separate branch, still need to follow these same rules to avoid complete chaos. (For example, running a continuous integration build requires at least one official branch to build from.)</p>
<p>The corollary to this commandment is that changes to source code not in the repository do not officially exist. Committing changes into the repository is therefore a critical part of doing development that is reflected in the next commandment.</p>
<h3>4. Thou shalt commit thy changes daily</h3>
<p>The principle behind this commandment is that the effort and difficulty involved in integrating separate changes increases non-linearly with the size of the changes, so it is best to integrate changes as often as possible. (This is an instance of the lean principle of flow which dictates minimizing large batch sizes and work-in-progress.) Requiring daily commits ensures that conflicts or duplication of effort are found quickly. </p>
<p>There are other benefits of daily commits. It forces developers to decompose their work into smaller, incremental pieces of work and ensure the quality of that work (since it cannot break the build as per commandment number one). Developers are more likely to use step-by-step refactoring rather than big-bang changes that are much riskier (and more likely to negatively impact the rest of the team). Daily commits provide a visible sign of progress per developer that can be used to assess when a developer is stuck or sidetracked (the commits tend to stop). </p>
<h3>5. Thou shalt treat thy version control system as mission critical software</h3>
<p>I have seen more than one company which did not treat their corporate version control system as mission-critical software. In one case the version control server was classified as a under-powered development server that could be bounced at any time or upgraded without prior testing. In another case the source code repository did not have robust backup and restore mechanisms in place.</p>
<p>If the version control server goes down it is safe to assume that regular development activities will start to grind to a halt within the day and any emergency fixes or scheduled releases will likely need to be delayed. It is a good idea to ensure that a version control server is available 24x7 with the ability to restore service within a half-day maximum. Why 24x7? Regular hours of development likely do not correspond to regular business hours (especially for emergency fixes), and scheduled builds typically run at night or the weekend.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2009/the-five-commandments-of-version-control/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Avoiding Distractions with Email</title>
		<link>http://www.basilv.com/psd/blog/2009/avoiding-distractions-with-email</link>
		<comments>http://www.basilv.com/psd/blog/2009/avoiding-distractions-with-email#comments</comments>
		<pubDate>Sat, 15 Aug 2009 13:09:48 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[productivity]]></category>
		<category><![CDATA[getting things done]]></category>
		<category><![CDATA[time management]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=428</guid>
		<description><![CDATA[This article continues the theme of my previous article on avoiding being disturbed at work by looking at another source of distractions – email. Email is an important form of communication for me at work, but I as previously discussed I cannot afford to let the use of email distract me during my dedicated blocks [...]]]></description>
			<content:encoded><![CDATA[<p>This article continues the theme of my <a href="http://www.basilv.com/psd/blog/2009/boost-productivity-using-a-do-not-disturb-policy">previous article on avoiding being disturbed at work</a> by looking at another source of distractions – email. Email is an important form of communication for me at work, but I as previously discussed I cannot afford to let the use of email distract me during my dedicated blocks of solo thinking time – typically architectural design or coding activities. In this article I discuss various approaches I tried and use to minimize the distractions that email can cause. I use Microsoft Outlook at work both for email and for its calendar event scheduling functionality.</p>
<p>The very first thing to do to minimize email distractions is to disable in Outlook all the indicators (like the bell, pop-up that fades, and system tray icon) that announce that a new email has arrived. I have always found these annoying and disabled them years ago. (Why are they enabled by default?) Every productivity expert I have read who mentions email also makes the same recommendation, so if you are reading this now and have those indicators set stop and disable them. </p>
<p>Without these indicators I still found myself becoming distracted by email. A typical scenario would see me working in one of my dedicated blocks of time focused on a task when I needed to either send an email or refer to an old one. I would open Outlook, see all the new emails in my inbox, and get distracted with reading and/or responding to them, especially if they were marked high priority. (This is the classic mistake of doing the urgent instead of the important.) So I tried a number of approaches.</p>
<p>First I tried to figure out how to send an email without opening Outlook. I wanted a shortcut in my Windows quick launch bar to do this, but what would have been trivial in an Unix environment turned out to be surprisingly difficult. In fact, I couldn't figure out how to do it using a command-line script, and I wasn't about to spend the time required to write a .Net program to do this. (If you know how to do this or know of such a program please let me know.) The best workaround I found was to invoke the Windows Run command (normally found in the start menu, it can be invoked by the shortcut of the Windows key + R), and type in the command "mailto:". The extra keystrokes were enough to prevent me from adopting this as a regular practice, and this didn't help anyways when I needed to reference an existing email.</p>
<p>Next I tried to figure out how to have Outlook check for incoming emails less often. I found a number of settings that seemed relevant, but they had no effect. New emails were still detected in less than five minutes. I was not sure if I missed the correct setting in Outlook, or if it was taking its email-checking configuration from the Outlook server. (If you know, please pass along the information via a comment.) In either case, I was pretty unhappy with Outlook. I considered simply shutting it down, but I needed it running in order to provide reminders for all the meetings I had scheduled throughout the day – including reminders for my personal design times. </p>
<p>I finally found a workaround through a coworker – switch Outlook to offline mode, and it will no longer check for emails. When offline Outlook does not send emails either, which was mildly annoying but a limitation I could live with. It took me less than a week, however, before I discovered another major limitation: while in offline mode changes to my schedule would not be communicated back to the Outlook server (and become visible to others) after I went back online. I discovered this via a not-so-amusing exchange with a coworker who was trying to book a meeting with me for an afternoon he saw as free that I had booked something while offline. The workaround to this annoying problem was to discipline myself to treat my calendar as read-only while Outlook was offline. Despite all the issues, offline mode worked quite well for me. </p>
<p>Recently, I have become more disciplined about remaining focused during my solo blocks of time and have found myself using offline mode less often. This seems to work best for me when I am crystal clear on my priorities (usually due to an impending deadline), so when I do see an email that would normally distract me I immediately think "not a priority" and file it for actioning later. There is usually a small amount of mental effort / distraction involved in scanning the email and making this decision, so it would be better to not have the emails come in until I want.</p>
<p>What approaches do you use to avoid getting distracted by email? I would love to hear your ideas, so leave a comment below.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2009/avoiding-distractions-with-email/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Ivy to Manage Build Dependencies</title>
		<link>http://www.basilv.com/psd/blog/2009/using-ivy-to-manage-build-dependencies</link>
		<comments>http://www.basilv.com/psd/blog/2009/using-ivy-to-manage-build-dependencies#comments</comments>
		<pubDate>Mon, 01 Jun 2009 15:00:25 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[ANT]]></category>
		<category><![CDATA[automated build]]></category>
		<category><![CDATA[Ivy]]></category>
		<category><![CDATA[software development]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=406</guid>
		<description><![CDATA[Ivy is a tool for managing build dependencies within the Ant build tool. In this article I share my experiences using Ivy and provide recommendations on what to do and not do. This article is not a tutorial on using Ivy: for that see the Ivy documentation. Before getting into the specifics of Ivy, the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://ant.apache.org/ivy/">Ivy</a> is a tool for managing build dependencies within the <a href="http://ant.apache.org/">Ant build tool</a>. In this article I share my experiences using Ivy and provide recommendations on what to do and not do. This article is not a tutorial on using Ivy: for that see the Ivy documentation.</p>
<p>Before getting into the specifics of Ivy, the first question to answer is why use Ivy at all? Why is managing build dependencies important? All the significant Java software I have worked on makes use of third-party libraries such as Hibernate for persisting objects to a relational database or JUnit for unit testing. Both the IDE projects and automated builds for these pieces of software have the common need to deal with these dependencies, most frequently by including them on the classpath for either compilation or at runtime. </p>
<p>These dependencies can be handled manually in an ad-hoc manner. This is what I have done in the past and what I have frequently observed to be done by other teams. But there are significant advantages to using a tool such as Ivy to manage these dependencies:</p>
<ul>
<li><em>Explicit tracking of the versions of the third-party software being used.</em> Too often I have come across projects with a library directory holding a collection of third-party jar files without any information as to the versions being used. Ivy supports defining dependencies explicitly by version number. If dependencies are defined more loosely, such as via a version range (e.g. version 1.0+), then Ivy can generate a report listing the specific versions used. Knowing the version of dependencies is important when trying to resolve issues or make use of the latest features.</li>
<li><em>Management of transitive dependencies.</em> If your software depends on third party software that itself has dependencies on other software, Ivy can automatically pull in these transitive dependencies. When multiple dependencies themselves depend on different versions of the same third-party software, Ivy can automatically resolve the conflict. An example will help illustrate this. Let us say that your software depends on two other libraries B and C. B in turn depends on D version 1.0 while C depends on D version 1.1. Ivy will pull in B, C, and D v1.1 and leave out D v1.0.</li>
<li><em>Standardized approach to storing dependencies.</em> Ivy uses one or more repositories of software as the source for obtaining dependencies. Each piece of software in these repositories is characterized by a standard set of metadata: the key attributes are organization, module, and revision. Using a public repository that the third-party software you require is updated within makes it trivial to upgrade to a new version: just change the version you depend on, and Ivy can then automatically download the new version. You can also use an enterprise repository to publish your own software into in order to facilitate reuse by others.</li>
</ul>
<p>There are a number of decisions to be made when using Ivy. In the remainder of this article I provide my experience and recommendations regarding these decisions.</p>
<h3>Building Classpaths</h3>
<p>There are two main options for building classpaths within your Ant build. The first is to use the <a href="http://ant.apache.org/ivy/history/2.1.0-rc1/use/cachepath.html">Ivy CachePath Ant task</a> to build an Ant path for your project's dependencies that references your local Ivy cache of dependencies. This nicely avoids any duplication of dependency information within your Ant build file. Unfortunately, the same cannot be done for your IDE classpath. Maven's solution is to generate the necessary IDE project files (e.g. Eclipse's .classpath file). The tooling support for Ivy to generate IDE files appears weak (I did not try it myself). Another limitation of this approach is that you will not have the libraries required for your project checked into version control. (You could, however, check an organizational repository into version control separately.)</p>
<p>The second option is to use the <a href="http://ant.apache.org/ivy/history/2.1.0-rc1/use/retrieve.html">Ivy Retrieve Ant task</a> to copy dependencies into your project workspace. You can specify the directory structure and file naming convention to use. I recommend copying the jars into a single lib directory (or one directory per Ivy configuration) and do not include revision information in the file names. This allows the classpath to be easily built in Ant using a simple fileset – e.g. <code>&lt;fileset dir="lib" includes="*.jar"/&gt;</code>. The IDE classpath must be manually maintained but at least keeping files revision-agnostic avoids needing to update the IDE when a dependency is upgraded. Because this lib directory is located within the project you can manage it in version control along with the rest of your project. One drawback of doing so, however, is that this lib directory full of jars now resembles a manual solution to maintaining dependencies so there is a risk that developers unfamiliar with the build or Ivy will directly add libraries to this lib path. I recommend using the retrieve task's option <code>sync="true"</code> to remove anything not specified as a current dependency.</p>
<p>I prefer the second option, partly because I am a fan of putting all project-related artifacts including third-party jars into version control, and partly because it makes it easier to manually manage the classpath within the IDE.</p>
<h3>Using Repositories</h3>
<p>Ivy requires at least one repository to be defined to obtain dependencies from and provides a number of options for doing so. One option is to use one or more public repositories: third-party repositories available over the Internet. Ivy provides built-in support for two: the public <a href="http://repo1.maven.org/maven2/">Maven repository</a>, which is probably the largest and best known repository, and <a href="http://www.jayasoft.fr/org/ivyrep/">IvyRep</a>, which only provides Ivy metadata for dependencies defined elsewhere (typically in the Maven repository). I recommend against using IvyRep: it appears it is no longer updated and I encountered errors resolving dependencies from it. The Maven repository seems like the best place to obtain third-party open source dependencies. You can use the site <a href="http://mvnrepository.com/">mvnrepository.com</a> to search for the metadata for the dependencies you are looking for.</p>
<p>The Maven repository does have its share of problems. Dependency metadata does not always match the directory structure or is plain wrong. For large projects like Hibernate or Spring with many dependencies, I was unable to resolve the complete set of their dependencies out of the Maven repository. I have also heard about and observed stability issues: sometimes downloads of dependencies fail. </p>
<p>Since I believe that builds must be reliable and repeatable I feel that relying solely on a public repository is a bad idea. The alternative is an organizational repository, which could be defined for the team or project or spanning the entire enterprise. In either case, Ivy supports a number of options for defining home-built repositories with my favorites being the local file system (typically on a shared network drive) or SFTP/SSH to access a remote file system. Ivy also supports defining a chain of repositories, so you could define an organizational repository first and then a public repository second. </p>
<p>The approach I prefer, however, is to only use an organizational repository for builds and use public repositories solely to install dependencies into the organizational repository. The <a href="http://ant.apache.org/ivy/history/2.1.0-rc1/use/install.html">Ivy Install Ant task</a> can be used to do this. It supports automatically installing transitive dependencies, which is very convenient but comes at a price. By default the install task fails if the dependency you are trying to install already exists in the target repository. This seems like reasonable behavior: you do not want to modify dependencies once they are installed. When combined with transitive dependencies, however, this is no longer useful: it is very likely that modules will have one or more common transitive dependencies, so when trying to install the second module, it will fail because it tries to transitively install a dependency that has already been installed. The workaround is to use the <code>overwrite="true"</code> option. I would prefer instead to have an option on the install task to ignore dependencies that are already installed.</p>
<p>When specifying a repository you must define the pattern used for the directory structure and file naming convention. My preferred pattern is: <code>${ivy-repository.dir}/[organisation]/[module]/[revision]/[artifact](-[classifier])-[revision].[ext]</code>. Making the revision into a sub-directory allows Ivy to use atomic publishing. Specifying the optional classifier was required for certain dependencies that define, for example, source code and javadoc artifacts as well as the compiled code – without the classifier specified, all three artifacts resolve incorrectly to the same file (which Ivy fortunately identifies as an error).</p>
<h3>Defining Dependencies</h3>
<p>When defining dependencies for a module I believe that the general goal should be to use the minimum set of dependencies that are required. To do this effectively requires that you use configurations, which are basically defined sets of dependencies for a given module. Typical configurations include compile, runtime, and test. If you do not define the configuration(s) you want from a third-party module then Ivy defaults to pulling in all dependencies. For a third-party library like Spring which defines a large number of optional dependencies (in a configuration appropriately called "optional") this will result in pulling in a large number of jars that you simply do not require to compile or even run your code.</p>
<p>Should you explicitly define all your dependencies or automatically pull in transitive dependencies? One of the whole points of using a dependency management system like Ivy is to handle transitive dependencies, so I am a fan of using them. If you want to be aware of all the dependencies that are pulled in, you can produce a report using the <a href="http://ant.apache.org/ivy/history/2.1.0-rc1/use/report.html">Ivy Report Ant task</a> that lists all the resolved dependencies for a module. </p>
<h3>Conclusion</h3>
<p>If you use Ant for your builds then I highly recommend using Ivy to manage dependencies. For an example Ant+Ivy build check out the <em>Java Examples</em> project available for download from the <a href="http://www.basilv.com/psd/software">Software</a> page.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2009/using-ivy-to-manage-build-dependencies/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why You Should Be Using FindBugs</title>
		<link>http://www.basilv.com/psd/blog/2009/why-you-should-be-using-findbugs</link>
		<comments>http://www.basilv.com/psd/blog/2009/why-you-should-be-using-findbugs#comments</comments>
		<pubDate>Mon, 02 Mar 2009 14:35:48 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[defects]]></category>
		<category><![CDATA[FindBugs]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[quality]]></category>
		<category><![CDATA[software development]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=284</guid>
		<description><![CDATA[Build automation has been the theme of my recent learning activities, so when I came across multiple positive references to a tool called FindBugs I decided to give it a try. My conclusion: FindBugs is worth using on all Java projects. Read below for the details. FindBugs is a Java static analysis tool that scans [...]]]></description>
			<content:encoded><![CDATA[<p>Build automation has been the theme of my recent <a href="http://www.basilv.com/psd/blog/2006/personal-learning-by-doing">learning activities</a>, so when I came across multiple positive references to a tool called <a href="http://findbugs.sourceforge.net/">FindBugs</a> I decided to give it a try. My conclusion: FindBugs is worth using on all Java projects. Read below for the details.</p>
<p>FindBugs is a Java static analysis tool that scans compiled java code for potential defects and bad programming practices. Think of it as the Java compiler on steroids: it operates in roughly the same fashion but reports on a much larger set of errors and warnings. Static analysis makes a great complement to <a href="http://www.basilv.com/psd/blog/2009/java-unit-testing-tutorial">automated unit tests</a>. Unit tests require effort to write, targets a specific piece of code, but can verify application-specific functionality. Static analysis requires no effort to write (beyond initial setup), targets the entire code base, but can only verify general code constructs. At least, that's the theory. How does it work in practice?</p>
<p>FindBugs supports a number of different ways of being used: command line, Swing GUI, integration into automated builds (i.e. via an Ant task and Hudson plugin), and Eclipse plugin. I decided to go with the plugin, and installation was as easy as adding the update site <a href="http://findbugs.cs.umd.edu/eclipse">http://findbugs.cs.umd.edu/eclipse</a> and installing it. Well, actually there were two gotchas. First, you need to be running Eclipse version 3.3 or greater for the plugin to work – RAD version 7 will not work. Second, you need to fully restart Eclipse after installing the plugin. I made the mistake of choosing the option to activate the plugin without doing a restart, which left portions of the plugin not working. It also seemed like you must bring up the Bug Explorer and Bug Details views, then restart Eclipse, in order to get those views working properly.</p>
<p>I used the <a href="http://findbugs.sourceforge.net/manual/index.html">FindBugs manual</a> to get started. I selected my <a href="http://www.basilv.com/psd/blog/2009/time-reporter-version-20-available">Time Reporter</a> project to be the first guinea pig and ran FindBugs on it. I keep my <a href="http://www.basilv.com/psd/blog/2007/why-you-should-polish-your-code">code well-polished</a> and well-tested with most Eclipse warnings turned on so I was not expecting FindBugs to turn up anything major. As I scanned the relatively small list of issues (under 30), I was surprised to see an actual defect! It actually took me a few moments of staring at it to find the problem. See the screen shot below.</p>
<p><a href="http://www.basilv.com/psd/wp-content/uploads/2009/02/findbugscaughterror.png"><img src="http://www.basilv.com/psd/wp-content/uploads/2009/02/findbugscaughterror.png" alt="" title="FindBugs finding a defect in Eclipse" class="alignnone size-medium wp-image-285" /></a></p>
<p>It turned out this same defect occurred elsewhere in the code. FindBugs also identified cases of bad error handling that I would classify as defects: I was improperly ignoring return values from method calls like <code>File.delete()</code> or <code>File.mkdir()</code>. Most of these serious issues were in test code rather than application code, which made me feel a little better (but not much).</p>
<p>I fixed all the issues reported by FindBugs that I agreed with, turned off one FindBugs warning I did not agree with at all, and was then left with a small number of false positives – incorrect warnings about code that was actually correct. My preferred approach to compiler warnings is to have none in the code base. This is based on the fact that if your code base has existing warnings that should be ignored then it becomes very difficult to tell when you write some code that produces a warning that should instead be fixed. People become blind to all warnings if there are always some present. Warnings should be produced as part of the developer's regular process (i.e. writing code) rather than requiring an extra step. It was trivial to configure FindBugs to run automatically, but how to get rid of the unwanted warnings? </p>
<p>Eclipse warnings can be eliminated by using the Java 5 annotation <code>@SuppressWarning</code>, but FindBugs does not appear to support this annotation (or if it does I could not successfully determine what text must be supplied to the annotation to ignore the warning). I found some hints on the web that FindBugs does have the ability to ignore specific warnings, but it appears this feature has only been implemented in the Swing GUI and not in the Eclipse plugin. After further investigation I found a solution. I exported the current set of project warnings to an XML file, and then configured FindBugs to use that XML file as a baseline of warnings to ignore. This causes FindBugs to only report issues not in the baseline, leaving me with an empty list of FindBugs warnings – for now at least.</p>
<p>One annoying limitation of the FindBugs Eclipse plugin is that all configuration can only be done on a per-project basis. Unlike most other Eclipse functionality with global configuration that can be overridden on a per-project basis, FindBugs must be enabled and configured individually for each project. There were a few other wrinkles with the FindBugs Eclipse plugin. My general impression is that the plugin is still in a beta state, lagging behind the functionality offered by the FindBug Swing GUI. </p>
<p>Next I tried including FindBug as part of a continuous integration build running in <a href="https://hudson.dev.java.net/">Hudson</a>. It was fairly easy to configure the Ant build to execute FindBugs on the project: the only snag was needing to allocate more memory for the JVM. Installing and configuring the FindBugs plugin for Hudson was likewise straight-forward, and resulted in a nice set of pages for viewing the trends and details regarding the FindBugs warnings. The big issue came when I wanted to filter out (exclude) all the warnings I did not want to fix. After much investigation and trial and error, I discovered that if I used the FindBug Swing GUI to create an exclude list, I could then configure the ant build to use that list as an exclude filter. Using the filter created by the Eclipse plugin did not seem to work. The FindBugs documentation concerning this was rather poor, but I did see a statement admitting that filter support was a bit messed up across the various FindBugs tools, and it sounds like this area will be targeted for improvement in the next year.</p>
<p>Despite these tooling problems, the ease with which FindBugs finds defects makes it definitely worthwhile to use on all Java projects. When I turned FindBugs loose against the code base of a reasonably-sized production application, it found 5 definite defects, 14 cases that were either potential defects or extremely bad coding style, and many other warnings (I didn't bother to count, but probably over 100) that were worth investigating and often worth fixing.</p>
<p>My conclusion from this is that using FindBugs is definitely worthwhile. I plan to roll it out to all my Java projects and integrate it into the automated builds so that the FindBugs results are also available from the continuous integration server. If you plan to adopt FindBugs then I recommend checking out some <a href="http://code.google.com/p/findbugs-tutorials/">FindBugs tutorials</a>. If you want to promote the use of FindBugs to your coworkers or management then I'll point out that FindBugs is a corporate standard at both Google and eBay and eBay reports that "using 2 developers to audit/review FindBugs warnings was 10 times more effective at finding P1 bugs than using two testers" (<a href="http://findbugs-tutorials.googlecode.com/files/UFIA-intro.pdf">http://findbugs-tutorials.googlecode.com/files/UFIA-intro.pdf</a>).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2009/why-you-should-be-using-findbugs/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Time Reporter Version 2.0 Available</title>
		<link>http://www.basilv.com/psd/blog/2009/time-reporter-version-20-available</link>
		<comments>http://www.basilv.com/psd/blog/2009/time-reporter-version-20-available#comments</comments>
		<pubDate>Sun, 01 Feb 2009 17:37:18 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[miscellaneous]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[unit testing]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=276</guid>
		<description><![CDATA[I have just released version 2.0 of my Time Reporter utility. It is available for download from my Software page. The major change in this release is added support for aggregated reporting across different task categories, which I call rollup groups. This required expanding the categories of types to three: base tasks, rollup tasks, and [...]]]></description>
			<content:encoded><![CDATA[<p>I have just released version 2.0 of my Time Reporter utility. It is available for download from my <a href="http://www.basilv.com/psd/software">Software</a> page. </p>
<p>The major change in this release is added support for aggregated reporting across different task categories, which I call rollup groups. This required expanding the categories of types to three: base tasks, rollup tasks, and aliases. This led to significant changes to the format of the task definitions file. These changes are backwards compatible: a version 1.X task definitions file will be interpreted as mapping aliases to base tasks. The report format was changed slightly - times for aliases are not reported, and the period report section is revised with the inclusion of the aggregated times for the rollup tasks in each rollup group. For more details see the updated user manual supplied as part of the release.</p>
<h3>Software Development Lessons Learned</h3>
<p>Once again I was reminded of the importance of careful testing. Despite a thorough <a href="http://www.basilv.com/psd/blog/2009/java-unit-testing-tutorial">suite of unit tests</a>, I was embarrassed to discover that my manual execution of the example files provided in the release failed due to a defect. This brought to my awareness several gaps in my testing: I was not automatically testing the example files, I had no realistic end-to-end automated system test, and my unit tests were obviously missing some scenarios. I spent some time correcting these gaps.</p>
<p>Believing I was now finished, I prepared my first beta release and put it to use. I quickly discovered deficiencies and even a defect as I iterated through a few beta releases to get to this final 2.0 release. I found it interesting that this release pattern matches what I described in my article <a href="http://www.basilv.com/psd/blog/2008/cyclic-incremental-growth-in-software-systems">Cyclic Incremental Growth in Software Systems</a> (assuming that the beta releases are counted as actual releases). Hopefully I won't discover the need to make a 2.0.1 release.</p>
<p><strong>Update February 21, 2009:</strong> I just released version 2.0.1 to fix some defects in error handling when trying to parse invalid dates. Lessons learned: I need to remember to test realistic invalid input for parsers and I need to be more paranoid about potentially null references.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2009/time-reporter-version-20-available/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Resume Calculator</title>
		<link>http://www.basilv.com/psd/blog/2008/resume-calculator</link>
		<comments>http://www.basilv.com/psd/blog/2008/resume-calculator#comments</comments>
		<pubDate>Mon, 15 Dec 2008 00:27:53 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[tools]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=218</guid>
		<description><![CDATA[I have added a new software utility called Resume Calculator to my Software page. Resume Calculator reads resumes in XML format and calculates the total months and years of experience across specified resume entries. This is useful for responding to formal requests for proposal that require named resources to specify years of experience across various [...]]]></description>
			<content:encoded><![CDATA[<p>I have added a new software utility called <strong>Resume Calculator</strong> to my <a href="http://www.basilv.com/psd/software">Software</a> page. Resume Calculator reads resumes in XML format and calculates the total months and years of experience across specified resume entries. This is useful for responding to formal requests for proposal that require named resources to specify years of experience across various categories. </p>
<h3>Using Resume Calculator</h3>
<p>Resume Calculator is a Java program that is executed on the command-line. A sample resume file is listed below:</p>
<pre class="prettyprint">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;resume name="Foo Bar"&gt;
  &lt;entries&gt;
    &lt;entry id="1" summary="Zoo Project" interval="2006-2007"/&gt;
    &lt;entry id="2" summary="Team Yak" interval="May, 2007 - Present"/&gt;
    &lt;entry id="Baz Project" summary="Team Lead for Baz" interval="Jan, 2008 - Mar, 2008"/&gt;
  &lt;/entries&gt;
&lt;/resume&gt;
</pre>
<p>Executing Resume Calculator against this file to calculate the duration of entries "1" and "Baz Project" produces the following output:</p>
<pre>
Resume Calculator
Copyright 2008 by Basil Vandegriend.  All rights reserved.

Executed on: 8-Dec-2008 6:29:45 AM
Working directory: C:\Dev\Java\ResumeCalculator\dist\release\example

Using resume "C:\Dev\Java\ResumeCalculator\dist\release\example\sampleResume.xml".
Calculating for "Foo Bar" the duration of the resume entries:
1: Zoo Project
Baz Project: Team Lead for Baz
<strong>Duration is 14.0 months or 1.2 years.</strong>

Finished execution successfully.
</pre>
<p>More details on how to use Resume Calculator and the full format of the XML file are specified in the user manual included with the distribution.</p>
<h3>Technical Details</h3>
<p>Resume Calculator uses <a href="https://jaxb.dev.java.net/">JAXB</a> for parsing XML (which I just <a href="http://www.basilv.com/psd/blog/2008/simple-xml-parsing-using-jaxb">wrote about</a>). I used the <a href="http://joda-time.sourceforge.net/">Joda Time</a> library for manipulating dates – it is far superior to the standard Java classes. The Joda library, however, does not include logic for calculating the duration of multiple intervals of time so I had to code that functionality myself. This proved to be an interesting algorithm to write – thank goodness for unit tests. The source code for Resume Calculator is included in the distribution if you want to learn more.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2008/resume-calculator/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Time Reporter Version 1.1 Available</title>
		<link>http://www.basilv.com/psd/blog/2008/time-reporter-version-11-available</link>
		<comments>http://www.basilv.com/psd/blog/2008/time-reporter-version-11-available#comments</comments>
		<pubDate>Mon, 08 Sep 2008 21:37:07 +0000</pubDate>
		<dc:creator>Basil Vandegriend</dc:creator>
				<category><![CDATA[miscellaneous]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://www.basilv.com/psd/?p=154</guid>
		<description><![CDATA[I have just released version 1.1 of my Time Reporter utility. It is available for download from my Software page. The significant changes in this release are: I added support for time adjustments by which you can explicitly specify an amount of time (positive or negative) to add to a task. I improved handling of [...]]]></description>
			<content:encoded><![CDATA[<p>I have just released version 1.1 of my Time Reporter utility. It is available for download from my <a href="http://www.basilv.com/psd/software">Software</a> page. The significant changes in this release are:</p>
<ul>
<li>I added support for time adjustments by which you can explicitly specify an amount of time (positive or negative) to add to a task.</li>
<li>I improved handling of parse errors: parsing continues when an error is detected,<br />
  and the full list of parse errors is returned at the end.</li>
<li>I changed the rounding algorithm to round up from 9 minutes instead of 10 (to 15 minutes).</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.basilv.com/psd/blog/2008/time-reporter-version-11-available/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

