Thursday, July 31, 2008

Behind the scenes, I see a lot of companies run on Excel and duct tape. So it's common for clients to hand me a slab of data organized into neat little rows and columns. Excel is just a handy way to throw some data over the wall and get things done. This might be a list of dealers, a collection of user profiles, product information, or anything that just needs to get somewhere else.

Depending on the scenario, I'll might massage this data and slide it into a SQL Server database or an XML file. I'm a web developer so I use the ADO.Net stack on a regular basis. If I were a Windows client developer, I might prefer to solve this problem with the Excel object model, but that really looks like more code to me, so here's how I like to roll:

The following code block accepts an Excel file path and returns an ordinary DataTable object, which can be manipulated easily by the code that calls this method. The first row of the Excel document becomes the columns in the DataTable object and each row thereafter are DataRow objects.

ImportDataFromExcel
(Click to enlarge)

If you like, take a look at both techniques for working with Excel data and see what one speaks to you. With this block of code, I can happily accept large chunks of data from a client without spending precious time fiddling with administrivia.

Thursday, July 31, 2008 8:00:16 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, February 04, 2008

...or two.

I've had two projects this week where their/my bacon was saved by the branching strategy used for the source code repository. In my line of work, I touch a wide variety of projects. Some are still shiny new and others were written years ago; they're all in a source control repository.

Modern source control repositories (and by modern, I mean things that are not your file server or P:\ drive) let you create a branch. Branching might appear complex at first, but it's really pretty simple - at least conceptually. Here's a little story to illustrate the point of branches.

When I create a branch, I have a snapshot of the code at a particular point in time. So, imagine that on Monday, I have a single branch called the "trunk". It contains all of the code for my web site. On Tuesday, I created a branch based on the code in the trunk. I named my branch "BR-1". When I created BR-1, it was a mirror image of the trunk. I edited the code in BR-1 for a couple of days and nearly got it how I wanted it. My edits were isolated to BR-1 and they did not exist in the trunk.

I got a call early on Friday morning about an important change that needed to go out right away. I couldn't implement the urgent change to BR-1 because it contained my partially completed work. It was a pretty small change; a few hours of brilliant coding and I would be ready for a peer review of my changes. So, I checked out the trunk and made the edit right there and checked it back in. I published the urgent change I made on the trunk out to the live web site in the early afternoon and went back to working on BR-1.

By mid-day on the following Monday, I had finished all of my changes to the BR-1 branch. I had merged the BR-1 code into the trunk too. Now my trunk code contained the changes from BR-1 as well as that urgent change that came through on Friday morning. Complete control with the flick of a switch.

In the previous story, I was able to handle the urgent request efficiently because I used branching to manage my code changes. If I didn't have branching available as a software development tool, I would have some bad choices to make. Either I merge the urgent fix with my own enhancements and risk problems by rushing it, or force the urgent change to wait until my own changes were done; neither are necessary.

Branching is great way to ensure that I can always put my work on the shelf in lieu of more pressing matters. Understanding the concepts of branching is essential to being a valuable member of the team. The keys you actually press to make a branch or merge two branches can be left up to the nerdy folk. For more info, check out Pragmatic Version Control Using Subversion.

Monday, February 04, 2008 10:28:37 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Saturday, November 10, 2007

In my experiences as a software developer, its fairly normal to hear comments like the following:

  • That's too many hours
  • They don't have the budget
  • I'm not paid enough

I had the good fortune of attending a Portland XP Users Group presentation a few weeks ago by James Shore. He got off on a slight tangent and gave us (well, at least me) a simple equation to chew on:

roi

He explained that at its core, Return On Investment is represented by the previous equation. It can help explain quite a bit about the world. This was in response to someone asking about the high cost of the software development methodology under discussion that night.

If you're presented with a scenario where the value is constant, then the only way to play the game is to minimize costs. Think of a job that never changes. If it always provides the same value to a business, management will seek ways to reduce cost in order to improve the ROI equation.

On the other hand, a scenario where value has the capability for growth is much more interesting. If you wanted to make $500,000 a year then you would be challenged to deliver some multiple of that cost as a value to the business.

Here's my favorite take-away: At some point along the graph, as value increases then cost becomes insignificant. This is the place to be.

The initial cost of software can make some people squeamish. I'm certainly not one to be afraid of zeros; I'm much more interested in the value.

  • What is this solution doing for the business?
  • Is there a practice in place for tracking ROI over time?
  • How soon can it begin providing value?
  • Can it provide even more value?
  • It is possible to reduce cost and drive the equation even higher?

This is why I love my job at Pop Art. Driving value higher and then swooping back to cut costs with new technology that makes me more productive. Value will often come in several forms including cash value, brand value and community value. In any case, it all starts with that equation.

Saturday, November 10, 2007 6:11:25 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, November 05, 2007

By some cruel trick of nature, I've been surrounded by web content management systems for the past several years. I've written several (who hasn't?) and stood up instances of DotNetNuke, Windows SharePoint 2007, and now Interwoven TeamSite.

I'm told Interwoven has been around for 14 years and they're currently on version 6.7.1 of their TeamSite product. This offering includes features for enterprise content management (ECM) and the assorted adjacent technologies that simply must accompany ECM in a large scale deployment. Since the beginning, their product has included version control and workflow features. I'll describe a few core parts of Interwoven TeamSite here.

Source Control Repository

First off, developers will get a quick leg up if they simply know that TeamSite includes a source control repository. It works like any other. You can get the latest source, edit something, check it back in, compare versions, label a snapshot of the repository as well as branching. There. You're farther ahead than I was when I got my first explanation, about two years ago.

Standards based developers can relish in the fact that they have carte blanche control over the HTML and CSS sent down the wire to the browser. I'm talking about the production site here, not the administration pages used to interact with TeamSite. Nearly everything you'll do with TeamSite is done through a browser, providing that browser is IE or Firefox. Sorry Safari, this car is just a two seater. Again, browser support for the production site you're building is up to you - just talking about the TeamSite administration pages here. You'll continue editing specific files in your favorite tool, such as Visual Studio, Photoshop or TextMate. So once you get the subtle nuances of this source control system in you're brain, the challenge is to build a compelling web site using the same tools you have now; no silver bullets here.

Its also worth noting that this is only a source control repository; not a web development platform. You'll still need IIS, Apache, or some other web server technology to host your site. Interwoven TeamSite is mature enough that it supports Windows, Unix and Linux environments and several popular databases such as SQL Server and Oracle; just what you'd expect from an enterprise content management system.

FormsPublisher

Interwoven's TeamSite product includes a feature called FormsPublisher. This is useful for scenarios where an information worker needs to contribute to the web site, but lack HTML and CSS skills. This type of user can complete a form, let the system validate it, and then press a button to have the system generate the equivalent HTML page. The form can include validation, business logic, database queries or anything else you can dream up. While an HTML expert would prefer their favorite text editor and complete control to the HTML page. An information worker without HTML skills can now edit an existing page, based on an customized form. Now the challenge shifts to having the information worker select the appropriate form to build the page.

A developer configures a set of files and folders to support this process. At a high level, there are three parts in motion. The Data Capture Template (DCT) is an XML file that describes how TeamSite should present the form to the information worker. A Data Content Record (DCR) is an XML file that contains an instance of a form completed by an information worker. You launch TeamSite, click File, New Form Entry and select the form you want to complete. Next, the given form appears in the browser. The fields of the form are defined by the DCT. After you click the Save button, the field values are serialized into a DCR file. These files are organized in a collection of folders on the TeamSite server; one folder per form. Each folder has a conventional set of child folders to hold the DCR files as well as the presentation template file(s), These are the files with the .tpl file extension.

A presentation template converts a DCR into something else. Most of the time, at least for me, that something else will be an HTML page. Imagine a single DCR file that contains both public and private information for a company; perhaps the DCR contains public information about a single product as well as private information for their tech support staff. The DCR file can be send around via workflow for approval and the finally be ran through both sets of presentation templates which results in two different HTML files - one file is deployed to the public and the other file is kept on the Intranet. Both files are assured of having the appropriate content via the approval process and the presentation templates apply the correct branding and layout. This model supports a good workflow model as well as good separation of design from content. Its just one example of using the FormsPublisher in the enterprise.

Since DCR files are just XML, it's relatively painless to import legacy data into TeamSite. These imported XML files map to a given DCT, then they're translated into HTML pages via a presentation template. For example, if you have the last 15 years of press releases on the legacy system, you can import the existing information with some batch processes and stand up a new TeamSite server pretty quick.

Workflow

A workflow describes an automated business process. It can instruct an author to perform an edit or add a new file to the site and manage the process of approvals, taking a snapshot of the system for archival purposes and finally deployment. When a task such as "Edit Content" or "Review Content" becomes active, an e-mail can notify the appropriate party. When the work is completed, the assigned person just pushes it through the hole. Reviewers can click "Accept" or "Reject" after previewing the changes, they don't need to know the next appropriate step in the process - its automated. The system tracks the state and flow of information of the activities throughout the lifecycle according to the established business rules approved by the given company rather than based on how the given employee feels that particular day.

TeamSite has always included a workflow mechanism, but I can only imagine how difficult it was to develop them in the past. This latest version includes a Windows client application that supports drag-and-drop editing of workflow designs. You can work locally with workflows saved to your desktop in an offline mode, but you will eventually need to save the workflow up to the TeamSite server via commands in the tool. Workflows are serialized into XML files in the background, but its rare to look at the raw information. The workflow designer application helps you do the things you would expect such as setting up a series of tasks linked by arrows; some might be conditional based on human interaction or automated entirely by Perl scripts, Java classes or some other business logic.

Its interesting that Interwoven prides itself on a large number of supported platforms for the server product, but the Workflow designer client requires the Windows operating system. As I understand it, some (or all) of the workflow client application was recently purchased from another company. My hunch is the client application is written in C++ based on the look and feel as well as the OS requirement. Its a little clunky but it gets the job done; I sure wouldn't want to hand code all of the XML it generates.

Conclusion

Overall, I'm happy with my experiences thus far with TeamSite. The documentation is rich, it has a thriving online developer community, and the paradigm isn't too hard to grasp. At one point, I started getting bogged down with the massive about of XML configuration files and customization points. After sleeping on it (and a stiff cup-o-coffee) I realized that any other enterprise level application has a similar amount of customization. Since TeamSite embraces a litany of platforms, it makes sense that they don't (or haven't) invested a lot in slick little Windows GUI programs for configuration needs. Why build a server GUI tools when Windows is only one of your supported OS platforms? On the other hand, they could build a few more web based administration forms to get around some of these XML file updates. Once I started tallying up how many configuration pages I go through for Windows SharePoint, I stopped feeling like I was building my own box and installing Linux and started thinking about the broader ideas and why I was configuring the system instead of how - perhaps it just semantics, but I felt better.

Monday, November 05, 2007 10:29:32 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, September 26, 2007

I just got a new Dell Latitude D830 laptop running Vista Ultimate and I'm going about the lengthy process of installing all my software. When I got to PowerShell, I grabbed a copy of the installation file from my 250GB external drive that I had previously downloaded for my previous laptop, a Dell Latitude D610, running Windows XP SP2.

When I ran the install program, I was repeated met with the following error message:

Not enough storage is available to process this command.

A lot of other people had the same problem, but no one had posted a solution. Then, I suspect I figured out the answer the same way others had. I was executing WindowsXP-KB926139-x86-ENU.exe instead of Windows6.0-KB928439-x86.msu, I had overlooked the fact that Windows XP and Vista had different installation programs for PowerShell.

Drat.

Wednesday, September 26, 2007 2:37:14 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, July 24, 2007

I've been battling some crazy ASP.NET 1.1 code the past couple of days. First, I was calling some web services with entirely hand written SOAP protocol management. That's always fun. While tedious and too low of a level to be mucking around, it was the fastest means to an end with a crotchity ol' Apache/AXIS web service. Even though I'm fresh off the WCF training regimen; that new stuff wouldn't have helped me here. Perhaps just having the new stuff in my head pushed me in the right direction to tackle this challenge - a man can dream, can't he?

Then, just to rub it in a little, the HTTPWebRequest object decided to give me a swift kick in the shorts. You see, in .Net 1.1, there's a tiny little unknown (unanswered) bug.

I have two instance methods and each make a single call over HTTP with their own HTTPWebRequest object, there's no sharing here. Every time, the second request would hang and throw a "System.Net.WebException : The operation has timed-out." error. The same code runs great in .Net 2.0 so I figure its a framework bug.

I call one method and return a string which is used as an input argument for the second method. Both calls go to the same top level domain, but call to different end points on the domain.

After much thought, trial and error, as well as reading about the same problem other folks were having, I finally figured out the workaround.

It turns out that calling the Abort() method on the HTTPRequest instance after completing the request is sufficient to break up the clog that is preventing subsequent calls. The following code block shows the working helper method. If I comment out the calll to Abort(), it no worky.

private string ExecuteHttpWebRequest(
   string url, RequestMethod method, string message)
{
   HttpWebRequest request = 
      (HttpWebRequest)HttpWebRequest.Create(url);

   request.Timeout = 30000;
   request.KeepAlive = false;
   request.Headers.Add("Cache-Control", "no-cache");
   request.Headers.Add("Pragma", "no-cache");

   switch( method )
   {
      case RequestMethod.Get :

         request.Method = "GET";

         break;

      case RequestMethod.Post :
         
         request.ContentType 
            = "application/x-www-form-urlencoded";
         request.Method = "POST";
         request.ContentLength = message.Length;

         StreamWriter sw = 
            new StreamWriter(request.GetRequestStream());
         sw.Write(message);
         sw.Flush();

         break;
   }

   string html = null;

   using( HttpWebResponse response 
      = (HttpWebResponse)request.GetResponse() )
   {
      Stream rs = response.GetResponseStream();
      StreamReader sr = new StreamReader(rs);
      html = sr.ReadToEnd();
      response.Close();

      // subsequent calls fail without this abort in .Net v1.1
      request.Abort();
   }

   return html;
}	
Tuesday, July 24, 2007 9:27:37 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, July 18, 2007

I've been using Google Reader for a while now and I love it. Its very quick to launch with my SlickRun shortcut of "gr" and it manages my current list of 96 RSS subscriptions very well.

In fact, I recently figured out that this application is perhaps one of the worst web applications to use with the mouse. The mouse is such an impediment to reading several posts efficiently. I launch Google Reader several times a day and its common for me to have nearly 50 unread posts from over 30 RSS subscriptions at any given perusal session.

Here are the Google Reader keyboard shortcuts I use on a regular basis.

  1. Click the "Show Updated" hyperlink in the left column to show only the RSS subscriptions with unread posts
  2. Click the first RSS subscription link of the list in the left column (getting in the mood)
  3. Click the first unread post of the list if the right column (tee it up)
  4. Press space bar to traverse multi-page posts and advance to the next unread post for a given RSS subscription
  5. When all the posts are read for a given RSS subscription, press Shift+N to advance the highlight to the next RSS subscription of the list in the left column
  6. Press Shift+O (this is my Oh face) to open the list of the new highlighted RSS subscription
  7. Press the space bar to traverse this new feed like the previous RSS subscription

 

 googlereader

To Summarize:

Space Bar Scroll through a long post, then skip to next post when the last line of current post is visible
Shift + N Highlight the next RSS subscription in the left column
Shift + O Open the list of posts for the highlighted RSS subscription

 There are a bunch of other keyboard shortcuts for Google Reader. These are the ones I use the most.

Wednesday, July 18, 2007 8:57:20 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Sunday, April 29, 2007

Google Reader I used SharpReader for a long time, then briefly used the RSS Reader in Outlook 2007, after an even briefer stint with IE7's RSS reader client (ack!). I don't categorize myself as superstitious, but was else do you call it when you suspect all those posts and media downloads in Outlook 2007 are slowing down your system and you have no real data to back it up?

I liked the Outlook 2007 reader because I was horrible at opening SharpReader on my laptop. I always had Outlook open. It took a while to launch SharpReader, but it was a great application. Then, I'd open SharpReader on a weekend and be horrified by (a) the number of posts that I was behind, and (2) the amount of information that I could have used during the previous week. I'm always looking to get my compile time down, so right or wrong, I'd close applications left and right to give my Dell Latitude D610 as much horsepower as it can wield during the week.

My buddy, Scott, turned me on to Google Reader. As a big time RSS fan boy and an even bigger nerd than I, his opinion is to be respected.

So this weekend, I imported my OPML file into Google's RSS Reader and away I go. So far, I'm pretty impressed. There's a few things I'd like to do, such as return certain posts to "unread" status as I want to come back to them later and rename some folders, but all in all, I likey.

Now, I can open my RSS reader without the cycles of a big application. ( type my new magic word, "gr", in SlickRun and launch my reader anytime I like. Booya!

Sunday, April 29, 2007 9:23:55 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, February 15, 2007

I attended the Software Association of Oregon (SAO) event today. The Development Special Interest Group (DEV SIG) hosted a discussion about Microsoft CardSpace, the open source framework of OpenID, and basic identity management.

Stuart Celarier walked the audience through Kim Cameron's paper called The Laws of Identity that articulate seven desired aspects of a good identity system.

Microsoft CardSpace was formerly named "InfoCard". This is a joint effort to implement the identity metasystem defined by the laws of identity. CardSpace is the "identity selector" for Windows. It needs IE7 and Microsoft .Net Framework 3.0 to operate. It implements the WS-* specifications in this service.

OSIS - Open Source Identity System: This is an open source group that's involved in the identity space.

Stuart also showed a demo of a system he's been working on. It logs a user into Wachovia banking site using CardSpace.  Scott Kveton of JANRAIN presented OpenID to the SAO DEV SIG group. OpenID hopes to solve the problem of having too many usernames and passwords.

  • Single Signon for the web
  • Simple, light-weight
  • Easy to use, easy to deploy
  • Open development process
  • Decentralized

Your OpenID is a URL: http://kveton.myopenid.com/

  • OpenID comes from the blogosphere
  • Biggest problem with identity; namespace
  • OpenID solves this by using DNS
  • Your identity is a destination
  • You have a unique endpoint on the web

Scott Kveton explained how sites enabled with OpenID enable users to authenticate. Visitors type in their OpenID, and the browser redirects to your OpenID provider. The visitor makes the appropriate decision and the browser redirects back the website.

Scott's site is http://scott.kveton.com

Last week Bill Gates announced support for OpenID. AOL announced support for OpenID this morning. More companies are about to make similar announcments. Here's some interesting stats on adoption:

  • 12-15 million users with OpenIDs.
  • 1000+ OpenID enabled sites
  • 10-15 new OpenID enabled sites each day
  • 7% grown each week with new sites

Kveton also brought up "Microformats" - a way to describe data in an HTML format (contact info, social network, calendar). These can be embedded on pages. There are some interesting ways to use OpenID with these technologies:

  • OpenID + iCal
  • OpenID + hCards
  • OpenID + Social Networking (XFN, FOAP or FOAF?)
  • OpenId + Reputation (jyte.com)

OpenID Predictions from Kveton:

  • 7500 sites supporting OpenID
  • 100 million users with OpenID
  • Big players adopt OpenID

OpenID.net has a ton of info.

Scott Hanselman explained how he enabled OpenID on his blog. Hte added two HTML <link> tags to his website. Simon Willison has an OpenID enabled blog. A visitor can click Sign in with OpenID. The OpenID logo lives inside the textbox. Scott entered his OpenID in the textbox on Simon's site. Using a web service, Simon's blog discovered Hanselman's OpenID provider, then it redirected the browser to Scott's OpenID provider.

Scott's website indicates the OpenID provider is www.myopenid.com

The OpenID provider prompts Scott to authenticate. After a successful login, the browser redirects back to Simon's page and recogizes Scott Hanselman. This is how Simon doesn't need to keep track of usernames and passwords for his blog; a huge benefit.

Stuart helped explain the difference between self-insued cards and managed cards: Business Cards from Kinko's versus a card issued from Visa.

Scott Hanselman displayed a different identity selector using Firefox on Windows. The page contains an HTML <object> tag of type "application/x-informationCard". It wasn't as pretty as the CardSpace in IE7 and .Net 3.0, but it had the same behavior.

There was some last minute discusson on "I-Name", an XRI technology (extensible resource identifier). It sounds like its still being baked.

2idi relays comments on Scott's blog. They will issue an I-Name. =kveton is Scott's I-Name. They have an DNS resolver where visitors may enter xri://=scott.hanselman/photo to redirect to his Flickr account.

Thursday, February 15, 2007 4:47:54 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Sunday, January 14, 2007

I had a need for a client services teammate to get their hands dirty with some XML. In this project, an XML file defines the hierarchy of pages in a web site. With a massive redesign under way, the team needed someone with familiarity of the existing pages to make the changes. With the hopes of giving my non-developer teammate a slick application to help them rearrange some angle brackets, I took a look at Xml Notepad 2007 and WCMHelp's XmlPad.

Xml Notepad 2007

The bits can be downloaded here and this document a nice explanation of the author's intent.

Xml Notepad 2007

The left window shows the tree. The red dots are attributes and the folder icons are elements. The right window shows the values of the attributes. There's an XSL tab for viewing transformations. You can point the application at an XSLT file and see the output too.

The part I like the best about this is application is its simplicity. I need my teammate to look at each node and make a determination. They might need to move it anywhere in the hierarchy. There are four buttons on the right side of the toolbar expressly for this purpose. If they feel a little more ambitious, they can click and drag the node to the new location in the left window.

WMHelp XMLPad 3

You can get the bits here. This application feels a little more powerful than the first application. It can create schemas and validate against them in a more flexible manner than XML Notepad.

WMHelp XMLPad

The attribute names and values appear in the lower left window of this application. There are different views of the XML available too. The picture above shows the source view. There are three other views (Grid, Table and Preview) in the bottom of the right window.

This application doesn't show the simple set of buttons in the toolbar for moving nodes, although they can be dragged around in the tree. I find that dragging can be a little unpredictable with a large node set. With all the on-the-spot decision making going on, I felt that the simple XML Notepad program was better suited for the specific task and user. However, if I'm the one doing XML work, I would probably choose XMLPad if VS.Net 2005 didn't do the trick for some reason.

At some point, I'd like to checkout XMLSpy. I've heard great things about it for years. I chose to examine these two because they were free and this was a one time gig. If I end up doing lots of work with my angle bracket hammer, then I probably will put in a request for the XMLSpy license.

Sunday, January 14, 2007 8:47:19 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [1]  | 
 Monday, November 27, 2006

I saw this post on Jeff Atwood's blog about a new tool from SlickEdit, the makers of SlickRun; easily the most frequently used program on my laptop day-in and day-out.

The Command Spy
Whenever you click on a menu item or toolbar button in Visual Studio, you are executing what is known as a "command". Unfortunately, it's almost impossible to tell what command is linked to which menu items or toolbar buttons. The Command Spy monitors command execution and allows you to see exactly what commands you've run, how many times you've run them and what key bindings are used to invoke those commands. The main purpose of this tool is to allow you to learn what commands are bound to which keystrokes, so that you can work faster within the IDE.

I installed Command Spy over the Thanksgiving holiday. It totally rocks! Just run the VS.Net add-in while you're coding for a couple of hours and then take a look at your metrics. Command Spy will tell you how many times you've run a command without using the short-cut keystrokes. Its a great way to improve on your productivity.

Monday, November 27, 2006 10:48:29 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [2]  | 

I started using the RSS reader in Microsoft Outlook 2007.

I was using SharpReader for as long as I've ever had an RSS reader and subscribed to feeds. I really like having just one application running for my communications and work items (email, tasks, calendar, RSS feeds...). Its super easy to add a feed when you're visiting a web page too. I used folders quite a bit in SharpReader to categorize feeds, but I'm trying the "one big folder" approach for now in Outlook.

Sometimes, I got lazy and didn't open SharpReader on my laptop for a while. The posts would get way out of control. Sure, I could add it to my Start Up programs, but one of my quirks is to keep that list short, if not empty. Some weeks I even tell SQL Server to not startup automatically. Perhaps that's one of the old carry overs from living too long with too little RAM on a weak laptop.

Outlook 2007 as an RSS reader is nice, but I miss some of the basics, like identifying the URL to a blog I've already subscribed to. There's probably a way to display that information easily in Outlook, but I haven't discovered it yet.

To date, the most frustrating thing has been refreshing feeds. It gets joined at the hip with my email send/receive request. So, when someone comes by my desk in a general freak-out mode and asks how to solve a problem raised in a recent e-mail, I click on Send/Receive if I haven't gotten it yet. Now, thanks to the additional RSS feeds, I have to wait much longer as everything is updated. There must be a way to decouple these requests from each other in Outlook.

Overall, I'm very happy with the switch so far.

Monday, November 27, 2006 10:39:22 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [2]  | 
 Friday, October 06, 2006

 One of our Pop-Art-Gives-Back-To-The-Community clients wants to implement some simple online donation services on their website. So, I was flipping through a PDF file from PayPal using my Foxit Reader and I noticed this little phrase at the top of a page:

They're giving me complementary technical documenation! No orange juice or bagel, but the doc is categorized and complete.

I saw another funny part on the PayPal site. The link to the PDF file says it requires (my emphasis) Adobe Acrobat to read it. Ha! I must be flaunting the rules with my Foxit reader; breaking the law! breaking the law!

By the way, I've had great experiences with Foxit up until yesterday. One of our black turtleneck shirt wearing designers created a PDF version of a client proposal. When I opened it in Foxit, some large background images flashed for a second, then the text content appeared without much styling. Each page behaved this way. When I opened it in Adobe Acrobat, the full beautiful proposal displayed great with background and content. Huh. I'm not sure if the designer was leveraging some custom Adobe feature or if Foxit was the culprit; it was the first and only time I didn't get parity though.

Friday, October 06, 2006 10:34:40 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Saturday, September 30, 2006
My first Windows Live Writer.
Saturday, September 30, 2006 10:08:49 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, September 27, 2006

The other day I fired up TortoiseSVN and it politely informed me that I might enjoy the latest release.

Hurrah!

Wednesday, September 27, 2006 10:54:52 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, September 13, 2006
Forced upgrades on the day of the new iTunes launch.
Wednesday, September 13, 2006 6:55:02 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, August 30, 2006
Image files don't have manifests.
Wednesday, August 30, 2006 8:46:09 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, August 10, 2006

I had a fairly minor change to some code today that modified the display order of some reports implemented as unique web user controls that are loaded dynamically based on which items you select.

I wrote out my plan and before editing any code, then I asked my co-worker, Kelly, to review it and see if it held water.

Turns out, I sprung a leak. It was such a simple mistake. The code I inherited used the Session object to store a value and my flawed plan slightly modified the values in the existing Session object. My plan assumed the web user controls executed serially, when in fact, I could not guarantee that level of access to the data in the Session object.

Sans code review, I would have gone ahead and modified the code, tested it, and (hopefully) seen the error of my ways before handing it off for final review before deployment. It would have ran without throwing an error, but not correctly. The peer review saved a significant amount of time, relative to the overall time spent on the task.

Peer reviews rock. Do them early and often!

Thursday, August 10, 2006 2:57:45 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, August 08, 2006
How to fix errors with dynamically loaded web user controls in asp.net that throw an invalidcastexception.
Tuesday, August 08, 2006 12:42:00 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, July 24, 2006
Atlas ridden!
Monday, July 24, 2006 7:33:16 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
Back to basics with Subversion
Monday, July 24, 2006 7:18:21 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Sunday, July 23, 2006
A refresher in use case modeling.
Sunday, July 23, 2006 9:38:46 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Saturday, July 22, 2006
A lecture on refactoring .Net code.
Saturday, July 22, 2006 12:39:34 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, July 14, 2006
Using the AnkhSVN add-in for VS.Net
Friday, July 14, 2006 10:20:56 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, July 12, 2006
Fiddler is a nice HTTP monitoring utility to inspect traffic between your browser and a web server.
Wednesday, July 12, 2006 1:18:57 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, June 08, 2006
Getty Up!

7/1/2006 - Partial Retraction: Ok, so after testing this on IIS (I was using Cassini when I learned about it) its a little less cool than I originally thought. You still need to add the file extension to the list in IIS so it knows which program is handling requests for the given file type. That's a little less cool. Stinky for sites where you only have FTP access and not direct control of IIS. The concept worked with Cassini because its all about .Net, all files seem to go up through the .Net handler. It looked a little funny running trace.axd and seeing requests for image files register in the trace utility. I guess that should have been my first clue.

I unearthed a real gem today. Our web standards movement has made our CSS files much more sophisticated. We're reaping the benefits of simple XHTML markup, flexible designs and everything else the web standards movement is enamored about.

There's always been this nagging problem of relative paths to image files in the CSS, javascript files or anything else that isn't really executed on the server before its rendered to the browser. The problem comes in when a web site is developed locally, which means it has an application name in its path. When the site is migrated to the staging or production server, the application name is gone. The following URLs point to the same file, depending on which environment you're working in:

Local Development Environment:
"http://localhost:1978/web/images/gobbler.png"

Staging or Production Environment:
"http://www.company.com/images/gobbler.png"

These can be referred to as "absolute" paths. Note, everthing before the forward slash in front of "images" will depend on the environment.

So here in lies the rub:

The CSS file(s) will often contain references to background images. They can reference the images using a relative path. Relative paths use the double period ("..") syntax to reference the parent folder and thus identify the path "relative" to the current location:

"../../images/gobbler.png"

That can be referred to as a "relative" path.

The problem comes in when two web pages use the same CSS file(s) and they're in different folders. Suppose one page is in the root folder of the web site and the other page is three folders down from the root. They would have to use different "relative" paths to reach the same file, right?

ASP.Net 2.0 to the rescue!

Now, we could always just write an .aspx file that contains the normal CSS content and embed server side code that conditionally renders the application name before all file references to make them "absolute" paths.

The issue with this approach is that your web page uses the <link> tag to reference the .aspx page like this:

<link rel="stylesheet" type="text/css" href="/css/print.aspx" />

I've been told that some browsers won't treat this reference exactly the same as one with a .css extension, so they always download the file instead of caching it. I don't know this to be exactly true, but this gem I describe below solves that problem, so everyone is happy.

Here's how ASP.Net 2.0 can be configured to use server side code inside .css files and dynamically insert the application name:

  1. Open web.config in a text editor
    1. Add an entry to <buildProviders> that tells ASP.Net which build provider to use:
      <system.web>
         <compilation debug="false">
            <buildProviders>
               <add type="System.Web.Compilation.PageBuildProvider" extension=".css" />
             </buildProviders>
         </compilation>
      </system.web>
      

    2. Add an entry to <httpHandlers> that tells ASP.Net which factory to use:
      <httpHandlers>
         <add type="System.Web.UI.PageHandlerFactory" validate="true" path="*.css" verb="GET" />
      </httpHandlers>
      

  2. Open you CSS files in a text editor
    1. In the first line of each CSS file, set the content type:
      <%@ ContentType="text/css" %>
      

    2. Add the application path before each file reference in the CSS file
      background-image:url<%= Request.ApplicationPath %>/images/gobbler.png");
      

Now you can easily move from your development environment to your staging environment without fear of breaking your image paths. Files in various levels of the directory structure can use the same reference because everything has a path that begins at the root. No more ".." syntax headaches. I love it!

Thursday, June 08, 2006 4:41:25 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, May 01, 2006

I've been meaning to learn more about the VS.Net 2005 details, so after a nicely grilled steak and a glass of wine, I set myself down to read the MSDN library on the topic of Code Snippets.

Code Snippets are one of the great new features in VS.Net 2005. They provide a method for a programmer to quickly insert snippets of code by typing just a few keystrokes.

An examination of the code over the course of several projects will reveal a set of patterns: classes, properties, event handlers, constructors and methods. Just a few characters vary in these patterns.

private int _name;

public int Name
{
   get { return _name; }
   set { _name = value; }
}

The preceding lines of code provide an example of the pattern inherent in a property. The values "_name" and "Name" represent the private and public values accessible to the class. Code Snippets allow you to produce this code with a minimal amount of keystrokes.

To produce the property show above:

Move your cursor to an appropriate position the class
Press Control+K, Control+X to bring up the Code Snippets Intellisense Context Menu
Type "prop" and press the Tab key

This will result in the following code:

The cursor starts at the first green section, which defaults to the integer data type. Entering the new data type will overwrite the characters "int". After the actual datatype is entered, pressing the Tab key will advance the cursor to the next green section, which defaults to "myVar". Entering the actual value here will overwrite the characters on line 19, line 23 and line 24 simultaneously. This is where you should see the value of code snippets. While C# is slightly more cryptic than VB.Net, there is still a great deal of value to be gained by using a tool like Code Snippets.

There are similar snippets for classes, interfaces and many other patterns. There are over 50 snippets by default. Custom snippets can also be created.

Anywhere a pattern exists in code, a solid case can be made for using Code Snippets. Imagine a class that has over 20 properties. The economy of scale becomes obvious.

Code Snippets are great, but its just the start. 3rd party vendors like Developer Express have built great tools like CodeRush, which represent the next level up in productivity. If you have a great deal of code that could be automatically generated, tools like CodeSmith represent the 3rd level. If you stand to gain a huge advantage from code generation, you can author your own code generator using Microsoft.Net classes. That's right; code that writes code. I just blew your mind.

Monday, May 01, 2006 8:02:51 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, April 12, 2006

I've occassionally sent email to the wrong address. Its to the right person, just the wrong account. When I open Outlook and create a new email message, the handy autocomplete feature lets me type just a few letters of the person's name and it shows me the matching entries. If I don't look really close, I sometimes send email to Dave's personal account, instead of his business account. That sucks, especially when its important, and he doesn't see it for a while.

Google to the rescue.

A quick Googling, and I had the answer to my problem in about 30 seconds.

http://www.feld.com/blog/archives/2005/09/clearing_your_m.html

I figured out how to clear my autocomplete cache in Outlook. I rarely send email to Dave's personal account, so now I can start fresh!

Yay.

Wednesday, April 12, 2006 1:29:43 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, April 10, 2006

Over the weekend, I was playing in a sandbox, working out some ideas for our client, PICA.

I was really impressed with all of the out-of-the-box functionality available in ASP.Net 2.0, specifically these:

  • Personalization
  • Membership
  • Menu Control
  • Security Trimming
  • Two Way Data Binding

I was able to build a full app, albeit wanting of some CSS love, in about four hours time.

The site shows a few pages of content. It lists some events that were created in a password protected part of the site. The events can be added to a cart and "bought" by a user by clicking a dynamic link to PayPal. The user's cart is persisted via cookies if they come back later. The user's cart is also migrated to a persistant data source if they decide to authenticate. The menu of the site uses the asp.net menu control and it has a nice "Security Trimming" feature that omits any items in the site map that the given user doesn't have access to view.

These features really let me focus on the core business problem, rather than getting bogged down by plumbing and implementation details. The number of new features in ASP.Net 2.0 is huge and a little overwhelming, but I'm starting to wrap my arms around it, after months of reading. I really dig it.

 

Monday, April 10, 2006 2:15:14 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Saturday, March 11, 2006
Fun with XSD Schema on a Saturday night. Wahoo!!
Saturday, March 11, 2006 11:43:14 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, March 10, 2006
The .Net programmers on my team were debating the concepts of how a generic class is better than an object array.
Friday, March 10, 2006 2:34:29 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, March 08, 2006
Software licensing benefits through Microsoft Certified Partner program and Action Pack program.
Wednesday, March 08, 2006 2:10:03 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, March 03, 2006

A project manager came to me this week and asked for a new web page on an existing site. No problem. Then she said this enterprise client is very interested in ROI for this page. How can the client track hits on this page and activity within the page? Well, they have software for log file parsing, but its not easily availlable to the client. So, I fired up Visual Studio.Net and built some software that writes the unique combinations of referring URLs and the date to an XML file. If two people come from the same referring URL on the same date, the counter of the element is incremented. If its the same referring URL, but the date is different, a new element is inserted into the XML file and the counter is set to one. I wrote the software for this mini-tracking service and passed it off to another developer for the actual build. 

This solution allows the client to capture the desired data and periodically recieve reports on the traffic to this specific page. I spent about 30 minutes writing 67 lines of C# code (including blank lines for readability). The Microsoft .Net Framework provided a very simple method for me to manipulate an XML file on disk, and increment counters based on the activities on the URL.

A few days ago, we had another rush order for a different client. The task was to create a simple form that enabled visitors to submit a varying number of email addresses to a central repository. The new ASP.Net Wizard control was perfect for this. It handled all of the state control and provided the Previous and Next buttons for me. I supplied the interface on each wizard step along with the logic for validation and data persistence. It was an easy way to plug in the logic that was unique to my application, but let .Net handle the common tasks of paging between steps and notifying the business logic of when it should ask for data validation or when its time to save the data. Glorious.

With the new presentation layer developer on staff, I was able to stick to what I do best, writing software, and hand off this application to the specialist who made it look just right in my browser. Its fantastic when you can leverage what people and frameworks do best; then you can focus on what you do best. It really helps you be curious about the other specialists skills instead of being wildly dependent on doing a sufficient job in those niche areas yourself. Its like having won the entire game in darts by surpassing 18 points and still having one more game of Cricket to play to complete the match. Its interesting, but not dangerous.

2006 is going to be a great year.

Friday, March 03, 2006 1:13:32 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, March 01, 2006


I did some research for my boss last week on the new Office 12 and the Exchange 12 products due out in Q4 of 2006. They look pretty good. There's a ton of information out there: blogs, sites, events and workshops. Everyone uses Microsoft Word, Excel, and PowerPoint. Email has been a mission critical service since the mid-to-late 90's. The Exchange 12 Server has been moved to x64 based architecture to increase reliability. They're not even bothering with lessor systems. I've been attending workshops regularly with my team on the new SharePoint tools and Workflow. Based on my research documented on our Wiki, it looks like we're targeting a deployment of Q1 2007. Its going to be a good year.

 

Wednesday, March 01, 2006 10:49:42 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, February 21, 2006

So I opted in for the beta of Windows Live Mail. It's pretty sweet. Everything you'd expect from a leading AJAX enabled browser application. Plenty of Windows client-like behaviors, right clicking, context menus, the works! The future looks bright.

Tuesday, February 21, 2006 2:57:14 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  |