Wednesday, July 15, 2009

Is ASP.NET slower than ASP?

Not much time for a good scientific discourse here, but I wanted to make a quick comment on a pet peeve of mine. I know a number of classic ASP programmers, who are involuntarily stuck in the stone age of web development. They belong to a nice website you have heard of, and which I read frequently. Like most people, they try to put a happy face on their predicament, and look on the bright side.

"I wish I wasn't coding in VBScript", they often say, "But at least it is fast. Classic ASP kicks the shit out ASP.NET in terms of performance. .NET is very, very heavy."

The first time I heard this statement I exploded in laughter. I thought that had to be the most preposterous thing I ever heard. I said so. My friends were offended. I got a URL in the mail. Various sources showed performance benchmarks which mocked up a standard master-detail crud form with about 30 master fields, and 20 records of 10 fields each in the detail. This seemed to be a standard crud form these folks had agreed on. They implemented each example in the most garden-variety manner possible. ASP using totally typical ASP tactics. ASP.NET using totally typical ASP.NET tactics.

These benchmarks corroborated the story my buds were telling me. How so? Let's make some clarifications:
  1. We are not talking about VBScript vs. C# speed. All parties admit that this is savage knock out. C# smashes VBScript in speed.
  2. Point #1 is not understood by some poor benighted folks
  3. We are talking about the ASP.NET kit or framework vs. Classical ASP kit, as a holistic system sense.
  4. The benchmarks focused on initial app start up time
  5. There was no attempt to NGEN assemblies
  6. There was no attempt to permanently cache compiled code
  7. There was an emphasis on quantity of post backs
  8. The focus was also on post-back speed.
Poor benighted folks quickly conclude (erroneously) that C# is slower than VBScript. VB.NET must also be slower than VBScript. How could it be any other way? ASP can't be faster than ASP.NET unless the stuff you make it out of is faster.

Not quite correct. There is a fallacy or two in there. So why the apparent problems of performance? Well, it is a sad story. In poorly done ASP.NET 2.0 applications:
  1. You post back to the server like crazy
  2. Anytime a control changes you just might trigger an auto-post back
  3. To make anything significant happen, you post back
  4. You have these two little things called View State and Control State that don't exist in classic ASP.
  5. View State and Control State are encoded in Hex64 in your page when you do a post back. This doesn't take up many bytes of bandwidth. Unfortunately...
  6. The overhead problem of View State and Control State cannot be measured in bytes that must be transported. Rather it is manifested in the number of clock cycles required to setup the page for return after the post back.
  7. System.Web contains a lot of code to consider what is included in your View State and Control State, and then take "an appropriate course of action" based on that state. All this code runs under the hood. It is more or less invisible to you.
  8. The more ASP.NET controls you plant on a page, the more your View State and Control State grows, and the longer it takes for System.Web to process that information and figure out what it must do. The more complex and heavy your page gets with ASP.NET controls, the more time, memory and processor clock it will take to do a post back to your server.
  9. In sharp contrast, classical ASP is much closer to the stateless ideal that the engineers of the web had in mind when they constructed the HTTP protocol.
  10. The consequence is that a big-fat heavy ASP.NET page, bloated with ASP.NET controls, can and will run slower than a classical ASP page that presents a simple and pure HTML form in some remarkably simple cases.
So how the hell did this happen? Why did Microsoft design a system like this? Why did they present the whole WebForm framework to the public? Why did this create such a craze when it happened? Why did the market accept this? How could they gain all the speed of a full-compiler and then toss it all out the window with a framework like this?

To make a long story short, Microsoft did what they had to do to make a very recalcitrant and stubborn crew of VB6 programmers migrate to the web. Many VB6 programmers were far less than thrilled with the web when it happened. Of course, we liked to use the web, but most of us did not want to program for the web. Why? Because we fucking hated the whole paradigm of web programming. It was so much harder to rig a webform and make it reliable and secure than it was to do this in VB6. You don't know how easy this was in PowerBuilder, VB, and Delphi. Crud forms were an almost automatic gimme in these systems. They performed also. You did not have web performance issues. And then their was HTML 3.2... This opens a nasty can of worms and I don't want to go there right now.

ASP.NET 2.0 was intended to be a VB6/Delphi programmers wet-dream. It was supposed to be the visual drag and drop, WYSIWYG, wizard driven process for web development. It handled all the nastiness of the web for you. At least this is the perspective of an old fashioned programmer. It basically worked. If the ASP.NET architecture was designed to optimally attract VB6 and Delphi programmers, it worked like a charm. Microsoft built it, and they came.

There were problems. There were natural consequences for pursing this architectural wet-dream. The biggest problem was statefulness. A windows app is naturally stateful. Very, very stateful. All of a VB6 programmer's expectations, his design patterns, his approach to problem solving implicitly or explicitly presumes the existence of a great deal of application state in the program. This is why they can't go parallel now. Step one in making a VB programmer comfortable on the web was constructing a stateful system that would allow him to work (more or less) normally according to his way of thinking.

This is why you have so much State in ASP.NET.

Step two was to construct an event driven system. Windows apps are naturally event driven critters. So much so that VB programmers frequently focus exclusively on how to stash the right code in the right event handler. Many write 100% of their code in the cookie-cutter auto-generated event handlers. A functional app can be constructed in this fashion. It won't be very good or deep, but it will do something positive for the corp.

This is why you post back all the time in ASP.NET. Every event must be handled on the server. You post back on each event handler.

Naturally, a hundred post backs will create some serious latency. You will spend some time waiting for the Internet. Naturally, the system of a stateful post back will cost your server some clock cycles. You will wait for the web server. If data from a Database is involved, you will incur SQL latency time also.

This is why classic ASP.NET apps can seem slow.

Of course, you can be a smart guy and write you ASP.NET app in pure XHTML 1.0. You can code all your form logic in JavaScript. You can have a single ASP.NET button control which says "GO" and does the magic stuff on the server which returns the magical result. I did this for Citibank once. In this case, you post back just one time. A single ASP.NET button control has no real state associated with it. Hence, View State and Control State become so small as to be totally irrelevant. My magic code constructed a hyper-elaborate Excel sheet using Syncfusion XLSIO. It returned the sheet containing mission critical analysis of data. My code is fast as hell. No complaints from Citibank.

Of course, I did not approach the problem the way the garden variety VB6 programmer approached ASP.NET 2.0 in 2005. I did things differently, and for a reason.

All of this is a de facto explanation for why Microsoft introduced the MVC framework recently. Many web experts have complained bitterly about the overhead associated with complex forms done with ASP.NET controls. They don't like it. They never did. Under the MVC framework, most state goes away. You can still do a session state (cookie) but that is limited stuff, and normal.

There was another reason for MVC: Testability. ASP.NET systems are notoriously untestable because their is no inherent separation of concerns. You could test most elements of an ASP.NET system, but you needed to break out a few DLL projects to do it. Most ASP.NET programmers were not hip to this approach, and they never did it.

So, I started this blog with a question: Is ASP.NET slower than ASP? Let me give you two answers. In application start up, it will be, unless you exploit NGEN and permanent code caching. If you program in an ultra-Basic fashion, maximally exploiting visual drag and drop WYSIWYG design, and if you make a complex data form, your ASP.NET app might just be slower than an classical ASP analog. Too many post backs, and too much state per post back.

However, this is not because VBScript interpreter is faster than C# of VB.NET compiler and JIT. Quite the contrary. Rather, the overhead of ASP.NET is so bad, it eats up all of the compiler's performance advantage, and then some. It also has to do with the fact that you are not programming well or wisely. Microsoft has encouraged you to reach that point, but your should be smarter than that.

To all those of you who don't want to incur the overhead of ASP.NET, but would like to get out of Classical ASP: Give the MVC framework a whirl. You will like it. You might even love it, if you get the knack of automatic testing.