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.
Factors | User control | Custom 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.
|
Creation | Creation 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.