Fog Creek Software
Discussion Board




Programming for Programmers

I'm a programmer, and if another programmer's idea of how to write an app targetted to me is to write a command line tool that takes any number of non-intuitive slashes, characters, and escaped words and outputs ascii as its primary form of output, he needs to rethink if he's really helping me out. 

When I write programs for programmers, I decompose them into reusable components and services, each of which has well-defined, well-named, somewhat strongly typed interfaces so that he doesn't have to type: 'myapp \?' over and over again every time he wants to use it doesn't have to write a text parser based on whatever cryptic format was determined to be the best way to provide the output.

JD
Monday, December 15, 2003

But what if I'm not using C++?

Michael Hobbs
Monday, December 15, 2003

If you're writing tools for programmers, you want to lean to the usability side of things, not the learnability. 

Learning the slashed may take a while, but once I learn them they are highly usual.


Monday, December 15, 2003

Actually I was taught by my Japanese friends that most Japanese folks prefer to eat sushi with their hands (the way we eat hamburger), not with chopsticks. The chopsticks are for dabbing at the wasabi and pickled ginger.

Brad
Monday, December 15, 2003

I find that not all "programmers' code" need to  be in C/C++ to be useful.  Some tidbits in other "high-level scripting languages" (please note the "" here!) can be useful if you're going through a quick hack or can't be bothered to get all libs together to write what you need.

I believe there will always be room for "windows culture" and "unix culture" and you'll be a better programmer if you can balance both.

Paulo
Monday, December 15, 2003

But Paulo, you're missing all the fun of the religious wars! :)

sgf
Monday, December 15, 2003

One of Joel's links in the article refers to chapter 16 of the book, a clever story of J. Random Newbie. While it does point out some of downsides of current software development, I think it places the blame in the wrong area, cultures aside.

The idea that because some closed, proprietary libraries provide inadequate functionality, source code is needed is wrong. The goal should be to improve documentation and consistancy within those libraries, not open them up so those failures can be fixed by the user. If management is purchasing libraries that are unsuitable, then that's the problem, not whether those libraries are open.

Jason Kozak
Monday, December 15, 2003

"The goal should be to improve documentation and consistancy within those libraries, not open them up so those failures can be fixed by the user. "

I agree with this statement 100%.  When I've encountered problems like this, it's almost always because the component doesn't a)  make its preconditions explicit and testable, or b) has undocumented side effects.  This should be present in even the most minimal set of documentation about a component, but you don't often see it.

anon
Monday, December 15, 2003

> But what if I'm not using C++?

Who said anything about C++?

JD
Tuesday, December 16, 2003

The word "component" has a strong correlation to the word "C++" for me. Even though you didn't say so explicitly, most component technologies, such as COM or CORBA, have their strongest bindings to C++.

Granted, there are good bindings for VB and Java, but one of the points made in the book is that Unix programmers like to draw from a wide range of languages in order to get their job done. This includes Perl, Python, shell scripts, Emacs-lisp, PHP, awk, Tcl, and others.

More recent component technologies, such as XML-RPC and SOAP, do a better job at being language-agnostic, but I can guarantee you that from a shell script, it's still much easier invoke the "wc" command than to try to connect to a word-count SOAP component.

That being said, when given a component of sufficient complexity, something like SOAP may be the only way to go. However, what the book tries to point out is to keep simple things simple. Don't underestimate the utility of a stand-alone process that does one thing well.

Michael Hobbs
Tuesday, December 16, 2003

>  if another programmer's idea of how to write an app targetted to me is to write a command line tool that takes any number of non-intuitive slashes, characters, and escaped words and outputs ascii as its primary form of output

In some environments providing a command-line tool for certain tasks is entirely acceptable; software builds are one example.

I'd agree that it should have at least some documentation, examples, and so forth (for example, running it without any arguments should print out a usage message), but I wouldn't reject the idea out of hand either.

Portabella
Tuesday, December 16, 2003

I like GUI's too -small time ago I had to 'fight' with alchemy, an MS-DOS image viewer/converter-, but I'll go further and will say: any respected developer should not feel any fear or pain around command line interfaces.

Ross
Tuesday, December 16, 2003

> any respected developer should not feel any fear or pain around command line interfaces

I agree, although I would also say that you don't have to *like* them, just roll-up-yer-sleeves and get the job done.

And, as I was hinting in my earlier post, command-lines should also follow usability guidelines. That seems to be the most solid point the original poster made: command-lines are OK, but wretched, horrible and painful ones are not.

Portabella
Tuesday, December 16, 2003

I strongly agree with the original poster.  I was just bitten today by cygwin; there was a big dir of stuff I wanted to look at, but there were a couple files with names like -pix-.tar.  Whenever I would do an rm *.tar or ls *.tar, the commands would complain that they couldn't understand the -p switch -- apparently the shell still expands wildcards then sends everything off to these commands, which interpret '-' as a switch prefix.  I had to use Windows Explorer to move the deadly files.  I'm just glad -p didn't mean "format this harddrive."

This is what I get for not installing scheme shell, which hopefully separates switches from args.  I'm sure there's a way involving shell scripting or metachar escapes that would fix this problem, but there was a faster Windows workaround.

Tayssir John Gabbour
Tuesday, December 16, 2003

FYI, I just RTFMed (the Unix Hater's Handbook), which lists two workarounds, one of which worked.  rm ./*.tar did the trick.

Tayssir John Gabbour
Tuesday, December 16, 2003

Programs decomposed into reusable components and services can indeed be useful for other programmers. But in my experience it's only easy to do if the other programmer happens to use the same language/development platform, and you still have to write a certain amount of glue code around it.

To use CLI tools OTOH, you don't need to know a programming language; you can simply use the tool at the command line, or include it in a simple script if you're not afraid of a bit of scripting.

For example, let's consider a tool for zipping and unzipping files.
One approach is to write just a GUI, which is (hopefully) easy to use, but lacks any possibilty of automation.

Another approach is to write a library or ActiveX object or Delphi component, and possibly supply a UI that uses said component. That makes it possible for me to add the zip feature to my application. If, however, I want to zip 1000 files into 1000 zipfiiles, I either have to do it manually or develop a small application to do it.

The third way offers a commandline tool instead of (or in addition to) a component. Now this is useful: zipping a thousand files is just a matter of creating a simple loop in my shell of choice. True, not intuitive, but much easier to learn than a whole programming language.

In conclusion, I'm inclined to say that the Unix approach is useful not so much for programmers, but for a much larger group of people who don't necessarily program, but who aren't afraid of a bit of scripting.

Roel Schroeven
Tuesday, December 16, 2003

> I was just bitten today by cygwin

It sounds like your problem was actually the shell, not cygwin or the rm and tar commands.  I'm an old veteran with shells, but I still get bitten occasionally too, particularly when trying to quote URLs on the command-line.

If you run rm --help, it actually tells you the workaround you need.

Portabella
Wednesday, December 17, 2003

"there was a faster Windows workaround. "

Baloney.  You're just more familiar with it so it seems faster to you.  Anyone who knows anything about unix knows the way to solve "problems" of this type is with the ./ prefix.  I can assure you that I can type ./ faster than you can move things in an explorer window.

You will say "cryptic."  Baloney.  How is clicking and dragging any less "cryptic" than ./?  It is not.  Why isn't it one click on each corner of the rectangle?  Why isn't it a double click, rather than a click and drag?  It's all arbitrary.  You just think it's "intuitive" because you have been trained into it.

Robert
Wednesday, December 17, 2003

Yes Robert, there is that well-known trick, to use a more specified pathname than the local one I was assuming.  I randomly chose a workaround, deciding not to look at the docs as Portabella helpfully took me to task for not doing.

However, the problem here is internal consistency -- you seem to implicity agree this is a fairly surprising problem within the commandline metaphor.  My ability to delete from Windows explorer did not have any such surprises.

I will admit to you though, if a process had a lock on one of the files, Windows might not have a helpful enough error message; it should probably attempt to mention who holds the lock.

I don't know what to say.  I solved a problem caused by surprising interface behavior.  I suppose a "programmer" should have a professional obligation to understand the semantics of every command typed, but the more I work with the machine, the less I like the term "programmer."  I'm just a guy who uses the machine.  I admit, my post took unix for granted, which I should never do again, but the OS is not always right either.

Tayssir John Gabbour
Wednesday, December 17, 2003

"However, the problem here is internal consistency -- you seem to implicity agree this is a fairly surprising problem within the commandline metaphor."

No.

It is not a problem of internal consistency, nor do I think it is surprising.  In fact, I think it is the least surprising alternative.

By convention command line arguments in unix begin with a dash.  By convention command line arguments may be issued separately, or they may be lumped together behind a single dash, so that I can write rm -rf instead of rm -r -f.  At this point it becomes clear that any filename of the form -* is entirely indistinguishable from an option specification.

The command line parsing, by convention, does the simplest, most consistent thing.  Assume all arguments of the form -* are command line options.

You can choose any syntax you like for command line options and I can always say "well I wanted to call a file that."

And you might then say "it should just Do The Right Thing."  And what is that? "Well if that file exists, then it should consider it a file, rather than a command line."  But then the command line semantics become context sensitive, and I think you will agree that such behavior is a mistake.  It adds complexity and "surprises" much more subtle than what you just encountered.

So you're back to the simplest, most consistent, most straightforward behavior, which is the one you saw.

Robert
Wednesday, December 17, 2003

The consistency problem is that the user typed:

rm *.tar

The user doesn't see the -p.tar - he didn't type it! The problem is that the shell does the wildcard expansion, so the program doesn't even get a chance to tell the difference.

Under most other OS's, the rm program would get the literal "*.tar" string and do the expansion itself (usually with the help of a system call or a library).

In the unix world, the shell does the expansion of "*.tar", and the rm command never knows that the user typed a wildcard at all. Makes it easier for the developer of rm, harder for the user.

This is also the reason why when you type "del *.*" on a windows box, you get that "Are you sure?" error message, while you don't on any Unix - the shell's eaten the wildcard.

Chris Tavares
Wednesday, December 17, 2003

Maybe I do not understand.  When the shell expands my *, it expands into objects of type filename.  Are you arguing that users should expect these objects to be interpreted as switches, if a filename happens to have within its text something that can be interpreted as a "switch"?

If so, we'll have to agree to disagree because that's just not typesafe.  When you say it's the simplest behavior, you're talking about implementation simplicity.  This perspective is well understood as part of the worse-is-better philosophy.  I'm not saying it's terrible, just pointing out it's something with advantages and disadvantages.

Tayssir John Gabbour
Wednesday, December 17, 2003

"Maybe I do not understand.  When the shell expands my *, it expands into objects of type filename."

No.  It expands into text.  Nothing more, nothing less.  This is so that typing into the command line is indistinguishable from the results of globbing.  They are precisely the same.

Otherwise, I would have to have some way of specifying your so-called "objects of type filename" when I am typing in a filename.  That would be, IMO, ridiculous.  It would result in a proliferation of such "types" along with means to indicate each one of them when interacting with the command line.  IMO, that would be a clearly worse system in just about every way imaginable.

"Are you arguing that users should expect these objects to be interpreted as switches, if a filename happens to have within its text something that can be interpreted as a "switch"?"

No, because there are no "objects" to begin with, other than characters.  So it's a nonsensical conjecture.

I am saying that the results of globbing should be indistinguishable from the results of typing into the command line directly. And they are.  Try it.

"If so, we'll have to agree to disagree because that's just not typesafe."

Red herring.  You haven't established that "type safety" (whatever that means) is a reasonable criterion for the semantics of command lines, given all the relevant constraints.  The primary one being that interaction is generally done by typing at a keyboard with letters on it.

"When you say it's the simplest behavior, you're talking about implementation simplicity."

No.  That is but one facet of a much more comprehensive objective function.  And in this case, it actually has essentially nothing to do with implementation simplicity.  It has everything to do with simplicity of semantics.

"This perspective is well understood as part of the worse-is-better philosophy."

It's also a straw-man argument, since I am not appealing to implementation simplicity in the first place.

"I'm not saying it's terrible, just pointing out it's something with advantages and disadvantages. "

Of course, as are all design decisions.  You have to consider the whole space, just not one little corner in isolation to proclaim it is an ugly corner.

Robert
Wednesday, December 17, 2003

I can't help myself to continue, because I think you've hit on a few things in your last post that really demonstrate where certain modes of fashionable thinking are in practical terms terribly counterproductive.

You said "the glob produces objects of type filename" and then went on to condemn "un-typesafe behavior".  IMO, this couldn't be more wrong-headed.

The case you're considering is passing the results of the glob to the program "rm" which we all know removes files from a filesystem.  So it seems natural that we could solve the problem of the ambiguity of filenames and command line options by making this "type" distinction somehow.

But consider what you've given up to gain that little tuft of ground.  What happens when I want to use that glob with the program "grep", which matches lines of text and displays them?  What is the meaning of "grep" on "objects of type filename"?  Do we need another program now "filegrep", for that purpose?  Maybe we should write special case code for every possible "type" that might get passed into the program "grep." 

Hey, I know, we can write "adapter objects" that turn "objects of type filename" into "text stream objects", and then write "grep" to be "type safe" for "text stream objects."  Of course, we'll need "adapter objects" for "directory objects," and "date objects" and "permission objects" and... and...

Hey wait, this is getting out of control.  Hey, I know, we need.... templates!  Shall I go on?

Of course, this is all a bunch of silly nonsense when you consider the trade-offs of the plaintext unix approach to all of this.  Yes, you may end up with the occasional need for disambiguation, but what you gain in flexibility, transparency, simplicity, and interoperability so far outstrips the occasional inconvenience that it is in the final analysis a no-brainer.

This is confirmed for me on a regular basis when I can automate otherwise incredibly montononous and mundane tasks with two or three pipes and utility programs to achieve something which is literally impossible to do in the equivalent object-oriented windows interface because the interoperability is simply not there.

Robert
Wednesday, December 17, 2003

So, the design trade off that you agree with is "make easy tasks difficult in order to make difficult tasks possible"

I can understand this, and at times, i might make that trade off myself. However, for a consumer oriented OS where 99.99% of users do the easy thing and most couldn't figure out how to do the hard tasks, it doesn't seem prudent to me.

What the heck, use the tool that works best for you.

pdq
Wednesday, December 17, 2003

Robert, I think you're reading a lot more into my post than is there.  I'm not talking about OOP or some nasty typesystem.  Just about users and surprise.

Chris's fix, where the shell doesn't eat the wildcard, is certainly enough to kill my objection.  And if I sound like I'm from the Windows world.. I'm definitely not. ;)  I always combine the two into one OS.

Tayssir John Gabbour
Wednesday, December 17, 2003

'So, the design trade off that you agree with is "make easy tasks difficult in order to make difficult tasks possible"'

No, it's more like "leave difficult tasks possible, because some easy things are not going to be as perfect as you'd want them to be anyway, no matter what you do."

Robert
Thursday, December 18, 2003

"Robert, I think you're reading a lot more into my post than is there.  I'm not talking about OOP or some nasty typesystem.  Just about users and surprise."

Well you're the one that used the words "objects of type filename" and "typesafe."  I didn't have to read anything into it.

"Chris's fix, where the shell doesn't eat the wildcard, is certainly enough to kill my objection."

I think that's an absolutely terrible idea, and is the kind of decision which in fact is central to the kinds of objections to Unix found in the Unix-haters handbook, a lot of which I agree with.

The problem with leaving globbing to the program are myriad:

1)  You have to recode it, or choose a library, for every single program.  This is obviously terribly inefficient from a development standpoint.

2) And more importantly is that every program is then free to implement globbing in a slightly different way, or not at all.  You'll have to remember now in every shell script you ever write "does this program support globbing?"  "Is it flavor A, B, C or D# of globbing?  Does it support [] notation? etc."

This is analogous to the situation with regexp engines, and I think you'd agree this is a terrible situation.  We've got perl regexps and emacs regexps and sed regexps and grep regexps and egrep regexps and they're all different.  Ugh.

No thanks on leaving globbing to the program.

Robert
Thursday, December 18, 2003

"Chris's fix, where the shell doesn't eat the wildcard, is certainly enough to kill my objection."

Not to mention that it does absolutely zero to solve the problem at hand.

Robert
Thursday, December 18, 2003

So, if the OS provided a system call that did globbing, how would that be inefficient?

As far as it "not fixing the problem", sure it would - you'd write the program so that the result of a glob is always treated as a filename, not a switch. The unix command line standard is to have all switches before filenames anyway, so that would work just fine.

Chris Tavares
Thursday, December 18, 2003


"As far as it "not fixing the problem", sure it would - you'd write the program so that the result of a glob is always treated as a filename, not a switch."

Amongst myriad other things, you've simply traded the difficulty of files of the form -* for files of the form *foo.

Robert
Friday, December 19, 2003

*  Recent Topics

*  Fog Creek Home