Last night I regaled The Smartest Guy I Know, as well as drsweetie’s high school pal Tony, with tales of how Kids These Days Don’t Know Anything and Nobody Does Things Right. It was a scene to warm the bitter soul of any software curmudgeon.
“So there I was,” I began, “optimizing the heck out of an ASP.NET application…” And my audience groaned–although I’m still not sure whether it was because they know how the story simply had to end, or because I was the teller and they couldn’t be sure that it would ever end. Because my stories get to be like that sometimes.
It was reading a cookie on every request, parsing an array out of the cookie, and using the elements of the array as keys into the SELECT of a rather large database join. This was fairly time-consuming and made a lot of hits on the database. That I could live with.
But because of the structure of the page, it repeated the process about eight times on every request depending on where the user was. That I could not live with.
The obviously best fix for that was to consolidate all that logic into a single class, and then to implement that class as a Singleton. That way, all the reading/parsing/selecting would happen only the first time my object was loaded; after that the object was already loaded and would just be referred to in something like
Now the straightforward way to create a Singleton is to keep the payload data in a (classwide)
static variable that is returned from the aforementioned getInstance() method. This made sense to me, and was quick and easy. In a few hours I had it wired! The code ran way faster, after doing away with all those repeated database calls, and the changes were transparent to the client side. Success! At my age!
A day or two later the next QA build went out. My reimplemented feature sort of worked, but users were reporting that their cookie contents were coming and going, in little bits, seemingly at random. They’d rarely lose their data all at once, but now and then a bunch of items would suddenly be added to their cookie data, or a few would drop on their own, but in any case it was hard to trace.
Huh. I wasn’t seeing any of those problems in my personal copy of the application.
“Personal copy” came to mind as a clue. And then I realized: ASP.NET statics are not your grandfather’s statics.
Tony and The Smartest Guy I Know, who are both a little older than I, saw where this was going.
See, boys and girls, back in nineteen hundred and fifty-eight, the wise scholars at IBM created the
COMMON statement in FORTRAN II. It was the first high-level-language implementation of a global data store in RAM. Programmers loved it, because
COMMON made it possible to share bits of data all over the address space of a single process without stepping on any other process.
When C came around much later, the
COMMON concept got refined as
static gave you controlled scope (so
statics didn’t have to be global) but let you keep all that lovely persistent storage. And it didn’t step on any other process.
Other languages like Clipper came along later, of which many had a
static keyword or equivalent. And their statics, guess what, didn’t intrude on other processes.
So here it is, 2009, and I discover that when Alice reads her cookie and loads from the database, and then Bob refreshes his browser, he sees Alice’s data. “How could that be?” I asked myself. “Alice’s data is in a
static object, wrapped by my Singleton. It’s safe in there!”
Now if you’ve ever programmed directly with threads, you know it’s not crazy for a static to be shared among threads. The OS doesn’t fork off a whole new address space for a thread–that’s part of the definition.
Here’s what is crazy: under IIS, each instance of an ASP.NET application is a thread, not a process. I’m oversimplifying that slightly, but the point is that
static data are shared throughout an application domain, and by default IIS creates a single application domain for each application it runs. Thus, every user of my application is looking at the same Singleton object.
It didn’t take long to figure this out once the defect was reported, but it was long enough for our dev team to enjoy a good laugh at my expense.
Back at the old programmer’s club–in drsweetie’s living room–The Smartest Guy I Know said, “That’s the trouble with Microsoft. They have to take something that everyone understands and make it mean something different.”
“It’s not like it was,” I said, more to myself than anyone else. “Time was, you could stick a static in there and it wouldn’t change unless you changed it. Nowadays they’re full of all these high-falutin’ ideas about application domains and whatnot. It just ain’t right.”
Tony harrumphed. I took that as a sign of assent.
I got out of the rocking chair and refilled everyone’s prune juice. The conversation moved along to griping about the designated hitter rule and that awful rock-and-roll music the kids are playing nowadays. It’s sad, really.