Saturday, September 26, 2009

Unit Tests, Heroes and Duct Tape

Recently, a friend twittered about an article by Joel Spolsky entitled The Duct Tape Programmer:
OMG, Spolsky is praising his hero--WHO DOESN'T LIKE UNIT TESTS! Can it be that Spolsky doesn't either?
I read the article and it could be that red flags go off in my head when I see generalities, or it could be because I was at a seminar on project management last week, or it could be that my outlook on things has changed in my old age, but I couldn't help but think of all the hidden assumptions.

Unit Tests

So, why do people write unit tests? What's the point? Are they just wasting their time? I mean, it's writing twice the code for the same functionality, right? Not quite. People write unit tests because unit tests are a useful tool that helps them accomplish one of their goals: to write reliable, maintainable software. How do unit tests obtain this? By having tests that show that the code does what it's supposed to do, they have confidence that the code continues to do what it should as changes are introduced because they can simply run the test suite to verify. And when tests that previously worked fail, they know they've introduced a bug in their changes and can quickly isolate and fix it.

The Test Driven Development (TDD) and Behavior Driven Development (BDD) people have brought these ideas to the front of the development cycle. If tests give you confidence in your code, why not write them first? Then as you develop your software, you can always and from the beginning have confidence that it does what it's supposed to do. The main difference between TDD and BDD is that with BDD the "tests" are expressed more in the language of the customer's problem domain than the language of the programmer. And thus there's more programmatic scaffolding to interpret the "tests". But the basic mechanisms are the same.

[It seems to me though that you had better pay really close attention to your design to avoid code churn where you may repeatedly write tests, then write implementations, but later delete both because that code ultimately didn't fit into your design. Sometimes you have to write code to vet aspects of a design before you know that's the design you're going to go with. This exploratory programming doesn't need tests up front IMHO]

In any case, at the end of the software project you have 2 sets of software: the software that you're going to provide to your customer and a set of unit tests that prove (to yourself and other programmers but not necessarily the customer) that the software does the things that it is supposed to do.

This is very similar to how scientific advancements are made. A scientist performs an experiment that gives some novel result. Then he publishes how he did it so that other scientists may reproduce his work. If others can not reproduce his work, then there may be something fishy going on or maybe the experiment was flawed in some way. If other people can reproduce his work, then our confidence in the validity of the experiment and its result grows. Unit tests are experimental proof that the software does what it is supposed to do (at least with regard to the things that are expressed as unit tests).

That's also why you find that code coverage tools are popular with people who write tests for their software. The tests may not exercise every bit of code in the system and a code coverage tool tells which subroutines or expressions or statements are executed. The more code that's exercised when running the tests, the more confidence that the entire software is operating as it should.

Having many unit tests that execute a high percentage of the code add up to show that statistically, the software performs as expected.

On Heroes

Spolsky's hero from the article is Jamie Zawinski (of xemacs and netscape fame) and is actually quoted as saying (in regards to unit tests) "Given a leisurely development pace, that’s certainly the way to go." So it's not so much that he doesn't like unit tests, as that he doesn't like unit tests for a particular type of development: get it out the door quick before the deadline.

But that's also a very short-sighted view of software development.

Does the programmer's obligation to the software end upon delivery to the customer? Sometimes. If, like Jamie Zawinski, your job is to get the product out *now*. Before the next guy. Before you're obsolete. Before the deadline that the sales people gave the client. Then, yes. Or if you're a mercenary programmer, it certainly does. You write some software that does a task, you give it to the customer and you're done. You're out of there. You're on to the next customer.

However, if you're not a mercenary programmer, then you're probably more interested in developing relationships. Sometimes it's a relationship with your customers; as when you develop a custom application for a customer and continue performing enhancements and upgrades long after you've delivered the initial product. Sometimes it's a relationship with your software; as when you're working on a software product that you wish to sell to the masses. Either way, you will invest more time and energy revisiting programs you've written in the past.

If you're a hot-shot programmer (HSP), you can write perfect code. You don't need tests because you're so meticulous and careful and just plain good at programming that you quickly find bugs and squash them. That's just how you do things. Jamie Zawinski is probably one of these people. Donald Knuth is famously one of these people. He is so confident in the perfection of his work (whether code or print) that he gives out monetary rewards that double as each bug is found.

And that's fine ... if you believe that HSPs are infallible and if the only programmer who will ever touch the code is an HSP or if all of the programmers that ever touch the code are HSPs. From the point of view of an HSP it doesn't matter if anyone else touches the code. Because as an HSP, you know that if you touch the code, all will be made well. But that's often not reality. Reality is that there are probably different programmers of varying skill that will ultimately touch the code over its lifetime.

From the point of view of the company that employs the HSP, they would be taking a risk not having some form of code verification as changes are introduced. Because from the employer's stand point, that HSP might be the only one on the team so other non-HSPs will definitely touch the code and they won't be as meticulous or careful. The HSP might not work at the company forever, and when he leaves, who's to say that the next guy the company hires will be an HSP or not? Odds are fairly good that he (or she) won't be. See Truck Number or Bus Number for more details on the risks involved.

Tools like unit tests help mitigate against some of these risks by codifying the correctness of the software into a test suite that can be run at any time by anyone.

On Context

These are some of the things that went through my head, but all of this is probably tangential to the point of Spolsky's article which really seems like a reaction against those people that have taken some good ideas and turned them into some sort of religion. People that latch on to the latest set of buzz-word technology and apply it everywhere. People that think that units tests are more important than the software they test. (If you're one of these people, tell me, which does the customer want?)

Spolsky praises Zawinski for his Worse is Better approach. I do too. Because it's very pragmatic. Write something useful, then let people use it. It may not be perfect, but you can iteratively refine it as needed. And do you refine it until perfection? Hell no! The perfect is the enemy of the good. Voltaire knew this 230-something years ago. Perfection is a chimera that leads you madness. The point is to just get useful things. So, you do the simplest thing possible to make the software more useful and that's it. Stop trying to predict the future. You can't. Stop trying to design for things that you imagine will be useful. Only design/write things that are actually useful now.

Oddly, these are the same ideas I hear from the practitioners of agile software development. The only problem is that when you name something, you can't be sure the name will mean what you want it to mean. I think these days when people say "agile", what's heard is "the Agile religion" rather than "that bunch of useful ideas".

Conclusion

So, with regard to unit tests ... a man with two clocks never knows what time it is, but a man with thousands of clocks invokes the law of large numbers and has a good statistical chance of knowing the time within a sufficiently small epsilon. (I hope everyone can draw the analogy :-) And if you're that man with thousands of clocks, don't get caught up in making clocks for the sake of making clocks.

Ultimately, who cares if Spolsky or Zawinski or I like or don't like unit tests? At the end of the day, to be a good developer or development company you have to find out what works for you or your team for a particular problem. Sometimes that might involve unit tests; sometimes that might mean you're a mercenary programmer; sometimes that might mean you're doing TDD. Or maybe something else entirely. Use what works.

And that's all I have to say about that. :-)

Monday, September 7, 2009

Things I wish were different in Padre

I've been using Padre as my primary editor for the last several days and I have to say that it's awesome. I've thoroughly enjoyed using it. However, there are some small things that tend to annoy so I thought I'd at least write them down so that, if nothing else, I'll have a list of potential things to hack into Padre if the mood takes me. And I'm making the list public in this way so that maybe even the LazyWeb will do the work for me :-)

In no particular order ...
  • The find dialog box appears right in the middle of the window and I always have to move it out of the way to see the text underneath. I think something like Firefox's find-at-the-bottom status bar would work well instead.

  • The mechanism for changing what language Padre thinks the document is written in is a little bit too cumbersome. There are times when I'm looking at some random perl file, but Padre doesn't figure out that it's Perl. So I have to go View -> View Document As -> and then select the appropriate language. I'd like something a little more Textmate-ish where I can click on the text in the status bar that indicates the language of the document and be able to select from the list there.

  • I wish there were a keystroke for deleting an entire line. There may actually be one, but I don't know what it is and I can't seem to find it.

  • The documentation could use a little work. :-) In searching for keystrokes that might delete a line, I stumbled across Control-D which apparently duplicates the current line. Later I was looking through the help and came across this:
    (TODO What is Ctrl-D ?, duplicate the current line?)

  • I can't seem to copy from the DocBrowser

  • DocBrowser Search doesn't seem to do anything useful as everything I search for ends in "no results found for ..."

  • Not really a Padre problem, but the vi plugin doesn't seem to support many editing keystrokes that I use all the time. I've been using Padre with the vi plugin turned off because of this, but I really wish one of two things would come to pass:
    1. the vi plugin supported more of the keystrokes I tend to use in vi or
    2. Padre provides some keystrokes of its own to do the things that I tend to want to do (like delete an entire line).
    Using Padre for the past week or so has made me realize that I'm not so tied to vi as I often think I am and that I could be happy with #2

  • There have been times when I'm clicking through a directory structure and the ".." entry at the top disappears. I'm not sure exactly when it happens, but it seems to happen whenever I click into a Catalyst project directory. I have to change the listing mode view to "navigate" to get it back and be able to navigate to the parent dir.

  • I really wish that padre would background itself when run from the command line. And that padre . would start the directory browser in the current directory.



Okay ... enough of that. These are just the little things that I've run across; nothing major. But it's the little things that affect your quality of life. Right now Padre is awesome but could use a few small QoL adjustments to make me happier.

CPAN.pm weirdness

The other day something strange happened. I tried azawawi's one-liner for upgrading Padre on my linux desktop. What happened was that the latest Padre (0.45) was downloaded and installed, but then so was version 0.40. I didn't realize that this had happened immediately, but once the upgrade was finished, I wanted to see something different, so I fired up Padre and went to Help -> About. I was shocked to see "Padre 0.40". So then I typed padre --version on the command line and again, it told me "Perl Application Development and Refactoring Environment 0.40". Still disbelieving, I asked on #padre how to tell the version of Padre installed and they, of course, said padre --version.

It was at this point that I realized I still had the window history available in the window I had typed the command originally. I scrolled back through the CPAN.pm output and there it was, plain as day; first in the original upgrade list was Padre 0.45 to upgrade Padre itself and then Padre 0.40 to upgrade Padre::Wx::Menu::Experimental (whatever that is). Weird. So, I ran the one-liner again while paying close attention to the output this time. This time it installed Padre 0.45 as expected ... and then installed Padre 0.44 because of Padre::Plugin::Perl5.

I don't know what was going on, but perhaps it was an old version of CPAN.pm because when I ran the same one-liner on my laptop, it worked flawlessly (I'll have to check the desktop tomorrow as it's at work and I'm not :). I have had weirdness before on my desktop since it was where I first installed Padre almost a year ago, so maybe that factored in somehow too. Anyway, in the end I just installed Padre 0.45 specifically and only and that worked just fine.

Monday, August 24, 2009

A Random Walk

Today I wandered around Perl6 stuff just a little bit. Here's some things that I ran into:

use.perl


First stop, masak's journal entry at use.perl. He's building a persistence layer for Web.pm that mimic's Ruby's ActiveRecord in a very simple way. Quite cool.

Drawing Blanks



Recently Rakudo Perl was changed so that make install could work. Actually, it was changed so that, in order to run the perl6 binary anywhere other than the build directory, you must run make install. Anyway, someone updated the page describing how to get Rakudo to include the make install instructions. Only they actually typed $make install where all of the other command-line-like lines have a space after the dollar sign and before the command. For some reason that little inconsistency was bugging me, so I thought, "I've got a login and edit rights, I'll just go change it!" The only problem is that when I tried to login, it took me to a blank page. Then, I was poking around on rakudo.org and there were several prominent pages that all ended up blank on my browser. Bummer. I left a note to alester with a bot on IRC in hopes that he'd know what to do.

Turtles all the way down



On a lark, I tried to install Rakudo on cygwin. However, the only Windows box I have handy is actually a VirtualBox instance. So, I tried installing Rakudo on a unix environment running on a virtual Windows environment running on a unix OS. In the process I realized just how much of Parrot's build process is dependant on Perl. It got a long way before it complained about not being able to find a compiler.

Unfortunately, it didn't work. After installing parrot, it died tried to execute parrot_install/bin/parrot_config. In fact, it seemed to die executing any of the parrot binaries from within the parrot_install/bin directory. In fact, it seemed that the only time executing one of the parrot binaries worked was when they were run from the parrot build directory.

The End



And here's where it ended because I was too tired to do anything else.

Monday, August 10, 2009

Perl 6 databases

Earlier today (or perhaps yesterday by the time I get around to publishing this) Tim Bunce showed up on #perl6 and asked who wanted a commit bit to his java2perl6 project that converts Java files into Perl6. I wanted one. I've long been interested in something like DBI on Parrot, but DBI on Perl 6 is the next best thing. So, I checked out a copy of java2perl6 and started poking around.

Wait ... what?!? What does Java have to do with DBI or Perl 6? A while back, Tim Bunce posted that the JDBC made a good model for the driver interface for DBI 2, so we might as well just use it. So, that's what's happening. We're starting with the java code for JDBC and writing software to automatically convert these java files to Perl 6. And then eventually, something like DBI wil be built on top of it all. But java2perl6 is the start.

Anyway, the java2perl6 README says
See the POD in java2perl6 (in the bin directory of the distribution) for information on how to use this module.
Great. I know how to do this, I'll just type perldoc bin/java2perl6and see what it takes to get started. Never mind that I only have passing familiarity with Java, I'll figure that out later. I know Perl 6 fairly well.

Oops! Perldoc had some problems:

POD ERRORS
Hey! The above document had some coding errors, which are explained below:
Around line 104:
’=end pod EOS’ is invalid. (Stack: =begin pod)

As it turns out, java2perl6 generates some POD as part of its output.
This POD is in a here-document which apparently confuses perldoc
since the directives that are part of the output are at the start of
lines. Aha! My first contribution to the java2perl6 project: making
java2perl6 accessible via perldoc.

Okay ... now what?

The documentation in java2perl6 gives me a good overview of the command line arguments, what the program is supposed to do, and some nice examples. So, after installing the dependencies, I do the usual perl Makefile.PL && make && make test dance and everything looks okay. All tests successful. Now to attempt a conversion or two.

There's a directory called testjavas which looks to contain some java code I can try this out on, so I do:

perl -Mblib blib/script/java2perl6 -j '-classpath testjavas' ClassTest

Since I haven't installed java2perl6, I invoke it from within the build directory and pass the testjavas directory as an argument to javap. The name of the file that I'm converting to Perl 6 is ClassTest.java. The result of running the above command is that I now have a ClassTest.pm file with some Perl 6 code in it that hopefully mimics the class definition specified in ClassTest.java.

Looking at ClassTest.pm, it seems that java2perl6 doesn't generate the various data members defined in the .java file. That seems like something I could try to implement. But, as usual, I have far too little time to continue pursuing this and I'm feeling sleepy, so perhaps updating the generator is tomorrow night's task.

On a lark, I reran the above command with the --check option to see what happened and it failed specatularly because it couldn't execute a perl6 binary in my path. That seems like something that's under-documented. Also, it would probably be nice to specify a particular location for the perl6 binary rather than relying on the
path.

There seems to be a goodly amount of low-hanging fruit for participation for when I'm not so sleepy. Awesome. For now, I'm off to bed.

Tuesday, July 28, 2009

Perl 6 Documentation

There's copious amounts of documentation for Perl 6 in the form of the Synopses but sometimes it just doesn't explain things in a way that mere mortals can understand. In order to help these mortals I've created a github project for other, hopefully more approachable Perl 6 documents. This repository can be found at http://github.com/perlpilot/perl6-docs

I figure there will be 3 kinds of documents that will be useful to have:
  • Introductions
  • Tutorials
  • Quick References
Check out the README for what goes in these documents.

I've seeded the repository with the beginnings of a Perl 6 Regex quick ref and an article I wrote a while back as an introduction to Perl 6 Regex.

I haven't actually thought too much about other people contributing to the repository yet. I mainly started this because I've always got ideas kicking around for things to write about but I rarely start something. This repository gives me a place to at least start writing (I have no excuses now!). But if someone wants a commit bit, just email me at duff@pobox.com.

Also, earlier today on #perl6 we talked about various book efforts relating to Perl 6. I don't know if books on Perl 6 should also go here, but I'm certainly not opposed to it if someone wants to contribute :-)

Saturday, July 25, 2009

Small, shiny focus.

Recently, I was reading Chad Fowler's excellent book, "The Passionate Programmer" and I'd gotten to Part III: Executing. Chapter 23, "Be Where You're At" struck a chord with me. The hypothetical person in that chapter was always looking for the next thing that will advance their career instead of paying attention their job, so they tended to do mediocre work. I'm not quite like that guy, but I have noticed that my procrastination manifests itself as an inability to focus on whatever it is that I should be working on because there's always another, more interesting problem to solve. In short, I'm easily distracted by small shiny objects :)

Then I was reading PerlMonks where kiz asked a question about Perl's auto-incrementing of strings. moritz replied with a brief
exposition
of how it works in Perl 6.

That post reminded me of one of the small contributions I made to Perl 6. I wrote some code to implement the Perl 6 semantics of string increment for Rakudo. That code has long since been replaced but the important thing was that at some point in the past, I was able to identify a small problem space in a language that I enjoy and did something about it. I was able to push through to a solution without being distracted by small shiny objects. (Although, I imagine that it was the shiny, distracting object for some other task that I should have been working on)

Thinking of that past contribution ignited some small desire to do that again despite the distractions in my life. Ergo, I intend on finding small perl-related things to focus on for as long as possible and then a little longer if necessary until I get to a stopping point and then I'll blog about it. Hopefully, as I exercise those neurons dealing with focus, they'll get stronger and the distractions will impinge upon my brain less.