Tuesday, February 05, 2008 -
A few months back, right before I was hired by Microsoft, I knew people wouldn't look kindly on the forthcoming ASP.NET MVC Framework and it's support of Inline Scripting. As part of my community effort I decided to take this issue on a bit and try to remind people that inline scripting on it's own isn't spaghetti code - it's the code itself.
As I always say - spaghetti is as spaghetti does.
Last night I had a fun (not really) experience, and for me it's thrown a whole new twist on what Inline Scripting and Maintainability mean. Code Generation and an old toolset don't add up to a fun maintenance issue...
Knock Knock Rob, it's 2003 Calling
I worked on a pretty nice site back in 2003 when I was in love with CodeSmith and Extreme Code Generation. I had this Killer Set of Templates that I could rock out a full-blown scaffold with (before it became a household control in .NET), and I used them to create the admin section of said site.
I won't dive into the details, suffice to say it works and I'm not very happy with why. It was an admin site and I reasoned that I didn't need to worry about perf (which is true). The code was readable, easy to follow, and while I could have/should have refactored it to be less verbose, I liked that I could rev the DB and then generate the code - this process was simple and
timely.
Ahem. Yes I know.
The site has worked great for the last 4 years, until today. Strange how these bugs can lie dormant for so long! I'd never had this happen before and the bug was pretty stupid.
In short, the site is for a Venture Capital company and the DB holds all kinds of "people info" - teams, groups, etc. The groups haven't changed at all over the last 4 years - until 3 days ago.
The admin for the site decided to add a group for a company they acquired, and when she went to the admin tool it exploded - complaining that the Data Table I was using wasn't mapped properly. The templates I created used the built-in DataTable.Update() support so I could work with any DB Provider - unfortunately if they don't map to your scheme precisely, you'll have a bug on your hands.
Oops. I changed the schema back in 2004 and forgot to regenerate my Code Page it seems. Bad Dev.
And The Feeling Of Dread Creeps Over...
The admin person was very nice - sending me an email that I take a look at the problem. That night, when I got home I fired up VS, grabbed the source from my Subversion server, and set about fixing the issue.
It's .NET 1.1. Uh Oh. Forgot about that...
I don't have VS 1999 (or whatever version that was) anymore and I don't know where that CD could be. Crap - I knew I should have held onto that! Frantically I think of all the PCs in the house (laptop, old box in the garage) and where/how I can install 1.1 so I can work on this site.
As I start to weigh the time up (finding and installing 1.1, getting the site setup, and redeploying) I start to think sideways (it's how my brain works) and I realize:
I only need Visual Studio so I can compile the dang solution - I know how to run "csc"... I can do this without it!
But I don't have .NET 1.1! It's easy to get - but now I have to install it and reboot and if I get errors this is going to take me a very, very long time tonight and I want to watch Lost! This is getting out of control...
I think about converting the whole thing to .NET 2.0, but this is a no-go as the hosting account is set to 1.1 and I don't want to deal with that. So I restate the problem to myself - this helps me from doing stupid stuff to solve a minor issue:
You simply need to add one line of code to account for the DB schema change.
There's no way I'm sitting here partying with VS 1999 and .NET 1.1 so I can accomplish a single line of code change. That, my friends, is a maintenance issue (and yes, it's my fault).
Sir, The Wall's Too Tall! No Problem, We'll Go Through It!
As I restate the problem to myself, it becomes clear that the only thing in my way here is the mechanism itself: fix the code and recompile. The only reason I'm installing these tools is to recompile - so let's remove that step from the equation so I can now fix the problem.
I moved all the code from the codebehind page, pasted it between <script runat="server"> tags, and then reset the @Page directive to not inheret anything. Took me 5 minutes: I made the fix, and FTP'd it up. Done.
It reminded me of my last post on the inline/codebehind debate, and one of the comments I received:
"I think inline script blows...No thanks. I think it's a very bad idea. Cleaner and more manageable? You must have been drunk when you posted this."
It may indeed blow, but it just saved my bacon :).
Summary and The Obligatory Hedge
I know this isn't an issue with ASP.NET 2.0, and yes I know that I should have been a LOT more careful with my Code Generation. But as I've been writing this I've been chuckling at the things I did back then (don't we all?). I loved Code Generation - to me it saved so much time, and I could be pretty certain that bugs were mitigated since I didn't handcode the stuff. I just had to remember to do it!
I'm not telling you to use Inline Scripting - I just found this to be very, very ironic since many people believe your application is "less maintainable" if you use it. Not in this case my friends :).
I spose the moral of the story is to always view the concept of maintenance with an eye towards shifting toolsets and platforms. In 4 years you will need to support the ASP.NET 2.0 site you're on now, using Visual Studio 2012 and it's Silverlight-generated Scaffolds :).
You may not want to go running through the house looking for VS 2005 and hopefully you won't have to since 2008 supports 2005 projects - but will VS 2012? Notice that 2005/2008 doesn't support 1.1...
And finally, while you may be thinking I'm a complete hack :), think back to what you did in 2003...
Couldn't you potentially do the same thing without inline script by not pre-compiling your site? Obvious perf hit, but isn't it possible?
"VS1999"- that was effin' hilarious!
Then you could have made your one-line code change, used MSBuild with .NET 1.1 targets to rebuild the solution, and deployed the updated DLL's and markup files. No "Visual Studio 1999" (Visual Studio .NET 2003) required. Actually, no Visual Studio at all required if you're comfortable executing MSBee from the command line.
I know, this was not the point of the post at all, but I just _had_ to mention it. :) Anyways, pretty good solution you came up with in the end and; yes, inline scripting can save your bacon. But then I don't much like Norwegian bacon, I prefer Danish... ;)
Output file doesn't exist in ${expected.output}
That's it!
<target name="build.winforms">
<solution configuration="${configuration}" solutionfile="HelloWorld.sln">
</solution>
<property name="expected.output" value="HelloWorld/bin/HelloWorld.exe"/>
<fail unless="${file::exists(expected.output)}">Output file doesn't exist in ${expected.output}</fail>
</target>