Eccentric Flower talk:201005/use useless

From Eccentric Flower

Comments on Eccentric Flower:201005/use useless

Comment:



Jweader:

If you put two carriage returns ('\c\c') at the end of your line the server will wait forever. It's not that people prefer newline (or more properly, line feed, but you know that) - it's the proper term. You can return the carriage to the beginning of the line without feeding the paper forward.

And this piece is presumably written by someone who spends most of his time writing functional code, not object-oriented code. Your disdain for functional encapsulation wouldn't get you very far in a C++ or Java shop. Concise, well-written APIs (and the functionality behind them) are stock and trade here. In fact, the project I'm working on right now is explicitly cleaning up an existing set of libraries (for controlling autonomous undersea vehicles) for more general re-use. The functionality already exists, from years of development over many projects. It's my job to help turn the whole mess into something that's accessible and understandable - which I think is really your complaint in the first place. Libraries are wonderful things, if they're well-written and the API is sensible. Sounds like LWP is neither.

-- 21:48, 5 May 2010 (BST)


Columbina:

Actually in Perl the code for a carriage return is \r, and yes, I know the difference. But I work in Unix, where we consider \r an oddity of other, less-well-developed OSes. Since we only ever encounter \r's when we're having to strip them from @#$! alien-format files, we can safely call newlines "carriage returns" without much danger of cosmic retribution. So there.

Again, I am not arguing against libraries per se. For example, speaking as someone who once was foolish enough to write his own date/time handling library, I can now say that the Perl Date.pm is well written, has good documentation, and nice, lucid function names. It is, in short, a sound API. But date libraries really ARE that complex. If you included an entire library/API for one function call that you could write yourself in twenty lines, I would wonder what your motivations were ... unless you were on a team and you wanted to make sure that no one went cowboy and tried to do it themselves and possibly failed miserably. ("Why isn't this code working? It's the same API as everyone else ... oh.") But I never work on a team. The last time I tried to be part of a programming team, my alleged superior nearly ended up at the bottom of the Charles with a slit throat.

If I worked in a Java or C++ shop, I would slit my own throat. Preemptively.

-- 21:57, 5 May 2010 (BST)


Columbina:

Incidentally, I was oversimplifying when I said the server would wait forever. What will actually happen is one of two things:

1. You'll try to send some output that's not legal HTTP header (for example, the content of the web page you intended to send), and the server will fuss at you and the user will see an error 500.

2. You'll never finish sending a header, and your code will end, and when the server falls off the end it will say, "Hey, I never got a full header from you, what's the deal?" ... and the user will see an error 500.

-- 21:59, 5 May 2010 (BST)


Ysabel:

There's lots I want to say, but I will stick to this one:

Libraries are not the cause of cargo cult programming, and if you have to deal with cargo cult programmers (some of us do), libraries make their code MUCH MUCH MUCH easier to untangle and fix later.

Unlibraried cargo cult programmers make truly frightening stuff. I've had to deal with it before.

-- 22:17, 5 May 2010 (BST)


DanLyke:

Is it too pedantic to suggest that for a "Location:" header element you really should include a "Status: 3xx", where "3xx" follows the appropriate semantics for the sort of redirect you want?

As someone who's used an ethernet sniffer to find a bug in router firmware that was causing a SOAP call to fail, I think you're being a bit hard on CGI.pm. Along side having the pretty worthless output stuff (although some of the form handling escape code is useful), it also silently handles the differences in semantics between running as a CGI or in an Apache mod_perl environment. Which can be handy; I've never had to learn mod_perl beyond that and a "BEGIN" block.

And it ain't SOAP.

Having said that, I'm pretty sure my next web app will be written in roughly bare metal C++, because my feeble little brain really doesn't have the neurons to keep up with all these silly newfangled application frameworks and languages.


-- 22:20, 5 May 2010 (BST)


Settsimaksimin:

i see the phrase 'carriage return' and i immediately hear the "ding!" my mother's old manual typewriter used to make.

-- 22:25, 5 May 2010 (BST)


Columbina:

Ysabel: While I agree that an unlibraried cargo cult programmer is far worse than a libraried one, my point was that libraries can encourage cargo cult programming in those who lack the impetus to look deeper. I didn't mean to imply an absolute link.

Dan: My thoughts on mod_perl will have to wait for another day; they are long and nasty. I have fought through many, many misguided mod_perl installations, and in fact, at my current job, I have turned it off and never looked back. If that sounds like a stupid decision, that's because I don't have the time for 6000 words right now to explain why, in my particular environment and situation, it was not. Suffice to say that my stance on mod_perl is akin to my stance on libraries; often useful, but just as often gets in the way of useful.

I have absolutely no use for SOAP or similar frameworks. Again, maybe useful somewhere; for my jobs and my environment, overkill that gets in the way.


-- 23:16, 5 May 2010 (BST)


Columbina:

I was thinking about this on the way home and I realized that I endorse two purposes of libraries, and that nearly all the libraries I like fit one of those two purposes.

The first is a library as the body of code and data which embodies an "object." I am not rigidly opposed to object-oriented code, any more than I am rigidly opposed to libraries; sometimes it can be very useful. In the case of Date.pm, the object is obvious - the data, the physical object as it were, is a single date. You then have a set of functions which set the date, all or in part ("set the year to ..."), which alter or manipulate the date ("advance one month"), or return/access the date, in whole or part, in various ways ("tell me what day of the week the date is" or "tell me this date in this format"). Combining these functions allows you to do very complicated operations intuitively. The Date.pm calls for "go to the date thirty days in the future, back up to the preceding Friday if that date happens to be on a weekend, and tell me what calendar month the date is now in" are only slightly less human-readable than the descriptive text I have just typed.

Similarly, I use a library for a database-handle object every single day of my working life. As it happens, I wrote this one myself because I didn't like the existing DAOs that were lying around, but it is nonetheless a library and I use it constantly. This makes sense not just because there is a set of database functions which seem to belong together (connect, disconnect, select, update, insert, delete, commit, rollback) but because, at least in Perl, the database handle is a persistent data construct which must be explicitly opened and which hangs around until it is explicitly closed (yes, Perl will do automatic closing if you leave it open as you fall off the end, but that's sloppy).

Meanwhile, the problem with CGI.pm or LWP is that there isn't really any sort of "object," yet in each case they insist on trying to pretend there is one. Each of those is basically a library of possible transactions or signals - they're protocols, they're not objects. If they handled themselves like protocols, I might like them more. But I don't want to be tied to an imaginary CGI object which pretends to have persistence when it doesn't (CGI is legendarily, remorselessly, heartbreakingly stateless). I just want the call for "Gimme the data" and another call for "Here's data comin' at ya."

The other library purpose I endorse is a group of essentially standalone, small utility functions grouped by purpose. Dan, you mentioned the escapement code for HTML entities. Yes, those are very useful utility functions. I eventually carved out a set of my own so I wouldn't have to include LWP just to get ten lines of (however useful) code. Where did I put my &escape_url and my &unescape_url functions? Why, in my standard web utility library, of course, which also has useful functions for URL dissection, host name munging, and many other small tasks related to the general purpose of "web/HTTP mongering" which otherwise I'd have to write fifty times in fifty places. As I say, I am not at all opposed to efficiency. If someone had put a Perl library on CPAN that had all those little pesky web-related functions, and ONLY those little pesky web-related functions, then I'd probably be using it right now. But it doesn't exist, because people seem to insist on grouping functions together in a way that doesn't make sense to me, or making me buy into some phony object paradigm just to get to the stuff that's actually useful. I figure that about once a year, I carve a useful function out of someone else's library, and move it to a place where it will actually be useful to me. I am in favor of using good code when I find it. The problem is digging through ten thousand lines of crap to find it.

-- 23:33, 5 May 2010 (BST)


Spc476:

I, for one, would be interested in seeing those 10 lines that implement form/multipart (why yes, I am calling your bluff).

In defense of CGI.pm (not that I use Perl (ack-ptui) but that I like playing Devil's advocate), the code you presented doesn't handle form/multipart; nor does it handle name/value pairs where the name part repeats (or rather, the code overwrites earlier values). You also don't handle the case where you POST to http://www.example.net/blah.pl?foo=1&bar=2. CGI.pm has to handle all those oddball corner cases (to be fair, my own C code (which I've been using since the mid-90s) doesn't handle QUERY_STRING in a POST either).

I think what you are slowly getting to is that all abstractions are leaky ( http://www.joelonsoftware.com/articles/LeakyAbstractions.html ) and that using a library without knowing all the details will come back and bite you.

I, too, tend to avoid external libraries, because there's already too many moving parts to troubleshoot (just today I found out why my custom written syslogd was hanging---I was using sendmail's sendmail instead of Postfix's sendmail when sending email notifications which was working about 99.9% of the time; it only took me four hours to track that particular problem down once I could reproduce it on demand).


-- 00:56, 6 May 2010 (BST)


Columbina:

This sample is more than ten lines but that's because it accepted many different bits of data in the POST request:

# The POST method uses the mixed content type because it may have a
# fileblob to post. This is called from the image browsing page.
elsif ($ENV{'REQUEST_METHOD'} eq 'POST')
{
	my $buffer;
	my $delimiter;
	my @params;

	read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
    	
	$buffer =~ /^(\S+)\s+Content-Disposition/;
	$delimiter = $1;
	@params = split($delimiter, $buffer);

	foreach my $param (@params)
	{
		my $paramname;

		# A param that does not begin with Content-Disposition is garbage
		next if ($param !~ /^\s+Content-Disposition:/);
		$param =~ s/^\s+Content-Disposition: form-data; name="([^\"]+)";*\s+//;
		$paramname = $1;
		$paramname = lc($paramname);

		if ($paramname eq 'type')
		{
			$param =~ s/\s*$//;
			$filetype = lc($param);
		}
		elsif ($paramname eq 'stockno')
		{
			$param =~ s/\s*$//;
			$stockno = $param;
		}
		elsif ($paramname eq 'imgfile')
		{
			$param =~ s/\s*$//;
			$filename_from_form = $param;
		}
		elsif ($paramname =~ /^delete_(\w+\.(jpg|gif))/)
		{
			$deletion = $1;
		}
		elsif ($paramname eq 'confirmation')
		{
			# If we send this then we also need to send the filename to delete
			# as 'imgfile' param; this is the second stage of deletion.
			$deletion = "confirmed";
		}
		elsif ($paramname =~ /^select_(\w+\.(jpg|gif))/)
		{
			$filename_from_form = $1;
		}
		# The fileblob requires special measures before hashing
		elsif ($paramname eq 'fileblob')
		{
			$param =~ s/^filename="([^\"]*)"\s+Content-Type: (\S+)\s+//;
			$filename_from_blob = $1;
			$fileblob = $param;
		}
	}
}

That code's several years old and I wouldn't necessarily write it quite that way now, but it's what I had handy.

URLs in the form url?param=1&param=2 are not POSTs, they are GETs, and the first code sample above handles them quite well, thank you.

If I encounter code where a parameter repeats (such as a multiple-selection listbox) I special case it. I also often special-case implied parameters, like when you want to pass in url?12345 and assume that 12345 is a value, not a variable name.

That all said:

I think what you are slowly getting to is that all abstractions are leaky and that using a library without knowing all the details will come back and bite you.

about summarizes my feelings.


-- 01:31, 6 May 2010 (BST)


Kymmz:

I am one of those people who generally skip the codey entries because beyond 1998-era html, code is a mystery to me, but I must say, that was a very interesting entry!

-- 03:54, 6 May 2010 (BST)


Andy:

Someone was telling me about a rant, which I think we'd both be in agreement with, about how programming has changed, which was part of an explanation of why MIT got rid of the old 6.001. Roughly, it said that programming used to be writing good code that did a task, while now programming is putting a little bit of glue between a bunch of ill-designed, poorly-documented, mostly-working libraries that do something close to what you want to do. And that old fogies like us hate this change.

I'm totally with you on libraries. On SNL many years ago, Guido Sarducci did a bit selling a new product he had invented called "Mr. Tea". It was sort of like Mr. Coffee, but for Tea. You just supply a cup, boiling water, and a tea bag, and Mr. Tea does all the rest! Far too many libraries are like Mr. Tea. The work to convert what you have into the format the library wants, and to convert what comes back into the format you want, is more work than the work the library actually does.


-- 19:58, 6 May 2010 (BST)


DanLyke:

Re Andy's "...now programming is putting a little bit of glue between a bunch of ill-designed, poorly-documented, mostly-working libraries that do something close to what you want to do.", I have spent the past few weeks porting a bunch of C# code to Visual C++, and thence to the Macintosh, and am now looking at the iPad as a target.

This. This is .NET, this is OS/X Cocoa, this is iPhone/iPad OS: I just wanna draw some freakin' dots on the goldarned screen, and have the hardware tell me where the user put their mouse or finger. That's all.

Instead I'm constantly in some recent CompSci grad's idea of "the one true way" of architecting my application, and it's super telling that none of those recent (as of when they wrote this stuff) CS grads agrees on what "the one true way" is.

The number of neurons I have devoted to figuring out what some other moron was thinking versus those devoted to actual algorithms to solve what should be the hard bits of all of these problems is wrong.

And there are many days when I yearn for the simplicity of the Apple ][.

-- 18:02, 7 May 2010 (BST)

Personal tools
eccentric flower
fiction