maradydd: (Default)
Suppose you're designing a protocol, and you're deliberating over whether to use XML, YAML, JSON, s-expressions (!) or some other data representation format for it.

The question you need to ask yourself is, "have I written an EBNF definition for my protocol yet?"

If the answer is "no," drop everything you are doing. Yes, everything. Step away from the keyboard. Get a pencil and paper, or go to the whiteboard, and work out your EBNF first.

Then, and only then, you may decide what to use as a data representation. Deciding what data format to use before you have determined the grammar of your protocol is like deciding what language to use before you have figured out what algorithms you're using.

Protocol structure is a design decision. Data representation format is an implementation decision. Do not intermingle the two; it will only end in tears, yours or someone else's. Probably yours.
maradydd: (Default)
By way of [ profile] sfllaw, a development paradigm I had not previously known about, and tool for developing in this fashion. Holy shmoley. I agree with Bill Tozier, I want this for Python yesterday.

Behaviour-driven development is basically test-driven development on steroids: it takes the principle we like to cite, "write your man pages first!", and hooks it right into the test-driven development cycle, except now you're developing one behaviour at a time, so you can write your tests piece by piece and have individual chunks of the system piece by piece. I like TDD, but sometimes I have to write code fast (and yes, TDD always ends up saving me time in the end, but we've all had those projects where OMG EVERYTHING IS ON FIRE AND THERE'S NOT TIME TO DO IT RIGHT. Behaviour-driven development eliminates your excuses to not do it right: you're producing code as discrete functional units, complete with tests to prove that they are correctly functioning functional units, and you're producing it fast enough to keep management/the client happy. (Clients are sometimes not happy when the first week of work goes into building the unit test suite. Yes, yes, I know, that week of work saves a month or more later on down the line. Some of my clients are no longer my clients for a reason.)

Behaviour-driven development is also a great tool for the "design the UI first" school of programming, and any project that doesn't follow that school of programming is doing it wrong. (Think of it this way: if you're writing a library, design the API first -- that is to say, write the man page first. If you're writing a web application, mock up the user interface, figure out what the damn thing's going to look like and do all your changing-your-mind about how the UI is going to behave before you start laying down AJAX requests.)

Also courtesy [ profile] sfllaw, a talk by Ben Mabey explaining not only these ideas but the business decisions which motivate behaviour-driven development. This is a really great overview and I strongly encourage any programmer with a pragmatic spirit -- or, even better, an entrepreneurial one -- to block out half an hour of your time to watch it.

Alas and alack, Cucumber is not available for Python yet, and from what I've seen, I really like the way it works. It apparently can be used with PHP, but I really would prefer to avoid PHP if at all possible; my preferred style is just way too functional these days to blend well with PHP. (I've developed a thing for continuation-passing style in the last month or so.) This may end up being the thing that finally motivates me to learn Ruby. I have a little side project going on right now that has a web-application-framework-shaped hole in it, and I had been planning on using Django, but given that it's going to be a Javascript-heavy front end with likely a healthy dose of, Rails could be a better tool for the job. I'll need to decide if I like how Rails talks to databases; I'm madly in love with the way Django does it and anything less will be a major disappointment, so this is definitely a factor to consider. (Current Rails devs, your input is welcome -- I know very little about your framework. I used to be cranky about the lack of integration with Apache, but there's mod_rails these days and I assume that removes a lot of the reasons I had for bitching.)

And I'd have real continuations. That's always a plus.

Decisions, decisions. But I do like the fact that tools like this exist at all; it's me who needs to get over my uncanny-valley problem with Ruby.

([ profile] karnythia, [ profile] thewayoftheid, [ profile] tanyad, I'm not talking about the project I'm doing for y'all, this is a different project. So many irons in the fire!)
maradydd: (Default)
Nothing written using Boost is ever self-documenting.
maradydd: (Default)
Readers of this blog may recall a situation I refer to as the Next Jackass Problem. In brief: if you find yourself doing something particularly clever or esoteric in your code, you'd better be damn sure you document it thoroughly -- not only why you did it, but what you did and how, so that the next jackass who has to maintain your code can understand it, because 99% of the time, the next jackass is you, six months later.

I've run into an interesting (as in "may you live in ~ times") variant on this, which I call the Last Jackass Problem: when you're supporting a legacy library/OS/what-have-you, and there's a nice way to handle it with the current tools but no nice way to do so with the legacy ones.

In this case, I needed to programmatically tell iTunes to open a file. This is presumably pretty easy in Leopard, thanks to the magic of the Scripting Bridge. However, I'm also supporting Tiger, which does not have this magic. Happily, there's appscript, a nifty event bridge which encapsulates all the gory Apple Events foo that talking to scriptable apps requires. So presumably, if you have a file path, you can do the following:

ITApplication *iTunes = [[ITApplication alloc] initWithName:@""];
[[iTunes play:filePath] send];

This programmatically constructs a reference to iTunes to which you can send commands, then constructs a command to play the file at filePath and dispatches it. Easy? Should be. Except for one thing: on OS X, there's more than one type of path: POSIX paths and HFS paths. POSIX paths are the ones anyone who's spent five minutes with UNIX should know: /path/to/file.ext. HFS paths are the old-school ones that you probably haven't seen unless you've been playing with Macs for a long time or actually use AppleScript: Macintosh HD:path:to:file.ext. And at least under Tiger, some scriptable apps expect HFS paths. (iTunes is one of them. I hear Finder is, too.)

Unfortunately, there does not seem to be any straightforward Cocoa way to convert POSIX paths to HFS paths. But you can tap into the guts of Core Foundation and do the following:

NSURL *ref = [NSURL URLWithString:filePath];
NSString *converted = (NSString*) CFURLCopyFileSystemPath((CFURLRef)ref, kCFURLHFSPathStyle);

That looks like a lot of typecasting, and frankly, for two lines of code, it is. Happily, though, it's safe: NSURL and CFURL are toll-free bridged for no-hassle conversion, as are NSString and CFString (what CFURLCopyFileSystemPath returns).

Nota bene: I have not actually tried the Scripting Bridge approach to this problem. I sincerely hope it silently converts POSIX paths to HFS paths where necessary, in order to prevent headaches of this sort. ([ profile] chanson, any remarks there?) But for those of you doing any kind of Cocoa-based application scripting without the help of the Scripting Bridge, at least now you know. (And do please document your code for the next jackass.)
maradydd: (Default)
Ten journalpoints and a cookie to whoever can come up with the best justification for the following code:
  for( i=0; i<2; i++ ) 
    Kd[i] = (double **)mxCalloc(str1len+1,sizeof(double *));
    for( j=0; j<str1len+1; j++ ) 
      Kd[i][j] = (double*)mxCalloc(str2len+1, sizeof(double));
I can just see the office conversation now:

TEAM LEAD: Jones, you keep forgetting to malloc() your arrays and we end up with segfaults all over the place.
DEVELOPER: Not this time! I malloc()ed those sons-of-bitches twice!

([ profile] cipherpunk, I am reminded of the infamous "if (j == 17) j = 17;" from the early days of Djinni.)

ETA: Oh, nevermind, it's frickin' 1:30 in the morning and I failed to notice the declaration of Kd as double **Kd[2] earlier in the source, not to mention the subscript in the first line of the for loop. Good thing I hadn't fired it off to the Daily WTF, though really, it wouldn't have hurt anyone to put in an explanatory comment. Subscripts are easy to gloss over sometimes.
maradydd: (Default)
I know a lot of people who worry about troubleshooting the logic in their code, to the point of serious anxiety. They agonize over their ability to translate their ideas into the language of their choice, and in the worst cases, it's so paralysing they never get any code written at all. If there's one thing that keeps people from taking up programming as a hobby, it's this pre-emptive self-doubt.

This is, in a word, silly.

Why? Because when bugs crop up, more often than not they will stem from something totally unrelated which throws a monkey-wrench into your logic, which in the end will turn out to be just fine.

Case in point. )
The moral of the story: Check your logs carefully, and remember that even whitespace can have a meaning if you assign it one.


maradydd: (Default)

September 2010

12131415 161718
26 27282930  


RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags