Archive for the ‘The Web’ Category

Thoughts on the effect and effectiveness of ranting

Sunday, April 11th, 2010

I’m intrigued by posts like this fix-our-goddamn-Rails-tickets-you-lazy-non-contributing-user rant and Zed’s shut-up-and-learn-C-you-noob rant. I find them relatively tactless, as I’m sure others do, but that says nothing about their effectiveness.

As a writer, it’s a classic value judgment: one one hand, you’re lowering the level of discourse; on the other hand, that may be what’s necessary to reach the pathologically uninformed. From a writer’s perspective, how many new Rails contributors or interested C programmers would justify that kind of entry? I’m reminded of an ESR post I read a while back:

I listened to the others on the channel offer polite, reasoned, factually correct counterarguments to this guy, and get nowhere. And suddenly…suddenly, I understood why. It was because the beliefs the ignoramus was spouting were only surface structure; refuting them one-by-one could do no good without directly confronting the substructure, the emotional underpinnings that made ignoramus unable to consider or evaluate counter-evidence.

Fighting against people’s irrationally-held positions with well-reasoned arguments can be ineffective. When you combine this phenomenon with the web’s insatiable attention to conflict and drama, trollish writing is a predictable and potentially effective result. Especially on the web, infamous and famous aren’t far apart.

Code ☃ Unicode

Thursday, April 1st, 2010

Let’s come to terms: angle brackets and forward slashes are overloaded. Between relational operators, templates, bitwise shift operators, XML tags, (HTML/squiggly brace language) comments, division, regular expressions, and path separators, what don’t they do?

I think it’s clear to everyone that XML is the best and most human readable markup format ever conceived (for all data serialization and database backing store applications without exception), so it’s time for all that crufty old junk from yesteryear to learn its place. Widely adopted web standards (such as Binary XML and E4X) and well specified information exchange protocols (such as SOAP) speak for themselves through the synergy they’ve utilized in enterprise compute environments.

The results of a confidential survey I conducted conclusively demonstrate beyond any possibility of refutation that you type more angle brackets in an average markup document than you will type angle-bracket relational operators for the next ten years.

In conclusion, your life expectancy decreases as you continue to use the less-than operator and forward slash instead of accepting XML into your heart as a first-class syntax. I understand that some may not enjoy life or the pursuit of happiness and that they will continue to use deprecated syntaxes. To each their own.

I have contributed a JavaScript parser patch to rectify the situation: the ☃ operator is a heart-warming replacement for the (now XML-exclusive) pointy-on-the-left angle bracket and the commonly seen tilde diaeresis ⍨ replaces slash for delimiting regular expressions. I am confident this patch will achieve swift adoption, as it decreases the context sensitivity of the JavaScript parser, which is a clear and direct benefit for browser end users.

The (intolerably whitespace-sensitive) Python programming language nearly came to a similar conclusion to use unicode more pervasively, while simultaneously making it a real programming language by way of the use of types, but did not have enough garments to see it through.

Another interesting benefit: because JavaScript files may be UTF-16 encoded, this increases the utilization of bytes in the source text by filling the upper octets with non-zero values. This, in the aggregate, will increase the meaningful bandwidth utilization of the Internet as a whole.

Of course, I’d also recommend that C++ solve its nested template delimiter issue with ☃ and ☼ to close instead of increasing the context-sensitivity of the parser. [*] It clearly follows the logical flow of start/end delimiting.

As soon as Emoji are accepted as proper unicode code points, I will revise my recommendation to suggest using the standard poo emoticon for a template start delimiter, because increased giggling is demonstrated to reduce the likelihood of head-and-wall involved injuries during C++ compilation, second only to regular use of head protection while programming.

Footnotes

[*] Which provides a direct detriment to the end user — optimizing compilers spend most of their time in the parser.

The source is the thing wherein we’ll catch the weirdness of the CSS bling

Tuesday, February 9th, 2010

I’ve always believed in the separation of content and style. Unfortunately, my faith in CSS is being shaken beyond the normal repetition and cross-browser normalization woes. This little snippet just threw me for a loop:

.entry ul li:before, #sidebar ul ul li:before {
    content: "\00BB \0020";
}

The little double-arrow bullet dealy-boppers (glyphs) that my blog theme uses, which I do think are nice looking, apparently aren’t cool enough to be in the default CSS list-style-type glyph set, like disc and double-circled-decimal. The result on the part of the theme designer was the above incantation. Maybe the CSS working group decided to exclude right-pointing double angle quotation mark because it’s slightly more to type than disc? I’m not sure.

Now to the crux of the entry: this all wouldn’t be so bad if there were some indication in either Firebug or the Webkit inspector that the value was present on my li elements. Seeing those two little magical greater-than signs in an HTML entity explorer would have saved precious time. I suppose it’s bug-filing time.

My futile attempt to use one of the entity explorer panes.

After the fact, I found that A List Apart is teaching this voodoo magic! Those rascals! ;-)

Moral of the story: don’t trust that everything relevant to the rendering is being displayed in your web developer tools. If something is styled in a strange way, don’t hesitate too much to run to the sources.

Eliminating web service dependencies with a language-specific abstraction barrier

Thursday, April 9th, 2009

Hyperbolic analogy: Saying, “You shouldn’t need to wrap the web service interface, because it already provides an API,” is like saying, “You shouldn’t need different programming languages, because they’re all Turing complete.”

Web services tend to deliver raw data payloads from a flat interface and thus lack the usability of native language APIs. Inevitably, when you program RPC-like interfaces for no language in particular, you incur incompatibilities for every particular language’s best practices, idioms, and data models. [*] The issue of appropriately representing exceptions and/or error codes in RPC-like services is a notorious example of this.

There are additional specification mechanisms like WSDL [@] that allow us to make the payloads more object-like. Additional structure is indicated through the use of user-defined “complex types,” but this only gets you part of the way to a usable API for any given language. In Python, it’s a lot more sensible to perform an operation like in the following abstraction:

from internal_tracker.service import InternalTracker
bug_serivce = InternalTracker(username=getpass.getuser(),
    password=getpass.getpass())
bug = bug_service.get_bug(123456)
bug.actionable.add('Chris Leary') # may raise ReadOnlyException
comment = Comment(text='Adding self to actionable')
bug.arbs.add_comment(comment)
bug.save() # may raise instanceof ServiceWriteException

Than to use an external web service API solution directly (despite using the excellent Suds library):

# Boilerplate
client = suds.client.Client(wsdl=wsdl_uri)
security = suds.wsse.Security()
security.tokens.append(UsernameToken(getpass.getuser(),
    getpass.getpass()))
client.set_options(wsse=security)
internal_tracker_service = client.service
 
# Usage
service_bug = internal_tracker_service.GetBug(123456)
service_bug.actionable += ', Chris Leary'
# Do we check the response for all WebFault exceptions?
# (Do we check for and handle all the possible transport issues?)
internal_tracker_service.UpdateBug(service_bug)
Comment = internal_tracker_service.factory['Comment']
comment = Comment()
comment.BugId = service_bug.Id
comment.Text = 'Adding self to actionable'
# Again, what should we check?
internal_tracker_service.AddComment(comment)

Why is it good to have the layer of indirection?

Lemma 1: The former example actually reads like Python code. It raises problem-domain-relevant exceptions, uses keyword arguments appropriately, follows language naming conventions, and uses sensible language-specific data types that may be poorly represented in the web service. For example, actionable may be a big comma-delimited string according to the service, whereas it should clearly be modeled as a set of (unique) names, using Python’s set data type. Another example is BigIntegers being poorly represented as strings in order to keep the API language-neutral.

Lemma 2: The layer represents an extremely maintainable abstraction barrier between the client and the backing service. Should a team using the abstraction decide it’s prudent to switch to, say, Bugzilla, I would have no trouble writing a port for the backing service in which all client code would continue to work. Another example is a scenario in which we determine that the transport is unreliable for some reason, so decide all requests should be retried three times instead of one. [!] How many places will I need to make changes? How many client code bases do I potentially need to keep track of?

Why is it risky to use the web service interface?

If the web service API represents the problem domain correctly with constructs that make sense for your language, it’s fine to use directly. (As long as you’re confident you won’t have transport-layer issues.) If you’re near-certain that the backing service will not change, and/or you’re willing to risk all the client code that will depend on that API directly being instantaneously broken, it’s fine. The trouble occurs when one of these is not the case.

Let’s say that the backing service does change to Bugzilla. Chances are that hacking in adapter classes for the new service would be a horrible upgrade experience that entails:

  1. Repeated discovery of leaky abstractions,
  2. Greater propensity to bugs, [^] and
  3. More difficult maintenance going forward.

Client code that is tightly coupled to the service API would force a rewrite in order to avoid these issues.

Pragmatic Programming says to rely on reliable things, which is a rule that any reasonable person will agree with. [&] The abstraction barrier is reliable in its loose coupling (direct modeling of the problem domain), whereas direct use of the web service API could force a reliance on quirky external service facts, perhaps deep into client code.

Is there room for compromise?

This is the point in the discussion where we think something along the lines of, “Well, I can just fix the quirky things with a bunch of shims between my code and the service itself.” At that point, I contend, you’re really just implementing a half-baked version of the language-specific API. It’s better to make the abstractions appropriate for the target language and problem domain the first time around than by incrementally adding shims and hoping client code didn’t use the underlying quirks before you got to them. Heck, if the web service is extremely well suited to your language, you’ll end up proxying most of the time anyway, and the development will be relatively effortless. [$]

What about speed of deployment?

If we have language-specific APIs, won’t there be additional delay waiting for it to update when additional capabilities are added to the backing service?

First of all, if the new capability is not within the problem domain of the library, it should be a separate API. This is the single responsibility principle applied to interfaces — you should be programming to an interface abstraction. Just because a backing service has a hodgepodge of responsibilities doesn’t mean that our language-specific API should as well. In fact, it probably shouldn’t. Let’s assume it is in the problem domain.

If the functionality is sane and ready for use in the target language, it should be really simple for the library owner to extend the language-specific API. In fact, if you’re using the proxy pattern, you may not have to do anything at all. Let’s assume that the functionality is quirky and you’re blocked waiting for the library owner to update with the language-specific shim, because it’s non-trivial.

Now our solution tends to vary based on the language. Languages like Python have what’s known as “gentlemen’s privacy”, based on the notion of a gentlemen’s agreement. Privacy constraints are not enforced at compile-time and/or run-time, so you can just reach through the abstraction barrier if you believe you know what you’re doing. Yes, you’re making an informed decision to violate encapsulation. Cases like this are exactly when it comes in handy.

assert not hasattr(bug_service, 'super_new_method_we_need')
# HACK: Violate abstraction -- we need this new capability right now
# and Billy-Bo, the library owner, is swamped!
suds_client = bug_service._suds_client
result = suds_client.SuperNewMethodWeNeed()
target_result = de_quirkify(result)

As you can see, we end up implementing the method de_quirkify to de-quirk the quirky web service result into a more language-specific data model — it’s bad form to make the code dependent on the web service’s quirky output form. We then submit our code for this method to the library owner and suggest that they use it as a basis for their implementation, so that a) they can get it done faster, and b) we can seamlessly factor the hack out.

For privacy-enforcing languages, you would need to expose a public API for getting at the private service, then tell people not to use it unless they know what they’re doing. As you can tell, you pretty much wind up with gentlemen’s privacy on that interface, anyway.

Footnotes

[*] In EE we call this kind of phenomenon an impedance mismatch, which results in power loss.
[@] And many others, with few successful ones.
[!] Or maybe we want to switch from HTTP transport to SMTP. Yes, this is actually possible. :-)
[^] In duplicating exact web service behaviors — you have to be backwards compatible with whichever behaviors the existing client code relies on.
[&] It’s a syntactic tautology. The caveat is that reasonable people will almost certainly quibble over the classification of what’s reliable.
[$] At least in Python or other languages with a good degree of dynamism, it will.

Fugly default avatars: a force for good?

Monday, February 23rd, 2009

One of the first things I observed in picking up a Twitter account (read: crack pipe of the Internet) was how fugly the default avatars are.

Daunting in its ugliness!

Daunting in its ugliness!

Needless to say, I was immediately repulsed by such an inaccurate representation of my facial features. Although my eyes do often reside in those exact proportions, I have a) more than one lip, b) pupils, and c) I tend to wear a hat. Following this line of reasoning, I had two choices:


Desire of all the avatar-ladies

Desire of all the avatar-ladies

He tries...

He tries...


After the makeover, it was a tough call. A toss up, really, but I decided to go with the slightly more handsome fellow on the right.

After I replaced the default avatar, I stopped for a moment to reflect on the experience. As I stared into the light blue ASCII characters that pass for a face these days, I realized that I had been tricked in a fairly brilliant way…

Fugly default avatars give users initial encouragement to get involved. I didn’t want to be represented by an entity with only one lip that clashed with the color scheme of the site, so I was tricked into putting some work into it. In contrast, the Gravatar default avatar is far too pretty — I could definitely live with an avatar that looks like this without feeling inclined to change it:

Belle of the ball

Belle of the ball

After I spent time working on my “Twitter identity”, I felt more invested in the account. Paying out some “sweat equity” tends to create a psychological attachment. You don’t want your work to be for naught; hence, the time and effort spent personalizing an account makes it more meaningful to you.

Additionally, with your (real) face plastered on every update, you can’t help but feel a sense of responsibility in what you create. All of a sudden, I had a reason to care about the quality of my user-generated content on the site! (People who use less personal avatars will obviously be less affected by this phenomenon.) Of course, there may exist people who like having other users read their content, look at their avatar, and intrinsically register, “Ah, so that’s what a douchebag looks like!” but I am not one of them.

At this point you might be saying, “You’re running out of ideas, man! That point you just made is a specific instance of the more general idea that an increased sense of identity on the web breeds an increased sense of responsibility.” I agree — that may be the case; however, it may also be a totally independent function of image. Case in point: I don’t want people to associate my personal image with douchebaggery, regardless of whether or not they know exactly who I am.