- As near as I can tell, it doesn't do fledgling shows any favors.
- Buffy ended years ago. Years. At what point will this obsession with crowning a successor end?
- If you want to watch a series like Buffy, why not, er, watch Buffy? It's available for home viewing, don't-cha-know.
- The people who ramble on and on about postmodernism (excuse me, pomo) will remind you that it's flourishing these days, Buffy or not. Mixing genres is common, and so is flipping audience expectations upside-down/inside-out.
- Continuing in the same vein, Buffy's uniqueness was not in its elements but in the combination of those elements. A show with hellish stuff in it is not enough to be the "next Buffy". Neither is a show with people who name-drop a wide range of artistic references and generally say comebacks that sound pre-scripted. Neither is a show that compares everyday life to extraordinary premises. Even if a show appears to have parts of the Buffy Secret Sauce, it isn't therefore just like Buffy.
- For TV show comparisons in general, remember that Buffy was (and is) probably compared to shows that aired before it. Comparisons don't communicate what a show is, only its similarities. The point is that, stating the obvious, new shows don't need to be Buffy to be good. Evaluate a show on its own qualities.
Tuesday, October 30, 2007
stop comparing TV shows to Buffy
Monday, October 22, 2007
peeve no. 251 is equating programming and art
I think I understand. Someone can appreciate art by contemplating a work's brilliant juxtaposition of shapes or colors, or by admiring the high level of craftsmanship, or by projecting his or her own reactions onto it (hence, art appreciation has a subjective aspect). Similarly, someone can appreciate code by contemplating its achievement of minimal complexity through a brilliant combination of simpler elements, or by admiring the high level of knowledge and skill applied to it, or by reacting to the symmetric use of whitespace.
Oh, right. The visual distribution of whitespace is entirely beside the point in code appreciation. Know why?
Code has a specific reason to exist. It has a purpose. (When the sentient programs in Matrix Reloaded, whether agents or exiles or Smith, talk about purpose, they're showing a laudable degree of self-awareness.) It does something. It operates. It executes. Data isn't merely one of the concerns addressed by a particular piece of code; data is in a fundamental sense the only real concern. Every cruddy program in existence performs one or more of the universal tasks of creating, reading, updating, and deleting data. True, some programs may do no more than yank pieces of data from here and there, transform or summarize the pieces, and dump out a transitory result. However, what came out (a display screen, a printout) still differs significantly from the data that came in, so data creation has happened. Even games process data: the data is a singularly trivial but highly-lucrative stream resulting from the iteration of a loop of the abstract form "Game State += UI input".
The definite purpose of every snippet of programming code, data processing, is what separates it from art. There is no inherently common purpose of art. Well, besides being the expression of the artist's vision, but a work's success in fulfilling this purpose is necessarily a subjective judgment by the artist, and once the work is finished that purpose is as completed as it will ever be. (Remaking and revising a work to better express the artist's original vision is the creation of a new work. Hi, George Lucas!) This difference in essence between code and art underpins several important distinctions. Although comparing programming and art may be instructional, these are reasons why equating programming and art is not quite right.
The practical conclusion is that the degree of beauty exhibited by code, as appreciated by discriminating programmers, is beside the point if it doesn't imply fewer short-term and long-term bugs. Evaluating and debating code prettiness is not something programmers need to do in order to have substantive discussions about software development. Why is using a popular, well-supported framework likely better than making your own? Yours probably has bugs you don't know about yet. Why is code modularization good? It cuts down duplication, enabling easier and more effective bug fixes. Why is uncluttered syntax good? It affords the programmer more time and attention for the subtler bugs of analysis and design. Why is increasing development agility (whether or not ye gods have deigned you Agile-Approved) good? It minimizes the possibilities for bugs to creep in. Why is understandable code good? It makes the tasks of finding and fixing bugs more productive later.
Don't show and tell me how shiny my code will be, thanks to your silver bullet. Show and tell me how bug-free, how effortlessly correct my code will be, thanks to your silver bullet. I am not an artist.
Oh, right. The visual distribution of whitespace is entirely beside the point in code appreciation. Know why?
Code has a specific reason to exist. It has a purpose. (When the sentient programs in Matrix Reloaded, whether agents or exiles or Smith, talk about purpose, they're showing a laudable degree of self-awareness.) It does something. It operates. It executes. Data isn't merely one of the concerns addressed by a particular piece of code; data is in a fundamental sense the only real concern. Every cruddy program in existence performs one or more of the universal tasks of creating, reading, updating, and deleting data. True, some programs may do no more than yank pieces of data from here and there, transform or summarize the pieces, and dump out a transitory result. However, what came out (a display screen, a printout) still differs significantly from the data that came in, so data creation has happened. Even games process data: the data is a singularly trivial but highly-lucrative stream resulting from the iteration of a loop of the abstract form "Game State += UI input".
The definite purpose of every snippet of programming code, data processing, is what separates it from art. There is no inherently common purpose of art. Well, besides being the expression of the artist's vision, but a work's success in fulfilling this purpose is necessarily a subjective judgment by the artist, and once the work is finished that purpose is as completed as it will ever be. (Remaking and revising a work to better express the artist's original vision is the creation of a new work. Hi, George Lucas!) This difference in essence between code and art underpins several important distinctions. Although comparing programming and art may be instructional, these are reasons why equating programming and art is not quite right.
- Primarily, programming is objective in a way that art isn't. Code has a specific purpose, which is processing data in a specific way. If a machine executes the code, but the data processing has not occurred correctly, the cause may be complicated and subtle (or so simple as to be overlooked), but something has undeniably failed. The purpose(s) of art are not so explicit and obvious, which means the failure(s) of an artwork are not so explicit and obvious. Horrible art may be "ugly", but horrible programming is borked.
- For computers and code to feasibly/acceptably automate data processing, the objectively-evaluated accuracy just described must be consistently reliable. Therefore, computers and code must be deterministic. Parts of the data processing may be "indeterminate", like a string of pseudo-random numbers, or parts of the execution order itself may be indeterminate, like a set of parallel threads, but taken as a whole, the guaranteeing of accurate results implies determinism. Determinism, in turn, implies that inaccuracies do not "happen spontaneously", but have a root cause. The root cause in any particular situation may in fact be an erratic one, due to flaky memory for instance, but nevertheless the inaccuracy has a determinate cause. More to the point, if the programming is at fault, then this cause is known as a bug. Since all parts of the code are intertwined, and code, while it can be fault-tolerant, certainly isn't self-conscious and self-correcting (that's what programmers are for!), it follows that, speaking in general of code from the metaphor of a "black box", an inaccuracy could potentially be due to any part of the code. When the code as a whole can objectively fail, then every part of the code can objectively fail, too. An artwork is much more forgiving of its parts. Critics of any art form will comment that a work had some "regrettable qualities", but "by and large, succeeded". Programming has a much more menacing antagonist, the bug, and no matter how artistically or aesthetically correct the code is, one lil' bug means the code, at least under some conditions, is fatally flawed.
- Continuing the bug discussion, the dirty little non-secret of programming is that, with few exceptions, no sufficiently complex code is entered without mistakes the first time, or the second time, or the third time. The wizards and geniuses of programming confess to regularly forgetting about some minor detail (is it array.length or array.length()?), and mistyping identifiers (what was the name of the variable for the number of combinations?). Speaking out of my ignorance and lack of artistic talent, the mental exertion/concentration required to perfectly perform the concrete actions of programming--obeying syntax, tracking semantics, remembering the general flow of the design/algorithm, error-free typing--outweighs the similar demand on the artist. In response, helpful programming-oriented editors arose, built for relieving some of the strain with auto-completion and other code assists.
- Moreover, bugs in the manual transcription of a design/algorithm are some of the easier ones to catch. Programming is an excellent illustration of how easy it is to gingerly proceed through a canned series of steps, appearing to conscientiously complete each one, and end up creating complete horsepucky (or, if you prefer, bulldooky). As people swiftly discover after exiting school, the unwritten assumptions and the errors in reasoning about the data domain can yield code which processes the wrong data, processes data irrelevant to the user's needs, processes the data insufficiently for easy use. Consequently, transactions with programming clients differ from transactions with art patrons. The art patron (editor, supervisor, commissioning official) has a set of loosely-defined outlines/parameters for the artist to follow, and the art should be acceptable if it is within those boundaries. The programming client quite likely also has a set of loosely-defined requirements, but, because code is not art, code is strictly defined: this input transformed to that output. Loose definitions of the purpose are insufficient for code because loose results from code are insufficient. Take a stupid example, a crayon illustration. Is the purpose of "calculating sales tax" met by code which assumes a tax rate for California? Yes--but just if the input and output is Californian! A programming client who loosely states he or she wants code that "calculates sales tax", receives that code, and runs it in Wyoming, is not happy.
- A greater amount of precision distinguishes programming requirements from artistic. Time does, as well. Artworks can be unchanging, and remain sublime expressions of the human spirit--this "requirement" of the artwork doesn't shift. In contrast, as the turn of the century reminded everyone, a shift in requirements around pristine code can make it useless. "Functioning as designed" turns to "bug". It's a cascading effect: the world changes, the data that represents the world changes, the processing of the data changes, the code that implements the data processing changes. No doubt, certain codebases are long-lived, but only by embodying the most general of concepts and nurturing areas of change. emacs continues both on account of meeting the continuing need to edit text and supporting arbitrary extensions.
The practical conclusion is that the degree of beauty exhibited by code, as appreciated by discriminating programmers, is beside the point if it doesn't imply fewer short-term and long-term bugs. Evaluating and debating code prettiness is not something programmers need to do in order to have substantive discussions about software development. Why is using a popular, well-supported framework likely better than making your own? Yours probably has bugs you don't know about yet. Why is code modularization good? It cuts down duplication, enabling easier and more effective bug fixes. Why is uncluttered syntax good? It affords the programmer more time and attention for the subtler bugs of analysis and design. Why is increasing development agility (whether or not ye gods have deigned you Agile-Approved) good? It minimizes the possibilities for bugs to creep in. Why is understandable code good? It makes the tasks of finding and fixing bugs more productive later.
Don't show and tell me how shiny my code will be, thanks to your silver bullet. Show and tell me how bug-free, how effortlessly correct my code will be, thanks to your silver bullet. I am not an artist.
Thursday, October 18, 2007
looking forward to completing your training
It's been a long time since I had anything on here about .Net or F#, but this news is too noteworthy to ignore. Plans are afoot to move F# from a research language into one of the officially-supported, "first-class" .Net languages. That probably means "first-class" more in the sense of IronPython/IronRuby than C#/VB, but in any case Microsoft will be starting to devote real resources to developing F# and further improving its Visual Studio integration (F# has always had the highly-useful "identifier mouseover to see inferred data types" as part of its plugin). Congratulations Don.
Monday, October 15, 2007
advanced playlists in amarok
Lately I've been making greater use of smart and dynamic playlists in amarok. I felt it would be criminally callous not to share my experiences and appreciation.
A dynamic playlist is really a configurable playback mode that automatically enqueues random tracks for playing and removes played tracks from view as each track ends. Each dynamic playlist uses one or more playlists, including smart playlists, as the source of tracks. (The built-in dynamic playlist "Random Mix" just uses the entire collection.) The user can add or remove or reorder tracks while the dynamic playlist is running, but the dynamic playlist will only add or remove tracks as it needs to, according to its settings. The aim of this feature is to keep the resource use of the player down, of course, and the visible list of tracks to a manageable level. It reminds me of the "stream" or "lazy sequence" concept--if one is only processing one or a small subset of members of the input at once, it's more efficient to sequentially retrieve or produce no more than that input portion for the algorithm, as it proceeds. In actuality, the input stream may be internally buffered for efficiency, though this doesn't matter to the consuming algorithm.
I'm more impressed by smart playlists, which aptly provide another demonstration of the value in storing audio metadata in a database. Smart playlists are defined by setting desired track characteristics. The smart playlist then automatically includes tracks with those characteristics. This is a straightforward idea for relieving users of the daunting alternative task: managing a custom playlist's contents through repetitive interface manipulations (for small playlists and collections, this is a chore, for larger playlists and collections, this is nigh-unworkable). What turns smart playlists from a helpful aid to a swoon-inducing beloved companion is the comprehensiveness of the create/edit window. The query-building capability is dreamy. Its power is intoxicating. A competing Ajax application (is there one?) would need to work hard to convince a user to stray.
The set of characteristics to query on includes the usual standbys, Title and Artist and Album and Genre. The additional options, that make one go week in the knees, are Length, Play Count, Year, Comment, First Play and Last Play date, Score, Rating, Mount Point, BPM, Bitrate, and Label. Labels, also known as tags in other contexts, are words associated with tracks in a many-to-many relationship. As usual, the value lies in the ability to create ad-hoc groups using the labels/tags. One smart playlist could contain all tracks with one label, another smart playlist could contain all tracks with another label, etc. This way of creating playlists by label may not seem superior to the technique of creating custom playlists. However, when a new track should be in five different custom playlists, it's easier to drag the five corresponding previously-used labels onto the new track and let the playlists do the grouping work.
To make the process of entering a filtered characteristic still more alluring, after choosing a particular characteristic from the drop-down list, a set of controls to the right of the list change to only offer the choices that make sense for that characteristic. For instance, a numerical characteristic leads to a drop-down list of connectives such as "is", "is not", "is greater than", "is less than", followed by an input box for numbers (and little increment/decrement arrows to change the value by clicking, if you swing that way). A textual characteristic switches the list of connectives to regexp-like choices such as "contains", "starts with", "does not start with", followed by a combobox whose assisting drop-down portion contains all the actual examples of the chosen characteristic in the collection. After choosing Genre, it might contain Reggae. This is more than "user-friendliness". This is admirable consideration in the partnership between interface and user. The fewer mistakes the user is likely to make, the less aggravation is involved in getting what he (or she) really really wants.
So the depth of each filtering characteristic reaches areas of need the user wasn't aware was there, but further enamoring is the possible breadth. On the far right of each characteristic are two buttons labeled + and -. Clicking + adds a new, identical row of controls for filtering based on an additional characteristic. As you might expect, clicking - on a row of controls removes it and its associated characteristic filter. A group of any number of filtering characteristics, that can grow or shrink on command (I've never craved more than three), is fine, but it lacks some flexibility: this assumes that all the filters must be satisfied simultaneously. What about when a user merely wants one or more of the filters to be satisfied by any one track? The filters the user wants to treat this way are separately grouped on screen under a header that starts with the words "Match Any" (the other grouping's header starts with the words "Match All").
Underneath, the window has some options for organizing the resulting list of tracks. The user may order the tracks according to a particular characteristic in ascending or descending order. At the time the playlist is loaded by the player, the tracks can be resorted easily, and a dynamic playlist based on the smart playlist would play tracks randomly in any case, so the order option isn't of much interest apart from its use in conjunction with the limit option. In the same way, using the limit option to keep a playlist small is not necessary if playback proceeds in a dynamic playlist. But put together, the order and limit options could enable the creation of a playlist of the "twenty top-rated tracks less than two minutes long", for instance. (Ratings and scores are different things in amarok, but that's a whole 'nother blog entry.) The "expand" option selects a characteristic to automatically group tracks into subsidiary playlists, in each of which all the tracks have that same characteristic in common. In the playlist choosing pane, the subsidiary playlists appear as "tree children" of the smart playlist--expanding the smart playlist like a folder shows all of its subsidiary playlists indented underneath it as separate playlists. Choosing an expand option is probably not an appreciable gain for most smart playlists, but for huge lists it's valuable.
Did you know that clicking the middle button (or possibly the scroll wheel, depending on the mouse) on the amarok tray icon pauses and resumes? If the devil's in the details, then amarok is my Dark Lord.
A dynamic playlist is really a configurable playback mode that automatically enqueues random tracks for playing and removes played tracks from view as each track ends. Each dynamic playlist uses one or more playlists, including smart playlists, as the source of tracks. (The built-in dynamic playlist "Random Mix" just uses the entire collection.) The user can add or remove or reorder tracks while the dynamic playlist is running, but the dynamic playlist will only add or remove tracks as it needs to, according to its settings. The aim of this feature is to keep the resource use of the player down, of course, and the visible list of tracks to a manageable level. It reminds me of the "stream" or "lazy sequence" concept--if one is only processing one or a small subset of members of the input at once, it's more efficient to sequentially retrieve or produce no more than that input portion for the algorithm, as it proceeds. In actuality, the input stream may be internally buffered for efficiency, though this doesn't matter to the consuming algorithm.
I'm more impressed by smart playlists, which aptly provide another demonstration of the value in storing audio metadata in a database. Smart playlists are defined by setting desired track characteristics. The smart playlist then automatically includes tracks with those characteristics. This is a straightforward idea for relieving users of the daunting alternative task: managing a custom playlist's contents through repetitive interface manipulations (for small playlists and collections, this is a chore, for larger playlists and collections, this is nigh-unworkable). What turns smart playlists from a helpful aid to a swoon-inducing beloved companion is the comprehensiveness of the create/edit window. The query-building capability is dreamy. Its power is intoxicating. A competing Ajax application (is there one?) would need to work hard to convince a user to stray.
The set of characteristics to query on includes the usual standbys, Title and Artist and Album and Genre. The additional options, that make one go week in the knees, are Length, Play Count, Year, Comment, First Play and Last Play date, Score, Rating, Mount Point, BPM, Bitrate, and Label. Labels, also known as tags in other contexts, are words associated with tracks in a many-to-many relationship. As usual, the value lies in the ability to create ad-hoc groups using the labels/tags. One smart playlist could contain all tracks with one label, another smart playlist could contain all tracks with another label, etc. This way of creating playlists by label may not seem superior to the technique of creating custom playlists. However, when a new track should be in five different custom playlists, it's easier to drag the five corresponding previously-used labels onto the new track and let the playlists do the grouping work.
To make the process of entering a filtered characteristic still more alluring, after choosing a particular characteristic from the drop-down list, a set of controls to the right of the list change to only offer the choices that make sense for that characteristic. For instance, a numerical characteristic leads to a drop-down list of connectives such as "is", "is not", "is greater than", "is less than", followed by an input box for numbers (and little increment/decrement arrows to change the value by clicking, if you swing that way). A textual characteristic switches the list of connectives to regexp-like choices such as "contains", "starts with", "does not start with", followed by a combobox whose assisting drop-down portion contains all the actual examples of the chosen characteristic in the collection. After choosing Genre, it might contain Reggae. This is more than "user-friendliness". This is admirable consideration in the partnership between interface and user. The fewer mistakes the user is likely to make, the less aggravation is involved in getting what he (or she) really really wants.
So the depth of each filtering characteristic reaches areas of need the user wasn't aware was there, but further enamoring is the possible breadth. On the far right of each characteristic are two buttons labeled + and -. Clicking + adds a new, identical row of controls for filtering based on an additional characteristic. As you might expect, clicking - on a row of controls removes it and its associated characteristic filter. A group of any number of filtering characteristics, that can grow or shrink on command (I've never craved more than three), is fine, but it lacks some flexibility: this assumes that all the filters must be satisfied simultaneously. What about when a user merely wants one or more of the filters to be satisfied by any one track? The filters the user wants to treat this way are separately grouped on screen under a header that starts with the words "Match Any" (the other grouping's header starts with the words "Match All").
Underneath, the window has some options for organizing the resulting list of tracks. The user may order the tracks according to a particular characteristic in ascending or descending order. At the time the playlist is loaded by the player, the tracks can be resorted easily, and a dynamic playlist based on the smart playlist would play tracks randomly in any case, so the order option isn't of much interest apart from its use in conjunction with the limit option. In the same way, using the limit option to keep a playlist small is not necessary if playback proceeds in a dynamic playlist. But put together, the order and limit options could enable the creation of a playlist of the "twenty top-rated tracks less than two minutes long", for instance. (Ratings and scores are different things in amarok, but that's a whole 'nother blog entry.) The "expand" option selects a characteristic to automatically group tracks into subsidiary playlists, in each of which all the tracks have that same characteristic in common. In the playlist choosing pane, the subsidiary playlists appear as "tree children" of the smart playlist--expanding the smart playlist like a folder shows all of its subsidiary playlists indented underneath it as separate playlists. Choosing an expand option is probably not an appreciable gain for most smart playlists, but for huge lists it's valuable.
Did you know that clicking the middle button (or possibly the scroll wheel, depending on the mouse) on the amarok tray icon pauses and resumes? If the devil's in the details, then amarok is my Dark Lord.
Thursday, October 11, 2007
hey Microsoft - fix THIS bug
Greatest of thanks to the Ran Davidovitz blog for investigating and publishing about this confounding IE bug. removeChild in certain cases will cause a secured (https) page in IE to toss up the security warning about mixed content (which, on some pages I've been to, actually means "the ad banners on this page are susceptible to traffic sniffing by third parties! oh noes!").
Obviously, IE isn't the only browser that contains bugs, and its CSS rendering alone should be addressed first, but my teeth hurt a little from grinding over an obtrusive security warning from the browser about normal execution of code on the page.
Obviously, IE isn't the only browser that contains bugs, and its CSS rendering alone should be addressed first, but my teeth hurt a little from grinding over an obtrusive security warning from the browser about normal execution of code on the page.
Tuesday, October 09, 2007
link: the agile memeplex
ACM Queue has an article analyzing agile development/methodology as a "memeplex": a collection of memes. Unlike some other writing on the 'Net, it goes to the hassle of defining what exactly a "meme" is, and it even uses the word to mean something beyond "blog fad". Its point is that all things Agile are more convincing and meaningful when context is included. Moreover, the vocabulary of Agile is less mystifying after people understand the more-traditional software development concepts the words are almost-synonyms for. As I read it, the article is not an attack on Agile, but a plea to delve into the ever-important details to extract and integrate agile (lower-case) ideas confidently.
The article also mentions in passing that the name "Extreme Development" may have incited both interest and disinterest among developers. Speaking as someone who's generally annoyed by X-treme usage of "extreme", I must agree. (Perhaps "extreme" is the new "awesome"?)
The article also mentions in passing that the name "Extreme Development" may have incited both interest and disinterest among developers. Speaking as someone who's generally annoyed by X-treme usage of "extreme", I must agree. (Perhaps "extreme" is the new "awesome"?)
Saturday, October 06, 2007
another Lost coincidence?
Jack Sheppard, infamous criminal.
Jack Shephard, Lost character.
Coincidence? Yeah, probably. The mere fact I'm wondering about it at all is a consequence of the writers embedding so many other miscellaneous references into the show. In any case, it's still more noteworthy speculation fodder that one of the characters shares the exact name of an extremely well-known philosopher.
Jack Shephard, Lost character.
Coincidence? Yeah, probably. The mere fact I'm wondering about it at all is a consequence of the writers embedding so many other miscellaneous references into the show. In any case, it's still more noteworthy speculation fodder that one of the characters shares the exact name of an extremely well-known philosopher.
Friday, October 05, 2007
db4o articles on developerWorks
The db4o series (that is one gnarly URL!) on developerWorks is intriguing and easy to read. I didn't know anything about db4o before reading it, but the first article starts at the bottom level. db4o is an object database specifically oriented toward Java and C#. It's designed to eliminate the object-relational impedance mismatch by...tossing out the "relational". Save an object. Retrieve it. According to the articles, db4o certainly meets the goal of higher developer productivity.
I'm still skeptical about how it compares to the usual SQL databases in several ways: storage efficiency/data duplication, performance, security, scalability. It was also interesting to note in the later articles that db4o faces some of the identical difficulties as ORM tools: lazy loading, inheritance hierarchies, collections of collections (of collections of collections), refactoring, mutually-referenced objects. As an object database closely integrated into code, db4o has distinct advantages when confronting these difficulties, though. The fact that every object has a unique ID automatically probably helps a lot.
For a new application (greenfield), db4o might be fun to try. Where I work, all the data that matters is stored in "legacy" keep' em-running-til-they-croak language-agnostic databases, so db4o isn't an option. Not without a messy bridging/replication layer, in any case. Software that makes data integration much easier is software that can conquer the world.
I'm still skeptical about how it compares to the usual SQL databases in several ways: storage efficiency/data duplication, performance, security, scalability. It was also interesting to note in the later articles that db4o faces some of the identical difficulties as ORM tools: lazy loading, inheritance hierarchies, collections of collections (of collections of collections), refactoring, mutually-referenced objects. As an object database closely integrated into code, db4o has distinct advantages when confronting these difficulties, though. The fact that every object has a unique ID automatically probably helps a lot.
For a new application (greenfield), db4o might be fun to try. Where I work, all the data that matters is stored in "legacy" keep' em-running-til-they-croak language-agnostic databases, so db4o isn't an option. Not without a messy bridging/replication layer, in any case. Software that makes data integration much easier is software that can conquer the world.
Subscribe to:
Posts (Atom)