I haven't posted here for a few days, because I've been completely engrossed in trying to get some software working. Long days, short nights, too much caffeine - I'm sure you know the drill. It's become a geek cliché.
There are two things that are somewhat remarkable about this, though. The first is that I thought I'd put this style of development behind me. Since thinking though my Golden Rules of Stress-Free programming and learning Java, then later discovering Extreme Programming and Test-Driven Development, I've hardly ever had to pull one of these "lost weekend" sessions.
The second remarkable point is the technology I have been using. As I mentioned before, I was coding in C to run on MSDOS. Well, at least at the start I was. Pretty soon, though, I got so fed up with the clumsy and largely untestable nature of writing DOS interrupt handling code in C, I changed down to an even lower gear and started coding in 8086 assembler.
All of this gave me a very strange feeling, a kind of technical flashback. Things I'd thought I'd forgotten came seeping back. There is defineitely a purity to writing in assembler. There's no second-guessing what the compiler will do with what you have written. There's no confusion over oveloaded or overriden names. There's no murmurs about "memory leaks" or garbage collection overheads. What you write, the computer does. Simple and clean.
One thing was different this time, though. The last time I messed with this stuff, there wasn't an internet! I've become so dependent on the web for resources that I found myself getting quite grumpy when I couldn't find what I wanted. In the Java world, everything is on the internet. Every spec, miles of source code, documents and tutorials until you get sick of them. In the twilight world of DOS programming, information is either proprietary (for sale to embedded and legacy developers), fragmentary and incomplete, or never made it on to the net in the first place. I even had to resort to faded books and dusty floppy discs.
It's not all bad news, though. The technology is old enough that some of the good software from the first time around is now available for download. I have done all the C development using the retro but very effective Open Watcom C/C++ compiler. After a 10 year gap, I went looking for my favourite assembler - Eric Iverson's shareware A86 - and found to my delight that not only is it still available, but it has even been upgraded several times. It's a good job, because the copy I bought and registered all those years ago is on a 5-1/4" disk, which I have no way of reading. I wonder if he'll honor my registration and let me have a new copy? :)
The other thing that astonished me is the speed. On my normal workstation both C compilation and A86 Assembly are effectively instant. No tedious startups, no fluttering of the disk drive searching classpaths. And the programs I have produced take near enough no time or space at all.
Now, time to breathe a huge sigh of relief, and get down to all the other jobs I'd pushed out of the way to get this done...
I have recently had the nostalgic pleasure of writing some software in C, running under DOS) to read from a serial port. After the first stages of tinkering with it I began to really miss the power of Test Driven Development. Now I'm sure I'm addicted!
I thought for a while of trying to write some sort of test harness to run my code on the target machine, bu this has several problems. The major problem is simply the time it would take. I can't afford to spend a week or so building/testing a test harness when the code really needs to be delivered by then. I have looked for JUnit equivalents in C/C++ before, and never found any that were at all portable, so that chance of getting someone else's test framework running on this slice of history seems very slim. Other problems include my general unfamiliarity with the (very neat and quick, but different) OpenWatcom development environment and compiler I'm using, and the non-OO nature of C (which would imply quite a different architecture to JUnit and chums.)
However, a few days ago I had a flash of inspiration. It happened because I suddenly realized that when I run thid DOS .COM executable on my Windows 2000 machine, it actually runs it in a resource constrained "dos box", not a real take-over-the-whole-machine DOS installation at all. So I'm able to run my software on this machine, and run other, "full fat" software at the same time. I'd already bought a "nullmodem" cross-connected serial cable and tried the software on a remote machine using HyperTerminal. The next step was to connect the nullmodem lead between the two com ports on the back of the development PC and try running the DOS box and HyperTerminal on the same machine at the same time. Flushed with this success, I then did a quick hack to the DOS software to recognize a command-line parameter to switch from the default "receive" mode to a more active "transmit mode. I set them both running and happily watched my sequence of characters wander along the serial lead at a stately 1200 baud from one DOS box to another. Now, I was really making progress.
Comfortable that I could drive my software from the same machine over a cable, I now set out to set things up using a powerful test framework that I am very familiar with - JUnit. Java (and thus JUnit) already has the features to test things lke the existence and content of files, so that part of the project will be easy. What Java does not have "out of the box" is the ability to write and read serial ports. I vaguely recalled hearing of a Java "comms" API, and few minutes searching at Sun found it. I downloaded the Windows version, unzipped it and got started.
Or at least, I tried to get started. Maybe I've had a sheltered life, but I found the javax.comm API one of the strangest Java installs I've had to do in recent years:
The installation documents assume you are using Java 1.1 (yikes!). Admittedly, there is an addendum about using with the "new" beta version of Java 1.2, but it's not immediately obvious that that is the place to look for the real installation instructions.
As well as adding comm.jar to the class path, you also need to put a .dll file in JAVA_HOME/jre/bin (not JAVA_HOME/bin, as suggested in the main install docs), and add a supplied properties file to JAVA_HOME/jre/lib. If you don't do the .dll and properties files right (for example, by following the obvious installation instructions) the code compiles and appears to work, but just thinks the machine has no ports.
The supplied example code seems to have been written by someone just learning Java. It's very poor, and doesn't even take advantage of the features of the comm API it's supposed to be demonstrating. For example, the API provides a neat callback mechanism to notify your code when events happen (such as when an output buffer is empty, indicating that the supplied data has been sent). The serial writing example enables this feature, but then never registers a listener and instead hard-codes a two second wait to "be sure data is xferred before closing". Yuck. The code also commits the cardinal sin of catching exceptions and just "eating" them in an empty catch block. This is inexcusible in a code example which people will use to check if the system has been installed correctly.
I could find no API documentation on the web site, just a confusing maze of links which all eventually end up back at the same, (largely useless) page. I did find some API docs in the download, but they were generated using the old JavaDoc, without frames and font/layout tidyups, so they are very clumsy to navigate.
Despite all this, I did eventually get things going. To aid my unit testing I put together a simple serial port writing helper class. It only does the things I need right now, and I can see that it might hit problems If I try to run too many tests in too short a time (because of the asynchronous nature of port open and close), but it does allow me to drive my DOS software from JUnit.
package tests;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.TooManyListenersException;
import javax.comm.CommPortIdentifier;
import javax.comm.PortInUseException;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import javax.comm.UnsupportedCommOperationException;
class CloseWhenEmptyListener implements SerialPortEventListener
{
private SerialPort port;
public CloseWhenEmptyListener(SerialPort port)
{
this.port = port;
}
public void serialEvent(SerialPortEvent event)
{
if (event.getEventType() == SerialPortEvent.OUTPUT_BUFFER_EMPTY)
{
port.close();
}
}
}
public class CommPort
{
private int baud;
private CommPortIdentifier port;
private static List findSerialPorts()
{
List ports = null;
if (ports == null)
{
ports = new ArrayList();
Enumeration portList = CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements())
{
CommPortIdentifier port = (CommPortIdentifier) portList.nextElement();
if (port.getPortType() == CommPortIdentifier.PORT_SERIAL)
{
ports.add(port);
}
}
}
return ports;
}
public static CommPortIdentifier findPort(String name)
{
CommPortIdentifier ret = null;
List ports = findSerialPorts();
Iterator it = ports.iterator();
while (it.hasNext())
{
CommPortIdentifier port = (CommPortIdentifier)it.next();
if (name.equalsIgnoreCase(port.getName()))
{
ret = port;
break;
}
}
return ret;
}
public CommPort(String name, int baud)
{
this.port = findPort(name);
this.baud = baud;
}
public void write(String text)
throws IOException, PortInUseException,
UnsupportedCommOperationException, TooManyListenersException
{
SerialPort serialPort = (SerialPort) port.open("CommPort", 2000);
serialPort.setSerialPortParams(baud,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
OutputStream outputStream = serialPort.getOutputStream();
serialPort.addEventListener(new CloseWhenEmptyListener(serialPort));
serialPort.notifyOnOutputEmpty(true);
outputStream.write(text.getBytes());
}
}
A bizarre thought occurred to me a few days ago. If my career were a video I'd think someone had accidentally sat on the remote!
Back in 2002 I had virtually no work at all. This was a bad time, Career and income were on "pause". It was costing a lot to keep myself and my family going without money coming in, and we nearly ran out completely. Eventually, after a year or so, I got another Java contract maintaining a large, clumsy and largely inept web application at BT - a different project, but strangely similar to the one I'd been working on before the crash.
Development on that project came to an end (maintainance was carried off to Mumbai), and I was back looking for work again. What came next surprised me - I was approached by someone I had last worked with in 1998, and asked to do some work on the current release of some software I had been involved with back on my first contract at BT in 1995. At least the project is now mostly Java, although the design and architecture still has some of that "mid 90's" feel to it. That work has now finished (for the moment, at least), and I am now working on software in C (not even C++) to drive serial port devices on machines running MS-DOS. This is disturbingly like some work I did around 1990.
If this trend continues, I'm looking forward to working with the GEM UI/Windowing system on an Atari ST, which I did from 1986-1988, random landscape simulations on a VAX minicomputer, like I did at university in 1985-86, or even Basic on a BBC micro or a TRS-80.
Let me explain. I have been using Linux for years. I have at least four machines here now that run Linux, and accounts on another half-dozen or so around the internet.
But I have simply never seen the attraction of Linux "desktop" or "GUI" software. I access all these machines using things like telnet, ssh, FTP, HTTP, or SAMBA. On the odd occasion that I have used one of the X GUI frontends on someone else's machine it's felt like someone has superglued all my fingers together and dipped them in treacle. It's not that I disklike GUI software completely - I use other systems that way, but it just seems so pointless with Linux.
Getting to the meat of my rant, I'm finding that there seems to be so much emphasis put on X interfaces, fancy GUI features and Window-manager wars that the core benefits of the system are in real danger of being lost. The last time I looked at a commercial Linux distro I was appalled that so much of the setup and confuguration assumed the use of X. Even the "server" installs seem to fill the disk with GUI fluff, unable to imagine that I don't want it.
I'm likely to be configuring and installing a new general purpose, non-GUI Linux box soon, and I'm interested in any hints and recommendations for distributions that offer up-to-date kernels and stuff, don't force me to install or unpick all those media players and screen clocks, and (most of all) don't need a GUI to configure hardware and low-level config support.
Can anyone help?
I've been involved in many open software projects over the years. Some have been all my own work, some have been team efforts. In all cases, one of the first things to cause problems was the choice of a project name. It's a remarkably tricky process, and lots of projects seem to have fallen into one of the traps. With that in mind, here is Frank's Guide to Naming your Project:
Do your research first. Search for similar projects, think about what keywords worked, and what names people have chosen for your "competition". Unless your project is a fork or spin-off from another one, you should really try and make sure that you choose a name that's visibly and conceptually different from other similar projects. If you are designing the next big thing in build systems to rival the popular Ant, think twice before choosing "Amt", or "Insect". Imagine that in five years time you are in a battle for "mindshare" - do you want to remind everyone of other choices every time they see your project name?
Don't include the technology in the name. I know it's tempting; your whole reason for starting the project was to show that you can make a powerful application server in JavaScript for a mobile phone, but that will shine through in the code, the documents, and the description. Code, documents and description are expected to change (probably many times) during the life of a project. If you decide to broaden the scope of your mobile app server to include organizer devices as well as phones, or if you decide that ECMAScript is a more politically correct name, you need to be free to change and adapt. The single hardest thing to change is the project name - don't tie it down.
Don't use the name of another project. You'd think this would be common sense, yet I have seen several such clashes. Search for any name you are considering and make sure it's not alreay taken. Even some backwater website with no updates in three years could still confuse your users. And think how much worse it would be if that other project got more popular than yours.
Checkout domain names first. If your project become popular you are going to want a top-level web site for it. You don't want to find you are in a fight with a European frozen food manufacturer for that perfect domain. If you are serious about the project, find a vacant domain and grab it now. Make sure to also check out the same name with different suffixes, though. If whatever.com and whatever.net are "adult" sites, it may not be a good idea to take whatever.org for your geek software.
Make sure people can say it. Don't underestimate the number of times a project might be mentioned over the phone or in a meeting. If the spelling and the pronunciation is obvious you have a much better chance of being remembered correctly.
Don't use a dictionary word or a person's name. It's astonishingly compelling. I know I've done it. It's so tempting to take a twist on the idea of a project, and find a regular word that fits. I've got a small knowledge-base called inkling, a content management system called barrel, and a site portal called Wayne. All of these are bad names, as you'll see if you try a search on google - can't see my project there :(
Don't use abbreviations. If you can't think of a single-word name for your project, please don't be tempted to use an abbreviation or acronym which breaks any of the above rules, especially if you "forget" that it was once an acronym and treat it as a real name. A classic example of this is Jess, the Java rule engine. A great project, but really hard to find on Google.
Don't EVER use "stealth" words. Stealth words are words so common that they slip in "under the radar" of the search engines. Search engines don't even bother to index them, because they are found in almost every page on the internet. For this reason, they are the worst possible names for projects. At least with "Jess" you can find it if you add enough qualifiers, but imagine a project "Application-Neutral Deployment", known by the developers as "AND". However hard you try, you are not going to find it with regular search engines; "and" is an ultra-common stealth word, deliberately ignored in searches.
Recently, I think I have been choosing some better names. Examples include my web collaboration software "Friki" (gets top place in a google search, but the domain name was already taken), and a collection of useful stuff "Stringtree" (currently second hit on google, but I got the domain). With a bit of thought, you too can choose a project name that is easy to find, easy to get a domain for, easy to remember, and easy to grow.
Finally, don't forget to use the name sensibly. There is a lot of spam about at the moment which uses apparently random collections of words to fool "learning" spam filters. Be careful that emails about your projects don't get mistaken for this stuff. I'm on a mailing list for some Jini-related software and I often get messages with surreal subject lines such as "persistent outrigger". I'm sure some of these have just gone direct to the trash.
I hope these suggestions have made a bit of sense, and if even one project team considers them and helps reduce the proportion of dumb names at sourceforge, I'll be happy.
One thing that particularly resonated with me was where Rowntree discusses different forms of diagrams. Here's a snippet:
In this kind of diagram, as David Hawkridge says: "lines connect words, reflecting connections of some kind without revealing exactly what. Moreover, many other lines could be added to show additional connections".
Furthermore, he points out that the map of educational technology "could be drawn differently ... by other educational technologists". I bring your attention to this perhaps obvious remark because many people setting out to draw a concept map seem to get obsessed with uncovering the "true, underlying structure" of the subject.
Even if such a structure exists, there is no need for that degree of dedication. Drawing such diagrams is a personal and subjective activity. It's purpose is simply to help you sort out your own understanding about how the concepts within your field connect up.So long as you find it helpful in your own planning, there is no need to worry that others might have mapped the territory differently.
This quote could just as well apply to the use of the UML in software development. I'm sure we've all met overcomplex diagrams, and been tempted to add more and more stuff in the hope of producing "perfect" pictures. UML pundit Martin Fowler has been known to encourage quick and loose, but effective use of UML.
Now I'm really looking forward to reading the rest of the book, in hope of other such.parallel insights.
Map made a slightly cryptic comment about "broiling" pebble. I still don't really understand what she was on about, but it did remind me of the doubly-appropriate story of stone soup.
Another pebble user Ryan mused back in October 2003 about why Simon decided on the name "pebble". Plenty of possibilities, but the stone soup metaphor is quite neat, as is the idea that a pebble is smooth and rocks a little.
Update. While I was writing this she went and added more to the post so it makes a little more sense. Underhand move, I reckon :)
It's another grand blogger tradition. After a handful of posts, I've felt the need to change the look and feel of the blog from the grey, compartmented look of the default pebble installation to something that suits me better.
I'm not proud, and I am keen to learn. So, if you like it, hate it, can't read it, or just don't care, please let me know.
In Uncontrolled Vocabularies, the redoubtable Map made mention of my compilable Haiku from yesterday. Thanks.
Unfortunately, she also offered a challenge: How about the public class Sonnet? This should keep Frank busy for a while.. I'll see what I can do.
In the meanwhile, here is a selection of a few Sonnets (and Sonnet-like) poems that I have written over the years:
In 1990, I took a course in English Language and Literature, which got me interested in some of the more precisely specified forms of poetry. Here's a Sonnet that I wrote for the course. I'm particularly fond of the fragmented "feet" of the Iambic Pentameter in the first stanza, which I feel echoes the "grainy patterns" and "half-deciphered faces".
Guard Duty Cold and cramped behind the only cover. Seeing patterns in the grainy star light. Half deciphered faces form in my sight: recent dead, a comrade or a lover. They might be here by dawn, and we must fight; and so I strain to scan the rocky ground, and start at every little movement sound, and wonder what will bring the end of night. A noise: the skitter of a tiny stone. My clammy skin anticipates defeat. My heart goes faster now with every beat, but fountains blood as blade cuts to the bone! Thrashing downward toward death from this attack, I stretch to reach my weapon. Fade to black.
Following that course, I had a vague idea of writing a "fantasy" novel, contrasting the songs of glorious victory with the gritty reality of the actual deeds. With that in mind, I tried for the oppsite end of the scale. In this one, I'm especially proud of the layered symbolism.
The Forging When Goroth, Eastfort's mighty Battle Lord heard evil demons clamour at the gate he called from Aurangrim the smith, a sword. A blade long, strong and sharp - a tool of fate. The smith, in knowledge of her sacred art, wrought with blazing iron and sorcerous charms. Her aching muscles pounded with her heart until, at last, the prize lay in her arms. Then Goroth, taking hold the tight-bound hide, swung with full might the blade flat to the stone. Blade, rock and mailed fist together cried - from flawless steel - a single joyous tone. And so he strode to teach both sword and hand the ways of battle, blood upon the land.
The next sample surprised me. I did a quick google search for "Frank Carver" sonnet and found one that I'd forgotten even writing. I wrote it in the context of a roleplaying game I was in at the time, set in the strange worlds of HP Lovecraft. You can read the whole article on page 12 of this digitised club magazine from 1993, but here's what I consider the most powerful of the poetry I wrote at the time:
What hope has mankind left with no more time, Where every breath is nine parts fetid smoke, And birdsong lost behind the engine’s whine. I can not even cry but only choke. A world of freaks, twisted, crushed in tiny cells, Sickly shown and sold for soulless mirth. The devil giggles, calls them to their hells, With dying flesh and heart they seek the earth. So now the time of joy and hope has gone. Who will weep to see what we have done?
Finally, not a Sonnet, but one that I quite like, nonetheless. I wrote this in 1999, in response to an ad for a "poetry for the internet" competition. Unfortunately, before I could submit it, I found that I was not eligible to enter. Sigh.
Flame As I look at his words I can feel, the hairs on the back of my neck. How could he be so stupid? How could he write so much dreck? I can't understand such a viewpoint. Who let him onto the 'net? Fuming, I scrabble an answer I'm ready to send it, I'm set... Then I notice a few silly letters, typed in unusual style. And I see, if I turn my head sideways, it almost, just, looks like a smile.I hope some of this has been of some small entertainment.
In his blog, Michael Ernest told some haiku, which reminded me...
Two weeks ago, as part of the PGCE (Postgraduate Certificate of Education) course I'm studying, some of the group presented their "microteach" sessions. In this context, a "microteach" is a short teaching session (15-20 minutes) on a subject of your choice. I'd already presented mine a few weeks before - an introduction to buying and selling on eBay, in the vague hope I might get a few sign-up referrals, but no luck there :(
Anyway, as well as two people who independently decided to teach us about British Sign Language, one decided to do a 15 minute lesson on Haiku. After an introduction to the form, some history and some examples, we got to have a go ourselves.
At last, a class where staring out the window and daydreaming is not just allowed - it's a vital part of the lesson :D
During this session I scribbled the following:
striding into college snowy pathways slip and crunch warm shoulders, cold ears
the snow clouds have gone a lonely pigeon wingbeats against the sharp wind
silent microteach upturned faces stare intent at Odette's fingers
But my favourite is still one I produced a few months ago in response to a thread at JavaRanch.com:
public class Poem {
public String toString() { return
"A Java Haiku" ; } }
And before you ask. Yes, it does compile and work. And yes, I did write a unit test:
void test() { assertTrue(
"A Java Haiku".equals(
new Poem().toString() ) ; } }
Programming in Haiku - how geeky is that?
Euxx writes I just complete over thousand lines of new code. Now it is probably ready for testing
Wow. I can't imagine running 10 or 100 lines of fresh code without having tested any of it, let alone 1000. I'd also hate to think how it is designed if there really is no way to test individual bits of this 1000 line monster.
I'm a great fan of unit testing, including test-driven development and the practices of Extreme Programming (XP). I try and develop unit tests for all the code I write.
Sometimes, of course, unit testing everything is simply not possible. On a project I'm working on at the moment I don't have access to the machines the final system will be running on, and only a sketchy idea of the input data my code will actually recieve. Sure, I have got a test suite to test that all my code does what I think it should do, but there are inevitably misunderstandings and hiccups when it runs on the real system.
Despite all this, the fault that irritates me most is one that I should, and could, easily have caught in my own testing. The doubly irritating part is that I got part way to detecting the fault before I delivered it, but then just got lazy.
In the example data are some integer timestamps, for example 1077797400. I did a little experiment:
Date timestamp = new Date(1077797400); System.out.println(timestamp);
The system has only been in existence for a few years, so when it printed out Tue Jan 13 12:23:17 GMT 1970 it seemed somewhat unlikely.
I got in touch with my client contact, and he told me that timestamps are stored in seconds, not milliseconds (as used by java.util.Date). "That's easy to fix, I thought. "What can go wrong with simply multiplying by 1000?".
If you are really sharp (or have faced this yourself recently), you should be able to guess the problem, already. Unfortunately, I didn't until I got client complaints about daft dates. My first assumption was that I had simply delivered the wrong code, but when I looked at it, there was my multiplication:
public static Date makeDate(int i)
{
Date ret = new Date(i * 1000);
return ret;
}
So I went back to my test code and added the multiplication, like I should have done in the first place:
Date timestamp = new Date(1077797400 * 1000); System.out.println(timestamp);
It printed out Mon Dec 29 06:30:08 GMT 1969. Multiplying by 1000 had made the same timestamp go back in time
I sure was baffled at the time, but something occurred to me in the middle of the night. First thing when I woke in the morning (well, after having a coffee, eating some breakfast, checking my mail and so on - I'm not that much of a geek) I added a single character to my test code, and got out the much more reasonable Thu Feb 26 12:10:00 GMT 2004.
Figured it out yet?
I added an 'L':
Date timestamp = new Date(1077797400 * 1000L); System.out.println(timestamp);
This forced the calculation into long arithmetic rather than sticking with integers, and allowed the result to increase rather than overflowing and "wrapping round" into a negative number. Once I realized, the answer was obvious and simple.
So, next time, when someone asks that question about "how do I know what I should test?", I'll remember this. Ten seconds of testing would have saved me the embarassment of client complaints after delivery and a restless night. Sounds like a good deal to me!
It's a long standing tradition, so I felt I had to join in.
I'm Frank Carver. I'm a "sheriff" at javaranch.com, a freelance Java programmer, a teacher at a local college, a father, a contributor to several open source projects, and so on. My definitive "home page" can be found at Frank Carver.
this is my first post in my "JavaRanch Radio" weblog. I'd imagine that future posts will be both occasional and episodic. Some may even be interesting. Don't hold your breath.
Thanks for taking the time to read this, anyway.