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.

Monday, April 16, 2007

another late commentary: Lord of War

There's a fairly large class of movies that pique my interest, then provoke my interest further when I read the reviews, but I just can't justify putting in the time, effort, money to go to a theater to see them (especially if I have other ways to fill my time, which I do, or if I know I'll be going alone). So I make a mental note to see them later on DVD. But the mental note ends up misplaced, or maybe it's under a stack of mental to-dos, or maybe it slithered out of one ear when I was sleeping. In any case, the rental store didn't have what I came to get, so I finally watched Lord of War, starring Nicholas Cage as a large-scale, illegal weapons dealer. To be fair, by the end of the movie, the question of the very legality of Cage's weapons dealing is thoroughly blurred.

For this is a movie exhibiting a remarkably blurry morality. Viewers who argue that it's pushing a particular political viewpoint aren't seeing the movie as is, like how someone who's been living in the overpowering red glare of a bright sign might mistake tomato juice for milk. Some of the back-and-forth on the imdb forum for this movie would be amusing if it wasn't tragic. Just as everyone watching V for Vendetta should be able to at least agree that loss of freedom is a Bad Thing, everyone watching Lord of War should be able to at least agree that people using huge quantities of weapons to kill innocents is a Bad Thing. As for specific decisions involving many factors, and situations without easy answers, well, that's different.

Naturally, Cage's character, Yuri, doesn't have much to offer in terms of positive platitudes. He does have many short, slanted observations about humanity, though. These observations are the counterpart to positive platitudes: instead of being naively optimistic, they are naively pessimistic. But it's unsurprising coming from someone who earns his cash mingling with humanity's worst. Overall, I don't see his narration as a weakness of the script, but as a window into Yuri's sometimes-disturbingly-accurate viewpoint. His statements are realistic and business-oriented from the start; he goes into the weapons trade after seeing a mob hit, because he figures people will always need weapons - no different than someone opening a restaurant because people will always need food.

The appeal of the movie is likely proportional to how much Yuri's inner contradictions appeal to the viewer. On the one hand, he's someone who gets away with doing what's supposed to be illegal. On the other hand, he's an expert at playing the menagerie of international legal systems so he can't be proven to be on the wrong side of the law. On the one hand, he supplies weapons to people who plan to use those weapons in despicable acts. On the other hand, he knows that if he wasn't selling, then his buyers would still obtain other weapons. On the one hand, he has close business relationships with killers. On the other hand, he involuntarily exclaims in protest when he sees senseless killing. On the one hand, he's practically printing money through being part of a black market (as he says when trying to go straight, the margins of legal work are too small). On the other hand, he doesn't want payment in drugs, women, or other criminal contraband. Diamonds are fine. In passing he mentions that diamonds used to fund violence have been called blood diamonds. Huh, fancy that.

As a conflicted character, Yuri doesn't smile a lot. It took me a little while to guess the most pivotal reason why he continues to do what he apparently doesn't enjoy. He has multiple minor reasons, which are easy to pick out because he narrates them: the money, his talent or knack for it, his desire to keep his wife satisfied, the thrill (he describes his first sale as "over too fast"), his clients' orders for more. I think he sells weapons to attempt to fit himself into a bleak world. He has contempt for everyone, which is why he doesn't take sides by selling weapons to one faction instead of another. His contempt is not only for his individual buyers but for countries, hence his nomadic globe-hopping, numerous passports, disregard for embargoes, and a willingness to sell to those who kill people in his country of origin. By being locked into the mindset that "people kill people regardless of what weapons are available" he emotionally shields himself from the guilt of complicity. Selling weapons in a world that he views to be inescapably violent is both a resignation and a condemnation: resignation because selling weapons does nothing to stop the violence, but condemnation because he is giving them the destructive mayhem they foolishly want. One of the responses to a fatalistic belief is to accelerate the enacting of that belief - it's a way to say "There may be nothing I can ultimately do to stop this, but I don't care! I'll prove how much I don't care, by going along with it!" As the saying goes, "if you can't beat them, join them". Yuri might say "Violence is here to stay. Since that's true, isn't it shrewd to earn money on it?"

In case I haven't made it clear, this movie makes for a depressing viewing experience. Violence, gore, drug use, nudity, and, oh yeah, profanity (in more than one language) are everywhere. The "dirtiness", of what has happened and is continuing to happen, is the point. I didn't find out until afterward that the director was the same one as for Gattaca. Like Gattaca, Lord of War has many compelling shots and it uses those shots to drive home the main point. It represents one big question or issue. I'm not knowledgable enough to offer any answers.

Friday, April 13, 2007

peeve no. 248 is politics on nonpolitical sites

I just seem to be racking up these peeves lately, haven't I? Well, I've been busier, and unlike other posts these peeves almost write themselves, are short, and require no inspiration beyond trivial dissatisfaction...

Seeing purely political diatribes, stories, links, ads, etc. on a web site that isn't geared toward politics unavoidably puts me in a bad mood (sequestering politics in a distinct "Politics" section is, of course, fine, as is politics with a connection to the site's topic matter). If I agree with the political point, I become upset that the point had to be made at all, because it's so obviously right! If I disagree with the political point, I become upset that there are nerfherding idiots polluting the 'Net all the time! The politics must surely be annoying for readers in countries outside the US, too...

If I want to read politics, there's no shortage of politically-geared sites I could go to. Drop the off-subject politicking everywhere else, please!

Friday, April 06, 2007

peeve no. 247 is equating FLOSS to communism

As with some of my other rants, my problem is not so much the existence of something, but how it is used - its connotations and motivations. Merely comparing FLOSS (Free/Libre/Open-Source Software) to communism per se is not what bothers me. Moreover, to some degree the comparison makes sense. FLOSS code wouldn't be FLOSS if it wasn't possible for the masses to use it, share it, study it, refine it, etc. The code is effectively in a massive "communal pool" (laying aside complications of legal incompatibilties between differently-licensed code...). Developers produce according to their abilities, and users consume according to their needs. If only communism worked this well in practice.

On the other hand, an important distinction divides FLOSS from communism: code can be duplicated at little cost, which makes economic analogies less apt because the "supply side" is virtually limitless. This is the premise of shareware; customers can handle the "manufacturing" and packaging and distribution of the product on their own, reducing everyone's cost/risk. Another distinction is the control of the "means of production". These days, compilers and interpreters and entry-level SDK often cost nothing except the time and bandwidth to download them. Depending on the target platform, no special equipment beyond a common PC may be required to produce code, either. Of course, there's still the cost of labor, but until computers comprehend human language, brainstorm brilliant ideas, design attractive images, and so forth, developers will continue to be required. The essential point is that the topics communism concerns itself with are not directly applicable to software methodology, so communism answers questions software methodologydoesn't ask and ignores other questions software methodology does ask.

Unfortunately, generally speaking, the people who compare FLOSS to communism aren't doing it to start up an interesting discussion. No, they do it to end the discussion with a strategy not far removed from name-calling. To turn people away from a vehicle, say "deathtrap". To turn people away from a philosophy (where I live, anyway), say "communism". And this is what irks me, not that the connection may be somewhat approximate, but that anyone thinks it is a convincing argument against FLOSS. "He has pointy ears, like one of those evil leprechauns, so he must be up to no good!"

What's so scary about sharing? What's so problematic about large numbers of people working together, benefitting everyone at once? Developers can still be paid to make the code (some projects have feature "bounties", and one of the dreams of any FLOSS project founder is to be hired by a company to work on that project full-time). The code can still be sold, though the right of anyone to copy the code does mean the most competitive price will be close to if not exactly zero. Speaking more fundamentally, not all code has to be FLOSS. Or someone could compromise. Conceivably, code could be proprietary at first, until the owner decides he or she has milked it enough, then released as FLOSS. Dual-licensing is another avenue, although many developers will be understandably reluctant to contribute to dual-licensed software. And let's be frank. Some software simply won't be written, or written well, unless pay is involved. I've worked on stuff that was so dull, it felt like work.

Charges of communism are pointless. Embrace the commune. Be not afraid. Think of it as a kibbutz, if that helps.

Monday, April 02, 2007

another Halting Problem description

I don't particularly like any of the descriptions of the Halting Problem that I found lying around the Web, so here goes. Assume there is a program, halt or H for short, that solves the halting problem, i.e., whether any program will halt on a hypothetical input. H's input therefore has two components: 1) any program that can run on a Turing Machine (treated or encoded as data), and 2) hypothetical input for the passed program. For Turing Machines, program instructions and data reside on the same "tape", so it's not that incredible for program instructions to function as data or vice versa - for instance, a (Universal) Turing Machine implemented (finitely and imperfectly) in hardware can simulate an incredible number of Turing Machines, so any program in software that can run on one of the simulated Turing Machines will run on the hardware (Universal) Turing Machine.

Now consider another program, NOT-halt or N for short, that builds on H. This is reasonable both because we started by assuming H's existence and because N's additional code is simple as can be: it does what H does to its input, then it performs the opposite of H's result. If H computes "halt", N will not halt. If H computes "no halt", N will halt. For any input x, N(x) does the opposite of whatever H(x) is.

Notwithstanding how rebellious it acts, N is a program like any other, which implies H can determine if N halts or not for any input. So H(y), where y is an input whose program component is N, must return either "halt" or "no halt". Above we established that for any x N(x) does the opposite of whatever H(x) reports, so certainly in the specific case of x=y, N(y) does the opposite of whatever H(y) reports. If H(y) computes a halt, then N(y) does not halt. If H(y) computes a non-halt, then N(y) does halt. But the program component of y is N! If N(y) halts, H(y) should compute halt, not its opposite! And if N(y) does not halt, H(y) should compute non-halt, not its opposite! For program N (input y), H does not work, therefore H does not work for all programs. The original assumption that H works for all programs has met with a contradiction, so there can be no H. The conclusion is that there is no fully general program for computing the halting problem. I hope readers with minds similar to mine, for whom some other Halting Problem descriptions feel unsatisfactory, will find this helpful.