Thursday, May 24, 2007

disjointed thoughts about the Lost season 3 finale

My overall experience with the Lost season 3 finale was strangely metamorphic. While I was watching, I was entranced. Saying or thinking "wha?!" got so repetitive that by the end I was numb to it. "Ben knows they're going to the tower!...oh, he's only taking Alex along with him." "Charlie's been captured!...oh, Desmond came in to save him." "Sayid's dead!...oh, it was faked." "Sawyer and Juliet are going to ambush the Others without weapons!...oh, Hurley just drove a VW van in." "Whoa, according to the flashback Jack and Kate met before the plan crash!...this flashback takes place in the future when they're off the island!!!" Okay, that last one doesn't fit the pattern.

Oddly enough, maybe the biggest surprise for me was that Naomi was not sent by Penelope Widmore. From the previous episode, Desmond's premonition of Claire getting into a helicopter had already tipped me to the "one or more of them will be rescued" reveal. Ditto for Charlie's bucket-kick, of course. And regardless of what else would happen, I think pretty much everybody had assumed Locke would survive (but recovering so much in so short a timespan was literally incredible). The "who does Naomi work for?" question is the next Big Question for me. That, and "when will another woman show up with an English accent?" because it excites me to an unwholesome degree.

Then again, Lost needs more mysteries like web browsers and email clients need more security holes. The next time Walt appears out of nowhere, someone needs to put a leash on him or hang a bell around his neck, before demanding some answers. Remember back to first season, when Locke said "Walt, do you want to know a secret?" (immediately prior to the shot cutting away) and when Locke appeared to take a special interest in spending time with Walt, teaching him certain skills like throwing knives into trees? Did you notice Ben saying the word "temple" in this episode? Have you noticed Richard closely interacting with Ben, both in Ben's flashback story and in the present? A fixed timeline for the remaining episodes is a good thing, because the important Secrets can be systematically exposed rather than kept hidden to protect the show's lifeblood.

People may complain, or even stop watching, because the events on screen aren't perfectly clear. Those people shouldn't be watching Lost because they don't appreciate it for what it is. You know how life is often mysterious, its answers are often ambiguous, and each step forward leads to new challenges? Lost is sorta like that, if you hadn't noticed. Patience and contentment with not having absolute knowledge are two essential skills. As I keep repeating, fictional shows can be escapist in some ways but in other ways all too relevant to be comfortable.

Enough of that thinking stuff. How about those beat-downs? Jack letting loose on Ben (I couldn't help comparing it to when Jack was advocating restraint in interrogating "Henry Gale" in season two), exploding tents, someone getting hit with a van, etc. The action quota almost shamed 24. Two people deserve to be singled out. As Sayid was sitting down, arms bound, he destroyed someone using his legs. Close to Bauer-worthy, if not there - I can't recall if Bauer has performed that move or something similar.

Then there's Mikhail, who has been remarkably visible in the later part of the season. The guy's so nuts, even Ben couldn't help muttering "don't shoot us" as he approached Mikhail's place. The eyepatch seemed to be a bit much at first, but I think he since proved that he's the eyepatch type. Convincing him to shoot his comrades is a pretty easy task, isn't it? I wouldn't want to share bunks with him. One would think the wound he sustained in this episode would stop him, but there he was at the end, using a grenade to flood the underwater station. If Ben is Lost's king of creepy, Mikhail was Lost's king of berserk. It's unfortunate he killed Greta, played by Lana Parrilla, who I wanted to see much more of. Lana was in season four of 24, by the way, as a CTU desk person who didn't last the entire time.

I'm aware not all episodes can be season finales and openers. But nevertheless, here's hoping the story arcs of season four progress with more rapidity and steadiness than those of season three. Also, here's hoping Jack won't have to act through a beard again for a long time.

Monday, May 21, 2007

DSL or API?

Consider this post to have the second function of a "pulse post", a post that proves the blog isn't dead yet. I could trot out numerous unconvincing excuses for my neglect, but I think I have the ultimate one: I haven't had anything sufficiently interesting, both to me to motivate the writing and, I daresay, to readers to motivate the reading.

Moving along...this ten question checklist for distinguishing a DSL from an API made me chuckle repeatedly. Is "DSL" a byword I missed? Hey, if Rails proponents can post "Hi, I'm Ruby on Rails" clips (spoofing the way Java development was done a few years ago), I think this is fair game.

Saturday, May 05, 2007

with our combined strength we can end this destructive conflict

I haven't written a .Net-related entry for months, simply because I haven't had anything noteworthy to write. The last time I even opened up a F# code file was about as long ago. (But the "Active Patterns" are interesting.)

The DLR seems like a fascinating idea, though: a common runtime/implementation abstraction layer for dynamically-typed languages, similar to the CLR and JVM for statically-typed languages. Hmm, sounds familiar...oh, Parrot. Microsoft does seem to end up creating doppelgangers for everything, doesn't it? A monoculture just has to stay competitive, y'know.

Kidding aside, according to the linked blog post by Jim Hugunin (who has Jython and IronPython cred), the code is under a "BSD-style" license. I'm not great at legalese, so I can't comment on what the specific license precisely allows/enforces. If Microsoft keeps paying talented folks to produce good shtuff that doesn't lead to vendor lock-in, I find it hard to complain. Conflict is overrated. Yet the lack of specifications and fully-functional alternative implementations for important .Net pieces, like ASP.Net, gives me the willies.

Wednesday, May 02, 2007

stating the obvious about digg and HD-DVD encryption

Here's the reply from Digg to all of the users who protested the removal of stories containing the HD-DVD encryption key.

Maybe I'm out of touch with the majority on this topic, but I hope the following points are obvious or at least clearly need refuting:
  • The law is on the side of those who requested the removal of the key. Even if this specific situation is merely iffy in legal terms, the best course is to not flirt with it. Not liking a law doesn't give one the right to break it or find creative loopholes. (On the other hand, laws that really are unjust may demand such drastic action in service to a just cause.) Changing the system from within, instead of acting outside it altogether, is one of the characteristics of a responsible citizen.
  • Digg isn't obligated to let anything onto the site. Digg isn't an arm of the government, which means it can suppress speech as much it wants. Moreover, Digg can demand that users agree to its terms. Digg is not a public forum.
  • Censorship is one of those curious entities that change shape when each person considers it. Someone who complains about censorship is likely complaining about the suppression of speech he or she likes, and someone who doesn't complain about censorship is likely not complaining about the suppression of speech he or she dislikes. I don't know that this observation implies anything, but I thought I should mention censorship's relativity.
  • It's ridiculous to argue that since it's futile to keep an easily-copied secret absolutely hidden once it's revealed, then the secret can and should be published and shared wherever and whenever. "Oh, some toxic gas has escaped. Might as well turn on a fan!" In general, I admit to being confused when people assert that (digital) information, whether that information encodes works of art or engineering, should never have an enforced, associated price. If the work encoded by the information had a cost of production, and the producer intends to earn a profit (arguing that people who produce information should never earn a profit is a separate issue), doesn't it make economic sense to reflect that value in the price? Now, when the same producer charges me twice for the same work, merely so I can obtain a different digital encoding of the work...I don't agree with that.

Sunday, April 29, 2007

time-sucking link: media tropes

Link here. It's not just TV.

The danger of a hyperlinked medium, as I've mentioned before, is that one can start on one subject but end up who-knows-where. I was reading a scifi-related page that linked to Planet of Hats (a term for when a work makes a point through a planet that has one defining characteristic). That page had many links to other pages on the same site, so I followed some of those links, and...

Anyway, it's a site full of pages of observations about common (perhaps overused) design/storytelling techniques used by creators of various media, even videogames. The fun is in reading the pages, and recognizing exactly what each one describes. Some might say that this wiki is evidence that (mainstream) entertainment media presents a distorted, escapist, and unoriginal version of reality. My reply is "of course"! If it didn't, it would be called "journalism". If I wanted reality, I'd be watching/reading/playing something else.

But then again, I've read some convincing arguments on the value of fiction for commenting about real life, so the "escapist" charge may be more applicable to someone who avoids the media under consideration, because it forces him or her to answer disturbing questions or confront new ideas.

Thursday, April 26, 2007

96th post: a look at some past comments

96 posts. Wowzers. To celebrate, here's some links to past blog comments that I found most memorable:
  • First comment. I was able to track down a problem in my KnoppMyth installation with some rather unimpressive tactics, but the root cause wasn't obvious so I posted my findings for others to find. And it helped someone! It never hurts to help!
  • Comment from Neal Gafter. I linked and commented about a blog entry someone else wrote about Java closures. Neal, in turn, commented on my lil' blog. (My feelings since then are if you want to use closures, why not just use Groovy?)
  • Haskell comment. Back before I had read more about Haskell, I was still on the fence as to whether it was too complicated to learn/grok. I linked to the commenter's blog as an example of hard Haskell code, which led to a fully-justified comment that more or less said, "The Haskell code wasn't the hard part at all. The hard part was the subject matter. It's to Haskell's credit that the code didn't need to be more complicated." Good call.
  • Abacus manual comment from Totton Heffelfinger. My post about the abacus linked to an online manual, along with some honest words about how much I liked it. The author thanked me.
  • Comments to "the worst interview question". Touched a nerve, did I? On one hand, having a blog entry on reddit is living the blogger dream: being published (and others online taking some valuable time to read what was published). On the other hand, the blog entry that appeared on reddit was an entry I barely spent any time or effort on, nor was it particularly insightful or deep. Que sera, sera.

Monday, April 23, 2007

software development bywords

Trends and fashions are amusing to observe, regardless of their actual merits (by which I mean that some are alternatively driven by marketing, or popularity). The software development world (no way am I going to condone the word "blogosphere") may be essentially susceptible to passing fancies, because of the difficulty in getting software development done right, on time, and within budget. Anything promising a marginal advantage is worth a look-see.

One characteristic that made me chuckle recently was the tendency to either coin or co-opt words, then repeat those words as a sign that one is "in the know". Hence, those words are bywords to prove which "side" someone is on. Again, the worth of ideas or movements expressed by a software development byword is not what I'm addressing here; those ideas of substance can be batted around endlessly by people other than me who (think they) have more familiarity with them. My point is only to call attention to the fact that bywords seem to garner so much importance.

Some food for thought, writing ™ after each byword:
  1. How long until someone decides to sell an agile™ alcoholic drink?
  2. When will there be an RFC for Web 2.0™? Did I miss the RFC for Web 1.0™? How about Enterprise 2.0™?
  3. Speaking of enterprise™, what was the magic point at which Linux suddenly stopped being a hobbyist's toy and started being a business tool?
  4. If I make a POJO™ that extensively relies on and calls into external tools to do many common tasks, is it still a POJO™?
  5. What are the last remaining gaps in WS-*™ to achieve XML document sentience?
  6. Who's the poor sucker whose project shall be stuck with the last remaining -ails™ name, Fails?
  7. Where do I find the TDD™ framework for unambiguously ensuring I have the client's software requirements correct?
  8. At the time all logic has been properly decentralized into separate services in my dandy SOA™, what happens when my messaging server goes kaput?

Saturday, April 21, 2007

making widgets from data in javascript

Here is a convoluted, extra-long tale of real-world software evolution. I'm one of those odd programmers who doesn't mind writing documentation because he likes to expound on his own code in fits of self-aggrandizement. I was working on (rewriting an existing app as) an Ajax application when I soon realized that the task of generating a widget from data was generally applicable to many parts of the interface. I imagine many others have thought the same. I created a function with these parameters: a parent node of the widget-to-be, a 'mapping object', a 'data object', and an optional 'context object' (the context object parameter wasn't in the initial design). The function interpreted the properties of the mapping object to create a widget out of the properties of the data object, and then it added the widget as a child of the passed parent node.

The mapping object had a reserved set of "special" properties with specific meanings to the widget-maker function, like 'widgetType' to specify which widget to create or 'nodeposition' to override the default append so the widget could be inserted at any point in the parent node's existing children. Any properties of the mapping object other than these "special" properties became properties of the widget. If the mapping property's value was a string, the widget-maker looked up that string as a property name of the data object, and then set a widget property with the same name as the mapping property to the property value of the data object - the mapping object's property served as a connecting link or data lookup-index ("to assign this widget property, look at this data property"). I thought this would work fine, for a few minutes. Then I realized I would want to set a widget caption to, say, data property A concatenated with data property B. So I set up an alternate behavior for mapping object properties. If the value was a function rather than a string (checked for using typeof), then the widget-maker evaluated the function with the data object as the parameter, and the return value became the property value on the widget. I abstracted the string-vs-function behavior into a separate function that let me write the equivalent of "I don't care if the mapping object property is a string or function, just do what you need to do for this mapping object property and give me a result to assign".

Was that enough? Not nearly. Even the best of widgets may not be complete as is. What if I had to add more text to the widget, or stick an icon on it, etc.? Generally speaking, a widget may need to have children of its own. I don't mean child widgets, which I'll explain the solution for later, but child content. I expanded the widget-maker to interpret a new special property, childNodes, which was a mixed array of strings or functions. Each element would be evaluated and then concatenated into the widget's innerHTML. (I started out by adding a text node for each element, but discovered that prevented me from having markup in the strings - the markup would actually become literal text in the text nodes, not HTML tags.) In practice, I often ended up just writing one big function, which meant childNodes was a one-element array, and that one element was a function! Eh, hindsight.

In addition to childNodes, some other noteworthy "complex" properties that I added were a domAttrs property for specifying a series of properties to apply to the widget's primary DOM node (not used much except for specifying a data-dependent node ID), a styles property for specifying style rules to apply, and a postCreation function for miscellaneous widget-related code that had to be run immediately after widget creation. The postCreation function might connect up some callbacks, for instance (this couldn't happen until after the widget was created). The callbacks created in the postCreation function could use any variables within the postCreation function, although by the time the callback ran the postCreation function would of course be long finished - closures! At first the postCreation function received the data object and the primary DOM node of the widget. Later there were two more parameters: a context object and the widget itself. The postCreation function had to be passed the widget because I found cases in which treating a widget as a child of a DOM node was incorrect - for everything to work properly, the widget had to be passed to another widget. To defeat the widget-maker's default behavior for those cases, I added yet another special property to the mapping object, manualAppend.

If making one widget from one data object is a common operation, then so is making one widget for each member object of an array. I made another function, an array-to-widgets function, that called the widget-making function as it walked the array. And if making an array of widgets from a data array is a common operation, then so is making a tree of widgets! After assuming that the data array was preordered by the relevant groups (meaning if any two elements are in the same group or subgroup then those two elements are contiguous in the array), the array-to-widgets function gained the capability to create trees of widgets by determining where the group breaks were in the array and then creating the right widget for each group or subgroup (and the right widget for each individual array element as children of those). Besides the data array and the parent DOM node, the parameters then included a list of properties the data was grouped on (contiguous elements with the same value for that property were in the same group or subgroup so the algorithm only add to check for changes in each group's "running value"), in grouping order going from the property for the "highest" or most-inclusive group to the property for the "lowest" or least-inclusive group, and another list of mapping objects that contained one mapping object for each of the groups/subgroups and one last mapping object to always run on each individual data element. It's less complicated than it may sound, once you get it right. A hierarchical tree list of cities grouped by state/province and country, in which each element in the data array is a city with 'country' and 'state' properties and the cities are preordered/presorted so that cities in the same country are contiguous and cities in each state/province are contiguous, might be created by passing the two lists ['country','state'] and [countryTreeMapper,stateTreeMapper,cityLeafMapper]. Naturally, I usually called the array-to-widgets function, rather than calling the widget-making function directly. (And just in passing, any element in the mapper list can be null, which the widget-making function handles by merely returning a 'placeholder' empty HTML element).

Ideally, the widget-maker function would be sufficiently distinct from the array-to-widgets function for reuse purposes, and it was - sometimes the postCreation function for a mapping object would call the widget-maker (so at some level the widget-maker was calling itself). But chances are, a group widget will need to summarize information about its group - showing its member count as part of some childNodes content, maybe. To do this, the functions in the mapping object must know 1. the array it is being generated from, 2. the index of itself (the starting index of the group) in that array. Although I wondered if there was a better way, I stuck a 'context object' parameter on the end of the widget-maker function but made sure the widget-maker function could work without it (remember, javascript functions can take a variable number of arguments). The array-to-widgets function updated the context object as it iterated, and passed the context to the widget-maker function. The widget-maker function would pass the context on to the functions in the mapping object (which also could be written to not take the additional context parameter at all).

I still wasn't done. Creating gobs of widgets out of a data array was a happy accomplishment, but consider what happens when the data array changes ever-so-slightly to have one more element. Is it reasonable to demolish and recreate all those widgets to accommodate one new red-headed stepchild? (The answer is no.) I started by trying to make the array-to-widgets function perform a data/widget "diff", but I gave up on that quite quickly. Instead, I modified the widget-maker function to first compute what the ID of the widget would be, check if that ID was taken, and only create the widget if the ID was available. Since IDs must be globally unique anyway, the procedure seemed reasonable. As for updates, if the widget-maker function found that the ID was taken, it reran the mapping object functions after setting a property on the context object to signal that the function was called for updating not creating. Otherwise, a new total might be appended on to the end of the old total instead of replacing it ("1011" instead of changing "10" to "11")!

For handling removals, I took a similar tack. The array-to-widgets function now kept track of the IDs of the widgets it created while iterating, and returned the list of created IDs as properties of an "old ID" object. It also took a new (optional) parameter, the object returned from the previous time the array-to-widgets function ran. If the old-ID-object was present, then after the array-to-widgets function was done iterating it checked to see if each of the properties of the old-ID-object were properties of the ID-tracking object it just created (the object it created for its return value anyway). Any IDs that were property names of the old ID object but not property names of the just-created ID object represented obsolete or outdated widgets, so the array-to-widgets function destroyed them (using the proper API so nothing was left dangling).

The refinement of my functions happened gradually as I better understood the problems the functions had to solve. Writing widget-creation code for any given chunk of data would be simpler or just more straightforward code, but I would then be forced to rewrite variations of that in perpetuity. I prefer a solution that makes use of javascript's no-fuss lists (javascript's "arrays"), hashes (javascript's "objects"), and anonymous functions/closures to let me compose program elements at runtime.

Bonus observation: It would be criminal for me to not give credit to Firebug. Apart from its impressive CSS features (dynamically adjusting style rules and immediately seeing the result is a favorite of mine), its javascript debugging is better than sliced bread. Literally. I would forgo sliced bread, chopping loaves with a cleaver, rather than forgo Firebug javascript debugging. Setting breakpoints in javascript code, even in anonymous functions, is my hero. The network activity tracking is also exceedingly convenient for finding out exactly what the asynchronous server request and reply looked like.

Friday, April 20, 2007

Ajax not AJAX

See here.
Apparently Ajax really is just a short, simple buzzword, and not an acronym, which is what I thought. Oops. Luckily many people are case-insensitive (those clods!).

Hey, it's still a step above writing PERL or JAVA.

Tuesday, April 17, 2007

today's edition of fun with english english

I just recently discovered that beaver can be used as an (intransitive) verb: as dictionary.com says, it means "to work very hard or industriously at something (usually fol. by away)".

Gor blimey, English is quite a messed-up language.