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

July 2008 - Posts

  • Going full circle with TDD

    A couple of years ago, I had lunch with JP. It was before TDD had clicked for me and I was still very much a skeptic. As always, JP was passionate but not forceful in his explanation of it but by the end of the lunch, I still wasn't sold. So much so that I wrote a nice little write-up that, upon re-reading, is akin to looking at pictures of my choice of clothing in the 80s. (What can I say? Corduroy worked for me.)

    So it is with some bemusement that I reflect on almost the exact same conversation I had with another young developer three days ago, except that I played the part of JP and he played the part of the skeptic. I recognized each and every argument he posed because I made them myself at one point: It takes too long. What's the difference whether I test first or test after? There's too much code. It's safe and warm and fuzzy in my world and I won't have you telling me otherwise.

    The argument wasn't all that heated because we're both Canadian. But in the end, the only real argument that stuck with him is the same one that stuck with me originally: it works for me. I've been doing it for a while now and I like the results I get with it. Maybe I can't quantify the specific time and/or cost savings over time but I can tell you, it "feels" right. I like looking at the software I build with it. I like going back to it to add features. There's a much smaller learning curve when reviewing it after a few months.

    Maybe I can get that same feeling just by adopting a few decent development practices rather than a full-on design methodology. That may be so, though it seems to me that TDD allows you to adopt such practices a lot more naturally. So that you aren't forcing yourself to learn them. Rather, you learn TDD and other design principles seem that much clearer.

    Of course, TDD isn't exactly a walk in the park itself and it sure does help if you can learn alongside someone who has done it. And even now, I'd rank myself only about a 4 or 5 out of 10 on the "TDD Afficianado" scale (though if a recruiter asks, the answer is always 7). Past the book-learning phase but still not practised enough that I could, say, teach a course on it.

    Which I think is part of the barrier to entry. It's hard (for me, at least) to learn on one's own without some real-world work backing it up when the class/seminar is over. Often, there is a sense of hopelessness anyway at having your eyes opened to a new world, then returning to your regular job at Niagra Inc.

    At one point, I had some vague plan to do an online Skype thing with whomever wanted to join to talk about something like this. Not to teach but to share my findings and see if anyone else would either learn from it or enhance my knowledge of it. I do hope I have the wherewithal to follow through on it because I do so love the idea. Kind of a real-time version of Derik's www.dimecasts.net site (which continues to be awesome if you haven't checked it out).

    Anyway, I'm not entirely sure where I'm going here. Just liked the symmetry of the two conversations, I guess but I'll stop now. Let me know if you'd be interested in a Skype coding session, possibly sometime in September when I've fled this foreign corporate cowboy world again.

    Kyle the Circuitous

    Posted Jul 28 2008, 05:32 PM by Kyle Baley with 12 comment(s)
    Filed under:
  • Incarceration Log - Day 4

    It has been only four days since my self-imposed, month-long incarceration in the prison known as Corporate Calgary, but already the three walls of my cell close in around me. My oppressors continue their assault on my psyche with inhuman tortures such as "Death by 1000 Quick Questions" and "Let's Talk About Weather" and "We Meet Because We Can".

    My jailors mock me with bizarre acronyms and epic tales of projects past. Yesterday, I nearly screamed in terror when I caught myself chuckling knowingly at one such anecdote. During a meeting to review progress of a system I didn't know existed, let alone used, no less. I fear I may be going insane.

    Two things keep me alive. One is the presentation I give next week on ASP.NET MVC to the Calgary .NET User Group on the 29th and the Edmonton .NET User Group on the 31st. During status meetings, I surreptitiously pull up my VM and review my code and notes, ignoring the sidelong glances at my insolent giggles. These presentations are my one tenuous grip on reality and I shall protect them with, well, not *my* life but probably the life of someone close to me.

    The second is the one ray of light in my task list: a throwaway application I pull up when I need an extra dose of lucidity. Just this morning, I discovered an error that made me nearly leap for joy for the mere mental exercise, slight as it was:

    private void ConvertFile( string converterName, string sourceFile, string destinationFile )
    {
        IConverter converter = FindConverter( converterName );
        converter.ItemProcessed += converter_ItemProcessed;
        int recordsProcessed = converter.processFile( sourceFile, destinationFile);
    }

    This (much simplified) piece of code contained an error. The first time it was called, it ran fine. Each subsequent call appeared to process the file multiple times. I.e. the second time it ran, the file was processed twice, the third time, thrice, the fourth, ummm...quadrice. And so on and so forth.

    Alas, the solution presented itself all too quickly. The file was not actually being processed multiple times. Rather, a brand new ItemProcessed event was being appended to the event handler each time through. So the second time the file was processed, the ItemProcessed event was called twice each time an item was processed. The third time, thrice. Etc, etc.

    Unfortunately, the fix was trivial:

    private void ConvertFile( string converterName, string sourceFile, string destinationFile )
    {
        IConverter converter = FindConverter( converterName );
        converter.ItemProcessed += converter_ItemProcessed;
        int recordsProcessed = converter.processFile( sourceFile, destinationFile);
        converter.ItemProcessed -= converter_ItemProcessed;
    }

    And now I am left to ponder my decision to work onsite for the next month in this soulless place. Left to wonder why I left my safe haven. To toil between a woman whose radio is always slightly off-station and a man with a cruel tendency to squeeze his squeaky, rubber duck at inopportune moments.

    Pray for me, readers. Pray. For hope.

    Kyle the Indentured

  • Adding a customer field to a UI: Proposed solution

    In yesterday's post, I described a UI problem I was thinking about. Namely, how can you add a customer field to a UI. That post contains the criteria I'm looking for which I won't repeat here because this sucker's already longer than I want it to be.

    I was going to let the thing germinate a little first but Ayende was kind enough to propose the exact solution I am considering in the comments. That is, the customer name field will be an auto-complete textbox, like Google Suggest. As the user types, it populates the listbox portion with search results based on what the user has entered. If the user selects one of those values, the other customer info textboxes get populated with the default values. The user is free to change them.

    I'll walk through a couple of scenarios. First, adding a job with an existing customer. We go to the customer name field and start typing. The list of search results pops up and we select one of them. This brings back the default contact info for the customer and populates other contact fields on the form as well as a hidden field with the customer ID. The user is free to change the contact details if the defaults aren't appropriate.

    When the job is saved, we create a link 'twixt the job and the customer based on the customer ID field we stored. But we save the contact data with the job (not with the customer), even if the user didn't change it from the defaults. The reason being: In the future, the default contact person may change but that doesn't change the fact that, for this job at this time, this is the contact person.

    Next scenario: adding a new customer. Again we go to the customer name field on the job page and type a name into the auto-complete textbox. It auto-populates with search values but we don't select any of them. We continue on adding the contact information for this job.

    When the job is saved, it recognizes that we didn't select an existing customer because the customer ID field is blank. So we create a new customer record in the database and provide it with the entered contact info as default values. The remainder of the process is the same as if we selected an existing customer, including copying the "default" values into the job record.

    Another requirement was that we wanted to update the customer with new default information if we so desired. This can be done with a checkbox. If checked, we update the customer record with the user-entered contact info before saving the job. Everything else in the process is the same.

    I can think of a couple of edge cases that may require some tinkering. Firstly, customers with the same name. The business deals with both individuals as well as companies and it's conceivable that they could have a couple of John Smiths (or more likely, given the area, John Kowalchuks) on their mailing list.

    Not sure how I'll deal with that or even if I'll address it. This isn't a customer management app after all. They just want some reports on where most of their business is going. This edge case doesn't sound like one that will skew the results one way or the other.

    Next edge case: The user misspells the customer name and mistakenly adds a new customer when they already exist. This falls under my personal adage of "You can't save everybody" and again, I don't believe this will have a statistical bearing on the results. Besides which, it's nothing an annual data clean-up can't handle.

    Next: What if the user selects a value from the auto-complete list, then decides it isn't appropriate and deletes it, choosing to enter a new customer instead? I won't go into details here mostly because I don't know them yet. Off the top of my head, this will involve some funky AJAX to ensure that the customer ID field is blank when the job is saved.

    Lastly: what if the user entered in the wrong customer, saved the job, then later wants to change it? Do we even allow that on the job entry screen? Or is that something an administrator should do in a separate process?

    Sounds like a question for the client to me but historically, the person entering the data *is* the administrator so my guess is to make it as easy as possible. Which means having the ability to change the customer for a job at any time.

    Final note: I don't intend for this to be the sum total of the customer management capabilities of this application. I still plan to have the ability to update customer information outside of the context of a job.

    But the job entry screen is where they will spend a good chunk of their time and it behooves me to make it flow as effortlessly as possible. Their business isn't in data entry and data capture. It's land surveying. My business is to make sure that this application works as seamlessly as possible so that they can focus on the tasks that actually make money for them (and don't ask me what those are because, despite my genetic leanings, I have little idea what land surveyors actually do).

    In short, I don't want to be the bottleneck in their process.

    Kyle the Averse

  • Adding a customer field to a UI

    The Dilemma

    I've always tried to be conscious of building a decent UI while still recognizing that I'm better at critiquing them than creating them. And now, I'm looking at a problem that's been staring me in the face for nigh on eight years.

    It's a simple one really. On a web page that adds or edits a "job" or "order" or "project" or whatever, how do I allow users to select and add customers to the job/order/project?

    Here's where my critiquing skills come into play. I know plenty of ways others have done it but I don't usually like them. And more importantly, if I *did* like them, it was because it was so seamless that it was unnoticeable. Which doesn't help me either because "unnoticeable" means I didn't remember where I saw it.

    This is an internal LOB application so it's a little different than your typical e-storefront. On almost every web page I've been on, the natural progression is:

    • Build up your order
    • Check-out
    • Go to a separate page to login or enter your customer info
    • If you're lucky, return to your existing order and carry on

    I've skipped a lot of steps here, mostly ones where you try to remember if you've ever shopped at that place before and try variations of common usernames you use, all of which don't &*%$ work so you finally *attempt* to create a new account and only AFTER you enter all your data (and it's a crap shoot whether it'll take a non-US address) you discover your e-mail address is ALREADY IN THEIR &*%*# SYSTEM SOMEHOW!!!1!!.

    I digress.

    For this internal application, the requirements are similar, yet different. I want to be able to determine whether the customer for the current job is a new one or an existing one, but I don't want to go to a separate screen to do it. (Note: pop-ups, either modal or modeless, count as separate screens, only evil-er.)image

    In addition, I'd like the ability to, when an existing customer is selected, populate a few extra fields with that customer's default contact information but still provide the ability to override it. This is for cases where, say, a company calls up for a job. You may have done work for them in the past but for someone else. You still want to register the job against the same company but you want to attach different contact information to the job in case you need to, y'know, contact them. 

    Furthermore, I'd also like the option of overwriting the default contact information for a company from the same screen.

    So yes, I know what I want the screen to do. Just not quite how to present it.

    If this was a different field, say a manufacturer or car model or something, this could be solved reasonably well with a drop-down list that has <New Item> as the first option. This is okay for simple fields that don't grow in length very often. For a customer, it won't do. There are just too darn many of them.

    So to sum up, I'd like the following on the job entry page:

    • Search for existing customers
    • If one exists, populate the customer info with default values
    • Allow user to override customer defaults for this particular job
    • Allow user to override defaults for the customer overall
    • If a new customer, automatically save the customer info to the database with the entered defaults when the job is saved
    • Do all this on the same page (assuming it can be done reasonably well)

    Keep in mind that all these requirements are my own. The client (i.e. my mom and dad and all my brothers) just want it done. They would probably accept a multi-page wizard-like solution but they already mock me for not going into the family business. So I'm not going to give them any more ammunition for the omnipresent "You went to college for this?" discussion.

    I do have a solution in mind and will post it shortly. But let's see where this preamble takes us first.

    Kyle the Interfaced

  • Trying to access Windows Search from SQL Server: An Appeal

    Had some time to review my search dilemma today and three billable hours later, I'm no further along in my task.

    There is no shortage of documentation on the new Windows Search and I do so desperately want to try it out. Just not as a client.

    To sum up my requirements, I have a search screen that combines meta data in a SQL database with a contents search. That is, the user types in a search word or phrase and/or selects meta data about the documents (e.g. country, document type, date, and so on and so forth).

    At present, using Indexing Services, I am able to perform such a query within SQL Server with a single SQL Statement. That is what I would like to do with Windows Search.

    Alas, all efforts to connect to Windows Search via SQL Server have failed. The nearest I've come is to find a couple of lost souls to commiserate with who are having the same problem. I've tried every possible combination of provider, datasource, and provstr I can fathom with the connection string, Provider=Search.CollatorDSO;Extended Properties=\"Application=Windows\", and have come up empty.

    The issue appears to be with SQL Server as I am able to run pretty much every sample app under the sun and get search results back. I've even overcome my fear of C++ to read through some samples in the Search SDK.

    So I'm appealing to you, generous reader(s), for some help. I know I've broken the unwritten rule of finding at least one workable solution, however hideous, before asking for help but the nature of Windows Search is such that any workable solution would be the one I glom onto.

    Again, the criteria is relatively straightforward: I want to be able to search for documents (Word, PowerPoint, PDF, and Excel only for the moment) based on their contents as well as metadata.

    I can do that with Windows Search now but it would involve retrieving a result set based on metadata, retrieving a second result set based on contents, then merging the two. Given the size of the repository (about 2600 documents), this is do-able but it's the kind of bastardized union that perpetuates the hillbilly stereotype. And I'm trying to be more PC.

    I would consider SharePoint only if someone can convince me it is an elegant solution that specifically meets these requirements. I am also open to a third-party component that indexes files and provides an API. But again, I can do this already with Windows Search. It would have to be something that can combine with SQL Server.

    And if I don't get a decent answer, then I'm gonna...well, swear a bit maybe but that's probably it.

    Kyle the Unthreatening

  • Review of the Check-In Dance

    This started as a promotion for the dimecast I recently did on the Check-In Dance but I think it's worth reviewing in more detail.

    Don't know if he coined the phrase but I first heard of the Check-In Dance from Jeremy Miller. His post on the subject is still, some three years later, accurate. In it, he describes it in relation to continuous integration but in my screencast, I talk about it in a more general setting.image

    But I'm being vague. Here's the problem it solves. In a multi-team environment, it is very easy to check in code that "doesn't work". Often it works fine on the developer's machine but when it is merged into the main version control repository, which is also being updated by other developers, we end up with a version in the repository that won't compile.

    Here's an example. We have a class Artist:

    public class Artist
    {
        public int Id { get; set; }
        public string First { get; set; }
        public string LastName { get; set; }
    }

    And here is some code in a user control that uses it:

    protected void Page_Load(object sender, EventArgs e)
    {
        var artist = new Artist();
        artist.First = "Frank";
        artist.LastName = "Sinatra";
        labelFirstName.Text = artist.First;
        labelLastName.Text = artist.LastName;
    }

    Now our first developer, we'll call him Huey, is working in the code and decides that First is incorrectly named. It should be FirstName to be consistent with the LastName property. So he changes the name of the property to FirstName and updates the Page_Load code that calls it. The code compiles on his machine and he checks in. All is right with the world.

    Cut to our second developer, Lewis. He's working away on some new code that uses the Artist class. Let's watch!

    public void SaveArtist( int artistId, string firstName, string lastName )
    {
        var artist = new Artist{ 
            Id = artistId,
            First = firstName,
            LastName = lastName
        };
        _repository.Save( artist );
    }

    Notice that Lewis is using the original implementation of the Artist class because he is oblivious to the changes Huey is making. But when he's done, he compiles and again, it works fine on his machine. He checks in and goes home with the knowledge of a job well done.

    The next day, another developer, Jackson, comes in to work. He's been away on vacation so the first thing he does is get the latest version. And lo! It won't compile. Heckuva a thing to greet a guy after two weeks of R 'n R at the local World's Strongest Man retreat. Now he has to go digging into code he hasn't looked at for weeks to find out what's wrong before he can be productive.

    The culprit here is Lewis (and even Huey though he didn't really make any breaking changes). He contaminated the "one true source" in the version control repository but checking in code that, while it worked locally, does not work in the context of the entire application.

    As Captain Understatement would say, this is bad. At this point, we have an application in version control that no longer compiles. Any developers that get the latest version are not able to work. And the onus to fix it is implicitly on the next developer to get the latest, not on Lewis, who created the problem. In any case, Jackson must either fix the problem or track down who made the error and calmly explain that it would be peachy keen if he fixed it when it tickled his fancy.

    Either way, this situation should be considered tantamount to eating babies or using genetically-modified dandelions as a base for your hooch. Your version control repository is sacred ground. It is not meant to be trod upon by blasphemous developers working in a vacuum. At any point, your client (or anyone) could walk in and ask for the latest version of the code and you should be able to give it to him with confidence.

    What Lewis should have done was the check-in dance:

    1. Make his changes to the First property
    2. Compile them locally and test to make sure they work
    3. Get the latest version of the code from version control and merge them into his local copy
    4. Compile again and test to make sure his changes still work
    5. Check-in

    The third and fourth steps are the important ones and the ones Lewis skipped. They are the ones that give you the requisite confidence you need in your version control repository.

    Like I said earlier, this version of the check-in dance differs slightly from Jeremy's. He was talking in the context of a continuous integration environment. This is something you should strive toward but if you don't have it yet, this version will help you get into the mindset. And even if you aren't interested in CI, the check-in dance is still a necessity to keep your repository as pristine as <editor's note: this metaphor has been removed to ensure CodeBetter does not get blacklisted by corporate web filters>.

    A word on the merge in step 3. There is no doubt that this can be messy. Especially if you aren't checking in often. What can I say? Not much you can do if you want to keep your repository clean. Either check-in often or start cozying up with a merge tool vendor.

    Keep in mind, though, that if you don't encourage a culture of checking-in often, you'll end up with developers that either avoid the check-in dance, or avoid checking-in at all. It's basic conflict-avoidance. If it hurts when I move my arm like that, I'm going to stop moving my arm like that.

    In either case, you are wasting expensive time. If you don't use the check-in dance, you are wasting the time of the developer who has to track down an error in code he didn't write. And if your developers aren't checking in often, they are wasting time doing massive (i.e. more error-prone) code merges.

    At this point in this little odyssey, I probably shouldn't be talking about wasting time. So I'll wrap up. If you want more info, I'm happy to continue this in the comments. Also, I've already linked to Jeremy's post and my dimecast on the subject above. Donald and I also talk about it in our DNR episode.

    Kyle the Versioned

  • Alt.net Canada Open Spaces is now taking requests

    Well, Canada turns 141 years old today and as we all know, 141 is the Conference anniversary. So in imagekeeping with that, registration is now open for the alt.net Canada Open Spaces Extravaganza. Get your requests in early because only the first 100 will be allowed in and at the time of writing, over 10% of those are filled already. After that, you'll have to do what all Canadians do and try to cozy up to the bouncer.

    I will personally guarantee satisfaction at *any* cost for all who attend so don't delay. It will be held in the future capital of West Canada: Calgary, Alberta at the University of Calgary. Full details on the site.

    Organizing, and in attendance, will be a gaggle of good Canucks, including (in alphabetical order by first name): Bil Simser, D'Arcy Lussier, Dave Woods, Donald Belcham, Greg Young, James Kovacs, Justice Gray, and Terry Thibodeau. And facilitating will be facilitator extraordinaire, Doc List, which was a bit of a coup for us.

    So if you haven't been able to make it to one of the previous events in Seattle or Austin because of "border troubles", no more excuses.

    Kyle the Hyped

More Posts

Our Sponsors

Proudly Partnered With