Outlook Lookout
While I wait for Google to fix their desktop search bug, I’m using Lookout (version 1.2.0.1924) to search Outlook. I was under the distinct impression that Lookout got killed after Microsoft bought the vendor (Lookout Software), especially when I read this post on Channel 9.
It looks like the helpdesk people at work squirreled away an old installation of it, because Googling for it brought back nothing but Windows Desktop Search links.
Google Desktop Bug
It looks like Google Desktop 5.5 has a bug that prevents users from opening forwarded e-mail attachments. There are more details in this Google Groups thread.
A brief note on version control, labeling, and deployments
One thing I didn’t realize about CruiseControl.NET until recently was that it automatically labels your builds. It uses a
We still need to get our continuous integration setup working again, but in the interim, manual labeling of releases is still helpful.
Exposing InnerException
This week, an application I work on started logging an exception that provided no help at all in debugging the problem. My usual practice of running the app in debug mode with production values in the config file failed to reproduce the error too. After a couple of days of checking a bunch of different areas of code (and still not solving the problem), Bob (a consultant from Intervention Technologies) gave me some code to get at all the InnerException values for a given Exception. Download the function from here.
StackTrace can be pretty large. Since we log to a database, I was worried about overrunning the column width. I also wasn’t keen on the idea of looking at so large a text block if an Exception was nesting four or five additional ones. So instead of implementing the code above, I changed the code to log at each level. Doing it this way adds a log entry for each InnerException. Because the log viewer I implemented displays the entries in reverse-chronological order, the root cause of a really gnarly exception displays at the top. The changes I made to global.asax looked like this.
The result of this work revealed that the app had been complaining about not being able to reach the SMTP server to send e-mail (which it needs to send users their passwords when they register or recover lost passwords).
Once we’d established that the change was working properly, it was time to refactor the code to make the functionality more broadly available. To accomplish this, I updated our Log4Net wrapper like this.
App_Code: Best In (Very) Small Doses
When I first started developing solutions on version 2.0 of the .NET Framework, I saw examples that had some logic in the App_Code folder. For things like base pages, I thought App_Code was perfect–and that’s how I use it today. When I started to see applications put their entire middle tiers in App_Code however, I thought that was a bad idea. Beyond not being able to unit test your components (and the consequences associated with a lack of unit testing, coverage, etc), it just seemed … wrong.
Fortunately, there are additional reasons to minimize the use of App_Code:
First earthquake
I was at the San Jose Airport waiting on a flight to Los Angeles when this earthquake hit. It didn’t register with me that an earthquake was happening until a few seconds went by and I saw the walls and ceiling moving more and more. Everyone in the terminal (including me) dashed toward the nearest doorway or arch they could find. It was quite a scary experience, and one I hope never to repeat.
Chocolate Sunday at Cacao Anasa
I spent a few hours this afternoon making chocolate at the Cacao Anasa kitchen. My friend Peter invited me to the third of these events since I’m in town for a conference. If it’s possible to have more fun in a kitchen, I’m not sure how. We made (and ate) truffles, cookies, chocolate bars, chocolate soup, and a bunch of chocolate-flavored drinks (spicy hot chocolate, and an assortment of stronger beverages).
Now that I’ve had freshly-made chocolate from my own hands, I’m sure I’ll be a lot more picky about what I buy. The CEO/owner of Cacao Anasa, Anthony Ferguson, gave us a great education on the making of chocolate (and some of the health benefits). Before today, I would never have known that chocolate is actually tempered, not unlike steel. His biography is even more impressive than the great chocolate.
Defending debuggers (sort of)
I came across this post about debuggers today. I found it a lot more nuanced than the Giles Bowkett post on the same topic. The part of the post I found the most useful was when he used the issue of problems in production to advocate for two practices I’m a big fan of: test-driven development and effective logging.
I’m responsible for an app that wasn’t developed using TDD and had no logging at all when I first inherited it. When there were problems in production, we endured all manner of suffering to determine the causes and fix them. Once we added some unit tests and implemented logging in key locations (global.asax and catch blocks primarily), the number of issues we had dropped off significantly. And when there were issues, the log helped us diagnose and resolve problems far more quickly.
The other benefit of effective logging is to customer service. Once I made the contents available to a business analyst, she could see in real-time what was happening with the application and provide help to users more quickly too.
Whether you add it on after the fact or design it in from the beginning, logging is a must-have for today’s applications.
What tests are really for
Buried deep in this Giles Bowkett post is the following gem:
"Tests are absolutely not for checking to see if things went wrong. They are for articulating what code should do, and proving that code does it."While it comes in the midst of an anti-debugger post (and an extended explanation of why comments on the post are closed), it is an excellent and concise statement of the purpose of unit tests. It explains perhaps better than anything else I've read the main reason unit tests (or specifications, as the author would call them) should be written before the code.
Quick fix for "Failed to enable constraints" error
If you use strongly-typed datasets in .NET, you’ve encountered the dreaded “Failed to enable constraints …” message. I most recently encountered it this morning, while unit testing some new code. There were far fewer search results for the phrase than I expected, so I’ll add my experience to the lot.
The XSD I’m working with has one table and one stored procedure with four parameters. A call of this stored procedure (via a method in a business logic class) returns a one-column one-row result set. My code threw a ConstraintException each time the result set value was zero (0). To eliminate this problem, I changed the value of AllowDBNull attribute of each column in the XSD table from False to True (if the value wasn’t True already). When I ran the unit tests again, they were successful.
I’ll have to research this further at some point, but I think part of the reason for ConstraintException being thrown in my case was the difference between the stored procedure’s result set columns and the table definition of the associated table adapter.
In any case, setting AllowDBNull to True is one way to eliminate that pesky error.
Multiple meanings of test-driven development
This Roy Osherove post surprised me because I hadn’t been aware of so many different interpretations of the idea before. Because I’ve always believed in at least some design up front, my understanding of TDD was the first of four mentioned:
"Test Driven Development: the idea of writing your code in a test first manner. You may already have an existing design in place."The fourth interpretation of TDD applies pretty well to what I do now whenever I inherit an application. Writing unit tests of the middle tier(s) of the application (if none exist) has proven to be very helpful whenever I've done this. Adding new features becomes easier, and regression testing becomes much easier.
Reactions to inherited code
This entertaining Phil Haack post on inherited code definitely tells the truth when it says:
"Here’s the dirty little secret about being a software developer. No matter how good the code you write is, it’s crap to another developer."Until I read this post, I hadn't even thought about the thousands of lines of code I've left behind at various employers and how my successors regarded them. I remember getting very positive feedback from a colleague who wrote the .NET replacement for my VB6/COM+/SQL Server 2000 implementation of our online recruitment tool, but that's it. My usual reaction to code I've inherited has rarely been empathetic. Phil's right in trying to be more understanding. And to anyone who has inherited my code in the past, I hope I didn't make your job too hard.
Between in T-SQL isn't truly inclusive for dates
I’d forgotten this when writing a stored procedure to provide access to log entries in a database table. This older post describes the problem, and two options for fixing it. I chose the version that uses the DATEADD() function call for my stored procedure.
Theory D or Theory P?
Earlier today, I came across this excellent post by Reginald Braithwaite on the management of software development. It does a great job of explaining many of the projects I’ve worked on in my career, whether they succeeded or not. Theory D clearly drove how I and various teammates ended up working. The post really helped me understand part of why the two years I spent managing projects was so difficult. I’m a Theory P guy at heart, and couldn’t pretend to be Theory D (much less actually believe it).
Braithwaite also writes a good follow up.
I really hate SQLDataSource
What I said about hating ObjectDataSource doesn’t count. SQLDataSource is worse. At least ObjectDataSource gives you error messages when it isn’t working. SQLDataSource appears not to work at all with stored procedures that have parameters. I found this forum thread that seemed to describe my problem. Unfortunately, none of the tactics suggested worked for me. I don’t even get error messages, just a screen with no GridView control in it. One of my colleagues looked at it and was just as stumped as I am.
Using an XSD, a couple lines of code, and an ObjectDataSource got me the result I needed with far less hassle.
Don't forget to Google prospective hires
One of my colleagues reminded me of that today. The developer we’re interviewing tomorrow was the #1 result from Google when I searched on his name, thanks to his blog. This works a lot better with uncommon names, of course.
My name (Scott Lawrence) is fairly common, so it’s only the #6 result on Google. The result is probably that high because one of last month’s blog posts referred to Scott Hanselman.
NCover goes corporate
I was on vacation when this happened, but NCover has become a product you pay for. The rationale for the change is a fair one, and I’m impressed by how Gnoso (the vendor of NCover) is looking out for people who donated to the project when it was free. NCover 1.58 remains free, but doesn’t have the same level of features as NCover 2.0 (or 2.0 Enterprise).
Gnoso has that product niche basically themselves since Cenqua, the vendor of Clover.NET, got bought by Atlassian in August. Since Atlassian is end-of-lifing Clover.NET, the coverage tool bundled with Team Foundation Server is the only option for .NET code coverage functionality. Given the choice between paying for functionality that used to be free and losing it altogether (as happened with NDoc), I’d fork over the dough in at least some cases. Whatever they intend to charge, odds are they won’t be Microsoft prices. It will be interesting to see how many other tools that are currently free make a similar transition.
Lessons from failure
It’s an older Reg Braithwaite post, but an excellent one. His four most important causes of failure are all painfully familiar. The paragraphs he writes on hiring practices and “development hygiene” are especially important. In an environment where the cheapest vendor wins, those two areas are the source of many problems.
The post does a very good job of pointing out how weak stakeholders can doom a project. There’s also a clear example of how office politics can play havoc with outcomes.
It’s a pretty long post, but very worthwhile reading.
Back from vacation
While I haven’t made much headway on my other four resolutions for 2007, I just accomplished the fifth one–a two-week vacation. From September 5-19, I visited Seattle, Vancouver (BC), and Portland. Two weeks was definitely the right amount of time to decompress from work and its typical concerns.
Of the three cities I visited, Vancouver impressed me the most. It’s the only city I’ve ever visited with a public transit system that can take you from the heart of downtown to the base of a mountain (Grouse Mountain). Stanley Park is a two-in-one attraction because it’s home to the Vancouver Aquarium too. Harbour Centre (in downtown Vancouver) has a Space Needle-like observation deck stuck on top of it that gives you a 360-degree view of the city. Vancouver was easily the most expensive of the three cities where I stayed. Some Canadians must be doing quite well financially, because there appeared to be an abundance of late-model Porsches on the streets.
Seattle was the first city I’d visited that had wi-fi on its public buses. It also proved to be as hilly as San Francisco. I got to enjoy plenty of great seafood there, though I didn’t see any flying fish at Pike Place Market. Seattle was also more of a college football town than I expected. There were fans everywhere in Washington State Cougars and Washington Huskies gear. There were also a lot of orange-shirted fans from Idaho (the Huskies opponent the weekend I was in Seattle). The most interesting thing about the Space Needle was the exhibit inside where you could view time lapse photos of Seattle over a 24-hour period taken from cameras mounted on top. The monorail was underwhelming, but I was quite entertained by the Experience Music Project and the Science Fiction Museum and Hall of Fame. People in Seattle have a great sense of humor.
The only really “touristy” things I did in Portland were check out Vista House and some of the waterfalls in the Columbia River Gorge. There’s a lot of forest and great hiking out there. The only thing missing was sunny weather (which Seattle and Vancouver had no shortage of).
One thing I wish I’d done in at least one of the cities was some cycling. Each one of them seemed quite bike friendly.
Now that I’ve spent a couple weeks in the Pacific Northwest, I can see why people are ditching California to move north.
I hate DTS
I’ve spent a good chunk of this week trying to revise some DTS packages to account for changes in how MapQuest provides access to data they’ve geocoded for us. Since I haven’t used it in years, I’d forgotten how much I dislike the user interface for it. It probably didn’t help that I was trying to edit this things with a plug-in you install for SQL Server 2005.
Trying to have separate development and test environments to avoid the horrors of doing development and testing in a production environment is quite a trial also. I think you can put settings in a configuration file, but it’s probably something like an INI file.
It’s probably just as well that DTS was replaced by SSIS. I did use that to do a bit of flat file validation for the same project and didn’t find it nearly as painful to use.