www.codinghillbilly.com   kyle.baley.org  Subscribe / Contact
 
 
 
 
LATEST POSTS
Tuesday, June 19, 2007

I'm a big fan of Prisoner's Dilemma. Actually, I'm a fan of picking out when it's being applied to a situation, not of the dilemma itself, which is inherently bad. You can read the details yourself but essentially, it's a fancy way of saying, "every man for himself". (I'd apologize for the male slantedness but I doubt female readers would want to be grouped into that bit of analogy anyway.)

It's a little more complicated than that though once you dive into the philosophy of the idea. Basically, it says that you should act in your own best interest even if it conflicts with the interests of the larger group. That's because everyone else in the group is thinking the same thing. If everyone cooperated, they'd all be better off as a group but as soon as one acts against the group, the whole thing falls apart.

If you generalize the concept, it applies to pretty much every major problem facing the world today: global warming (we should all take mass transit), world hunger (featuring the parental mainstay: "There are starving people in Africa and you want to throw that away!"), the election of George Bush (actually, I can't explain that one). In short, we should all act for the betterment of the group but we rarely do.

Except for a large section of the software industry. What do I, as a supposedly rational person, gain from taking time away from my family, friends, and clients to elucidate you people on a regular basis? I don't have Google ads and even if I did, they aren't going to pay for my extravagant lifestyle of cutting code and skinnin' rodents. In fact, this thing is actually costing me money in the form of hosting fees.

One could argue that I do have ulterior motives in that presumably, my reputation would be enhanced and I would reap all the rewards that rock stars enjoy. And that is probably a factor for most bloggers to varying degrees, depending on the author's degree of optimism.

But I don't think it's the driving factor for most, at least not for the ones in my blog roll. A common characteristic to the ones I know is modesty, almost to the point of self-deprecation. Any praise heaped on one is usually deflected and distributed among at least two or three others. The general vibe I get is that people are genuinely interested in helping others.

Of course, there's often more than a hint of pride involved (who doesn't want to tell the world when they figure out a really tough problem?). And there's nothing wrong with that. As long as pride doesn't give way to ego which it rarely does.

Open source projects are another anomaly with respect to the Prisoner's Dilemma and it's one that's even mentioned in the Wikipedia article. Another example of people working for the good of the group more so than for personal gain.

It's an interesting phenomenon, as is the original dilemma. Maybe it's that the group and the individual both have similar goals. Or maybe the industry attracts people of this nature. I suppose one explanation is as valid as the next and I should stop questioning a good thing.

Kyle the Philosophical

Monday, June 18, 2007

Every year, I am invited to London to help provide technical assistance for the course I alluded to in my previous post. And it's a credit to the lecturer that he continues to invite me even though I have all but automated away my usefulness long ago. From a strict cost/benefit ratio, I stopped being a fiscally sound expense two years ago. So before I start rambling, here's a shout out to him for allowing me to tag along every June because I absolutely adore this city. E-mail me if you want to know why I don't mention him specifically by name. I might respond truthfully if I can face the embarrassment again.

The real point of this post (other than the fact that the venue FINALLY has wireless Internet) is the aforementioned automation. Not the mechanics behind it but rather its consequences. The course is very computer interactive and involves the Big Three of Office 2000 (or higher): Word, Excel, and PowerPoint. Nothing fancy for PowerPoint but the Word and especially the Excel components involve some macros. The spreadsheets have some automated charting features as well.

When I first started helping with the course, the charting was not automated for the students. They were asked to chart things by hand as an exercise. And the presentation was printed out and given to them rather than the PPT file itself. And the shortcut key I had originally chosen to launch the macros was Ctrl+W which was not a wise decision. (Give it a try in a normal Excel spreadsheet.) Plus, in my zeal to impress, I originally had the macros in a VBA add-in, which does NOT lend itself to easy deployment on forty computers.

The result is that I would spend a good chunk of my time jumping from one student to another fixing technical glitches (like running the macros on the current spreadsheet rather than the original one in case more than one copy is open) or helping them run the spreadsheet several times for the purpose of charting.

So over the years, I've cleaned up the macros and the instructor and I have moved more to the computer and away from paper. Installation now consists of copying a folder from a USB (or several if Mrs. Hillbilly, who acts as his manager of operations, helps out) on to the student's desktop. The changes have been incremental but in terms of my tasks, I do nothing that Mrs. Hillbilly and/or the lecturer can't do themselves. Any problems that come up are generally due to a student not being familiar with Excel (no, really).

It wasn't really my design to automate myself out of the equation. It was just me doing what comes natural. And the fact is, it hasn't happened. The nature of my tasks while "on course" has changed along with the interactivity of the course itself. No longer do I bob and weave back and forth among participants putting out fires. I have real-live development work that I do for the lecturer on occasion but it has always been secondary to his main source of income, which is oil and gas consulting. And the nature of both his and my work is that we are very rarely both free at the same time to work on his projects. In fact, we are rarely even in the same country at the same time since he is sort of a consultant to the stars with respect to the oil and gas industry.

For the other fifty-one weeks of the year, our working relationship is such that I work on something for a few days, then pass on questions and work in progress to him. Then I wait for a few weeks until he has time to review it and get back to me. Then I fit in some more work over the next few weeks. Rinse and repeat. But this one week each year is our guarantee that we will both be in the same place at the same time. And now that my course responsibility has been relegated to "baby-sitter", I can be that much more productive on the other work, which is generally more interesting than even my regular contract.

It's a nice counter-argument for consultants who like to build "job security" into their work. Just because your goal may be to automate yourself out of a job, doesn't mean you'll be out of work when you're done.

Kyle the English

Monday, June 18, 2007

Have moved over to my usual haunt for my annual trip to London. The conference I'm helping out with is being held here as it has been since before I started coming four years ago. I won't dwell on it except to say it's very nice and, while not as conveniently located as the one we vacated yesterday, the staff is exceptional and the bathrooms are outstanding, including a separate shower with five nozzles each with water pressure so awesomely powerful, it should be declared an environmental hazard.

The conference is on fiscal systems for oil and gas from around the world which I mention only for completeness.

On the first morning, I overheard a snippet of conversation 'twixt two of the attendees. One of them was an older gentleman who clearly had invested the bulk of his career in the oil and gas industry and they were discussing the upcoming course. The other asked him why he needed to attend given how much experience he had. The reply: It's a life-long process.

Whereby you now see where I'm going with this post. The gentleman clearly said it with a great deal of enthusiasm, such that I hope I show half as much when I'm attending the "Why Won't VB Just Die Already?" conference in 2021. Here was a man in his late 50s or early 60s barely containing his excitement at attending a course on oil and gas economics. And having "attended" the course eight times in the last four years, I have to admit that he's in for a treat even with my limited understanding of oil and economics (but not necessarily gas).

Here's a tip for fledgling developers: If the prospect of taking at least one training courses per year for the rest of your working life seems only slightly less palatable than an "All Rosie All the Time" TV channel, then learn to fake it or get out now. As JP says, you need to develop with passion (or in Justice's case, lust). And that kind of fervor requires that you get excited about learning the industry.

And it's drop-dead easy to develop an obsession in software development these days. Yes, it can be overwhelming. But by the same token, you aren't starved for choice. If you can't find something that interests you, you are trying too hard to complain. Go be an actuary.

I use a pretty loose definition of "training course". In these days of blogs and white papers and "How-to" articles, you don't necessarily have to shell out cold hard cash to sit in an over-air-conditioned room for a week. But it does mean you need to spend the time. Which generally means taking time out of your contract/job to do it unless you don't sleep.

I'll leave it at that for now so as not to belabor the point and also because you don't need a humble hillbilly telling you how to run your career. You've heard this advice before from smarter people than me...er, I mean, I. But it doesn't hurt to hear it again, if only to give the impression that I engage in such a practice to prospective employers.

Kyle the Learned

Friday, June 15, 2007

The Coding Hillbilly is abroad (tee hee) for the next two weeks and is wondering about the Internet charge methodology at his hotel. The hotel is Thistle Piccadilly, in the heart of Piccadilly Circus, (and I defy anyone to find a better situated hotel anywhere in London). It is business-related travel which explains the extravagance but here's how they charge for high speed wireless Internet: Six pounds per hour or ten pounds for a twenty-four hour period.

Clearly they want to discourage Internet service by the hour the same way they discourage booking rooms by the hour. But that's not the real curiosity. Why bother charging for Internet service at all? Given the nature of their clientele, it can be assumed that a good percentage will use the service. And very likely, a sizeable chunk choose not to given that you have to pay for it and/or you need to collect a little card at the front counter every day.

Setting up wireless Internet can't possibly be the high-cost operation their fees reflect. And I may not be a typical client, but "free high-speed wireless" is something that jumps out at me when I'm scanning through hotel features.

But let's assume it costs more than the four cents a day I suspect it does to run the network. The fee structure of the hotel is such that an increase of, say, five pounds a day would hardly be noticed by the average guest.

In general, I guess I just don't understand why hotels need to make it so hard to offer something I could set up in my house in less than half a day. Maybe there are security aspects I'm not considering. Maybe the idea of people using their precious air without paying for it scares them. Who knows. But if they don't change their attitude soon, I'm gonna...well, keep right on paying I suppose.

Kyle the Threatening

Friday, June 08, 2007

While I will profess my undying love of ReSharper, I do have a bit of an annoyance with its auto-closing delimiters (as explained here). I've talked before on my love of white space but it comes with a price. Whenever I type the opening parenthesis of a method, ReSharper helpfully adds the closing one. It's also smart enough to recognize when you type the closing one yourself and won't duplicate it if you do so. If you don't have a space there, that is.

Here's an example. Let's assume I type the characters: "this.gethashcode(" without the quotes. Here is how it looks right after I type the (:

this.GetHashCode( )

ReSharper has helpfully added the closing parenthesis and even respected my choice of using white space after opening parentheses and before closing ones. The problem is that the cursor is now situated right after the first parenthesis and I need to Right-Arrow or End my way to type the closing semi-colon. And neither key is situated in an area that lends itself to quick access on my laptop. If I type the closing parenthesis, ReSharper does not recognize that this is the same as the one it just helpfully added (the way it does when there is no whitespace). So I'm left with:

this.GetHashCode( ) )

(Note: I added the space after the first parenthesis manually. It's a habit I'm hoping I don't have to break.)

There is a way around this that I haven't quite got into the habit of using. That is to take advantage of ReSharper's advanced IntelliSense. Here's what appears when I start typing GetHashCode:

image

At this point, I can press <Tab> and get the following:

this.GetHashCode()

Plus the cursor is sitting helpfully at the end of the line. And no worries about my precious gestalt. I need only type the closing semi-colon and either ReSharper or Visual Studio will format it into the beacon to gestalt I am looking for:

this.GetHashCode( );

The problem with this method is that it kind of slows me down. I find it much faster just to type "gethashcode(" than to start typing "get", search through the list for the one I want, arrow down if necessary, and press Tab. My way has more keystrokes to be sure, but does not require that I pay attention to the UI.

The habit I'm trying to get into is: rather than typing "gethashcode(", instead type "gethashcode<tab>". Theoretically, this should be easier...

Kyle the Habitual

Tuesday, June 05, 2007

So I'm back in ASP.NET AJAX/Atlas world for the time being while I work on my dad's application. And like a kid in a candy store, I'm trolling through the AJAX Control Toolkit trying to see which ones I can use. As opposed to picking out the cool ones and trying to find a way to wedge them into the application. It's a subtle difference.

Anyway, the TabContainer caught my eye and I played with it both online and locally with the source code. One thing I think is a nice touch is the effect you get when you hover over the tabs, something you are accustomed to in WinForms but not as often on the web. I'm sure I've said it before but the guys on that time are counting with all ten fingers.

In the HTML for that page though is some javascript that caught my eye and it led me on a wondrous journey:

        function ActiveTabChanged(sender, e) {
            var CurrentTab = $get('<%=CurrentTab.ClientID%>');
            CurrentTab.innerHTML = sender.get_activeTab().get_headerText();
            Highlight(CurrentTab);
        }

        var HighlightAnimations = {};
        function Highlight(el) {
            if (HighlightAnimations[el.uniqueID] == null) {
                HighlightAnimations[el.uniqueID] = 
AjaxControlToolkit.Animation.createAnimation({ AnimationName :
"color", duration : 0.5, property : "style", propertyKey : "backgroundColor", startValue : "#FFFF90", endValue : "#FFFFFF" }, el); } HighlightAnimations[el.uniqueID].stop(); HighlightAnimations[el.uniqueID].play(); }

At first I thought this was their funky way of animating things when you switch tabs. But if you check the sample, there isn't really any animation on the page when you go from one tab to the next. Unless you look VERY closely at the text beside where it says "Current Tab". If you do, you'll see a short little fade effect that I tried to duplicate on my project with much frustration.

For those readers who actually have the Ajax Control Toolkit source code and are so inclined, here's an exercise for you: In the sample page for the Tabs control, remove the two CollapsiblePanelExtender controls at the bottom of the page and refresh your browser. If you have a default installation of Firefox with no extensions, you'll notice the fade animation is no more. If you use IE or have a Firefox extension that reports javascript errors, you'll notice a little more than that. Namely, that AjaxControlToolkit.Animation doesn't exist.

The reason is that the ScriptManager will output only those scripts it deems necessary for the controls on the page. And the Animations.js script (located in the Animation folder of the toolkit source code), which is the one that declares the AjaxControlToolkit.Animation "namespace", is not deemed necessary by the TabContainer control. But it *is* necessary for the CollapsiblePanelExtender, which you can see by opening CollapsiblePanelExtender.cs and having a boo at the [RequiredScript] attribute.

So what if you want to do this funky animation without adding an Extender that requires it? There are at least two ways I can think of:

  • Include the Animations.js file in your project and reference it like any other script. I've taken this approach in my dasBlog theme because it is, in fact, the only way to include toolkit objects in the template files since they don't allow server-side controls.
  • Add an empty AnimationExtender to your aspx page, either in the code-behind/beside or in the .aspx file:
  • <ajaxToolkit:AnimationExtender id="MyExtender"
      runat="server" TargetControlID="Tabs">
    </ajaxToolkit:AnimationExtender>
    

Both are mildly icky. The first seems a little too manual to me. What if I later add an extender that requires the Animations.js file? And worse, what if I upgrade to a later version of the toolkit that has a different version of Animations.js?

The second is safer but the TargetControlID is required, so you have to have at least one server-side control on the page to attach the extender to.

As it turns out, that little tidbit of javascript that inspired this post isn't actually necessary for the TabContainer control. It was added, I suspect, by some mean-spirited AJAXer who was acutely aware of my inquisitive nature and tendency to be easily interrupted.

Kyle the Animated

Tuesday, June 05, 2007

This is kind of an extension to my earlier post on Blowery.web and ScriptResource.axd. I've completed the migration to dasBlog 1.9.7-ish (doesn't it look awesome?). Which probably wasn't a wise thing to do since a brand new release version is expected in the next couple of weeks after which time, it looks like I won't need to upgrade the project to ASP.NET 2.0 myself anymore. But Scott's timing doesn't mesh with my vacation schedule (come June 14, I's be a European Hillbilly for a couple of weeks).

Tweaking dasBlog to work with the current version of ASP.NET AJAX and the AJAX Toolkit will wait for a future post. For now, I just want to discuss an issue that actually came up the last time I did this but I didn't look into it in much detail. Essentially, whenever a postback was required (posting a comment, updating the configuration, etc, etc, and so on and so forth), I would get an error that WebForm_PostBackOptions was undefined.

The most likely reason for this: Something is messed up with your WebResource.axd file. I know not the details of this file but apparently it is required for ASP.NET 2.0 forms to do postbacks. And in fact, it's not actually a file but a file served up by (I think) an HTTP handler.

So if you get this error, chances are the WebResource.axd file isn't doing its job. Or the HTTP handler isn't do its job and isn't even serving up WebResource.axd. The easy way to check for that is to look at your page source and see if you can find a line like the following:

<script
src="/ajaxtoolkit/WebResource.axd?d=cCvonavza7NGh4PxQfj5rw2&amp;t=633135374249468480"
type="text/javascript"></script>

The path to WebResource.axd will be different of course (this was taken from one of the samples over at http://ajax.asp.net/ajaxtoolkit). If you can't find that reference, I dunno, try Google to see if you need to register an HTTP handler somewhere. Maybe your ISP doesn't have it in the machine.config. I haven't run into this particular problem.

The one I *have* hit is when the reference to WebResource.axd does exist but you still get this message. Normally, when you navigate to the path specified by the <script> tag, you'll see a bunch of javascript (with the very first function being WebForm_PostBackOptions, in fact). But if you get this message, you will probably get a blank HTML page when you navigate to WebResource.axd.

As happened last time, I had to add WebResource.axd to the excluded paths for <blowery.web>. I guess this isn't a file that want compressed (although ScriptResource.axd seems to handle it fine, provided blowery is the only thing compressing it).

And just like last time, when I moved it to my server, it didn't work. This time though, I was a little wiser and had more time to kill so I thought I'd try to track it down.

Turns out you don't exclude WebResource.axd from compression in blowery.web. Rather you need to exclude ebResource.axd. That's not a typo. Here is what my blowery.web section looks like:

<blowery.web>
<httpCompress preferredAlgorithm="gzip" compressionLevel="high">
<excludedPaths>
        <add path="WebResource.axd"/>
            <add path="ebResource.axd"/>
        </excludedPaths>
        <excludedMimeTypes>
            <add type="image/jpeg"/>
            <add type="image/gif"/>
        </excludedMimeTypes>
    </httpCompress>
</blowery.web>

For whatever reason, blowery has code that skips the first letter in its excluded paths. And I can't take any credit for discovering this.

So there you have it. I now have a current dasBlog installation with compression turned on. You can tell all your friends about me now.

Kyle the Decompressed

Tuesday, June 05, 2007

Am in the process of upgrading to the latest dasBlog build in an attempt to combat some of the referral spam I've been getting (which is a little odd since I don't show my referrals anywhere). Would like to be able to turn the pingback and trackback services back on here too. I have a feeling Akismet isn't going to solve all of these problems but I've got some time on my hands.

Which is a good thing because I've been putting this off on the grounds that it will take time to get up and running again with a new version of dasBlog. The reason being my hillbilly theme (which is looking more and more like it needs upgrading every day) uses Atlas. Not ASP.NET AJAX Extensions. As in, I got Atlas working with dasBlog many moons ago and never looked back. So there be some work to do not only making sure I upgrade my AJAX installation but also with the client-side scripting I'm using to render the AjaxControlToolkit doohickets I'm using.

But that's for another post. Today's tidbit involves ASP.NET AJAX and the blowery.web control which dasBlog uses. It seems they don't play nicely together out of the box (or at least not the way dasBlog configures blowery.web by default). After getting the latest dasBlog source, upgrading it to ASP.NET 2.0, and adding my ScriptManager, I get getting a javascript error: Line: 1 Error: Invalid character.image

To get the solution out of the way for those looking to get on with their project: Modify the <scriptresourcehandler> node in your <system.web.extensions> section of the web.config:

    <system.web.extensions>
        <scripting>
            <scriptResourceHandler 
enableCompression="false"
enableCaching="true" /> <webServices> </webServices> </scripting> </system.web.extensions>

This is merely speculation but I suspect that both AJAX and blowery.web are trying to compress the ScriptResource.axd that is output by the ScriptManager. I'm guessing you could also configure blowery.web to exclude ScriptResource.axd instead if you were inclined to let ASP.NET AJAX do its own compression.

I was going to relate my entire odyssey in discovering the error but now that the solution is in print, it seems kind of moot now. I will point out that I had to switch to Internet Explorer to figure this out though. It may be my configuration but Firefox didn't through any javascript errors at all.

Kyle the Compressed

Monday, June 04, 2007

A couple of days ago, I started having problems with VisualSVN (and thanks to honorary hillbilly, Tom Opgenorth, for putting me on to it). VS2005 would crash whenever I tried to Commit or Update or do anything that required dimming the IDE to open TortoiseSVN. Here's the error I was getting in my Application Event Log:

EventType clr20r3, P1 devenv.exe, P2 8.0.50727.42, P3 4333e699, P4 mscorlib, P5 2.0.0.0, P6 4333ab80, P7 25e, P8 123, P9 system.formatexception, P10 NIL.

Not particularly clear but hopefully it'll help someone Googling the same problem. It's also pretty much identical to what is described here.

After a couple of back and forth e-mails with VisualSVN's support team (on the weekend no less!), they zeroed in on the problem pretty quickly. Last week, I installed (and quickly afterward, uninstalled) Office 2007 and it seems that the installation unregisters actxprxy.dll in C:\windows\system32. Re-registering that DLL has fixed the issue for me. I make no claim as to whether this affects Office 2007 but the VisualSVN support desk pointed me to this link so make your own judgement.

So hopefully, I've saved some poor soul from having to contact VisualSVN's help desk. Which is not to discourage anyone from doing so because they were very responsive and very helpful. More so than I was when describing the problem anyway.

Kyle the Supported

Saturday, June 02, 2007

Re: TestDriven.NET v. Microsoft

I have been following it and have nothing important to add that has not already been said. That is all.

Kyle the Neutral

P.S. I said the same thing when the Anna Nicole thing hit.

Friday, June 01, 2007

Lots of talk on the new Live Writer. I'm just glad I can finally use the Ctrl+RightArrow key combination again the way I'm used to.

The real topic of the day is repositories. In my last post, I raved about ActiveRecord but in that little mini-project, I didn't actually use any repositories. I'll admit that I didn't actually do strict TDD on that project, nor did I even write tests for it. The reason being...actually, I don't need to explain myself to you people. I have my reasons, lame as they may be.

But that was important because I now understand what Jimmy Nilsson was talking about in his chapter on PI for repositories. I'm back in PD mode implementing tests against my repositories and it now occurs to me: I'm going to need two repositories. A fake one for the tests and a real one that hits the database and wraps my use of ActiveRecord/NHibernate. (Yes, Nilsson talks about this very explicitly. Hillbillies ain't what you might call "book learners".)

To explain the issue (and thus, to pad my post) here is a sample test:

    [ Test ]
    public void ShouldBeAbleToRetrieveJobFromRepository( )
    {
        int jobNumber = 42;
        MockRepository mockery = new MockRepository( );
        using ( mockery.Record( ) )
        {
            IJob fakeJob = mockery.DynamicMock<IJob>( );
            SetupResult.For( fakeJob.JobNumber ).Return( jobNumber );
            jobRepository.AddJob( fakeJob );
        }
        IJob job = jobRepository.GetJob( jobNumber );
        Assert.AreEqual( job.JobNumber, jobNumber );
    }

So I implement a basic (read: fake) JobRepository that adds a Job object to List<IJob> and in GetJob, I iterate through the list and find it. In the real repository, it'll use ActiveRecord to pull it from the database.

But now I have a couple of questions. First, what's the best way to wire in the fake repository for the tests and the real one for production? Is this where something like the Windsor container comes into play (he said without totally knowing what it does)? You reference one repository in your test web.config and another in the production app.config?

Secondly, and more importantly, do I even need this test? Why am I testing to see if I can pull objects from a fake repository? I don't even think an interaction-based test would work here since the underlying implementation will be different for each repository.

In the book, Nilsson adds a layer of abstraction so that the repository itself will be the same in both scenarios. That pushes things out of the repository but you still need a fake implementation of something, in this case the abstract layer. In that case, it makes sense to test the repositories since they are always "real" implementations. But then I'm not so sure about testing the abstraction layer.

So...ummm...help, I guess.

Kyle the Faked-Out

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Copyright © 2008 Kyle Baley. All rights reserved.
 
LATEST POSTS
 
POPULAR POSTS
 
LINKS
 
BLOG ROLL
 
CATEGORIES
 
ARCHIVE