<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Daniel Read's blog</title>
  <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/blog/danielread"/>
  <link rel="self" type="application/atom+xml" href="http://www.developerdotstar.com/community/blog/1/atom/feed"/>
  <id>http://www.developerdotstar.com/community/blog/1/atom/feed</id>
  <updated>2006-10-13T10:11:56-07:00</updated>
  <entry>
    <title>SSIS Data Flow derived columns missing downstream--stuck behind Union All Transformation?</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/730" />
    <id>http://www.developerdotstar.com/community/node/730</id>
    <published>2007-04-19T16:01:43-07:00</published>
    <updated>2007-04-19T16:03:53-07:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="SSIS (SQL Server Integration Services)" />
    <summary type="html"><![CDATA[<p>Unfortunately, one of the most annoying SSIS bugs did not make the cut for the <a href="http://support.microsoft.com/default.aspx/kb/921896">SQL Server 2005 SP2 bug fix list</a>: namely, when you add additional output columns to a Derived Column Transformation (and maybe other kinds as well) that is upstream from one or more Union All Transformations, the new columns you add get "stuck" behind the Union All transformations--that is, they do not show up as input columns in the Union All, and consequently do not flow past the Union All.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>Unfortunately, one of the most annoying SSIS bugs did not make the cut for the <a href="http://support.microsoft.com/default.aspx/kb/921896">SQL Server 2005 SP2 bug fix list</a>: namely, when you add additional output columns to a Derived Column Transformation (and maybe other kinds as well) that is upstream from one or more Union All Transformations, the new columns you add get "stuck" behind the Union All transformations--that is, they do not show up as input columns in the Union All, and consequently do not flow past the Union All. Generally, for me anyway, this comes up when you edit an upstream Derived Column Transformation that already has one or more Union All Transformations downstream from it.</p>
<p>The best way I have found to fix this is to delete and re-add each and every Union All Transformation that is downstream from the place where you added the new column(s). Alternately, you can edit each Union All and manually add the missing columns, but since this usually happens to me with multiple columns, I don't prefer this solution most of the time.</p>
<p>Has anyone else found a way to prevent and/or fix this pesky bug? Or have I mis-characterized the problem?</p>
<p>Dan</p>
    ]]></content>
  </entry>
  <entry>
    <title>IDENTITY_INSERT with SSIS OLE DB Destination</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/727" />
    <id>http://www.developerdotstar.com/community/node/727</id>
    <published>2007-04-13T14:42:06-07:00</published>
    <updated>2007-04-17T08:28:52-07:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="SSIS (SQL Server Integration Services)" />
    <summary type="html"><![CDATA[<p>This post describes some initial troubles I had inserting into a SQL Server table with an Identity-based PK with SSIS while keeping the surrogate PK values from my source data, which happily led to a solution suggested by commenters to the original post.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p><b>Update:</b> Feel free to read my original post (rant included) and the comments thread that follows, but helpful commenters to the original post pointed me to the solution:</p>
<p>If you want to retain your original surrogate primary key values from your source data when inserting into a target table that has an Identity-based primary key, use the OLE DB Destination and choose the <i>Table or view - fast load</i> option for the "Data access mode" option. This will make visible a "Keep identity" checkbox. After checking that all you need to do is map your source key column to the target Identity key column, and it should work.</p>
<p>In my situation, this worked with a local source Access MDB file and a remote target SQL Server 2005 database connected through SQL authentication; in both cases the Connection Managers used OLE DB connections, and used the OLE DB source and target in the data flow.</p>
<p>Here is the original post:</p>
<p>After several happy months of *not* working with <a href="http://www.developerdotstar.com/community/taxonomy/term/58">SSIS</a>, I returned to the tool today to help me with a medium-complexity data migration. It hasn't even been one day, and already I'm facing a near-show-stopping limitation that's going to force me to either abandon SSIS or implement some kind of ugly hack. I'm starting remember why I was so happy to put SSIS in my rear view mirror after spending several months fighting with it on a previous project.</p>
<p>The problem I have today is transferring a table from a legacy database where I want to keep the original numeric PK values when I insert into the new destination table, which uses an IDENTITY column for the PK. The only way to do this is to use the SQL Server Destination, which only works in a bulk insert fashion (which is just so stupid--why can't we have a SQL Server-aware destination that is not limited to bulk insert?); bulk insert is no good to me because I'm not inserting into a local database connected via Windows authentication (another truly stupid limitation). The OLE DB destination sees an Identity column as "read only."</p>
<p>I found a blog post elsewhere lamenting this sorry state of affairs, with the suggested workaround of inserting first into a holding table and then calling a stored procedure that moves the rows from the holding table to the real table. This might be the way I end up going--IF I stay with SSIS for this project. I might have to sleep on that. I hate to walk away from SSIS, though, because I've already invested a day getting this far into my project, and if I go to a custom-coded solution I'm going to lose all of the convenient bootstrapping features of SSIS.</p>
<p>Aaarrgghhhh! I hope by now people at Microsoft have realized how poorly SSIS has been received (from my reading of the blogs and forums, anyway). It's not that it doesn't do some things pretty well, but the flaws it does have (don't get me started) are *really* annoying. Maybe my problem is that I just keep trying to use SSIS for things just outside of it's envisioned sweet spot... I hope someone at Microsoft has a master plan to stop SSIS from sucking. We need a tool like this that doesn't suck and that doesn't cost huge amounts of money in licensing fees.</p>
<p>I feel better now. I guess I better get to hacking...then I can take a shower.</p>
<p>Dan</p>
<p>UPDATE:<br />
In case you were wondering whether you could use a pair of Execute SQL tasks to call SET IDENTITY_INSERT before and after the data flow task, it does not appear so. I tried this and received the error "User does not have permission to write to this column" on the first attempted insert.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Are You Real?</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/723" />
    <id>http://www.developerdotstar.com/community/node/723</id>
    <published>2007-03-20T11:10:00-07:00</published>
    <updated>2007-03-20T11:16:25-07:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="Career and Profession" />
    <summary type="html"><![CDATA[<p>All this puts me squarely in the programming mainstream, but there's no getting around the fact that people persist in seeing my world as less worthy of respect. I've learned to live with it, even embrace it, though early on in my programming career I was somewhat insecure about it.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>I can't agree more with the sentiments expressed by Bob Grommes in his recent post "<a href="http://bobondevelopment.com/2007/03/19/what-is-a-real-developer/">What is a 'Real Developer'?</a>". This is one of those posts where I'd like to just quote the whole thing, but I especially like this bit:</p>
<blockquote><p>
To my way of thinking, a "real developer" is someone who consistently produces quality software systems that delight customers. "Real developers" do this in spite of whatever handicaps happen to exist in their world. They know that no technology, platform, API or software ecosystem is perfect, but they know how to leverage the strengths of what they are given to work with to produce excellent results. And if they don't know, they can admit it to themselves, and learn quickly.
</p></blockquote>
<p>I also like this from Bob's <a href="http://bobondevelopment.com/about-2/">bio</a>:</p>
<blockquote><p>
I’ve been an independent software designer / developer for 24 years. In this business, that makes me a Really Old Fart. In the past I’ve done everything from Z-80 assembler to Visual FoxPro (in the early 90's I wrote two books on that product, and edited <i>FoxTalk</i> for a couple of years). These days I mostly concentrate on the .NET platform, architecting and building line-of-business applications, usually involving large databases.
</p></blockquote>
<p>Leave it to an old <a href="http://en.wikipedia.org/wiki/XBase">Xbase</a> guy to know what it's like to work in what some programmers who consider themselves to be more "elite" like to think of as a technology ghetto! I can relate.</p>
<p>After a childhood spent two versions of the Tandy TRS-80 Color Computer, I started out hacking DOS and Clipper in my first IT job; after that I spent several years in the worlds of VB 4-6 and ASP (with a good measure of Oracle and Java thrown in), and since then have been using .NET. To make me even more unfashionable, I am the co-author of two editions of a <a href="http://www.amazon.com/vbscript_reference/dp/0764559931/ref=nosim?tag=developerdots-20">VBScript book</a> (with a third edition in the works); few would consider VBScript a "cool" technology, but it is nonetheless a powerful and enduring (though not always elegant) one.</p>
<p>All this time, my primary job has been to design, build, and support business- and database-oriented solutions for clients who just want something to work. In the big picture, all this puts me squarely in the programming mainstream, but there's no getting around the fact that some people persist in seeing my world as less worthy of respect. I've learned to live with it, even embrace it, though early on in my programming career I was somewhat insecure about it.</p>
<p>(Just when I thought we had made some progress, an otherwise excellent article in a recent <i>Dr. Dobb's Journal</i> categorized Visual Basic as a "scripting language," despite the fact that there are at least four flavors of "Visual Basic," only one of which can be considered a scripting language. I've lost count of the number of times I've seen this kind of thing, and the <i>Dr. Dobb's</i> editors should know better. I don't mean to suggest that the author or publication has the kind of active condescension we've been discussing here, but this example does underline the impression that people who operate outside of the Microsoft development stack have that "Visual Basic" is some kind of toy.)</p>
<p>I'm adding "Bob on Development" to my RSS reader.</p>
<p>Dan</p>
    ]]></content>
  </entry>
  <entry>
    <title>Ideal Design/Structure for Lookup Tables</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/lookup_table" />
    <id>http://www.developerdotstar.com/community/lookup_table</id>
    <published>2007-03-19T14:36:30-07:00</published>
    <updated>2007-03-19T20:05:22-07:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="Database Design" />
    <category term="Design Patterns" />
    <summary type="html"><![CDATA[<p>In my work over the years that I have continually strived for the ideal structure of a lookup table. I must have designed hundreds of them by now in at least four different RDBMS engines. I may have finally arrived at a structure I really like, so I thought I would share it, with the hope that other people may benefit from adopting it, or even better, suggest improvements to the design.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>In my work over the years that I have continually strived for the ideal structure of a lookup table. I must have designed hundreds of them by now in at least four different RDBMS engines, sometimes using a modeling tool, sometimes using a graphical table designer, sometimes writing the DDL by hand. I may have finally arrived at a structure I really like, so I thought I would share it, with the hope that other people may benefit from adopting it, or even better, suggest improvements to the design.</p>
<p>At first I thought that the meaning of "lookup table" might be obvious enough not to require much explanation, but later I changed my mind. I started where lots of people start these days and looked up <a href="http://en.wikipedia.org/wiki/Lookup_table">lookup table in Wikipedia</a>; I realized that the term does not necessarily have a universal meaning. The Wikipedia entry (at the time I am writing this) defines the term in more general terms:</p>
<blockquote><p>
In computer science, a lookup table is a data structure, usually an array or associative array, used to replace a runtime computation with a simpler lookup operation. The speed gain can be significant, since retrieving a value from memory is often faster than undergoing an expensive computation.
</p></blockquote>
<p>This definition hints at my usage of the term, but Wikipedia's context assumption is different, whereas every time I've used this term it has been to describe a table in a relational database that is designed to provide a set of possible values for a column, which serves to limit the possible values for a column, standardize input, and reduce the amount of data stored in a table.</p>
<p>Another term I have encountered for this same concept is <i>reference table</i> (not to be confused with <i>cross-reference table</i>, which is used to define a many-to-many relationship between two other tables; lookup/reference tables are typically used to define one-to-many relationships).</p>
<p>Lookup tables are often used to populate dropdown lists and are also often used as a sorting/grouping mechanism for a query or report.</p>
<p>Just be clear about what I mean, this table structure...</p>
<p>        <b>Customer Name</b><br />
        <b>Customer Type Name</b></p>
<p>        ACME Products<br />
        Retail</p>
<p>        Some Store, Inc.<br />
        Retail</p>
<p>        Pity the Fool Enterprises<br />
        Wholesale</p>
<p>        Crazy Time Industries<br />
        Wholesale</p>
<p>...becomes this when we add a lookup table to the design:</p>
<p>        <b>Customer Name</b><br />
        <b>Customer Type ID</b></p>
<p>        ACME Products<br />
        1001</p>
<p>        Some Store, Inc.<br />
        1001</p>
<p>        Pity the Fool Enterprises<br />
        1002</p>
<p>        Crazy Time Industries<br />
        1002</p>
<p></p>
<p>        <b>Customer Type ID</b><br />
        <b>Customer Type Name</b></p>
<p>        1001<br />
        Retail</p>
<p>        1002<br />
        Wholesale</p>
<p>With the above definition in mind, I have described below my (current) preferred design for a lookup table.</p>
<p>        <b>Column</b></p>
<p>        <b>Surrogate Primary Key</b></p>
<p>        <b>Short Name</b></p>
<p>        <b>Description</b></p>
<p>        <b>Active Flag</b></p>
<p>        <b>Display Order</b></p>
<p>        <b>Created Stamp</b></p>
<p>        <b>Last Modified Stamp</b></p>
<p>A description of each column follows:</p>
<p>Surrogate Primary Key<br />
Depending on your stance on the <a href="http://builder.com.com/5100-6388-1045050.html">endless debate over surrogate vs. natural keys</a>, you may prefer a natural key, but I'm a surrogate key person myself. Naturally, I'm sure you'll agree with me and design your database using surrogate keys. :-) Regardless of what kind of key you choose, though, if you're using anything like the lookup table pattern I'm describing here, your lookup table will need a primary key, and that primary key will be used as a foreign key in other tables, along the lines of the "Customer Type ID" example above.</p>
<p>Surrogate primary keys have different implementation mechanisms in different database engines. Oracle has its SEQUENCE object, SQL Server has IDENTITY columns, and Access has the AutoNumber. Usually these are numeric keys, but I have started to notice a trend in the SQL Server world towards using GUIDs for all keys; often the explanation for this is that database replication in SQL Server requires GUID-based keys, though I'm not so sure that's as much of a concern for lookup tables.</p>
<p>Short Name<br />
The "Short Name" column might also be labeled just "Name." If you imagine your lookup table showing up in a dropdown list or in a column on a report or query output, you can probably imagine as well that a longer name could make things awkward; you dropdown list or report column might need to be exceedingly wide in order to accommodate longer names. My preferred method is to use a "Name" column in conjunction with a "Description" column, which can be used to help users and administrators understand the meaning conveyed by the Name. I can imagine in some circumstances where instead of, or in addition to, a Description column a "Long Name" column might make sense. Along the same lines, it is sometimes also appropriate to have more than one "Name" column for different purposes--perhaps one for display, and one for sorting (see also "Display Order," below).</p>
<p>Description<br />
As described above under "Short Name," the "Description" column is intended to convey additional meaning. For a simple lookup table, a "Description" column may be overkill. However, I have found this column very handy in the presentation tier; most commonly, this has come up when there is doubt about whether the user will be able to figure out the meaning of a lookup table entry based on just the "Name." If there is a possibility that the Name could be confusing, or that entries might have similar names that are difficult to distinguish, then you can display the Description in the user interface to help the user out, perhaps in a "tooltip" that floats over the field in the UI or some similar mechanism.</p>
<p>Active Flag<br />
This is one of those I had to learn about the hard way. Here's what happens: when you design and build your application for your client, they have exactly six Customer Types. So you design a lookup table, put those six entries in it, and proceed to design the rest of the database, using the CustomerType lookup table key as a foreign key in various tables. Most likely, you are using referential integrity (RI), so once you start adding "parent" rows that utilize your "child" lookup table rows, the database engine will prevent you from removing any of your lookup table rows because they are locked in by the RI. You also write code that retrieves the rows for the lookup table for dropdown lists, reports, etc.</p>
<p>Six months later, your client wants to drop one of those Customer Types because it's not relevant anymore. You can't just remove it from the table because of the RI, and you wouldn't want to do that anyway because all that old data is still valid. But you have a Catch-22 because the now defunct Customer Type is still showing up in various dropdown lists, report parameter prompts, etc.</p>
<p>If you had designed your lookup table with an "Active" flag column *and* written all of your queries to filter on the Active flag, then "deactivating" the defunct Customer Type would be as simple as flipping the Active flag. You get the best of both worlds: the old Customer Type will still show up as a label when querying old data, but it won't be available as an option any more for the creation of new data.</p>
<p>Display Order<br />
You may have noticed that people (especially your client) do not think about the order in which they want lookup table values to be sorted. It's almost always after the fact that this comes up (unless you're savvy enough to ask the question in advance and your client client is forward thinking enough to have the right answer). Regardless, it sure is nice to be able to manipulate the sort order of a dropdown list or other query/report without having to write new code or (as is often the case) implement some kind of hack in the presentation tier. Save yourself the trouble and build a Display Order column into all of your lookup tables. I generally use a numeric type for this column that is the same width as the numeric surrogate primary key. As you write any queries that select from this table, include an ORDER BY clause that uses the Display Order column. When requirements change relative to the sorting of your lookup table, all you have to do is manipulate this value. (In a SQL Server environment, you might also consider using the DisplayOrder column for a, <a href="http://msdn2.microsoft.com/en-us/library/ms190639.aspx">clustered index</a>.)</p>
<p>There is one exception to this rule, I think: some lookup tables might so obviously lend themselves to a pure alphanumeric sort on the "Name" column that a Display Order column seems silly.</p>
<p>Created Stamp<br />
This column is a simple date/time column that reflects when the lookup table row was first created. Some might argue that Created and Last Modified audit columns are overkill for lookup tables, but I have found them useful and almost always use them. They are especially handy in an application that includes an administrative interface that enables users (not just database administrators and developers) to manage the data in lookup tables.</p>
<p>Last Modified Stamp<br />
This column is a simple date/time column that reflects when the lookup table was last modified. In some applications it might also make sense to have "Created By" and "Last Modified By" columns to reflect which user made a change.</p>
<p>*&nbsp;*&nbsp;*</p>
<p>A lookup table is also much like a <a href="http://en.wikipedia.org/wiki/Dimension_table">dimension table</a> in a <a href="http://en.wikipedia.org/wiki/Star_schema">dimensional data warehouse</a> design, a context in which the fascinating topic of the <a href="http://en.wikipedia.org/wiki/Slowly_Changing_Dimension">slowly changing dimension</a> also comes into play. The connections between lookup tables in a transactional database design and corresponding slowly changing dimensions in a downstream data warehouse is an area for additional interesting discussion, I think. For example, typically a lookup table in an OLTP system does not support changes over time (though with the suggested Active Flag, I believe this could be done), but Kimball Group consultant Joy Mundy <a href="http://www.intelligententerprise.com/showArticle.jhtml?articleID=194500329">advocates tracking "attribute changes" over time</a>:</p>
<blockquote><p>
The key flaw Kimball Group typically sees in existing enterprise data warehouses is a lack of historically accurate attributes. Almost all data warehouses track transaction history--what was sold, to whom and for how much--but many do a poor job of associating the transaction with the attributes as they were at the time of the transaction. This attribute history is very important for data mining and other smart enterprise applications. Suppose, for example, that you want to build an application that will present product choices to a potential customer based on where he lives. If the data warehouse only keeps the customer's current address, then for the purposes of queries, analysis and prediction, it looks as if the customer has always lived where he does now. We lose the vitally important information about how the customer's behavior changed when he moved from a cold climate to a warm climate. And once that history is gone from the data warehouse, it's difficult or impossible to reconstruct it.
</p></blockquote>
<p>Another thing I've wondered is whether OLTP database designers could do certain things with their table designs to make it easier for OLAP database designers and ETL coders to come along later and do their thing.</p>
<p>I'm sure my quest for the "ideal" lookup table design will continue. Your thoughts are most welcome.</p>
<p>Thanks for reading,<br />
Dan</p>
<p>P.S.<br />
A quick Google search turned up an opinion piece by Don Peterson called <a href="http://www.sqlservercentral.com/columnists/dpeterson/lookuptablemadness.asp">Lookup Table Madness</a>. It appears that the author makes a case against the whole practice of using lookup tables, which sounds very interesting to me--but unfortunately that particular site locks their content behind passwords, so I have not read it.</p>
<p>(Irrelevant rant: Granted, the account I would need to read that article is free, but I always find myself annoyed when a page comes up at the top of the search results and when I click through I find that the real content is hidden. When that happens, I make a mental note to avoid that site in the future. If people want to hide their content, that's fine by me, but I think search engines should reciprocate by penalizing these pages rather than keeping them at the top of the results).</p>
    ]]></content>
  </entry>
  <entry>
    <title>Daylight Savings Time Software Problems: Who Is At Fault?</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/718" />
    <id>http://www.developerdotstar.com/community/node/718</id>
    <published>2007-03-09T11:40:24-08:00</published>
    <updated>2007-03-11T14:27:54-07:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="Software Design" />
    <summary type="html"><![CDATA[<p>What do you think? Are there fundamental lessons here that software designers and companies should be heeding? Are there some products or manufacturers that got this *right*, who have not experienced difficulties with the great 2007 DST transition? If so, what can we learn from their example?</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>A colleague stopped by my office today and we had a friendly debate about the challenges that software and hardware vendors are having supporting the impending Daylight Savings Time change in the United States, a change that is mandated by recent legislation. In particular, Microsoft and Sun have had well publicized difficulties, and on another DST software bugs thread on this site, I posted <a href="http://www.developerdotstar.com/community/node/459#comment-7046">this description of a consumer device whose embedded software will not be patched in time</a>. I'm sure one could do a survey and find a long list of software vendors and hardware manufactures having similar problems.</p>
<p>In my colleague's view, setting aside the question of whether or not this legislation was a good idea, the blame for these problems rests squarely on the shoulders of the software and hardware vendors whose products require patching, support, etc.--they should have seen this coming, they should have designed their products to be more flexible, etc. This is their fault, plain and simple. After all, he says, DST is not a force of nature; it is not embedded in reality at such a fundamental level as something like the Gregorian calendar or the metric system.</p>
<p>On the other hand, commenter Kevin Dean <a href="http://talkback.zdnet.com/5208-12558-0.html?forumID=1&amp;threadID=31072&amp;messageID=575660&amp;start=-1">posted recently on a ZDNet thread</a> a view that we should give these vendors a break:</p>
<blockquote><p>
<b>Why is this Microsoft's fault?</b></p>
<p>Microsoft isn't the only one having problems with this. I opened a case with Sun regarding the availability of their DST-patched Java runtimes and got a resolution to the problem only last week. Now I'm scrambling to get all my client workstations, my application server, and my database properly patched.</p>
<p>The blame for this fiasco lies squarely with Fred Upton, a Michigan Republican, and Edward Markey, a Massachusetts Democrat, for sponsoring the amendment to the Energy Policy Act of 2005. The amount of energy saved is miniscule at this time of year (unlike in summer with its longer days) and the disruption they have caused to computer systems and transportation schedules (especially airlines) is phenomenal.</p>
<p>I, like everyone else, would have loved it if Microsoft could have made things smoother, but this is a massively complex undertaking that every computer software provider is having trouble with and the fault lies squarely with a political system that rewards style over substance.
</p></blockquote>
<p>Again, setting aside the question of the wisdom of the legislation (which is certainly also a legitimate topic of debate), Mr. Dean's position is that the complexity of this issue dictates that we should cut software vendors and hardware manufacturers a break on this.</p>
<p>Is there a way that vendors and designers could have avoided this? Or is this an inescapable problem once you decide to cross the boundary into making your software "smart" about changing the time automatically relative to DST, rather than just keeping your software "dumb," like my microwave oven, which I have to change manually twice a year.</p>
<p>In a <a href="http://www.developerdotstar.com/community/node/459">DST software bugs</a> post I wrote in April of 2006, before I had heard anything about this impending DST start date change, I took the position that we have ourselves to blame for difficulties with software bugs and system synchronization problems related to DST, because after all, the time changes happens twice a year, every year, and we should not be caught with our pants down, beepers going off, support phones ringing, every time it happens. However, I think the context of that discussion was a little different (but maybe not); Scott Rosenberg <a href="http://www.wordyard.com/2007/02/26/stealth-fighter/">posted similar sentiments recently</a>, more from a support/logistics standpoint.:</p>
<blockquote><p>
Back when my job as Salon managing editor involved overseeing our daily production, I noticed that, every spring and fall, almost without fail, our publishing system would experience a glitch of some kind on the weekend that the clocks got moved forward or back — nothing serious, mind you, but enough to throw a wrench in the works of our site updates. It wasn't a single bug, but some sequence of related bugs, so we'd fix one and then six months later something else would happen. Eventually we got in the habit of just making sure that one of the developers kept a close eye on things when that weekend rolled around. It was prudent.
</p></blockquote>
<p>In the same post, Rosenberg speculates that perhaps these kinds of challenges are related to something deeper:</p>
<blockquote><p>
It seems that this is one of the unexpected consequences of living in a world operated by software: new danger zones lie where human abstractions — borders, measurements, languages — change or conflict or fail to behave as expected. Clocks and calendars and maps are no longer just assists for human understanding; they are symbols at the heart of systems upon whose performance lives depend. I suppose this started with the first railway schedule, but with the dateline-addled F-22 it has entered a whole new realm of disconcert.
</p></blockquote>
<p>What do you think? Are there fundamental lessons here that software designers and companies should be heeding? Are there some products or manufacturers that got this *right*, who have not experienced difficulties with the great 2007 DST transition? If so, what can we learn from their example?</p>
<p>Thanks for reading,<br />
Dan</p>
    ]]></content>
  </entry>
  <entry>
    <title>Lessons Learned Automating Excel from .NET</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/automate_excel_dotnet" />
    <id>http://www.developerdotstar.com/community/automate_excel_dotnet</id>
    <published>2007-03-07T17:26:21-08:00</published>
    <updated>2007-03-07T17:34:24-08:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term=".NET" />
    <category term="VB.NET" />
    <summary type="html"><![CDATA[<p>Recently I had occasion to write a moderately complex component that used "<a href="http://en.wikipedia.org/wiki/OLE_Automation" title="Windows COM OLE Automation">automation</a>" (using the old fashioned COM term) to communicate with the Microsoft Office Excel application installed on the same computer. In this post I share several tips and tricks that may help you in your Excel automation adventures.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>Recently I had occasion to write a moderately complex component that used "<a href="http://en.wikipedia.org/wiki/OLE_Automation" title="Windows COM OLE Automation">automation</a>" (using the old fashioned COM term) to communicate with the Microsoft Office Excel application installed on the same computer.</p>
<p>The scenario I was working in was an import scenario--that is, reading a provided Excel spreadsheet file and importing into a database. Some of my tips below may be tied to this assumption, but I think my advice will apply to most Excel automation scenarios. (Also, I'll be a lot of this applies to automating other Office applications such as Word.)</p>
<p>First, a bit of background: keep in mind that the Excel API is implemented in COM, which is a precursor to .NET. Microsoft has gone to great lengths to make .NET backwards compatible with COM (and vice versa), but the fact remains that when you are communicating with Excel from your .NET code you are not communicating with something that is native to .NET.</p>
<p>One more thing: my experiences as documented here are based on using Excel 9.0 (Office 2000) and Excel 11.0 (Office 2003) from .NET 2.0 running on Windows XP SP 2. I can't say for sure whether anything would be different relative to newer versions of Excel, .NET, or Windows. Feel free to add comments to this post to provide more up-to-date information.</p>
<p>The links at the end of this post point to some related information that you may find useful.</p>
<p>On to the tips...</p>
<p>Tip #1: Seriously Consider NOT Automating Excel from .NET</p>
<p>I don't mean to be flippant: the most significant conclusion I have reached from my experience is that if I ever have to do this again, I will twist whatever arms I have to in order to purchase some kind of Excel component so that I do not have to program against the Excel API at all. There are many .NET component libraries on the market that can read from and write to Excel spreadsheet files without Excel even needing to be installed on the machine. I recommend strongly that you seek one of these out. As you read the rest of my tips, you will have a better idea why. A quick Google search should turn up several options.</p>
<p><i>(Component vendors, please refrain from adding comments to this post to advertise your Excel library; requests to advertise, review, or plug your component will be politely declined. Thanks for understanding.)</i></p>
<p>Tip #2: Use VB.NET instead of C#</p>
<p>Even if your preferred .NET language is C# (or some other .NET language), even if you absolutely hate VB.NET (it's really not so bad), I strongly recommend that you use VB.NET instead of C#. If the rest of your solution is written in C#, break out your Excel-related functionality into a separate VB.NET DLL. I got about 10% into the initial attempt at my solution before I said "Screw this!", threw out my C# code, and started over again in VB.NET.</p>
<p>Why? In short, two reasons:</p>
<p>First, Office applications make prodigious use of optional arguments--in many cases a single function can take a dozen optional arguments. C# does not know how to handle optional arguments, so you end up passing a ton of useless null or Object values. This might not be so bad if there weren't so many, and if the lack of useful Intellisense in the IDE didn't make it even more difficult to tell which argument is which.</p>
<p>Second, C# is not really hip to the Variant data type, which is used often in Excel's <a href="http://en.wikipedia.org/wiki/Visual_Basic_for_Applications">VBA</a>-centric API.</p>
<p>Trust me: just use VB.NET. If you're still not convinced, check out the link to the article "Programming Office Applications Using Visual C#" at the end of this post.</p>
<p>Tip #3: Communicate with Excel in a late bound manner</p>
<p>Late bound? That's not a term you hear much these days since .NET has overtaken COM. This term refers to a technique of not compiling a reference to the Excel library into your assembly. Late binding is otherwise known as IDispatch binding, with early binding otherwise known as vtable binding. Since Excel is still a COM application, these terms still apply in a .NET interop context.</p>
<p>I recommend NOT adding an early bound reference to Excel in your project. Microsoft has not done a good job over the years in managing the compatibility between the various versions of the Excel library; depending on which version of Office you have installed, you will have different version-specific Excel reference options in your COM references list. Don't be tempted by these early bound reference opportunities. Late bound all the way, baby. Protect yourself from version incompatibilities when you find out that you compiled against Excel 11.0 and your client is using 9.0. Similarly, you can protect your solution from breaking when your user or administrator upgrades Office.</p>
<p>In .NET, going late bound requires some syntax and techniques that may be unfamiliar to you, but it's not that bad. </p>
<p>To instantiate an Excel Application object, use the Interaction.CreateObject() method, which is much like the old VB6/VBA/VBScript CreateObject() function. It is part of the Microsoft.VisualBasic namespace (see Tip #4 if you decide to go with C# instead of VB.NET). Here is my LoadExcel() method:</p>
<div class="codeblock">
<pre>Private Sub loadExcel()<br />    m_excelApp = Interaction.CreateObject(&quot;Excel.Application&quot;, &quot;&quot;)<br />    If m_excelApp Is Nothing Then<br />        Throw New Exception(&quot;The Excel libarary could not be loaded. &quot; &amp; _<br />            &quot;You may an incorrect version of Excel installed. &quot; &amp; _<br />            &quot;Please consult your system administrator. The instantiation &quot; &amp; _<br />            &quot;failed without an exception.&quot;)<br />    End If<br />End Sub</pre></div>
<p>Similarly, in order to invoke any properties or methods on the Excel.Application object, you want to use InvokeMember, like so:</p>
<div class="codeblock">
<pre>workbooks = m_excelApp.GetType().InvokeMember(&quot;Workbooks&quot;, _<br />    BindingFlags.GetProperty Or BindingFlags.Public, _<br />    Nothing, m_excelApp, Nothing)</pre></div>
<p>If that code looks a little cumbersome to you, see Tip #5. If you wrap your Excel calls, your main application logic won't be burdened with the more verbose code required for late bound automation.</p>
<p>Check the .NET documentation on InvokeMember(). You may also prefer using Interaction.CallByName(), which offers a kind of shorthand version of InvokeMember(), but I prefer the more explicit control offered by InvokeMember().</p>
<p>The original version of my solution used an early bound reference. When I refactored my code to be late bound, I did not notice any significant performance difference. This jibes with my experiences with early vs. late binding performance when I used to write a ton of COM code in VB 6. If performance is a real concern, I return your attention to Tip #1; I think there is a pretty low performance ceiling you'll hit when automating Excel no matter what you do; theoretically, a good Excel component would be faster.</p>
<p>(You may also need an Imports System.Reflection statement at the top of your class file to do late binding. I have this at the top of my class, but as I write this I can't remember why.)</p>
<p>Tip #4: If you use C#, go through VB to get to Excel</p>
<p>While researching my Excel automation solution, I came across a great Dan Appleman article that is linked at the end of this post. It shows how you can reference the VB.NET runtime library from your C# project to make use of the Microsoft.VisualBasic.Runtime namespace, which is where you will find the aforementioned Interaction.CreateObject(). I think it's safe to say that you can't do late bound COM programming from C# without going through the Visual Basic library.</p>
<p>Tip #5: Wrap your Excel communication points</p>
<p>I strongly recommend that you use good old <a href="http://en.wikipedia.org/wiki/Information_hiding">information hiding</a> to protect the main logic of your code from the particulars of communicating with Excel. Here are a few of the functions I developed:</p>
<div class="codeblock">
<pre>Private Function getRange(ByRef rangeString As String, ByVal worksheet As Object) As Object<br /><br />    Dim range As Object = Nothing<br /><br />    range = worksheet.GetType().InvokeMember(&quot;Range&quot;, _<br />        BindingFlags.GetProperty Or BindingFlags.Public, Nothing, _<br />        worksheet, New Object() {rangeString})<br /><br />    Return range<br />End Function<br /><br />Private Function getCellValString(ByRef columnLetter As String, ByRef rowNum As Integer, _<br />    ByVal workSheet As Object) As String<br /><br />    Dim expectedCell As Object = Nothing<br /><br />    expectedCell = getRange(columnLetter &amp; rowNum.ToString(), workSheet)<br /><br />    Return cellToString(expectedCell).Trim()<br />End Function<br /><br />Private Function cellToString(ByVal singleCell As Object) As String<br />    <br />    &#039;The Value property is a VBA Variant, which does not<br />    &#039;translate well to .NET. When the cell is blank, the<br />    &#039;Value property will be Nothing<br />    Dim singleCellValue As Object = Nothing<br /><br />    singleCellValue = singleCell.GetType().InvokeMember(&quot;Value&quot;, _<br />        BindingFlags.GetProperty Or BindingFlags.Public, _<br />        Nothing, singleCell, Nothing)<br /><br />    If singleCellValue Is Nothing Then<br />        Return String.Empty<br />    Else<br />        Return singleCellValue.ToString()<br />    End If<br />End Function</pre></div>
<p>Note: I have omitted by retry wrapper code from these methods for the sake of clarity; see Tip #7 for an explanation. If you reuse these methods, you may want to add in the retry wrapper--though in my testing so far, it looks like when the "application is busy" error happens, you may be irrevocably screwed.</p>
<p>See Tip #6 for an explanation for why I use cellToString().</p>
<p>Tip #6: Watch out for empty cells</p>
<p>In testing I ran into some annoyances related to empty cells, so I developed the cellToString() wrapper function you see above. The issue is that Range.Value is a Variant, not a String or numeric type. So when a cell is empty you can (but not necessarily always) get Nothing back instead of an empty string.</p>
<p>Tip #7: Watch out interruptions and disconnects</p>
<p>I don't have a lot of information to provide for what causes this problem, but in testing I have run into problems with lost communication between the .NET code and the running instance of Excel. What I mean is, if your Excel automation code is running and the user makes use of the Excel application at the same time, instability may occur. The main scenario we've been able to reproduce is, oddly enough, if the user opens a .XLS file by double clicking on it (as opposed to using the File-&gt;Open menu) then your .NET code will suddenly lose its ability to connect with Excel. This is the error we saw in this scenario:</p>
<blockquote><p>
System.Exception: There was an error during the main import process: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---&gt; System.Runtime.InteropServices.COMException (0x8001010A): The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))
</p></blockquote>
<p>It's possible that other Excel usage scenarios could cause this same problem.</p>
<p>If this scares the hell out of you (and it should) see Tip #1.</p>
<p>One solution I tried is wrapping all of my Excel communication calls in some trap-and-retry logic. So a statement like this:</p>
<div class="codeblock">
<pre>range = worksheet.GetType().InvokeMember(&quot;Range&quot;, _<br />    BindingFlags.GetProperty Or BindingFlags.Public, Nothing, _<br />    worksheet, New Object() {rangeString})</pre></div>
<p>becomes this:</p>
<div class="codeblock">
<pre>Do<br />    Try<br />        range = worksheet.GetType().InvokeMember(&quot;Range&quot;, _<br />            BindingFlags.GetProperty Or BindingFlags.Public, Nothing, _<br />            worksheet, New Object() {rangeString})<br />    Catch ex As Exception<br />        If ex.Message.Contains(&quot;application is busy&quot;) Then<br />            If m_excelRetryCount &lt;= MAX_EXCEL_RETRIES Then<br />                m_retryExcel = True<br />                m_excelRetryCount += 1<br />                System.Threading.Thread.Sleep(EXCEL_RETRY_DELAY)<br />            Else<br />                m_retryExcel = False<br />                m_excelRetryCount = 0<br />                Throw New Exception(&quot;The Excel application is apparently busy, which is &quot; &amp; _<br />                    &quot;interfering with the import process. We have retried communication with Excel &quot; &amp; _<br />                    MAX_EXCEL_RETRIES &amp; &quot; times with a delay between each retry, but we are not &quot; &amp; _<br />                    &quot;able to establish communicatation with Excel.&quot;, ex)<br />            End If<br />        Else<br />            m_retryExcel = False<br />            m_excelRetryCount = 0<br />            Throw ex<br />        End If<br />    End Try<br />Loop While m_retryExcel<br />m_retryExcel = False<br />m_excelRetryCount = 0</pre></div>
<p>Note that I declare EXCEL_RETRY_DELAY, m_retryExcel, and m_excelRetryCount at the class level since I had to repeat this retry logic in several of my Excel wrapper functions. That may or may not have been the best technique, but there it is.</p>
<p>Your mileage may vary. So far from testing it appears that the retries cannot ever reestablish the communication link.</p>
<p>Some Potentially Useful Links</p>
<ul>
<li>This <a href="http://msdn2.microsoft.com/en-us/library/aa537157(office.11).aspx">MSDN article "Programming Office Applications Using Visual C#"</a> contains some useful information and tips.</li>
<li>I found a nice tip in <a href="http://www.ftponline.com/members/login.aspx?ReturnUrl=http://www.ftponline.com/vsm/2004_08/magazine/columns/gettingstarted/default_pf.aspx">this article by Dan Appleman</a> on how you can reference the VB.NET library from C# and use VB.NET's methods to make late-bound calls to Office (or any other IDispatch-able COM library). Unfortunately, this article was published by Fawcette, which requires a paid account to read online. However, you can try searching Google for <i>appleman c# invokemember</i> and try clicking Google's "cached" link. You also might have some luck reading the article via <a href="http://www.ftponline.com/vsm/2004_08/magazine/columns/gettingstarted/">this link</a>.</li>
<li><a href="http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&amp;ixPost=44930">This discussion on the Joel on Software board</a> offers some interesting suggestions and insights that could be particularly helpful to someone weighing whether or not to automate Excel or take a different approach</li>
<li><a href="http://www.blog.methodsinexcel.co.uk/">Methods in Excel</a>, and Excel-oriented blog; lots of links there to other Excel blogs and sites</li>
</ul>
<p>Good luck!</p>
<p>Thanks for reading.</p>
<p>Dan</p>
<p>P.S.<br />
If you thought this was helpful and feel compelled to do something nice in return, considering buying one of our <a href="http://www.developerdotstar.com/books/softwaredevelopmentbooks.html">high quality software development books</a>, published by developer.* Books. You will be doubly enriched. :-)</p>
    ]]></content>
  </entry>
  <entry>
    <title>Book Publishing in a Time of Transformation</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/716" />
    <id>http://www.developerdotstar.com/community/node/716</id>
    <published>2007-03-05T14:09:37-08:00</published>
    <updated>2007-03-05T14:09:37-08:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="Software Development Books Blog" />
    <summary type="html"><![CDATA[<p>Some people have asked us, "You've started a book publishing company? Huh? Why would you do that? I thought all the publishers are going out of business." These articles do a great job of describing why we think there is a future for new publishers to succeed by embracing the change happening right now.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>Anyone interested in the current transformation of the book publishing industry should read "<a href="http://books.guardian.co.uk/review/story/0,,2025116,00.html">Publish or be damned</a>," by Stephen Page, published in the Guardian. Kassia Krozser of the <a href="http://www.booksquare.com/">Booksquare Blog</a> also does a fine job of riffing on Mr. Page's article in "<a href="http://www.booksquare.com/archives/2007/03/05/2315/">Do Publishing Houses Have A Future?</a>."</p>
<p>This <a href="http://smallpress.typepad.com/index/2007/02/morris_rosentha.html">recent interview with digital publishing advocate Morris Rosenthal</a> is also revealing. </p>
<p>You may also recall the <a href="http://www.loudthinking.com/arc/000580.html">Shaking up Tech Publishing</a> post on David Heinemeier's Loud Thinking blog that generated some buzz last year. Reading through the original post and all of the comments (particularly Tim O'Reilly's) is enlightening.</p>
<p>Some people have asked us, "You've started a book publishing company? Huh? Why would you do that? I thought all the book publishers were going out of business." The above linked articles do a great job of describing why we think there is a future for new publishers to succeed by embracing the change happening right now.</p>
<p>As an aside, Mr. Rosenthal is part of a groundswell that sees the new digital printing and distribution methods as a tool to empower self publishers. I do agree that it this is important, and a good thing. However, more along the lines of Mr. Page, I do not believe that the future will be changed in a fundamental way in the balance of publishing houses and self publishing. There will always be books that will succeed quite well as self published books (as 37signals found with <i>Getting Real</i>), largely owing to their particular subject matter (how-to books do quite well, traditionally), timing, and the ingenuity, perseverance, and audience reach of their authors; digital, on-demand printing, ebooks, and online distribution definitely make things easier, but the dynamics of self publishing are essentially the same as they always have been, IMO. And there will always be a role for publishing houses to "curate" and add value to books through editing, packaging, and promotion.</p>
<p>We hope that people who read our first two books, <a href="http://www.amazon.com/software_conflict_robert_glass/dp/0977213307/ref=nosim?tag=developerdots-20">Software Conflict 2.0</a> and <a href="http://www.amazon.com/software_creativity_robert_glass/dp/0977213315/ref=nosim?tag=developerdots-20">Software Creativity 2.0</a> agree that the books are worth the effort and reflect the care and design that went into them after the author finished the writing.</p>
<p>Happy reading!</p>
<p>Dan</p>
    ]]></content>
  </entry>
  <entry>
    <title>Five and Counting: developer.* Past, Present, and Future</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/714" />
    <id>http://www.developerdotstar.com/community/node/714</id>
    <published>2007-02-26T14:14:48-08:00</published>
    <updated>2007-02-26T15:21:34-08:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="developer.* News" />
    <summary type="html"><![CDATA[<p>Editor Dan Read belatedly reminisces about the recent passage of the five year anniversary of developer.*, considers where we are today, and speculates on the future.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>Hello, I am Dan Read, the proprietor of this web site. Longtime readers and newcomers alike might be interested to learn what's been going on lately with me and with DeveloperDotStar. I'll cover a little historical ground, catch up on current events, and talk about what the future looks like for the developerdotstar.com web site and developer.* Books. If some of the history and reminiscence starts to bore you, feel free to skip ahead to the "future" stuff at the end. :-)</p>
<p>It's emblematic, I think, of how insanely busy 2006 was for me that the five year anniversary of developer.* passed in the middle of last Summer without any comment or celebration here on the site. Five years! It's hard for me to believe it was June 2001 that I posted two of the first essays on the site, "<a href="http://www.developerdotstar.com/mag/articles/read_princprog.html">Principled Programming</a>" and "<a href="http://www.developerdotstar.com/mag/articles/read_impact.html">The Human Impact of Software</a>."</p>
<p>Those early pieces published on the site were some of my first forays into writing about software development, and they reflect not only where I was at the time as a person, as a writer, and as a software developer. The story of DeveloperDotStar's changes and growth reflects my own story over the same period. As such, there are both successes to relish and disappointments to reconcile. I'm proud of the many accomplishments, and of all the great software writing that has been published here (mostly by contributors other than myself), but lately, because last year I tried to do too much, I have also been feeling the sting of loose ends left frayed and people let down.</p>
<p>The story of DeveloperDotStar can also be seen as one of increasing scope (and it is my hope that this expansive trend can continue into the future). Originally the site started out as a place to publish my own essays about software development, like the two linked above. At the time, early 2001, the blogging thing had not really taken off yet. At the time, as I recall, <a href="http://www.joelonsoftware.com">Joel on Software</a> was the closest analog on my radar screen, though I'm sure others were doing similar things at the time. (FWIW, according to Alexa, Joel On Software went online July 29, 2000, just under a year before developer.*.)</p>
<p>I had some things I wanted to say, but I did not see any publication or web site where they would seem to fit, and I also knew that my own writing voice needed some time to develop, so I started my own publication-of-one in June 2001 (according to Alexa, it was actually in March of that year, but I think it took me a few months to get things together). The first version of the site was hosted on an early server-side web hosting product called Internet on a Stick, which was owned by my friends Bryan and Stan Sedwick. Looking back on it now, what I really wanted was a blog, but I didn't know to call it that; so I started what amounted to a blog, but I called it a "magazine," replete with its own old fashioned <a href="http://www.developerdotstar.com/mag/letters_top.html">Letters to the Editor</a> page.</p>
<p>Over the next couple years I continued to publish occasional essays, and the site built up a small following. The next phase of developer.* started when I decided that my own voice was not enough; if I'm honest with myself, the expansion of the scope of the site was also related to my own growing dissatisfaction with my writing, both in terms of content and style. Through my own growth process I was realizing that I was not satisfied with the <i>certainty</i> in my writing, nor what I felt was a tone that was too didactic. My essay "<a href="http://www.developerdotstar.com/mag/articles/read_designprog.html">Software Design and Programmers</a>," published on this site in March of 2003, was the significant piece of polished writing that I wrote for developer.* (not counting the many blog posts, editorials, and book reviews I have written since then).</p>
<p>One memorable event around this time was my attendance at one of Gerald Weinberg's last Problem Solving Leadership workshops (where, incidentally, I was lucky enough to be in attendance at the same workshop as Agile/XP people such as Martin Fowler, Andrew Hunt, Alistair Cockburn, Ron Jeffries, and John Brewer). This coincided with my increasing admiration of the writing styles of authors such as Gerald Weinberg and Martin Fowler (and probably also Alistair Cockburn) who always manage a fine balance between a confident and humble tone, speaking with authority, but also empathy, with an appreciation for complexity (and a corresponding avoidance of ideology), and with an attitude that says that the author is ready to be proven wrong.</p>
<p>I continue to strive for these ideals; I have found that the best writers in our field (Brooks, McConnell, DeMarco, Weinberg, Glass, Parnas, Yourdon, Spolsky, Wiegers, and too many more to mention) exhibit these qualities. I think what these writers have is more than a highly developed writing style; I believe these people have also been in the software game long enough to have been humbled by software, by computing machines, and by the enormous difficulty of pulling together teams of people to make all that software stuff happen. These words of Gerald Weinberg, quoted from his personal biography on his web site, have always been a great inspiration to me:</p>
<blockquote><p>After almost 40 years working with computers, I've learned a couple of things, but I still can't make sense out of most of it. Most of all, I've discovered that people are at the bottom of just about every problem - but I think I knew that when I was little, then got talked out of it somewhere along the way. I've worked hard at relearning this lesson, and learning how to do something about it. While educating myself, I learned a second principle: I'm the "people" at the bottom of most of my problems.</p></blockquote>
<p>When I first read that it about knocked me over, and went and re-read <a href="http://www.developerdotstar.com/mag/bookreviews/read_understanding.html">Understanding the Professional Programmer</a> in a whole new light. The move from being DeveloperDotStar's only author into the role of editor and curator allowed me to gain some distance from my own writing, to process some of these insights, and to focus more on my own growth as a software professional and a person. In the meantime, I was able to work with some great people who contributed so much to this site from the Summer of 2003 until now.</p>
<p>The first article published the "new" developer.* was by Danny Faught, another attendee of the aforementioned PSL workshop and a talented writer (mostly on QA-related topics). It was called "<a href="http://www.developerdotstar.com/mag/articles/faught_testfirst.html">Diving in Test-First</a>." We published it on July 26, 2003, just over two years after "<a href="http://www.developerdotstar.com/mag/articles/read_princprog.html">Principled Programming</a>." I will be eternally grateful to Danny for contributing it, and to every other writer who contributed writing to this site in the three years since. (You can check out the full list of edited articles published on this <a href="http://www.developerdotstar.com/mag/articles_top.html" title="Software Development Articles Published in DeveloperDotStar Magazine">here</a>.) </p>
<p>I posted the first official blog post to developer.* on Halloween (October 31st) of 2004. It was titled, predictably, "Welcome." Since then, the blogging platform of developer.* has seen its share of periods of high activity as well as slow times. The original idea was called the "<a href="http://www.developerdotstar.com/community/node/262">developer.* Cooperative Digest</a>," and it was to be a "community blogging platform." Partly this was driven by the limited individual blog personalization capabilities of the open source CMS framework we adopted, Drupal (an unfortunate flaw to this day in this otherwise best-in-class tool), but the "Cooperative Digest" idea was also based on the seeming promise of community-based blogging.</p>
<p>We've had surges of blogging over the years, followed always by lulls whenever the inspiration for the surge wears off. Partly I know that my own inconsistency as a contributor to the blogs and discussion have been a large factor in the failure to sustain a thriving community of bloggers. But I try not to feel too bad about it since none of early attempts at creating a community blogging space has really survived. Instead, the blogosphere has evolved into a true distributed network, with each blogger controlling his or her own node, connected but still apart. Things like social bookmarking and wikis have instead provided the glue. My deepest thanks go out to the many people who have blogged or commented here--most especially the indefatigable Edward Nilges, who was one of the first bloggers to join the "Cooperative Digest"; Edward has never needed my prodding or guidance to share his unique viewpoint on software, philosophy, culture, and politics. (There are too many other names to mention, and I fear if I start I'll miss someone important.)</p>
<p>The future of blogging on the developer.* web site remains uncertain. I can say for sure, however, that I have no regrets about our experimentation thus far with various blogging ideas for one reason: some really great writing has been posted here, all without me standing in the middle as editor. It has been a great complement to the edited articles side of the site, and has filled in during many quiet times between edited articles.</p>
<p>Over the years I've stubbornly kept the developer.* web site free of a commercial focus. This comes from my vision of developer.* as an "indie" enterprise, inspired partly by <a href="http://en.wikipedia.org/wiki/Bbs">BBS</a> sysops (in the days before the web hit big I spent many late night hours in on independently operated BBS systems and reading Jack Rickard's wonderful <a href="http://en.wikipedia.org/wiki/Boardwatch"><i>Boardwatch Magazine</i></a>), partly by the many small press zines I used to read in college by the stack (anyone else remember <a href="http://en.wikipedia.org/wiki/Factsheet_Five"><i>Factsheet Five</i></a>?), and partly by the example of great indie record labels like <a href="http://en.wikipedia.org/wiki/SST_Records">SST</a>, <a href="http://en.wikipedia.org/wiki/Touch_%26_Go">Touch and Go</a>, and <a href="http://en.wikipedia.org/wiki/Dischord">Dischord</a>.  </p>
<p>I was also deeply affected by what happened to software publishing, especially on the web, during and after the great gold rush circa 1997-2001: many of the best sites on the web, which had been created by people just like me, people who might have been BBS sysops or zine editors a decade before, were bought up by exceedingly lame big media companies who promptly covered the sites with ads, popups, and tracking cookies, locked the good content behind passwords, and started spamming their mailing lists with "newsletters" and "special offers from partners" every two hours or so. (The new site <a href="http://www.infoq.com/">InfoQ</a> gives me hope that the future of commercially oriented software development publishing will be brighter. I could give other examples of excellent sites that are operating now in the post-media-consolidation era, but I'll resist further distraction from the present topic...)</p>
<p>Our independent posture will hopefully continue, but the nature of the game has changed somewhat with the most recent step in the evolution of developer.*: the new <a href="http://www.developerdotstar.com/books/softwaredevelopmentbooks.html">developer.* Books</a> publishing enterprise, in which I am joined by my business and life partner, Gayle Devereaux. By necessity of survival, and in order to do the right thing by the authors who sign up to have their books published by us (nothing is more disheartening to an author than to have his or her book disappear when the publisher goes under), developer.* Books must operate as a business, independent spirit or not. It may be a number of years before it's a business that will pay anyone a full salary, but it is much more a business than a hobby, as the web site has always been.</p>
<p>As such, developer.* Books requires a more serious commitment of time and energy. This commitment to book publishing must be balanced with the fact that I still have a challenging day job designing and building software for my employer's clients, with the demands of keeping up a web site, with promises already made to writers with articles in the works, and with all of the other important aspects of life.</p>
<p>Books have always been a passion of mine, and the chance to be involved in their development and production was something I could not resist. 2006 saw the publication of our first two books, <a href="http://www.developerdotstar.com/books/software_conflict_glass.html"><i>Software Conflict 2.0</i></a> and <a href="http://www.developerdotstar.com/books/software_creativity_glass.html"><i>Software Creativity 2.0</i></a>, both by software luminary Robert L. Glass. We are immensely proud of these two books, not only because they are fine books, but also because they ask critical questions and offer important insights for the field of software. Most importantly, they are excellent examples of what we have always searched for as a publisher of software writing: a timeless quality. We have more books in the works (stay tuned for announcements in the near future).</p>
<p>An early version of draft of this long post you are reading about the past and future of developer.* (which I have been trying to finish writing for two months) started off with this hook sentence: <i>developer.* has a big problem: me.</i> The current draft you are reading (for the few who have made it this far) does not start off this way, but the sentiment still holds because it reflects perfectly what happened in 2006: I tried to take on way too much, said "Yes!" too often, indulged too many of my ambitious ideas for the Great Web and Book Publishing Company In the Sky, and made promises I couldn't keep. I don't like letting people down, and I did that a lot last year--so much so that here it is the end of February 2007, and I have yet to finish picking up the pieces from what fell off of my overfull plate in 2006.</p>
<p>(If you're one of the people who are wondering if I fell off the face of the earth, please accept for now my sincere apology in this public forum; I hope to catch up person-to-person soon. I was voted Most Dependable by my 1987 high school class, believe it or not--a date which puts me squarely in mid life crisis territory. My dad bought a <a href="http://www.cardomain.com/ride/2120726">1985 Mustang GT 5.0</a> for his mid life crisis; I started a book publishing company...there's something backwards about that. Interestingly, another thing that happened to me at the end of 2006 is that I realized that I was devoting too much energy to my online life, to "virtual" things; I think my dad had the right idea with that Mustang; I think it made him feel more connected to something <i>real</i>, something connected to physical things like gravity and torque, something directly under his control.) </p>
<p>Which brings us to now, looking ahead. What is the future of developer.*?</p>
<p>I can't say for sure, other than to say that as a general matter developer.* will hopefully be around for at least another five years. I can also say for sure that the book publishing side of developer.* must remain my primary focus. That ship has left the port, and I have to steer it. Not to mention, I'd like to repeat as often as possible that wonderful feeling that comes from holding in your hand the first copy of a new book, hot off the press, as they say. (In the case of <i>Software Conflict 2.0</i>, I go to repeat the experience again when the new <a href="http://www.developerfarm.co.kr/JSPWiki/Wiki.jsp?page=SoftwareConflict">Korean edition</a> arrived in my mailbox.) </p>
<p>However, I still feel strongly that the developer.* web site is an important outlet for diverse software writing, particularly by less experienced writers, whom I have always enjoyed working with, no matter how many drafts it took to get the article in first class shape. In some ways the blogosphere, which gives everyone his or her own publishing platform, supplants the need for a "magazine" of edited articles based on gift culture principles, but I believe there will always be room for edited articles. Writers want to write them, and readers want to read them. The problem is that I just can't keep up with both the articles and the books.</p>
<p>So what to do? If you have any ideas, I'd love to hear them. My best idea at this point is that developer.* needs one or more volunteer articles editors; this person or persons would work with writers to get articles ready for publication. I've got several excellent pieces in the hopper from last year (if the authors have not given up on me altogether), and I get emails every week or so from new and established authors seeking a home for their work. Ideally, this person or persons would also share with me a passion for our unique content niche: diverse, general interest, mostly non-technology-specific, articles, essays, and interviews with, as we like to say, "a timeless quality." The person or persons would also need to share the "indie" spirit of the web site, which pretty much means that it will remain for the foreseeable future a non-money-making enterprise. (I'd rather shift the web site into archive mode than give that up.) The job also requires (despite my own shortcomings in some or all of these areas) the basic traits of all editors: strong opinions; a passion for writing; some knowledge of grammar and language mechanics; a willingness to be frank; and perhaps most importantly generosity, empathy, and patience.</p>
<p>This would be a tall order even if I was offering money for the job. Unfortunately, there is no money to offer. The work is its own reward, as I can attest. I regret in some ways that my own journey has brought me to a place where I cannot make room for it any longer.</p>
<p>Maybe, here in the midst of Web 2.0, there is a technical solution to this problem: a web-based software platform that will "harness the crowd" to turn ideas and rough drafts into polished, edited, articles. Kind of like a Web 2.0 writing workshop, but with a very pragmatically focused end game: the edited and polished article can be published right here on the developer.* web site once the process and people have deemed it ready.</p>
<p>I welcome any thoughts, comments, questions, and/or ideas you may have related to anything in this post. Feel free to use the comments form to share them, or if you prefer <a href="http://www.developerdotstar.com/mag/contact.html">email me privately</a>. I am honored and humbled by your interest.</p>
<p>Thanks for reading,<br />
Dan</p>
<p>P.S.<br />
As for my own writing, I do plan to get back some day to doing more than writing the occasional blog post. I have two software books that have been in the works for some time (really, for as long as there has been a developer.*), and when the time is right I aim to finish them. I believe that both will have that elusive "timeless quality" and will be worthwhile contributions to the field. I also believe that while curating, editing, and publishing have in some sense been distractions from the writing, these activities have also made me a better writer and a better person (it's hard to achieve the former without the latter, I think), so no regrets here. If having a mid life crisis has taught me one thing, it's that there is little time in this life for regrets.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Calling All Death Marchers</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/712" />
    <id>http://www.developerdotstar.com/community/node/712</id>
    <published>2007-02-25T08:53:19-08:00</published>
    <updated>2007-03-01T15:03:43-08:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="Career and Profession" />
    <category term="Software Development Books Blog" />
    <summary type="html"><![CDATA[<p>Author Ed Yourdon is working on a third edition to his well known book about agonizingly bad software projects, <a href="http://www.amazon.com/Death-March-Second-Edward-Yourdon/dp/013143635X/developerdots-20"><i>Death March</i></a>. Mr. Yourdon has also recently wikified one of his classic books, <i>Modern Structured Analysis</i>.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>Author Ed Yourdon is working on a third edition to his well known book about agonizingly bad software projects, <a href="http://www.amazon.com/Death-March-Second-Edward-Yourdon/dp/013143635X/developerdots-20"><i>Death March</i></a>. In a <a href="http://yourdon.com/personal/blog/2007/02/18/i-need-your-help-for-a-new-edition-of-death-march/">recent blog post Yourdon sent out a call to software professionals to share their death march stories</a>:</p>
<blockquote><p>If you’re just embarking upon a death-march project, and you want to share the agony and the ecstasy with all of us in the blogosphere, get in touch with me. If you’ve been trapped in a death-march project for six months, and you desperately want to tell everyone what went wrong, and/or why nobody else should suffer a similar fate, send me an email. If you’ve finished an amazingly complex, high-pressure death-march project with triumphant success, and you want to share your secrets with everyone else, let me know. If it was a tool, or a technology, or a methodology, or an amazing management approach that turned out to be the difference between success and failure, track me down and tell me.</p></blockquote>
<p>This is your chance to have your tale of woe enshrined in an important book, and maybe your story can help someone else down the road.</p>
<p>Speaking of Ed Yourdon and important books, Mr. Yourdon has also recently taken a very interesting publishing leap that should be getting more attention: he has converted his book <i>Modern Structured Analysis</i> into a <a href="http://www.yourdon.com/strucanalysis/wiki/index.php?title=Introduction">free and open wiki</a>. (As far as I can tell, Mr. Yourdon has now released the text under the GNU license.) The new version is called <a href="http://www.yourdon.com/strucanalysis/wiki/index.php?title=Introduction"><i>Just Enough Structured Analysis</i></a>. He blogs about the project, and how you can participate, <a href="http://yourdon.com/personal/blog/2007/02/19/jesa-wiki-is-completely-uploaded/">here</a>. I've been digging into the wiki, and not only is the wiki itself extremely well done, but much of the material is still very relevant and readable.</p>
<p>All the best,<br />
Dan</p>
    ]]></content>
  </entry>
  <entry>
    <title>Quick Fixes for SLOW DataGridView</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/706" />
    <id>http://www.developerdotstar.com/community/node/706</id>
    <published>2007-02-07T12:58:55-08:00</published>
    <updated>2007-02-07T12:58:55-08:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term=".NET" />
    <summary type="html"><![CDATA[<p>After learning that you really don't want to try using the DataGridView in unbound mode (just get your data into a DataTable and let binding do the heavy lifting--binding doesn't suck anymore!), I had to next learn that the DataGridView can be really, really slow after you get more than a trivial amount of data in it. Here are a few tips.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>After learning that you really don't want to try using the DataGridView in unbound mode (just get your data into a DataTable and let binding do the heavy lifting--binding doesn't suck anymore!), I had to next learn that the DataGridView can be really, really slow after you get more than a trivial amount of data in it.</p>
<p>For example, in a winforms app I'm working on, with a couple thousand rows in it, the grid would pause for up two seconds after the user clicked a checkbox in a cell. Ouch. The grid was also very slow to load, even using some tricks with SuspendLayout() and ResumeLayout().</p>
<p>Turns out all this slowness is due to painting issues, not data issues. Before you give up on the DataGridView as hopelessly slow, try these things:</p>
<p>* Set both AutoSizeColumnsMode and AutoSizeRowsMode to "None." If you want to call the AutoSizeColumns() method one time after you load the grid, that works pretty well, especially if you auto size based on the headers. You can also resize certain columns using the AutoSizeColumn() method or by setting a literal value for the Width propery.</p>
<p>* Set EnableHeadersVisualStyles to False. You will lose a little bit of "slickness" in your grid's appearance, but it will speed up considerably. It seems that enabling this feature makes the grid "inherit" its visual style from the OS style. Check the documentation or intellisense for a more specific description.</p>
<p>* I saw a suggestion on <a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=117093">this page</a> to turn off cell borders (CellBorderStyle = DataGridViewCellBorderStyle.None), but I did not try this one myself.</p>
<p>That <a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=117093">same page</a> linked above also confirms that the .NET 2.0 DataGridView is slower than the .NET 1.1 DataGrid. They must not have done a lot of testing with the autosizing and visual styles turned on. Hopefully a future release will improve things, but I shall not be holding my breath since I half suspect Microsoft is going to start letting winforms languish in favor of WPF...</p>
<p><a href="http://blogs.msdn.com/jfoscoding/archive/2005/11/16/493727.aspx">This page also points to a DataGridView FAQ</a> document that has some useful information.</p>
<p>Hope that helps,<br />
Dan</p>
    ]]></content>
  </entry>
  <entry>
    <title>C# and VB.NET IsNumeric() and IsDate() Functions</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/672" />
    <id>http://www.developerdotstar.com/community/node/672</id>
    <published>2006-12-04T12:46:32-08:00</published>
    <updated>2006-12-08T13:05:13-08:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term=".NET" />
    <category term="C#" />
    <category term="VB.NET" />
    <summary type="html"><![CDATA[<p>For some reason they left IsNumeric() and IsDate() functions out of .NET. I end up needing these is almost every non-trivial project. In this post I share C# and VB.NET versions of the functions I use. Your mileage may vary depending on your performance needs; if you're calling these thousands of times in a loop, then be sure to test them against alternate techniques. (<b>Updated</b> in light of new native IsNumeric() and IsDate() functions in VB.NET 2.0.)</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>As you have probably already realized if you found this page through a search, for some reason they left IsNumeric() and IsDate() functions out of .NET. I end up needing these is almost every non-trivial project.</p>
<p><b>Update</b>: I'm a little slow on the uptake, but a week after writing this post, I noticed that VB.NET now has intrinsic IsNumeric() and IsDate() functions; check the Microsoft.VisualBasic namespace. Keep reading, though, if you need these for C# or for VB.NET 1.x.</p>
<p>Your mileage may vary depending on your performance needs; if you're calling these thousands of times in a loop, then be sure to test them against alternate techniques. Here are C# and VB.NET versions of the functions I use:</p>
<p>C# IsNumeric() Function</p>
<p>Double.TryParse() is available in .NET 1.1 and 2.0, so this function works with either.</p>
<div class="codeblock">
<pre>public static bool IsNumeric(string anyString)<br />{<br />    if (anyString == null)<br />    {<br />        anyString = &quot;&quot;;<br />    }<br />    if (anyString.Length &gt; 0)<br />    {<br />        double dummyOut = new double();<br />        System.Globalization.CultureInfo cultureInfo = <br />            new System.Globalization.CultureInfo(&quot;en-US&quot;, true);<br />        <br />        return Double.TryParse(anyString, System.Globalization.NumberStyles.Any, <br />            cultureInfo.NumberFormat, out dummyOut);<br />    }<br />    else<br />    {<br />        return false;<br />    }<br />}</pre></div>
<p>C# 1.1 IsDate() Function</p>
<p>Since we're assuming a strongly typed language, if the value already exists in a DateTime variable, then we can assume that it is a valid value. So we start with the assumption that the user has the value in a string or something easily converted to a string. This routine is .NET 1.1 compatible since we're not using DateTime.TryParse().</p>
<div class="codeblock">
<pre>public static bool IsDate(string anyString)<br />{<br />    if (anyString == null)<br />    {<br />        anyString = &quot;&quot;;<br />    }<br />    if (anyString.Length &gt; 0)<br />    {<br />        DateTime dummyDate = null;<br />        try<br />        {<br />            dummydate = DateTime.Parse(anyString);<br />        }<br />        catch<br />        {<br />            return false;<br />        }<br />        return true;<br />    }<br />    else<br />    {<br />        return false;<br />    }<br />}</pre></div>
<p>An alternate variation removes some of the cohesion from the routine, but you could also make resultDate variable in this an 'out' argument and make it that much easier for the caller to get a DateTime value once it's been confirmed that the value is indeed a date; (this is basically how the DateTime.TryParse() function added in .NET 2.0 works, anyway, so it's not inconsistent). Here is my version of this alternate syntax. In C# it's easy enough to offer overloaded versions of both (also .NET 1.1 compatible):</p>
<div class="codeblock">
<pre>public static bool IsDate(string anyString, out DateTime resultDate)<br />{<br />    bool isDate = true;<br /><br />    if (anyString == null)<br />    {<br />        anyString = &quot;&quot;;<br />    }<br />    try<br />    {<br />        resultDate = DateTime.Parse(anyString);<br />    }<br />    catch<br />    {<br />        resultDate = DateTime.MinValue;<br />        isDate = false;<br />    }<br /><br />    return isDate;<br />}</pre></div>
<p>VB.NET IsNumeric() Function</p>
<p>Double.TryParse() is available in .NET 1.1 and 2.0, so this function works with either.</p>
<div class="codeblock">
<pre>Public Shared Function IsNumeric(ByVal anyString As String) As Boolean<br />    If anyString Is Nothing Then<br />        anyString = &quot;&quot;<br />    End If<br />    If anyString.Length &gt; 0 Then<br />        Dim dummyOut As Double = New Double()<br />        Dim cultureInfo As System.Globalization.CultureInfo = _<br />            New System.Globalization.CultureInfo(&quot;en-US&quot;, True)<br /><br />        Return Double.TryParse(anyString, System.Globalization.NumberStyles.Any, _<br />            cultureInfo.NumberFormat, dummyOut)<br />    Else<br />        Return False<br />    End If<br />End Function</pre></div>
<p>VB.NET 2.0 IsDate() Function</p>
<p>This code will only work in .NET 2.0 and above, since it depends on DateTime.TryParse(), which was not added until 2.0. If you need a VB.NET 1.1 IsDate() function you can rewrite the C# 1.1 version above without too much trouble.</p>
<div class="codeblock">
<pre>Public Shared Function IsDate(ByVal anyString As String) As Boolean<br />    If anyString Is Nothing Then<br />        anyString = &quot;&quot;<br />    End If<br />    If anyString.Length &gt; 0 Then<br />        Dim dummyOut As Date = Nothing<br />        Return DateTime.TryParse(anyString, dummyOut)<br />    Else<br />        Return False<br />    End If<br />End Function</pre></div>
    ]]></content>
  </entry>
  <entry>
    <title>.NET BackgroundWorker Mysteries Solved</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/671" />
    <id>http://www.developerdotstar.com/community/node/671</id>
    <published>2006-12-04T09:48:29-08:00</published>
    <updated>2006-12-04T13:21:54-08:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term=".NET" />
    <summary type="html"><![CDATA[<p>I've found the BackgroundWorker to be very handy, but a little tricky to start using at first. I like that it has built-in support for reporting incremental progress for a long-running operation, and that it has a simple way of allowing a long-running operation to be canceled. And the big benefit, of course, is that your form remains responsive to the user and the operating system as it runs on the main UI thread. But there are some subtleties I had to overcome that are not covered in the documentation, especially in the area of exception handling.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>I'm coding a multi-tier VB.NET winforms application, and decided to take advantage of the BackgroundWorker object from the System.ComponentModel namespace for any cases where code in one of my forms is calling down to methods in one of the application's DLLs. For those not familiar, the BackgroundWorker is a simplified wrapper for situations where you want to implement multi-threading for your GUI-centric application without messing around with the thread plumbing yourself. (And for those wondering why not C#, I've chosen VB.NET because of the very handy <a href="http://msdn.microsoft.com/msdnmag/issues/06/00/VisualBasic2005/default.aspx">Application Framework</a> that is not available for C#, but that's a story for another post.)</p>
<p>I've found the BackgroundWorker to be very handy, but a little tricky to start using at first. I like that it has built-in support for reporting incremental progress for a long-running operation, and that it has a simple way of allowing a long-running operation to be canceled. And the big benefit, of course, is that your form remains responsive to the user and the operating system as it runs on the main UI thread. For a basic tutorial, <a href="http://msdn2.microsoft.com/en-us/library/hybbz6ke.aspx">MSDN has you pretty well covered</a>. But there are some subtleties I had to overcome that are not covered in the documentation, especially in the area of exception handling.</p>
<p><a href="http://msdn2.microsoft.com/en-us/library/system.componentmodel.backgroundworker.dowork.aspx">This entry on MSDN about the BackgroundWorker.DoWork() event</a> contains the following paragraph:</p>
<blockquote><p>If the operation [that you call from your DoWork() handler] raises an exception that your code does not handle, the BackgroundWorker catches the exception and passes it into the RunWorkerCompleted event handler, where it is exposed as the Error property of RunWorkerCompletedEventArgs. If you are running under the Visual Studio debugger, the debugger will break at the point in the DoWork event handler where the unhandled exception was raised.</p></blockquote>
<p>That's all good, but what MSDN fails to mention is that "unhandled" means that this DoWork() handler must not have Try-Catch block around any of its code. We need to let the error happen unhandled, and then the backgroundworker will take care of getting it to the RunWorkerCompleted() handler. I spent some frustrating time being stuck on this point, because it is my normal practice to put a Try-Catch block in *all* event handlers, because an event handler is effectively the top of the stack. The DoWork() handler is now my one exception to this rule. If you want the control to behave as advertised, then you need to let errors bubble up from your DoWork() handler as advertised.</p>
<p>There is another reason to make sure that you conform to the BackgroundWorker's exception handling model: if you want to manipulate any of your form's controls when an exception comes out of DoWork(), then you *cannot* do that in your DoWork() handler. It's very common to need to do something on your form after an exception, such as disabling a button or changing a label. This must be done in your RunWorkerCompleted() handler, as confirmed by MSDN:</p>
<blockquote><p>You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the BackgroundWorker events.</p></blockquote>
<p>As long as you don't put a Try-Catch block in your DoWork() handler, you should fine on this point. However, as soon as you craft your code to work this way, you'll run into another effectively undocumented issue: in a debugging scenario, whether you launched the app from within the IDE or from a compiled debug assembly, whenever you have an exception in any of the code that is called from the DoWork() handler, the debugger will stop on what it of course sees as an unhandled exception--damned if you do, damned if you don't.</p>
<p>If you "handle" the exception with a Try-Catch block in the DoWork() handler, the BackgroundWorker won't work, but as soon as you leave it out, the debugger implements it well intentioned by mostly just annoying behavior of stopping on the line that produced the exception. The trick to get around this is to decorate your code with the DebuggerNonUserCodeAttribute attribute from the System.Diagnostics namespace. I discovered this trick in <a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=830881&amp;SiteID=1">this thread from the MSDN forums</a>. Here's what the attribute decoration of the DoWork() handler looks like in VB.NET:</p>
<div class="codeblock">
<pre>&lt;System.Diagnostics.DebuggerNonUserCodeAttribute()&gt; _<br />    Private Sub myBackgroundWorker_DoWork(ByVal sender As Object, _<br />        ByVal e As System.ComponentModel.DoWorkEventArgs) Handles verifyFileBWWorker.DoWork</pre></div>
<p>However, I had to take this a step further since in my case what I was calling from my DoWork() handler was a method on a class in a separate DLL assembly--in other words, I was calling code that did not reside within my form, but in another class. What I found was that the debugger still saw exceptions that happened in this child class's code as "unhandled." I solved this by adding the DebuggerNonUserCodeAttribute to the class decoration as well:</p>
<div class="codeblock">
<pre>&lt;System.Diagnostics.DebuggerNonUserCodeAttribute()&gt; _<br />Public Class MyClass</pre></div>
<p>Now my BackgroundWorker code behaves in a consistent way whether I'm debugging or not. (<b>Update:</b> an unfortunate side-effect of setting DebuggerNonUserCodeAttribute on the whole class is that the debugger won't visit that class at all, even when you set a breakpoint--so it looks like I'll have to put up with the debugger stopping on "unhandled" exceptions...)</p>
<p>Here's one more gem I was not able to find in the documentation: if, like me, you are implementing the code that you want to call with BackgroundWorker in a separate class and/or DLL (rather than keeping the code in the form, which the simplistic MSDN examples do--a practice I don't recommend if the code in question is not specifically presentation-oriented logic) then you will wonder how you are going to report progress back to the GUI, or check for a cancelation, down in that code that's outside the form. My solution to this was to provide a way for the form to pass the BackgroundWorker object down to the class method. However, part of my goal with putting my business logic is a separate DLL is to make it reusable in other contexts, and I don't want to tie in a hard assumption that the code is being called from a BackgroundWorker. So the way I did this is to make the BackgroundWorker optional in the class. This could be done with a Property, and then the code in the class method could check to see if it's been set:</p>
<div class="codeblock">
<pre>if (m_myBW != null)<br />{<br />    m_myBW.ReportProgress(50);<br />}</pre></div>
<p>You could also accomplish this by making the BackgroundWorker object an argument, but I recommend making the argument optional (in VB.NET) or using overloaded methods (in C#).</p>
<p>Implementing my first BackgroundWorker was more work than it needed to be, but I'll be implementing dozens of these in this application, so I expect the effort to pay dividends. Hopefully this article helps someone else get up to speed more quickly that I was able.</p>
<p>Hope that helps,<br />
Dan</p>
    ]]></content>
  </entry>
  <entry>
    <title>Watching Vista and .NET 3.0 from Afar</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/644" />
    <id>http://www.developerdotstar.com/community/node/644</id>
    <published>2006-11-13T20:34:30-08:00</published>
    <updated>2006-11-13T20:40:12-08:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term=".NET" />
    <category term="developer.* Links Blog" />
    <summary type="html"><![CDATA[<p>I remain behind the curve when it comes from the latest from Redmond, specifically Vista and the ".NET Framework 3.0" (the latter being a choice of name I'm still not sure I understand). I have not even seen Vista in person yet, and I'm only just now having some real fun with "old fashioned" Windows Forms coding in C# 2005, and Windows XP works pretty damn well, so...</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>I remain behind the curve when it comes from the latest from Redmond, specifically Vista and the ".NET Framework 3.0" (the latter being a choice of name I'm still not sure I understand). I have not even seen Vista in person yet, and I'm only just now having some real fun with "old fashioned" Windows Forms coding in C# 2005, and Windows XP works pretty damn well, so...</p>
<p>Not that I'm resisting--merely lagging. One of the things I like about my job is that it won't be long before our clients expect us to use this stuff.</p>
<p>For those who are not lagging as far behind as I, Charles Petzold does us a service with <a href="http://www.charlespetzold.com/blog/2006/11/080248.html">this collection of links to get going with ".NET Framework 3.0"</a>. When it comes time to get down with some XAML, it looks like Petzold's book will be the one to get (though based on my recent experiences with giganitc the XML files used by SQL Server Integration Services, I'm skeptical about--though admittedly ignorant of--more giant XML files to contend with in my day-to-day development).</p>
<p>Thanks for reading,<br />
Dan</p>
    ]]></content>
  </entry>
  <entry>
    <title>Does Software Need an Apgar Score?</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/635" />
    <id>http://www.developerdotstar.com/community/node/635</id>
    <published>2006-11-01T11:31:15-08:00</published>
    <updated>2006-11-01T14:30:20-08:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="Professional and Personal Development" />
    <category term="Quality" />
    <summary type="html"><![CDATA[<p>This morning I was reading the Oct 9, 2006 issue of <i>The New Yorker</i> magazine, which contains an interesting article called "<a href="http://www.newyorker.com/fact/content/articles/061009fa_fact">The Score: How childbirth went industrial</a>." The article is about the process of childbirth, and more specifically, the medical techniques and industry, for lack of a better word, that have developed around childbirth. When I started reading the article, I was not expecting to encounter an intriguing idea related to software development--but ideas often spring from unexpected sources.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>This morning I was reading the Oct 9, 2006 issue of <i>The New Yorker</i> magazine, which contains an interesting article called "<a href="http://www.newyorker.com/fact/content/articles/061009fa_fact">The Score: How childbirth went industrial</a>." The article is about the process of childbirth, and more specifically, the medical techniques and industry, for lack of a better word, that have developed around childbirth. When I started reading the article, I was not expecting to encounter an intriguing idea related to software development--but ideas often spring from unexpected sources.</p>
<p>The article narrates dramatic improvements that were achieved in childbirth and mortality rates in the 20th century. Author Atul Gawande describes a stark situation for childbirth in the U.S. in the 1930's:</p>
<blockquote><p>But in 1933 the New York Academy of Medicine published a shocking study of 2,041 maternal deaths in childbirth. At least two-thirds, the investigators found, were preventable. There had been no improvement in death rates for mothers in the preceding two decades; newborn deaths from birth injuries had actually increased. Hospital care brought no advantages; mothers were better off delivering at home. The investigators were appalled to find that many physicians simply didnâ€™t know what they were doing: they missed clear signs of hemorrhagic shock and other treatable conditions, violated basic antiseptic standards, tore and infected women with misapplied forceps. The White House followed with a similar national report. Doctors may have had the right tools, but midwives without them did better.</p></blockquote>
<p>The author then describes how childbirth was improved through standardization of techniques, training, and regulation of who exactly was allowed to perform certain procedures (based on whether they had the training and experience):</p>
<blockquote><p>These standards reduced the number of maternal deaths substantially. In the mid-thirties, delivering a child had been the single most dangerous event in a womanâ€™s life: one in a hundred and fifty pregnancies ended in the death of the mother. By the fifties, owing in part to the tighter standards, and in part to the discovery of penicillin and other antibiotics, the risk of death for a mother had fallen more than ninety per cent, to just one in two thousand.</p>
<p>But the situation wasnâ€™t so encouraging for newborns: one in thirty still died at birthâ€”odds that were scarcely better than those of the century beforeâ€”and it wasnâ€™t clear how that could be changed.</p></blockquote>
<p>Later in the article, the author describes huge improvements that came in the second half of the century:</p>
<blockquote><p>In the United States today, a full-term baby dies in just one out of five hundred childbirths, and a mother dies in one in ten thousand. If the statistics of 1940 had persisted, fifteen thousand mothers would have died last year (instead of fewer than five hundred)â€”and a hundred and twenty thousand newborns (instead of one-sixth that number).</p></blockquote>
<p>How did these huge improvements happen?</p>
<blockquote><p>...a doctor named Virginia Apgar, who was working in New York, had an idea. It was a ridiculously simple idea, but it transformed obstetrics and the nature of childbirth. ... she took a less direct, but ultimately more powerful, approach: she devised a score.</p>
<p>The Apgar score, as it became known universally, allowed nurses to rate the condition of babies at birth on a scale from zero to ten. An infant got two points if it was pink all over, two for crying, two for taking good, vigorous breaths, two for moving all four limbs, and two if its heart rate was over a hundred. Ten points meant a child born in perfect condition. Four points or less meant a blue, limp baby.</p>
<p>The score was published in 1953, and it transformed child delivery. It turned an intangible and impressionistic clinical conceptâ€”the condition of a newly born babyâ€”into a number that people could collect and compare. Using it required observation and documentation of the true condition of every baby. Moreover, even if only because doctors are competitive, it drove them to want to produce better scoresâ€”and therefore better outcomesâ€”for the newborns they delivered.</p></blockquote>
<p>Is anyone else seeing the parallels to software development here? Am I off base thinking that the idea of a simple "score" to assess the "health" or "quality" of a software system could be a powerful tool, as it was, apparently, for obstetrics? Such a score, I think, would have to be as simple as described above for the Apgar score, based on easily observable phenomena, and only marginally dependent on subjective factors.</p>
<p>Typical "ility" descriptors used often in software circles would, I think, be ineffective in this context. Is the software maintainable? Is the software secure? These are too fuzzy, too broad, too open to interpretation. We need things more like, is the baby pink or blue? Is the baby crying?</p>
<p>Does the application have an exception handling scheme, or doesn't it? Is there clean separation of presentation logic and business logic, or isn't there? These are things that can be assessed relatively objectively by someone with the proper knowledge and experience.</p>
<p>I've spent the last five months on my day job spelunking through our client's entire enterprise of back office and web software systems, reading tons of old code, combing through databases, and trying to make sense of arcane user interfaces. All this has resulted in about 500 pages of maintenance documentation for my client, who recently purchased a company and wanted to know whether the software it purchased would scale up for further growth and acquisition. I've done similar system assessments many times in the past (though not usually this large), and my gut tells me that assigning a score to each of the systems I've examined would be very useful to my client.</p>
<p>On the front side, with a known scoring system in mind, is the novice (or even "senior") developer more likely to produce software that at least attempts to implement the necessary elements to achieve a respectable score? Would developers working in team environments encounter the same peer-related effects as seen in obstetrics?</p>
<blockquote><p>The Apgar score changed everything. It was practical and easy to calculate, and it gave clinicians at the bedside immediate information on how they were doing. In the rest of medicine, we measure dozens of specific things: blood counts, electrolyte levels, heart rates, viral titers. But we have no measure that puts them together to grade how the patient as a whole is faring. Itâ€™s like knowing, during a basketball game, how many blocked shots and assists and free throws you have had, but not whether you are actually winning. We have only an impression of how weâ€™re performingâ€”and sometimes not even that.</p></blockquote>
<p>More parallels with software development abound in this article about birthing babies:</p>
<blockquote><p>Thereâ€™s a paradox here. Ask most research physicians how a profession can advance, and they will talk about the model of â€œevidence-based medicineâ€â€”the idea that nothing ought to be introduced into practice unless it has been properly tested and proved effective by research centers, preferably through a double-blind, randomized controlled trial. But, in a 1978 ranking of medical specialties according to their use of hard evidence from randomized clinical trials, obstetrics came in last. Obstetricians did few randomized trials, and when they did they ignored the results.</p></blockquote>
<p>...</p>
<blockquote><p>The question facing obstetrics was this: Is medicine a craft or an industry? If medicine is a craft, then you focus on teaching obstetricians to acquire a set of artisanal skillsâ€”the Woods corkscrew maneuver for the baby with a shoulder stuck, the Lovset maneuver for the breech baby, the feel of a forceps for a baby whose head is too big. You do research to find new techniques. You accept that things will not always work out in everyoneâ€™s hands.</p>
<p>But if medicine is an industry, responsible for the safest possible delivery of millions of babies each year, then the focus shifts. You seek reliability. You begin to wonder whether forty-two thousand obstetricians in the U.S. could really master all these techniques.</p></blockquote>
<p>For the record, I've always been skeptical of software engineering metrics and their usefulness in the software shops where I've worked. (See my "Balance in Scoring" comment, below.) But something about the directness, simplicity, and apparent effectiveness of the Apgar score struck me. The author of this article, himself <a href="http://www.hsph.harvard.edu/faculty/AtulGawande.html">a physician at the Harvard School of Public Health</a>, was it seems struck by it also:</p>
<blockquote><p>In a sense, there is a tyranny to the score. Against the score for a newborn child, the motherâ€™s pain and blood loss and length of recovery seem to count for little. We have no score for how the mother does, beyond asking whether she lived or notâ€”no measure to prod us to improve results for her, too. Yet this imbalance, at least, can surely be righted. If the childâ€™s well-being can be measured, why not the motherâ€™s, too? Indeed, we need an Apgar score for everyone who encounters medicine: the psychiatry patient, the patient on the hospital ward, the person going through an operation, and the mother in childbirth. My research group recently came up with a surgical Apgar scoreâ€”a ten-point surgical rating based on the amount of blood loss, the lowest heart rate, and the lowest blood pressure that a patient experiences during an operation. We still donâ€™t know if itâ€™s perfect. But all patients deserve a simple measure that indicates how well or badly they have come throughâ€”and that pushes the rest of us to innovate.</p></blockquote>
<p>Even if this is a good idea for software, obviously many details would need to discussed and worked out. For example, would we really need multiple scoring systems for different kinds of software? However, I'll stop writing at this point and assess whether there is any further interest in this idea. What do you think?</p>
<p>Thanks for reading,<br />
Dan</p>
<p>P.S.<br />
I've quoted heavily from it here, but I recommend the <a href="http://www.newyorker.com/fact/content/articles/061009fa_fact">full article</a> as a worthwhile read.</p>
    ]]></content>
  </entry>
  <entry>
    <title>Core Software Reading with Scott Rosenberg</title>
    <link rel="alternate" type="text/html" href="http://www.developerdotstar.com/community/node/604" />
    <id>http://www.developerdotstar.com/community/node/604</id>
    <published>2006-10-13T09:06:41-07:00</published>
    <updated>2006-10-13T10:11:56-07:00</updated>
    <author>
      <name>Daniel Read</name>
    </author>
    <category term="developer.* Links Blog" />
    <summary type="html"><![CDATA[<p>I just came across something cool, Scott Rosenberg's <a href="http://www.wordyard.com/category/code-reads/">Code Reads project</a>, in which Scott presents a series of "core" reading material in the software field. Each suggested reading has a companion discussion (open to all to participate) to go with it.</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>I just came across something cool, Scott Rosenberg's <a href="http://www.wordyard.com/category/code-reads/">Code Reads project</a>, in which Scott presents a series of "core" reading material in the software field. Each suggested reading has a companion discussion (open to all to participate) to go with it. Scott started a few weeks ago with <a href="http://www.wordyard.com/2006/10/02/mythical-man-month/"><i>The Mythical Man-Month</i></a>, and followed up with Djikstra's famous essay "<a href="http://www.wordyard.com/2006/10/10/dijkstra-goto/">Go To Statement Considered Harmful</a>." Coming up next is a <a href="http://www.wordyard.com/2006/10/12/code-reads-progress-report/">set of three more</a> essays by Djikstra (one of which is a big favorite of mine, "<a href="http://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html">The Humble Programmer</a>").</p>
<p>I'v been a big fan of Scott Rosenberg's writing for several years now at <a href="http://www.salon.com">Salon.com</a>, which he co-founded. (I happen to mostly identify with the political slant at Salon.com, but even if you don't, in my opinion you have to admire the way they have survived and thrived as an online-only publication through many years that people said they'd never make it--Scott's role on the technology side of Salon, not to mention his autorial and editorial roles, were a big part of that success.)</p>
<p>Scott has a new software-related book coming out in January 2007, which sounds interesting. It's called <a href="http://www.dreamingincode.com/"><i>Dreaming in Code</i>,</a> and it will be published by mainstream trade publisher Crown--a feat for which Scott deserves a special congratulations. We'll offer more coverage of the book here in the future.</p>
<p>Dan</p>
    ]]></content>
  </entry>
</feed>
