The Chinese Interpreter

Mar 2008

There was a man who wanted to visit Italy, during his vacation. It is difficult to go around in Italy if you don't speak Italian, so our man was about to spend some time studying Italian. Italian has the reputation of being an easy language to learn, so our man was not very bothered by this chore, but he happened upon an old friend.

What do you need to learn Italian for?, asked the friend. Even if Italian is easy, why should you spend even a day of your life learning it?

But I don't have a choice, protested our man, In Italy, one has to speak Italian.

The friend took him aside by the arm, as if wanting to share a secret, and told him in a toned down voice, while leaning nearer: Trust me and do the smart thing. He glanced around to see if anyone was ovehearing. I have the perfect solution for your troubles.

He silensed for a moment, to make sure he was building up a tension. You don't need to learn a word in Italian. Besides, Italian is very verbose. Talking directly in Italian would be counter-productive. Believe me, you'll find yourself talking to exhaustion just to order a meal.

I'm afraid I don't see your point, puzzled our man. What do you mean “talking directly”, and what alternative do I have?

The friend slapped him on the shoulder and stood erect like a man on a soapbox: I know where you can hire a Chinese interpreter for less than a penny a day!

Our man was dumbfounded. What good would a Chinese interpreter do? Won't I need to speak Chinese to him?

The friend looked at him with a paternizing expression. That's what I meant with “smart thing”. Don't believe the common wisdom that Chinese is difficult and Italian is easy. The truth is, that you can get by with a handful of Chinese, but you have to learn most of Italian to achieve the same level of communication. Do you know why?

Our man shrugged in incomprehension.

The friend continued aloud, suddenly not caring for overhearers. Because the Chinese interpreter has a great knowledge of your everyday needs. He understands your intention with just a hint from your part.

Our man stayed silent and made sure that “disbelief” was written prominently on his looks.

The friend continued with great conviction. You'll never go into much detail. All you'll have to do, is utter a few words - heck, Chinese is so terse that the few words will rather sound like a few syllables - and you'll hear the Chinese interpreter go on for many minutes chit-chatting with Italians and taking care of everything on your behalf.

To make a long story short, our man decided to try out his friend's advice. He went to Italy and hired the Chinese interpreter. At first, the deal was working out very well. He spent like half an hour learning basic Chinese words, and he roamed the streets all day, buying stuff, ordering in restaurants and having a great time.

After the first week, though, things started looking less encouragingly. Certainly, he was getting by and all his needs were covered, at a basic level, but there were little things that bothered him. For example, his breakfast never seemed to have the egg boiled like he wanted it, or the bread toasted like he wanted it.

So he learned a bit more Chinese, to be able to describe his needs to the Chinese interpreter. It had an immediate effect on his quality of life, and he was very pleased with himself. Not only was he getting things done, but he was also slowly mastering Chinese, which was no small an achievement. Soon, he was spending a good part of the day on Chinese grammar, Chinese syntax and Chinese idioms. He made friends with the Chinese interpreter, as his mastery of Chinese progressed. He begun spending more and more of his vacation exercising his Chinese, instead of visiting museums and interesting places. He even caught himself showing off his ability in Chinese in front of other tourists. The low-lives! Anyone could learn Italian, what's the credit in that?

But he couldn't help notice that, even though things were a lot better than before, there was still a small discrepancy between what he wanted and what he got. He took great pride in his Chinese, but he wasn't learning it fast enough to be fluent soon. Besides he saw other tourists talking enthusiastically to one another about their vacation, and he couldn't avoid being a little jealous.

However, he had invested a lot of time and energy in his Chinese. He couldn't possibly back out now. Surely there was a way to coerce his interpreter into saying the correct Italian every time. So he spent some time listening to the Chinese interpreter while he was translating in Italian. With the help of a self-study book, he spent some time on Italian grammar and vocabulary (by the way, he found that Italian was, indeed, very easy to learn). Now, as his Chinese phrase was being translated to Italian, he was able to figure out what was wrong with it, and why it was producing the result it did. He begun trying different formulations in Chinese, in order to tune the Italian the way it should have been. This consumed even more of his time. In the end he did very little in the way of tourism every day.

The allegory

This fictitious story came to my mind when I first approached ASP.NET programming. The ASP.NET world is supposedly very productive for "line-of-business development" (Microsoft's terminology). Well, it might be true that a running page can be set up very quickly in the ASP.NET way. But I also saw people sweating over so many minute things to go the extra 1% to a fully-functional, debugged page, spending so much time to overcome unintended interactions and startling behaviors of the framework itself, that I sincerely doubt that the total time per page ends up being less than that for other, competing technologies (whichever they might be).

The particular allegory of the “Chinese Interpreter” talks of one particular aspect of ASP.NET development: the alienation from the underlying HTML. HTML, warts and all, is so simple that attempting to "hide" it behind another layer cannot possibly gain you anything. ASP.NET demands a leap of faith, with the promise of taking care of rendering completely. In the end, people understand that surrendering control of HTML rendering is not a good idea, because it works in 99% of the cases and doesn't in 1% of the cases, which invariably end up taking a lot of time to fix, struggling with a fundamentally black box. The more talented teams end up creating their own controls to regain back control of rendering. And you can forget about support for outputting anything else than desktop-grade HTML (meaning all kinds of other markups, like XHTML Basic, WML, cHTML etc) and especially multi-channel rendering, where you need to output the same content in many markups simultaneously.

The amount of effort exerted in order for "line-of-business" programmers to simply make things work for them, is apparent in the plethora of forum threads where more seasoned programmers explain to greener ones the tricks to apply to ASP.NET. Surely something that needs so much explaining cannot be regarded as simple, in any meaning the word might have.

An example that pops into my mind, is CSS that breaks in different browsers, when ASP.NET renders different HTML for them. The framework pushes you to stay inside it, since trying to work at the level of HTML is a hussle. Integrating external Javascript libraries, applying the last CSS trick you saw on the Web, usually take so much trouble that most people don't do it. If you abolutely want to do it, you end up reverse-engineering the HTML and the Javascript, just to be able to talk to it through DOM.

Another example I remember is someone trying to debug a faulty Prototype-based script. In the end, we found out that ASP.NET redefined $, which is a utility function used extensively in Prototype. ASP.NET redefined it to return a DOM node based on a string (the ID), but failed to implement it exactly the way Prototype did. The problem here is not the redefinition of $, as many frameworks mimic Prototype and provide their implementation of this handy utility. The problem is that ASP.NET encompasses a Javascript framework of its own, which is attached automatically to your page and is nowhere explained. Why? Because you're not supposed to know. Because you're supposed to let it work automagically and don't look under the hood. Because you're not supposed to integrate anything else with it, or debug it.

Taking over HTML rendering is only one aspect of ASP.NET and it is not my only qualm. I will go as far as saying that it is orthogonal to its other aspects that bother me, as one could imagine a framework that had various combinations of them. However, all of them embody a single philosophy, which is:

Carry Windows/VB skills over to Web development.

Is this a reproachable goal? Not necessarilly. But, in reality, even though you get drag-and-drop controls and an event model, nothing else carries over. You have to learn a gigantic framework from scratch. My favorite description of this process is ascending the Masonic degrees from apprentice to master. Central in ASP.NET processing is the page lifecycle, which consists up to a dozen discrete steps (the amount of detail you learn about is concordant to your degree) which interact intricately with your code. Very soon you occupy yourself more with how to use the framework in the "correct" way, than with solving your client's needs. And this is the slippery slope of ASP.NET.

During my first days of learning about ASP.NET, I roamed the Web in order to find an example for doing something that was supposed to be very easy: vary the contents of a table cell according to different data. For example, if amount is more than 0, show the amount, else show a link to the "GetLoan" page. It appears that the "correct" way to do this to intercept some internal event that fires as each table row is being created internally, and hack the different markup snippets in code. Yes, code. Apparently, even though ASP.NET uses a template language to create markup, once you want to do conditionals and such, you have to do it in code ("codebehind", it's called). And once you pass the barrier from template page to code, you cannot go back. You find yourself assembling markup, piece by piece, from elementary controls.

Controls, in themselves, are curious beasts. They fall in two categories: user controls and server controls (of which template controls are a subcategory). User controls have a markup part, and server controls are defined solely in code.

FactorsUser controlCustom control
Deployment Designed for single-application scenarios. Deployed in the source form (.ascx) along with the source code of the application. If the same control needs to be used in more than one application, it introduces redundancy and maintenance problems. Designed so that it can be used by more than one application. Deployed either in the application's Bin directory or in the global assembly cache. Distributed easily and without problems associated with redundancy and maintenance.
CreationCreation is similar to the way Web Forms pages are created; well-suited for rapid application development (RAD) Writing involves lots of code because there is no designer support
Content A much better choice when you need static content within a fixed layout, for example, when you make headers and footers More suited for when an application requires dynamic content to be displayed; can be reused across an application, for example, for a data bound table control with dynamic rows
Design Writing doesn't require much application designing because they are authored at design time and mostly contain static data Writing from scratch requires a good understanding of the control's life cycle and the order in which events execute, which is normally taken care of in user controls

Yes, you can't have your cake and eat it, too.

Peculiarities alone, the problem with automagical rendering is that, when something breaks, you can seldom trace it back to its origins and fix it. To use the Chinese interpreter allegory, when you order a crusty pizza with onions and you get a punch to the face by an angry Italian waiter, there's no way to know what went wrong. Even if you pay attention to the Italian that offended him, it is not easy to know which Chinese word caused the trouble, and what word to use in its place to fix things.

This problem is exaggerated through the use of 3rd-party controls, supposedly productivity-boosters, where control of rendering is usually at the mercy of whatever custom parameterization the vendor offers (remember that ASP.NET does not promote easy CSS styling but custom properties). Since each control retains some of the design decisions of its vendor, the UI risks becoming a “franken-UI”.

Rendering magic is not proper to ASP.NET, even though it is here carried to ridiculous lengths (see sidebar link on how to create a... link to another page). But ASP.NET adds another automagical layer, that probably does more overall harm: it hides HTTP.

You can read about adverse effects this has in some links in the sidebar. Basically, by brushing aside the essential addressability of the Web, it loses everything that is given at no cost:

  • Testability and traceability. Forget JMeter, LiveHTTPHeaders and HTTP logs. Postbacks send mangled data, and viewstates' bytesize run to the hundreds.
  • Bookmarkability. You're never in a place where you can go back later. Wherever you are, you got there with a series of interactions which are not reflected in the URL.
  • Reload and Back button. Everything is based on POST, so these operations can be problematic.
  • Easy paging through results with index parameters.
  • (I've also read that asynchronous AJAX calls can fail with ViewState exceptions if more than more than one request fires at a time.)

I'm not prepared to give up so much. I like HTTP, and I know inside me that sticking to what is natural with HTTP leads to less effort. With HTTP navigation, there's always someplace you are, and this someplace is naturally defined as a URL with a static part that reflects the overall location, and dynamic parameters that specify the exact location. This query-based approach to navigation gives a lot of functionality at exactly no cost. The user's behavior is directly discernible by the pattern of HTTP calls, and the content of those calls is self-evident. The URLs are bookmarkable. Even though they might not return the same data the next time you visit them, the call will mean the same thing. Reload and Back work naturally. Paging is just another qualifying parameter in the URL.

ASP.NET leads to a user experience that is more like Access than the Web. Since postback goes back to the same page, the most natural thing to do is to create pages that encompass both the query form and the results. Furthermore, due to a design decision, the whole page should be created as a single, undivided form (forget reusable search forms or other peripheral widgets). ASP.NET 2 did add the ability to postback to another page, but it is still a kludge. And, in any case, the user experience is still that of Access. You search, the results pop out. No addressability. The application becomes a number of disconnected areas where you manipulate disconnected data. Adding to the Access effect is the omnipresent data grid, that displays tabular data. First of all, as far as tabular data presentation in HTML is concerned, the data grid is extremely poor in capabilities. But the worst thing is that is leads to a display of dead data that is the opposite of what a Web application should be. Whenever an entity identifier appears in a page, you should make it a link to its main location where the user can browse its details. This is hyperlinking at the data level, and it is a natural implication of addressability. When you see a person working a Web application with a scratchpad and a pencil on the side, using it to jot down identifiers from one page to enter them in another page, you know that something is wrong. Yet, this is the result of simply displaying dead data.

Natural HTTP interactions are very well suited to the concept of navigation. But a lot of what happens in an HTTP application concerns modifications. Fear not, as HTTP carries within it powerful idioms to handle that as well. See the link on Post/Redirect/Get in the sidebar. This is a way to ensure proper navigation and the Back button, even in the face of POSTs (it works on practically all browsers save some quirky mobile ones).

And, speaking of mobile browsers, working with them is really an experience that will wear out all ASP.NET enthusiasts. Lacking client-side Javascript to support the "canonical" ASP.NET operation, one understands really how poor ASP.NET is to handle HTTP (and every markup other than HTML, by the way). I strongly suggest a month of developing HTTP applications for mobile phones to everyone who kept thinking how much I have misunderstood ASP.NET, while reading this text.

My ASP.NET Survival Guide

I do not wish to bash ASP.NET, but my opinion is that deep involvement with ASP.NET not only sidetracks from proper work, it also results in HTTP applications that are deficient and unnatural. Myself, I have chosen to give up practically all the automagical workings and the 12-step lifecycles and work simply. First of all, the lifecycle is condensed to two steps: Load and Render. Page_Load interprets HTTP parameters, invokes back-end logic and leaves values in properties (or redirects). ASPX/ASCX markup uses values to render the appropriate HTML.

Second, the markup itself is generated the reverse way than usual: first a front-end architecture is designed (if time permits, to the level of working HTML mockups), where the exact markup (including form parameters and links) and scripts are defined, then ASP.NET is used to generate exactly the prescribed front-end architecture. This also has the effect that it decouples the application from any specific technology. Repeaters and nested repeaters are used for looping (all but the outermost can "Bind()" declaratively). Placeholders are used for conditionals (all but the outermost can have their "Visible" property set declaratively). <%= %> and <%# %> are used to output content items. User Controls are used for individual panes in a page, which are reusable. Not only that, but, minimizing the named controls in the page that need to be refered to by the code, has the effect that the code is reusable (copy/paste-reusable easily, OO-reusable through indirection) with different ASCX markups: The markup is dependent on the code (through the use of properties holding values) more than the code is dependent on the markup.

One could regard this methodology as simplistic and unproductive, but I believe that the boost in productivity from straightforward coding and debuggability is a lot more than the losses.

Back

Rants

Interesting reads