The Value of Cross-Training
While my job focuses on ASP.NET development, I still find myself going back to Python and SnakeSkin for personal web development projects. There's really two reasons for this. One, I've got a pretty nice Linux virtual server hosting account through OpenHosting, so hosting on Apache gives me a lot of freedom. Two, I like the fact that it's a bit lower-level than ASP.NET (so I'm a little closer to the HTML code) and not as opinionated as an MVC framework like Rails or CakePHP. Three, real men code in vi from the command line.
One of the great strengths of SnakeSkin/Albatross is its handling of form and session state. It's roughly equivalent to ASP.NET's ViewState. However, this makes AJAX work a little tricky. When a form is submitted, the posted fields are validated against the original structure of the form on the page; if they don't match, SnakeSkin throws an exception. Great for keeping spammers out of your contact forms--but not so hot for changing page structure on the fly. And for years, I've sort of had to deal with this limitation. Usually, my workaround was to use a separate controller that returned XML data, which I then used to update the page through JavaScript. Fine for small things (and certainly less bandwidth-intensive), but not convenient.
I could go into the complexity of the problem even more, but it boils down to this: you can't easily update one portion of the page directly. It's all-or-nothing.
I eventually hit upon half of the solution to the problem a few months ago. If I updated an entire <form> tag in its entirety using prototype's Ajax.Updater, then the form data would remain intact, and wouldn't break when I submitted it again. But this was a very limiting solution. If you used multiple <form> tags on a page, then their session state (stored in hidden fields) would get out of sync as you updated each one individually. So, the only way to really make this solution work was to include only one <form> tag on the page. And if you're doing that, you might as well not use AJAX at all.
It took some time, but the solution finally hit me. It was during Wally McClure's ASP.NET AJAX presentation at ETNUG. I had a pretty good idea of what was going on behind the scenes with ASP.NET AJAX, but I'd never really thought about it too much up to that point--the details were safely hidden from me in the Microsoft library, so there was no point in delving into the complexity.
But part of Wally's presentation was to open up Fiddler and show the actual text of an ASP.NET AJAX response. The response contained the HTML code to be inserted into each UpdatePanel--which was pretty much what I expected. But it also included the updated ViewState as a separate field in the response. And that's when it clicked.
All I had to do was modify SnakeSkin to spit out both the session state and the HTML response as part of an AJAX call. Then, when the response came in, I would iterate through the <input> tags on the page, and replace the contents of each hidden session state field. This didn't require a lot of work on the back end (surprisingly, as I'd imagined the code to generate session state was hidden deep within the bowels of SnakeSkin), and only some minor tweaks on the front-end code I'd been using for AJAX.
So, last night, I actually got two-panel demo working. It's obviously nowhere near as complicated as ASP.NET AJAX's UpdatePanel--modifying my SnakeSkin page class to support updating multiple sections of the page in one call would just overcomplicate it at this point. But it is a somewhat elegant solution to the problem--that is to say, it's encapsulated enough that the details of "how" are nearly invisible when you're creating a page class.
I'll post some samples if anyone's interested, but SnakeSkin (and probably Albatross, the project it forked) is so obscure this doesn't really matter to anyone but me.
The point is, I found it interesting that I solved a problem in one framework just by looking at another. I didn't copy the solution directly, but it gave me a new way of looking at the problem. So, while you shouldn't learn every framework, language, and platform out there, it helps to know more than one.
This is especially true in web development, because in a sense, web frameworks don't matter. Every web application--every HTML-based application that is, since Flash and Silverlight aren't constrained by the same limitations--is basically working with the same set of inputs, outputs, and limitations. From the user's perspective, what you can do with one, you can do with any other framework, whether you're using PHP or ASP.NET or Rails or SnakeSkin or Perl. Obviously, that doesn't mean they're all equally suited to every task. The value in the framework is on the back end--maintainability, productivity, data, and support. So as different as they are, all web frameworks can't be that different in their fundamentals, which means it's easier to compare, contrast, and borrow concepts in the web arena than it is on the desktop or server.
Comments
Polygot Programmers
One a side note, I am still really impressed w/ the fact that you all rolled your own framework. The Asp.Net framework is, sometimes, this magical language that I use to get my work done. It is really easy to take it for granted and not consider all that might be going on under the covers.
Anyway, very cool conclusions.
The good borrow, the best steal...
The Python "mixin" pattern used in SnakeSkin/Albatross I've always loved. We can do the same in C# with Interfaces - who knew we were already on the path to IoC lol?
Snakeskin, Mixins, etc.
I like mixins a little better than the IoC concept (as I understand it). With IoC, you have to write a class that "knows" about all of the capabilities it's going to end up having (just not what implementation they're going to use). With mixins, you can cobble together a base class and all manner of extended features that can be stored in their own separate classes and don't have to know about each other.
FWIW, soon after I wrote this post, I wrote a post sort of analyzing why I'm still using Snakeskin/Python to do web development (or at least the way I was thinking about it at the time I wrote it). It ended up being kind of snarky and the conclusion I came to was a bit surprising. I may post it later today.
Ninject
Basically, in both cases you class holds a reference to something that deals with Session State (for example). You class doesn't care about the details of how Session State is stored, only that it respect an agreed upon interface to use it. You class may not even know until run time which Session State implementation it is using - and doesn't care. Code wise, this gives you separation of concerns and easy of testing (because you can mock the session object in unit tests).
If you go down the path of IoC/DI you'll want something to help - normally called an IoC container. I really like Ninject because it follows KISS and doesn't use crazy XML configuration files to setup. I also think the Ninject Walkthrough is one of the best intro on the subject: http://dojo.ninject.org/User%20Guide.ashx (and also shows the "by hand" method - which for simple projects is just fine imho).



Post a Comment
To post a comment to this blog entry, login below: