CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Kyle Baley - The Coding Hillbilly

"We are stuck with technology when what we really want is just stuff that works" -- Douglas Adams
  • Researching search

    I've had "searching" on my mind lately but in a very narrow focus. Specifically, I have a Brownfield application for a client I dig up every so often whenever new features need to be added to it. (Off topic: As soon as I can re-brand the sucker, it'll make a dandy little sample app for some Brownfield-related posts and webcasts. There, I said it on the Internet so the guilt will be that much greater if I don't follow through.)

    One of the key components to this application is a document repository that you can search both with meta-criteria as well as a full text seaLegalSearchrch of the documents (see screenshot).

    The meta-criteria part is boring. Bunch of lookup tables in a SQL Server database and I'm building up a SQL query manually in the search process. (I *did* say this was a Brownfield application.)

    The full text search is done through a kind of poor-man's search index. I'm using a custom catalog with Microsoft's Indexing Service, available on Windows Server 2000 and later.

    To do this, and I'm going to skim partially because it's not really the focus of the post but mostly because I think it's outdated, I create a catalog that indexes the document folder. Then, I make the catalog accessible to SQL Server so I can combine queries to it with queries to the metadata. Here's the SQL to do so:

    EXEC sp_addlinkedserver <linkedServerName>, 'Index Server', 'MSIDXS', '<name of catalog>'

    Now I can write queries like the following:

    SELECT DocumentID, Title, Date, Filename
    FROM doc_list_view dl,
    OpenQuery( <linkedServerName>, 
       'SELECT Filename FROM SCOPE( ) 
        WHERE CONTAINS( Contents, ''<queryTerm>'' ) '
    ) q
    WHERE Date BETWEEN 'January 1, 1850' AND 'December 31, 2008'
    AND q.Filename = dl.Filename
    ORDER BY Date DESC, Title

    Easy as raccoon pie, yesno? The nice thing about this is that it will automatically index all Microsoft Office docs and PDFs are handled by installing Adobe Reader 8.0 (though it's a separate download for 64-bit).

    Fast-forward to 2008 and the Indexing Service is no longer turned on by default on either Vista or Windows Server 2008. Posed a problem for the client who runs it locally on his laptop but it was easily remedied simply by turning the service on. For my own newly-minted Server 2008 machine, Indexing Service and the new Windows Search can't run together. And I'm loathe to enable the older technology so it's time to update if I can.

    That led me to this page which confuses me to no end. Starting with the terminology: Windows Search, Windows Desktop Service, Instant Search, Windows Indexing Service, Indexed Search, MSN Desktop Search are the terms used to discuss various incarnations of the technology. And that's not including codenames or different versions of the same technology. Adding to my addlement is when Microsoft changes terminology from one page to the next. One example is this page which, in the section on the History of Windows Search, leads you to the download page for Windows Search for Windows Server 2003. That one is titled: Description of Windows Desktop Search 3.01.

    So now I'm facing the unenviable, but oddly ironic, task of having to search through the myriad of search options for a solution that will run on Windows Vista, Windows Server 2008, and Windows Server 2003 (where the main site is hosted). At first glance, it seems Windows Desktop Search is the way to go for Server 2003 as it appears the new Windows Search is API-compatible with it.

    In any case, this'll make one heckuva a sample for the Brownfield series on managing integration with external systems. Because as you've probably guessed by now, there are no automated (or even manual) tests for this whole process.

    Kyle the Researched

  • Sparring before DevTeach

    'Tis the day before I head out for DevTeach and have already completed my pre-conference ritual with my wife. It's a fun game we play a few times a year called "Why do you do this?"

    I was just settling in for some quality time with Bear Grylls when she starts the first round off with the standard "So you're taking a week off work?" opening. We'd just had a pretty fun day at the beach so her heart isn't really in it. So I counter with a half-hearted "Yep. Should be a fun time" to let her know I'll take it easy on her, too.

    She responds with a biting "Didn't you just start your contract last week?". It's a slight breach of etiquette upping the ante that early but I give her the benefit of the doubt and play along: "Yeah, I cleared it with them before I started. They were good with the time off for this as well as our trip to London next month."

    She gives an appreciative nod at my subtle volley but then her eyes harden for a few seconds while she plans her next move. She throws out a quick "I thought we agreed to cut back on these things" which stuns me for a moment. If I didn't know her better, I'd chalk it up to an amateurish mistake. But in fact, she's looking to buy some time. I'm not letting her off that easy: "We agreed to no such thing and you know it."

    Her delay tactic isn't long but it's enough: "Do you actually learn anything at these conferences or is it just an excuse to get drunk and speak whatever language it is you people speak?" It's a baiting ploy because we both know I don't imbibe but I don't rise to it and instead bring out the heavy artillery in an effort to return to normalcy: "I've done the cost/benefit analysis already and believe I will gain more than I will lose (though admittedly, the benefits are more long-term and intangible). I'll remind you of our agreement that all aspects of my career remain solely to my discretion as long as we remain on this island. We have already received direct benefit of my community involvement in the form of the upcoming book and my last contract being a direct result of my blogging."

    There is more admiration than resignation in her face and the battle is all but won. But she can't resist a parting shot. With a twinkle in her eye, she snuggles up to me just in time to see Bear chow down on a live frog and says: "Oh well, I guess I'll just stay home and watch Brokeback Mountain while you go off 'fishing' with your buddies."

    Kyle the Victor (I think)

  • Good Gestalt!

    The hillbilly recently upgraded his trailer to Windows Server 2008 but it wasn't interesting enough to talk about, mostly because it went so seamlessly. So much so that I'm hauling out a post from my old blog rather instead of relating my experience. But I will say that so far, I'm very happy with it, thanks in part to these instructions.

    The reason I'm regurgitating is because I've been looking at other people's code recently, including some of my own from way back (trust me, that's an "other" person too). And as I scan through it, I was reminded of something: I'm a big fan of white space.

    In coding standards, there is usually much said about things like putting curly braces on a single line and wrapping single line if statements in braces to enhance readability. But for some years now, I've adopted a personal standard that goes a little further. It was after discussions with Simon Watfa way back when I was looking over some code of his and it stood out more than usual.

    I'll start with two examples. The first is a more "traditional" white space scheme:

    private void returnSomeValue(int parm1, string parm2)
    {
        // if, for and foreach
        if(i == 1)
        {
            // Do something
        }
    
        for(int j = 0; j<100; j++)
        {
            // Loop
        }
    
        if(i == 100) return;
    
        foreach(var item in items)
        {
            // Process item
        }
    
        // Function calls
        string theValue = i.ToString();
        theValue = String.Format("The value is {0}", i);
    
        // Casting
        TextBox textbox = (TextBox)Page.FindControl("textBox1");
        string text = ((TextBox)Page.FindControl("textBox1")).Text;
    
        // Square braces
        string[] myArray = theValue.Split(',');
        myArray[0] = "moo";
    
        // Lambdas
        User user = userList.Find(u=>u.Username=="moo");
    }

    And here's the same code with my preferences:

    private void returnSomeValue( int parm1, string parm2 )
    {
        // if, for and foreach
        if ( i == 1 )
        {
            // Do something
        }
    
        for ( int j = 0; j < 100; j++ )
        {
            // Loop
        }
    
        if ( i == 100 ) return;
    
        foreach ( var item in items )
        {
            // Process item
        }
    
        // Function calls
        string theValue = i.ToString( );
        theValue = String.Format( "The value is {0}", i );
    
        // Casting
        TextBox textbox = (TextBox)Page.FindControl( "textBox1" );
        string text = ( (TextBox)Page.FindControl( "textBox1" ) ).Text;
    
        // Square braces
        string[] myArray = theValue.Split( ',' );
        myArray[0] = "moo";
    
        // Lambdas
        User user = userList.Find( u => u.Username == "moo" );
    }

    That is, there are spaces almost everywhere. The only places I don't use them are within array indexes and when casting.

    Fairly minor differences, to be sure but they really help me follow code, especially when it gets particularly dense (in both senses of the word). Coupled with a decent IDE colour scheme (and the hillbilly still *strongly* favours dark text on light backgrounds), I can more easily pick out the meaty parts of the code while filtering out the noise. The nice thing is that this can all be enforced with ReSharper's formatting options and, I think, even with Visual Studio itself, sans add-ins.

    Couple o' downsides, though. I often work on code on my laptop where I don't set the standards. This requires setting up project specific styles in ReSharper depending on how much work I'm going to be doing in it. Bonus points if the project already includes a ReSharper style. But in general, the lesson is: if you adopt a similar coding style to this, *never* contribute to an OSS project.

    ReSharper sometimes actually gets in the way here, too. With these styles in place, I would type the opening parenthesis of a method call and ReSharper would helpfully add the extra space, then the closing parenthesis for me. When there is no space, you can type the closing parenthesis yourself and ReSharper is smart enough to recognize you've just typed what it's already added. That is, it won't re-add the closing parenthesis. But with the space, you end up with two closing parentheses. It's not as much an issue if you get used to using live templates and auto-complete more often but still an annoyance at first.

    As I mentioned in the original post, I can make up semi-lucid reasons why others should use spaces in this way but the reality is: I just like how it looks. It says to me that the author cares about how the code is presented. Or that the author has eyesight problems.

    Kyle the Aging

  • BahaNET Meeting 1: A Recap

    NOTE: This post is about a day and a half late. I could claim that I wanted the event to sink in first but the reality is I was trying to get a handle back on things after a very hectic week. Part of it was a short but very successful trip to NYC. So dense was the wife's and daughter's shopping-to-waking-hours ratio that I'll be looking for sponsors for our next trip (anyone from Visa and/or American Girl in my readership?). Closest I got to purchasing anything of value was walking by a Best Buy after closing and laughing at a fellow who tried to sell me a router for $120, which was over half off the ticket price.

    But that's not what I came to babble about today.

    Encouraged and invigorated. That's what I felt right after the first BahaNET meeting and what I still feel now two days later. Attendance, including myself and Dave Noderer, was a whopping seven people. Experience ranged from an IT Pro looking to get into programming, to a game programmer (watch for Rudolph the Red-Nosed Reindeer for the Wii this Xmas), to a young lady acting as the sole .NET programmer at a local bank.

    It was a very interactive meeting with everyone showing genuine interest in solving not only the problems I lamented last time but a few others. Everyone was active in the discussion, especially at the end. And I got the sense that from these seven people, we'll have a good base from which to grow.

    The main problem I see is simply getting people to see the value of such a group. As such, this was something we discussed for some time. We veered into some unfamiliar territory for me as we talked about some practical ideas as well as some more...ummm...let's say "long term" plans (like a robotics competition).

    There was much talk on how to change attitudes in the country. This, by far, is why I foresee any real change taking several years. In my last post, I talked about people who have no interest in "talking computers" after working on them all day. But as was pointed out at the meeting, that shouldn't be the focus initially. So I'll be tweaking things more toward the social aspects of the gatherings.

    But even with the small group, one of the major benefits of regular meetings like this came up several times. Namely, people learned things that they may not have known before. There was tremendous interest in DotNetNuke as a possible platform for creating websites (which is a common business model in the Bahamas), which some of the attendees had never heard of. This was not the only example of side conversation enlightenment by any stretch either.

    All in all, I believe those that attended will be back and will bring friends. And I got what I wanted out of it: a sense of how to proceed for the benefit of everyone.

    The final pleasant surprise came when I handed out prizes. People were offered a choice of items and not a single XBox game was claimed. Instead, people took Visual Studio licenses, a book on SQL Server programming, and a copy of Communication Server.

    We even discussed the next meeting: May 30 at the same location (IPBS House). Topic will be: Creating a Website in ASP.NET. See you there!

    Kyle the Re-animated

  • Twas the day of the first BahaNet meeting...

    Bahamas .NET User Group's first meeting is tonight and I'm using my little pundit here to document some pre-game thoughts for posterity. So that I can compare notes to the post-game show.

    If I were to be honest with myself, I'd admit that the lead-up to this has been more frustrating than exhilirating. I simply have no clue what is going to happen tonight, but not entirely in a good way.

    I've sent out several e-mails to people and organizations that might want to attend. (That's not including the mail-outs to the people that were nice enough to register for the group. That's been the only concrete evidence of any kind that people are interested in attending.) With one exception, all of these e-mails have remained unanswered.

    The exception was from someone who said no one at the organization was interested because they work with computers all day and they have no interest in doing it in the evening as well. A common enough response, albeit a somewhat misinformed one. The assumption is that they have better things to do with their time than learn about software development. Fair enough. It remains up to me to encourage the social aspects of the group rather than the professional ones. Frankly, I'm just happy I got a response because it means I now have an actionable item on my to-do list.

    Part of the anxiety comes with not knowing how many people to expect (which is a symptom of the unanswered e-mails in some respect). The only confirmed attendees I have are myself and Dave Noderer. More on him later. And neither of us are exactly qualified to discuss the nature of software development as it applies to the Bahamas.

    A couple of other general attitudes I've encountered. One was summed up succintly by someone who has lived and worked here most of his life: Bahamians aren't good enough for Bahamians. The problem being Bahamians, while a very proud group, do not have confidence in their fellow citizens to pull through on things like this. Unfortunately, even in my limited experience, there is evidence supporting this line of thought. One of my goals with this group though was to reverse it. Or prove it wrong.

    The second attitude I've come across is an overwhelming sense of protectionism in one's intellectual property. Bahamians seem to be overly secretive about their ideas for fear that someone else will steal them and make money from them. This doesn't really lend itself to open discussions about software techniques. Again, a problem I've recognized and have grandiose plans to counter.

    I know there are some Bahamians reading this, most of whom don't actually work in the Bahamas anymore. When I first started planning the group, I was excited about the possibilities. I still am. The country remains an untapped resource with unique potential. Realizing it will be, by my estimate, a multi-year process. But it'll be a fun process.

    Back to Dave Noderer. He represents a group of people that has shown unwavering support and encouragement for the initiative. Namely, the outsiders. That is, people from other groups, Microsoft, INETA, various sponsors, even colleagues and passing acquaintances. I have received nothing but praise and inspiration from them. Granted, a few of them are probably thinking ahead at attending a possible code camp in the Bahamas...

    Dave, in particular, has been nothing short of stellar in his support, providing me with tips on managing, passing on info on sponsors, and even flying into the country for the night just to attend the first meeting. It's because of people like him and others like him that I've even stuck it out this far.

    Depending on how things go tonight, I have a couple of back-up plans on how to tweak the direction of the group. Try to my nature, I remain optimistic. Optimistic that there are enough like-minded individuals to sustain the group in some form. Optimistic that the issues I've come across are behavioral rather than cultural.

    And optimistic that Code Camp in Paradise will happen in early 2009.

    Kyle the Rose-Coloured

  • Bahamas .NET User Group - April 30

    Quick announcement/reminder today. The inaugural meeting for the Bahamas .NET User Group is in two days. Thanks to IPBS for allowing us to use their office to host it. They are located on Moseley Lane.

    You can get to it by going west on Shirley Street and turning right on to Moseley Lane right after the entrance to Harbour Bay. And I mean RIGHT after the entrance, like about ten feet after so don't miss it.

    It's a one-way street going north, too so you can't get to it from Bay Street. If you are coming from the west, you can turn into Harbour Bay, head to Shirley Street, then make a U-turn on to it.

    Festivities start at 6:00pm and will end whenever we run out of things to say. It will be a round-table discussion on the nature of software development in the Bahamas.

    Thanks to our sponsors for their support, especially the local businesses who see some potential in our little gang:

    Come for the free food and prizes, stay for the stimulating conversation.

    Kyle the Marketeer

  • What do you do if you're Salieri?

    Watching the Polyglot Programming video courtesy of enabler-extraordinaire, Dave Laribee, and it revealed (or rather re-revealed) something about myself that I hope is common enough that I'll get at least one BOOYAH in the comments.AMADEUS

    I watched Amadeus when I was just a wee country whelp. And even at a young age, I could identify with the narrator, Antonio Salieri (at least how he is represented in the movie). It's a simplified comparison, to be sure, but one that has stuck with me. In the movie, Salieri is a composer caught in the large shadow left by Mozart and he becomes increasingly enraged at what he feels is a cruel, cosmic joke. Namely, he has been instilled with the ability to recognize genius and the desire to create good music, but not with the talent. (This is compounded into murderous intentions when he is able to recognize that genius in Mozart, who seems to treat his gift so cavalierly. I don't generally identify with him this far.)

    Ten years into my career, and some thirty-six years into my life, I don't have many illusions about what I can and can't do anymore. On the strong end of the  stick, I can learn new applications and languages relatively quickly. I can be pretty productive when I put my mind to it and am able to communicate my intentions clearly. At least that's what my resume says and it's on the internet so it must be true.

    But watching this video, and indeed, hanging out with the alt.net crowd in general, makes me refer back to Amadeus on more than one occasion. I can't help thinking there are a lot of Mozarts out there. And I don't mean in their day-to-day work. That's the easy part. I can pound out good code and talk best practices, often coherently.

    Rather, there are people out there who are able to create beautiful music in our industry by asking the right questions and having a clear vision of what the state of the world should be. Or at least, they recognize problems I didn't know existed (and, it must be said, some problems I still don't have - still a challenge to differentiate the two) and are able to steer the conversation in a way that facilitates solving those problems in a clear way.

    On the other hand, I am able only to recognize when a "good" idea has been mentioned, or when a vision is worth being part of. "Good" being relative to my immediate sense of the world. Plenty of good ideas go whooshing by if they don't have an short-term impact on what I'm doing. I'm able to run with an idea, maybe even expand on it a little. And I can certainly document my trials, hopefully for potential mass benefit.

    I'm pretty sure this has to do with my tendency not to take anything in my career too seriously. Not sure if the attitude causes the problem or vice versa, but there it is.

    Whatever the reason, the attitude has worked for me for over three decades so it's not going anywhere. As for the lack of overall industry vision, as mercenary as it sounds, I'm good with that too. It's hard enough copying what others are doing (e.g. starting a user group), without having to make up the rules as you go.

    To tie this back to alt.net, I'm happy in my role as semi-silent observer. At least with respect to the bleeding edge trends like polyglot programming and future architectures. It'll help to have that background for when I catch up.

    And to tie it also back to the metaphor I'm using, it doesn't mean I need to react the same way Salieri did upon realization of fate's sense of humour. (That is, I won't drive the likes of Laribee and Scott Bellware into madness and death, steal their work as my own, then absolve the masses for being as mediocre as I am.) I can still be active in my own way and play off the strengths I have. There are plenty of people in the same boat I'm in now and plenty in the one I was in five and ten years ago. I may not be able to push the boundaries of the playing field, but I can certainly invite more people to the game.

    Kyle the Metaphoric

  • Deserializing JSON into a list of abstract base classes

    More adventures in JSON serialization. I'm tellin' ya, it's like a Saturday morning cartoon, it's so exciting. And I'm afraid that's about as far off topic as I'm going to get with this one because there'll be a lot of code which tends to push posts into the "Sweet Jayzus, ya think I got that kind of attention span?" territory in my RSS reader. I promise I won't try to learn ya too much agin in the near future.

    The scenario

    I'm serializing to the browser a List<Location>. Location is an abstract class with two implementations: RuralLocation and UrbanLocation. The method I'm using to serialize this collection to JSON is based on Scott Guthrie's post (though updated to use the DataContractJsonSerializer class:

    public static string ToJson( this object obj )
    {
        var serializer = new DataContractJsonSerializer( obj.GetType( ) );
        var memoryStream = new MemoryStream( );
        serializer.WriteObject( memoryStream, obj );
        string jsonString = Encoding.Default.GetString( memoryStream.ToArray( ) );
        memoryStream.Close( );
        return jsonString;
    }

    Here's the code to deserialize:

    public static T ToObject( this string jsonString )
    {
        var serializer = new DataContractJsonSerializer( typeof ( T ) );
        var memoryStream = new MemoryStream( Encoding.Unicode.GetBytes( jsonString ) );
        var newObject = (T)serializer.ReadObject( memoryStream );
        memoryStream.Close( );
        return newObject;
    }

    The problem (until this morning) was, I couldn't use the code to deserialize. On my page, I was creating JSON objects representing RuralLocation objects and UrbanLocation objects with an AJAX call using this same ToJson method. Here's the MVC action to create an UrbanLocation JSON string:

    public void GetUrbanLocationAsJson( string Lot, string Block,
            string Plan, string Address )
    {
        var location = new UrbanLocation
        {
            Lot = Lot,
            Block = Block,
            Plan = Plan,
            Address = Address
        };
        Response.ContentType = "application/x-javascript";
        Response.Write( location.ToJson( ) );
    }

    This returns the following JSON string: {"Lot":"1", "Block":"2", "Plan":"3", "Address":"111 Hoe Down Way"}. And the corresponding method for RuralLocations created something similar.

    The issue was that on the client, I had a collection of heterogenous JSON objects with no indication of what type they were. Yes, each one inherited from the same base class but there was no sign of the type when it was serialized. So when I got the JSON string back on the server, I couldn't make a call like Location[] locations = jsonString.ToObject<Location[]>( ) because it would try to create actual Location objects, not the inherited UrbanLocation and RuralLocation objects.

    At the time, my solution was to get any solution working so I deserialized old school: by parsing the string and building the objects by hand. But this morning, I noticed the output of a call to myLocations.ToJson( ). It had the objects the way I expected but there was something else tagging along for the ride:

    [
      {"__type":"UrbanLocation:#Trilogy.Gunton.Model",
        "Address":"",
        "Block":"115",
        "Lot":"2",
        "Plan":"2"
      },
      {"__type":"RuralLocation:#Trilogy.Gunton.Model",
        "Lsd":"NW",
        "PrimeMeridian":"1W",
        "Range":"19",
        "Section":"23",
        "Township":"10"
    }]

    So it seems the JSON serializer *was* including type information, but only when it serialized a list of Location objects, not when it serialized a single RuralLocation or UrbanLocation. So that's easy, once I get the JSON from the server for a location, I can manually add a __type to it in the Javascript and populate it with the typename before I send it back to the server.

    I'll admit, I actually did consider such nastiness. But then my well-honed Hack Alert started going off as I hope it did for each of you.

    What I really wanted was to have the ToJson method specify the type in the resulting string. And to accomplish that, I modified the ToJson method accordingly (changes in bold):

    public static string ToJson( this object obj )
    {
        return ToJson( obj, obj.GetType( ) );
    }
    
    public static string ToJson( this object obj, Type baseClass )
    {
        var serializer = new DataContractJsonSerializer( baseClass );
        var memoryStream = new MemoryStream( );
        serializer.WriteObject( memoryStream, obj );
        string jsonString = Encoding.Default.GetString( memoryStream.ToArray( ) );
        memoryStream.Close( );
        return jsonString;
    }

    And I modified the final line in GetUrbanLocationAsJson to: Response.Write( location.ToJson( typeof( Location ) ) ).

    Now, when I retrieve Location objects as JSON, they have the __type included and I can call myLocations.ToObject<Location[]>( ) freely without having to parse a JSON string manually. Hooray!

    Boy, this is so much easier than learning Ruby.

    Kyle the Unparsed

  • There's a voice...

    This is a rehash of a post from the last blog but I was reminded of it again after reading about Chris Ortman's Developer Exchange Program, an idea with promise and I'll be watching to see how it plays out. (Sorry I can't participate, Chris. Have a hard enough time convincing companies to take on a remote developer, let alone one who's tag-teaming.) And I don't mind revisiting it because 99.8% of you haven't read it yet and the other 0.2% are Canadian, and will jump at the chance to talk about a piece of Canadiana that few outside the country are aware of.

    In Canada, there was a long-running TV series called the Littlest Hobo. In it, a very well-trained and patient German Shepherd roams the countryside helping people out as the situation warrants. Kind of a pre-cursor to Quantum Leap but instead of the hero doing some sort of phase shift from one situation to another, he just kinda trots off. Plus he's a dog. The theme song is so sing-along-able, it's practically a bar song. (Everybody: "EVERY STOP I MAKE/I'LL MAKE A NEW FRIEND!").

    London Maybe tomorrow, he'll wanna settle down. But until tomorrow, he'll just keep codin' on.

    As applied to software, this would be a useful person to have, particularly in an environment that has several projects on the go at the same time. The idea is that someone would go from project to project, lending a hand wherever they were having trouble. Taken from my original post:

    Someone whose sole job is to pair with a developer for a morning on a task, then review code on a different project in the afternoon. The next day, he or she would examine the build process of a third project and see if it could be improved (and it always can). Another time, perhaps he or she could mentor someone on ReSharper shortcuts while they code.

    Essentially, I'm thinking of someone working outside of a single project who can provide an outsider's perspective during the development process. And it doesn't necessarily need to be one person's full-time job. It could be a role that is passed around among senior developers every week. It doesn't even need to be a role that is fulfilled every week either. If you have a small group, maybe one person takes it for a week, and then it stays unfilled for a couple of weeks.

    I haven't formalized the role much more than this in the six-odd months since I posted it. Except that I'm convinced the role should be passed around to different people. And that it would probably be practical only for about a week each month, depending on how many projects you have on the go. If it's five or less, I can see it becoming a burden having to deal with someone dropping in on your project once a week.

    But then, the role shouldn't be too ceremonial either. That's not the way of the hobo. If you go to a development team one afternoon and say "How can I help?" and they say "Not now", don't force yourself upon them. Move on to the next project.

    The short duration is important too. It keeps the hobo from becoming too entrenched in a project. Keeps the focus on quick tasks that the team always needs done but that no one has bothered to take the time out to do.

    I'd have to see how the idea plays out in practice before I fully endorse it. It kinda sounds like one of those "good intentions" dealies, where the idea has merit in theory, but in practice, you end up passing around the kid who's always picked last for sports. It's definitely one that could fall prey to a crappy corporate culture.

    Many companies have someone who kinda, sorta plays this role, even if it is not formally defined as such. In these cases, I say formalize it and pass the baton around a bit so that it's not always the same person.

    So I look forward to the day where I can test it out. In the meantime, do yourself a favour. Become The Littlest Hobo in your organization today.

    Kyle the Nomadic

  • How to convince your boss to let you go to DevTeach

    Having backed out of the alt.net conference this weekend (for reasons I can make up if you care enough), my travel schedule focuses instead on DevTeach next month. And having typed that sentence out, I can't help wondering if my priorities are a little skewed but lesson learned for next fall I guess.

    One of the e-mails I got updating me on DevTeach had a link on the top ten ways to convince your boss to let you go. I got pretty excited when I saw the title but was quickly dismayed. The industry is evolving too fast? Networking opportunities? Wireless access to stay in touch? How are these going to help me convince my boss?

    Then it dawned on me. These are ways to convince your boss *at work* to let you go. And as a consultant, that's often a no-brainer for me. I tell them I'm taking the week off and usually they're happy they don't have to pay and/or deal with me.

    But that doesn't mean I don't have some challenges to overcome in order to go. I'm not exactly a sole proprietor when it comes to taking a week off work with no pay to hang out in Toronto.

    So without further ado (and with thanks to Derik Whittaker):

    The Top Ten Ways To Convince Your *REAL* Boss To Let You Go To DevTeach

    1. I have too much free time on my hands
    2. You're just jealous 'cause I'll be learning about ASP.NET MVC and you won't
    3. I promise I'll turn my cell phone on this time
    4. I'll bring you back something nice. Like a P&P mug
    5. "Party with Palermo" is just a code name. For...uhhh....Pinochle with Palermo
    6. I bet that broken washing machine *will* fix itself while I'm gone
    7. If I don't go, all the other developers will laugh at me!
    8. I...uhhh....kinda need to leave the country for a while
    9. Where else am I going to get the social interaction and stimulating conversation that is missing from my life?
    10. At least I'm not going "fishing" like they did in Brokeback Mountain

    And if none of those work, it's time to bring out the heavy artillery:

    • You wouldn't deny me a face-to-face meeting with Justice Gray, would you?

    Feel free to add your own. Anything to help spread the word. I don't want anyone to miss out because "My wife/husband/significant other/eight-year-old daughter with a surprisingly stern voice said I couldn't go".

    Kyle the Convinced

    Posted Apr 16 2008, 11:13 AM by Kyle Baley with 3 comment(s)
    Filed under:
  • On diving into NHibernate

    Here's the thing with NHibernate: It's hard. I'm mildly, bordering on moderately familiar with it and while it's a powerful product, it's a complicated one. This is due in no small part to the fragmented nature of the documentation. Some is on the official site, some in discussion groups, some in FAQs, and some in books. It's getting better but it is still a very daunting and frustrating task to do seemingly simple things when you aren't a master.

    We'll look at the example that you knew was coming: Select all Jobs that have at least one Location with a Section = 15. Here is the SQL:

    SELECT		*
    FROM		Job
    WHERE 		JobID IN
    	( SELECT 	JobID
    	  FROM		Location
    	  WHERE 	Section = 15 )

    Not too bad thanks to years of SQL that have been ingrained at the expense of remembering vital statistics and, on occasion, basic motor skills.

    Now before I post a solution, I should point out that one of the reasons NHibernate is hard to figure out is that the domain does not lend itself well to Google. Take this example. I want to convert this SQL to ICriteria format. Searches for various combinations of NHibernate, Subqueries, Collections, and Children do not make one reach for the "I'm feeling lucky" link. I did find this somewhat helpful link until I discovered that the whole thing could be replaced with an Expression.IsNotEmpty criteria.

    I'll show *a* solution to my problem:

        var subquery = DetachedCriteria.For<job>( );
        subquery
            .SetProjection( Projections.Property( "Id" ) )
            .CreateCriteria( "Locations" )
                .Add( Property.ForName( "Section" ).Eq( "15" ) );
    
        var query = DetachedCriteria.For<Job>( );
        query
            .Add( Subqueries.PropertyIn( "Id", subquery ) );

    I'm going to venture an opinion that this is *not* an intuitive piece of code when, in the back of your mind, you're trying to map this to what you know of SQL.

    Here is what is going on as I see it. The subquery is equivalent to the following:

    SELECT      JobID
    FROM        Job j
    INNER JOIN  Location l
    ON          j.JobID = l.JobID
    WHERE       l.Section = 15

    This is different than the subquery above and there is a reason for that, which I think I'll get to. But first, here are some specific areas of confusion:

    • SetProjection is essentially saying "what fields do you want to return?" If you ignore it, it will return whatever object the query is for (in this case, a list of Jobs).
    • CreateCriteria( "Locations" ) is used for the INNER JOIN on Job. The Add will create a criteria for the Location (which is why I indented it further).

    The reason for my confusion is the disconnect between the terms when mapping them to what I know of SQL. Could be my cursory knowledge of the underlying theory. Could be that it's just hard coming up with names for these things.

    Now we get to the reason why the subquery is on Job and not Location. In my domain model, Job contains a collection of Location objects. The Location objects do not have a reference back to the parent, nor do they have a JobId property. There is a JobId column for the table in the database but that's used only by NHibernate to populate the collection of Locations for a particular Job.

    If I were to create the subquery on Location, I have nothing to return in the Projection. There is no JobID property on the Location. And NHibernate deals with objects in its queries (mostly), not database schema. So I needed to create an INNER JOIN subquery solely so that I could return the ID property on a Job object.

    Once that is finished, we create the main query, again on Job. The sole point of confusion I had here was that I saw In in the list of methods on Subqueries and tried to use that instead of PropertyIn.

    It took an inordinate amount of time to get to this point compared to how much time I spend with other tools. Like I said, maybe it's the problem domain. Maybe it's the way my brain is wired for this type of problem.

    The underlying point is...well, I'm not all too sure actually. Not sure what the recommendation is here. I'm not knocking NHibernate because the fact is, it does make my life easier for the 90% of the time I'm not doing stuff like this. The point isn't really to stick with it either, though again, I think you should if you've tried it and dismissed it for being too complicated. Guess I just wanted to say I worked really hard today.

    Concluding note: I'm aware of the existence of HQL. I'm building a search screen and the prospect of converting an arbitrary number of search parameters into HQL didn't appeal to me.

    Kyle the Unrelenting

  • jQuery and the ConventionController

    Well here's a fine how-do-ya-do. I'm using the ConventionController from MVCContrib which means I have controls with IDs like dto.JobName and dto.OrderedDate.

    Problem is, I can't get at these things by ID in jQuery anymore. "#dto.JobName" in jQuery means (if my memory of CSS serves) select all elements with an ID of dto and a CSS class of JobName. Even if that's wrong, it doesn't matter much. The end result is $( "#dto.JobName" ) returns a useless object.

    Current workaround is to select by name. Like so: $( "input[name='dto.JobName']" ) or $( "select[name='dto.JobTypes'] ).

    Kyle the Selector

  • Who's the next guy?

    Have been playing with testing against an in-memory database recently but that's not the subject of this post. Tt was one of the enablers for it, though.

    One of the ideas I talked about on my old home was Conscientious Coding, which is capitalized solely in case the term takes off so I can later claim a copyright. There's not much to it really. The underlying principle is: Someone else is eventually going to have to deal with your code. Be nice to them.

    It's a subjective principle, to be sure. And as I've been working on what could very well turn into someone else's Brownfield application, I can't help wondering what that fellow is getting himself into if I ever get hit by a runaway dolphin.

    The app I'm working on is for my dad's company, a small- to medium-sized land surveying company, and a good twenty percent of the staff is comprised of the entirety of my immediate family, save the missus and the young'un. The company is based in Virden, Manitoba (population 2500 - 3000 depending on how many times you count sister-wives and brother-uncles) with an office in Brandon (known locally as "The City").

    I've mentioned before that the application is an update of one I whipped up nigh on eight years ago over a couple of weekends. It was in classic ASP and made heavy use of ADO, XMLHTTP, and JavaScript. It didn't do a whole lot but they quickly become utterly dependent on it such that I didn't need any formal notification system to tell me when our hosting company went down because they'd be on the phone to me if it so much as hiccuped.

    It's not the cleanest code I've written but I've been able to add a couple of little features here and there (like the ability to delete) without requiring a day to re-learn the app each time I went back to it.

    Now here I am two months into the re-write and I haven't even managed to duplicate what the existing app does yet. This is partially due to my veering off to hone some skillz and learn new technologies but it's also because I'm not quite as cavalier about my code as I used to be. The new version now has more VS projects than the old version had physical .asp files. In case you think I'm kidding, the old app consists of: AddEditJob.asp, JobSearch.asp, SearchResults.asp, and DeleteJob.asp. Plus supporting CSS, JavaScript, images, and XSLT files.

    Now we get to my would-be successor. Typically, a company of their size wouldn't hire an intermediate-with-senior-aspirations developer to build custom software to run their business. They're having a hard enough time simply finding time to update their website. It's just a happy coincidence that the one black sheep in the family can actually help streamline things a bit.

    So I've been thinking about who they would potentially get to maintain the software I'm writing for them. There's a very high probability, it would be a junior person, possibly even a network person with grandiose ideas of being a rock star programmer. And I'm imagining his reaction when he opens the solution (assuming he's familiar with Subversion) for the first time and finds things like a) a very large number of objects aren't "created" anywhere, and b) there are no SQL statements or stored procedures. This is not to mention what he'll make of the .build file in the root folder.

    In a large company, where I work as a part of a team, I don't pay this no never mind. They have the resources to retain a senior resource who should either be familiar with IoC and O/RM or be able to figure it out without much trouble. Junior developers on that team would almost always have someone they can turn to in times of crisis. But what about this lowly single-developer application owned by a company whose IT department consists of whoever comes into the office first to turn on all the computers? What are the odds they would be able to find someone in their area who could look after it?

    Assuming they find someone relatively keen, how much can I assume of this person? Can I assume they'll be able to Google their way through NHibernate, StructureMap and/or Windsor, NAnt, CruiseControl.NET, Linq, NUnit, and MVC? Will he look at my repositories and think, "why doesn't he just call stored procedures directly on the database?" followed by "where the &*%$ or the stored procedures?"

    These are moot points in some ways because I see little justification for "dumbing down" anything I do in the off-chance this application outlives me. At this point, a well-crafted readme file is probably all that is in order to assuage my guilt of using all this new-fangled technology. One that outlines the technologies that are used and where to start looking if they need help. This is kind of an extension on a post I did just over a year ago on how to make sure your family's IT department will continue to run after your untimely demise, basically saying in my own terse way that you should document everything.

    I like this approach because it doesn't assume the next person is incapable of handling it while still providing guidance if they aren't familar with all the little gadgets embedded in it. Assuming it remains more current than the comments in the code...

    Kyle the Death-Wished

  • Linq to NHibernate - The Day After

    What a difference a day makes. Spent the better part of yesterday trying to figure out the Linq to NHibernate so that I could use Contains on something other than a string, like so:

    from job in session.Linq( )
    where officeIds.Contains( job.Office.Id )
    select job;

    The book Linq in Action, as well as Matt Warren's series on query providers, both provided a lot of help in understanding the code. As I started sifting through it and looking at failing tests, I started making some fairly sweeping changes to the code. Not necessarily to check it in, mind you, more for my own eddy-ficashun. I was in spike mode, not "someone else may actually look at this" mode.

    In the end, it wasn't quite as hard as I first thought. 'Course, I have a built-in advantage since parsing expression trees is much like parsing the family tree, what with all the AndAlso's and OrElse's. ExclusiveOr was a new concept though.

    By the time I was done, I had an ExpressionVisitor very similar to the one Matt Warren specified and I had implemented it in a couple of the visitors in the codebase. It still didn't do what I wanted but I was a lot clearer on how things flowed. It fixed a couple of bugs while introducing others and while I wasn't any further ahead in my specific task, it was a nice break to do something I haven't in a long time.

    Then I updated to the latest and lo! Chadly (who I'd link to if I had a blog for him) has implemented what appears to be the same thing, albeit in a much cleaner way. And even better! Doug Mayer (also conspicuously unlinked) has implemented the exact Contains support that I needed! Well, almost. Contains works on arrays now but not on Lists (or anything deriving from ICollection methinks). But ToArray helps out there.

    Anyway, here I am a day later having learned about query providers and my work still got done for me in my absence. All hail OSS!

    Kyle the NHiberLinq'd

  • Trying out Linq for NHibernate

    The hillbilly loves to be humbled. It's why he refers to himself in the third person. It's a liberating feeling knowing there are people out there who are smarter, faster, and know more lyrics to Air Supply songs than you. And I always like to give people that smug feeling of being better than someone, even if it's just me.

    Such was the feeling I've ended up at after a foray into Linq to NHibernate. But before we get to the part where I felt stupid, the path that led me to Linq to NHibernate is interesting in a "let's pad this out" kinda way.

    I'm building a search screen for an application for land surveyors. In it, you enter a bunch of criteria for various fields, click Search and moan about how it was easier when everything was on paper while you wait for the results to appear.

    My initial plan to implement this was to have a search DTO in the client that would collect all the criteria up. That DTO would be converted to a collection of SearchCriteria domain objects which would be passed to the data layer. The data layer would then convert it once more into NHibernate expressions for use with the query. Nice and encapsulated, albeit a little conversion-heavy.

    Then I got to thinking about Linq for NHibernate and decided to give it a test drive. The end result was a slightly different approach. Namely, I convert the DTO into a collection of Linq Expressions and pass *that* to the data layer, which could then iterate through each of them and append them to a preset Linq query.

    Here's an example of the code to execute the query in the repository.

        public IList<T> FindAll<T>( IList<Expression<Func<T, bool>>> criteria )
        {
            var query = from item in CurrentSession.Linq<T>( )
                        select item;
            foreach ( var criterion in criteria )
            {
                query.Where( criterion );
            }
            return query.ToList( );
        }

    A little different from the traditional from x in y select x where moo examples mostly because I don't know what the where clause is going to be at design time. The type for the criteria looks a little intimidating but because of it, I can add criteria to the list in an aesthetically pleasing way. To wit:

        searchCriteria.Add( job => job.JobNumber.Contains( suppliedJobNumber ) );
        searchCriteria.Add( job => suppliedOffices.Contains( job.Office.Id ) );
        searchCriteria.Add( job => job.OrderedData > suppliedData ) );

    Here's where things start to go awry. Linq to NHibernate is still very much experimental. For example, the second criteria above doesn't actually work. It assumes that Contains will be called only on strings, not lists. And during my travels, I discovered two other examples that won't work:

        searchCriteria.Add( job => "Name1Name2Name3".Contains( job.Name ) );
        searchCriteria.Add( job => job.Id == idList[0] ) );

    That is, it won't allow an expression to be evaluated as the argument for a Contains call on a string. And you can't use an array index in your comparisons either.

    But I did get the code from a branch called "experiments" after all. So rather than complaining, and since I've got the time, why not try to actually implement these? So I started with the one I actually had an immediate need for: getting Contains working on a List.

    I started to feel a little nervous about this early on what with the advanced Reflection/Linq concepts involved, not to mention my tenuous grasp of the Visitor pattern. Eventually, I ended up at the line of code that was failing:

    return Expression.Lambda(typeof(Func<>).MakeGenericType(expression.Type), expression)
        .Compile().DynamicInvoke();

    I don't doubt that this kind of code is necessary. We are, after all, dealing with a Linq provider that needs to build and parse an expression tree. And I'm pretty sure that with some initial guidance, I'd be reasonably productive in implementing this. (To be fair, looking more closely at that line of code, it's only the MakeGenericType call that baffles me completely. And at the time of writing, I was still too lazy to look it up.)

    To put Linq to NHibernate back into context, the reason I like it is because I can essentially do what I originally intended (build a list of criteria and pass it to the data layer) without having to write a bunch of conversion code and without having to create NHibernate expressions in my service layer. As a result, it holds great promise for me but the next couple of days will tell if it's a time/productivity trade-off I can make right now. So if you have some time on your hands, I'll respectfully add my vote for taking a look at Linq to NHibernate.

    But don't let it interfere with your banjo lessons...

    Kyle the Time-slotted

More Posts Next page »