March 2005 Archives

Exiting on Error in a Shell Script

| No Comments

This is an embarrassing story. I had a bourne shell build script. In it I would perform various checkout and compilation steps, and finally copy the end result to a directory for deployment. It ran under Cygwin and when it worked, all was well.

When one of the build script steps did not succeed, the script kept running regardless. Unless I had happened to see an error message scroll by in the terminal window, I might miss a broken build. (I should mention that the build script takes a while to run and generates voluminous output.) I did miss broken builds. I need not elaborate on how painful this experience was.

The solution I ended up with is simple. The Cygwin shell is really bash, and bash has a nice error trapping feature.

  • changed #! /bin/sh to #! /bin/bash
  • added the following at the stop of my script
function error_exit {
 echo "exiting because of error"
 exit 1
}
trap error_exit ERR

Now I no longer need to babysit the build script. Three cheers for the Bourne Again Shell!

Laurent Bossavit's Incipient(thoughts): essay on

Laurent Bossavit's Incipient(thoughts): essay on defining risk reminds me of some discussion I have read about risk in the context of finance. The risk of a portfolio of investments is often measured in terms of volatility compared to some reference portfolio (the so-called beta). Usually, a portfolio with a higher average return also has a higher variance, which means it more likely to be higher or lower than you expect.

In software, the type of risk that comes closest is the risk of using new, unproven technology. In an ideal world, that would be the only risk that mattered. In the real world, projects often fail for reasons that have nothing to do with technology per se. In the worst cases, an IT project seems to amplify whatever dysfunction exists in the host organization.

Portfolio management as a tool for risk mitigation should work for technology risk. However, it can't help with the risk that the normal risks that cause a project to fail:

  • doesn't meet the deadline
  • overruns its budget
  • doesn't deliver what was expected
  • delivers software to spec that turns out to be less useful than anticipated

What is Design

Laurent Bossavit has written one of his thought-provoking articles, this time on design.

Anyone who has worked with any of the CASE tools knows the problem: you create your initial design using the tool, quite possibly UML diagrams. The first step of coding can be easy: press a button and code gets generated. Within a short time, however, programmers do their work. Questions arise that weren't considered before and the answers to them affect the source code directly. There are details and addtional features that were never in the initial design. Nearly all commercial CASE tools boast the ability to round-trip, that is to automatically update their design models based o nthe code. They never seem to work.

This isn't because of programmer laziness (thought that is a factor). David Parnas famously called UML the undefined modeling language. Compared to code, any design language is ambiguous. Not only that, but some things that really matter are most naturally conveyed using a programming language.

To me, design is all about making decisions and communicating those decisions. Usually it's considered a highly technical task, the responsibility of the development team. Having read Eric Evans' book, I believe it can be useful (sometimes essential) to share responsibility for design with domain experts.

In some ways, the idea of a Ubiquitous Language comes close to a universal design or, better, a way of talking about design. If the application is to be useful in its business domain, it really helps to have a coherent way of talking about what it does in the language of the business domain.

On the other hand, there are technical decisions to be made that fall outside the scope of the business domain. Those decisions are best expressed in different languages.

All of which leads me to think that there can never really be one design. Depending on who is talking and at what level of detail, the needs are different. Some people are more comfortable with visual diagrams than text and vice versa. (I tend to prefer text, mostly because I have yet to find software that makes editing diagrams with a mouse anything less than painful.) Programmers like source code; domain experts are unlikely to understand it.

The touchiest question of all is who gets to do design. The agile answer is usually the whole team. That means devolving power to the lowest level, so that the most junior programmer has a say in decisions that affect the success or failure of the project. It is asking quite a lot of the team to pull together to make good decisions and hold by them.

However, the alternative of decisions handed down from on-high, from analysts or architects or even team leads doesn't necessarily work all that well. For one thing, it's bad for morale. For another, if the decision doesn't take all relevant factors into consideration, it may have to be worked around or even subverted in order to get anything working at all. Inflexible decisions made at the start of a project pose serious risks.

A computer program embodies design decisions in a way that no other document can. 1 Decisions will be made at the coalface, even if nothing has been specified at a higher level. If earlier decisions are unworkable, they may be quietly overturned in the code.

[1]That's a reason why unit tests are popular as design documents: they are highly specific, relevant and clear. A unit test suite is as like any other bad design document, but it can be seen as such by applying normal coding standards. A team that can write competent code can write competent unit tests. (That's not always the true of UML or English for that matter.)

Cheap SSL Certificates and Java

| No Comments

... don't always go so well together.

We recently had an SSL certificate expire. Getting a new one was a bit of an adventure (best told another time). In brief, we got a cheap SSL cert from godaddy.

They claim 99% browser recognition and that's true at least for recent versions of Firefox and Internet Explorer. It's not true for most installations of the Java runtime.

I didn't record the details, but some versions of the JRE throw a nasty exception. At least one version was bit more friendly, at least asking the user if they wanted to continue although the certificate was not trusted. Only the 1.5.0_02 update fixes the issue.

Quick tip: when using Java Web Start, a plus sign in the JNLP file can help.

  <j2se version="1.5+"/>
  <j2se version="1.4+"/>

This indicates that a recent of 1.5 version (or newer) is ideal but a recent version of 1.4 will do in a pinch.

Binary Output Using Java Inside ColdFusion

| No Comments

Banged my head against the wall a bit with this question a bit today: how to write binary output with ColdFusion?

The obvious choice would be to store the binary content in a file and use ColdFusion's cffile action = "readBinary" tag. However, there is this ominous note in Macromedia's documentation:

Note: This action reads the file into a variable in the local Variables scope. It is not intended for use with large files, such as logs, because they can bring down the server.

I could work around this by writing some custom Java code to read/generate the binary output. Which brought me to the next question: how do I get a suitable filehandle into my Java code?

After some searching around, the light dawned. ColdFusion MX runs in a servlet container (JRun), so there must be a way to get at the servlet environment. Indeed, there is an escape hatch: GetPageContext(). The PageContext it returns seems quite similar to the JSP equivalent.

My proof-of-concept code ended up looking something like the following:

    <cfobject action="create" type="java" class="bla.foo.JavaObject" name="javaObject">
    <cfscript>
    context = getPageContext();
    context.setFlushOutput(false);
    response = context.getResponse().getResponse();
    out = response.getOutputStream();
    javaObject.write(out);
    out.flush();
    out.close();
    </cfscript>

[ Late update: my example code now works properly after I put getResponse() in twice as suggested in Christian Cantrell's weblog entry on the subject. ]

[ Late update the second: in order to avoid the scary error message

Application server is busy. Either there are too many concurrent requests or the server still is starting up.

it helps to close the output. The example code is now much more close to the Cantrell version. ]