<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-2088901786978801075</atom:id><lastBuildDate>Fri, 02 May 2025 06:19:44 +0000</lastBuildDate><category>Software Development</category><category>Musings</category><category>Best Practices</category><category>Technology</category><category>Productivity</category><category>.NET</category><category>Open Source</category><category>Quality</category><category>Testing</category><category>NValidate</category><category>VB.NET</category><category>Code Reviews</category><category>Spam</category><category>Batman</category><category>C#</category><category>OSS</category><category>Refactoring</category><category>Unit Testing</category><category>Usability</category><category>Validation</category><category>BCL</category><category>City of Heroes</category><category>CodeQuality</category><category>Generics</category><category>JavaScript</category><category>Microsoft</category><category>NDoc</category><category>Ninja</category><category>Release Engineering</category><category>SCC</category><category>SQL</category><category>Sandcastle</category><category>Software Maintenance</category><category>SoftwareDevelopment</category><title>Coding from the Trenches</title><description>&lt;i&gt;A blog from a grizzled software veteran with no formal education.&lt;/i&gt;</description><link>http://mikehofer.blogspot.com/</link><managingEditor>noreply@blogger.com (Mike Hofer)</managingEditor><generator>Blogger</generator><openSearch:totalResults>64</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-5914925819955990734</guid><pubDate>Wed, 16 Mar 2011 02:53:00 +0000</pubDate><atom:updated>2011-03-15T22:53:25.090-04:00</atom:updated><title>The Sanctity of Life</title><description>&lt;p&gt;Over the years, I’ve often heard those of a religious background preach about the “sanctity of life.” They do so as if their membership in a religious organization gives them some special insight into what “sanctity of life” means. To a certain degree, I suppose they’re right. After all, &lt;em&gt;sanctity&lt;/em&gt;&amp;#160; means, in essence, holiness. But to the layman, what it means is that you shouldn’t take it lightly, you shouldn’t corrupt it, and you screw with it at your own peril.&lt;/p&gt;  &lt;p&gt;Now, if you don’t believe in God, or any particular god, &lt;em&gt;sanctity &lt;/em&gt;is probably best replaced with a more apt term. Something akin to &lt;em&gt;rare&lt;/em&gt;, though it fails to capture the essence of the idea on a colossal scale.&lt;/p&gt;  &lt;p&gt;See, religious folks seem to think that you need to have religious morals to appreciate the sanctity of life. But that’s simply not so. Let me explain my point of view to you.&lt;/p&gt;  &lt;p&gt;We’ll start by putting things in perspective. The age of our universe is currently calculated at somewhere between 12 and 14 billion years old. That’s about 2 years for every single person living on this planet in the year 2010 (6.91 billion, according to the US Census Bureau). Our sun, however, has only existed for 4.5 billion of those years. So we have more people on the planet than we have years for the sun. Further, human beings have only existed as a genus for a few million years. We have &lt;em&gt;way &lt;/em&gt;more people on the planet than years that people, in general, have been hanging around.&lt;/p&gt;  &lt;p&gt;So what does that mean? What it means is that the universe is &lt;em&gt;ancient. &lt;/em&gt;You, however, will live, at most, if you are extremely lucky and blessed with very long life, good genes, and a phenomenal health and dental plan, 120 years. Get that? 120 years compared to the 4,500,000,000 that mark the age of the sun alone. 120 compared to the 14,000,000,000 that mark the age of the &lt;em&gt;universe.&lt;/em&gt; &lt;/p&gt;  &lt;p&gt;Don’t ever tell me you feel old again. There are dust particles floating in orbit that were around during the Triassic period.&lt;/p&gt;  &lt;p&gt;You get 120 lousy years. Billions of years the universe has been around, and you get, at most 120. Most of us won’t ever get anywhere near that. We’ll be lucky to hit 70.&lt;/p&gt;  &lt;p&gt;Now, let’s leave our age out of the picture, and consider not just the age of the universe, but its sheer size for a moment. &lt;/p&gt;  &lt;p&gt;Our nearest neighbor is a lovely little star named Proxima Centauri. It’s a paltry 4.2 light years distant. Now, as anyone knows, light travels at the mind-numbingly slow velocity of 186,000 miles per second. Here on earth, that’s so fast that it’s virtually instantaneous. But when you start travelling across interstellar distances, things change, and quickly.&lt;/p&gt;  &lt;p&gt;Imagine, for example, that you had a colony on a planet circling Proxima Centauri. Then, imagine, that you wanted to send a text message to the folks on Proxima Centauri, updating them about the latest episode of Glee. (Hey, someone’s gotta keep them updated.) It would take 4.2 years for the message to arrive, and 4.2 years for the response to get back. Total round trip: 9.4 years. &lt;/p&gt;  &lt;p&gt;The vast majority of our universe is cold, vacuous space. It’s empty, with the possible exception of solar wind. Stars and planets are so far removed from each other that the distances are measured in either millions of miles, astronomical units, or light years. They have to be. If they were any closer, gravity would have smashed them together, and they’d no longer exist.&lt;/p&gt;  &lt;p&gt;So think about it. The night sky is filled with countless millions of stars that you can see. Turn a telescope at it, and you can see BILLIONS of stars. A mind-boggling number of them turn out to be galaxies, or star clusters composed of billions of stars. Every star has a chance of hosting its own system of planets. But (and here’s the gotcha) the planets must be located within a certain “safety zone” for them to harbor life. Too far, and everything freezes. Too close, and everything’s incinerated. Or, its atmosphere is blown right off. Or it might not have the right chemical makeup to support life. Or it could be so volcanic that there’s no way in hell (pardon the pun) that anything could ever exist there. Or, a rogue comet or asteroid could smash into it and obliterate whatever life had managed to begin evolving.&lt;/p&gt;  &lt;p&gt;You see, the universe craves life, but goes out of its way to destroy it. It surrounds it in the death grip of the cold vacuum of space, but once it gets going, life flourishes and evolves in myriad ways and in surprising environments that constantly amaze even the most diehard skeptic.&lt;/p&gt;  &lt;p&gt;For me, this is a simple idea. When I look at the night sky, I see tiny pinpoints of light, separated by millions and billions of miles of empty dead space. Most of them don’t have planets. Most of those that do can’t support life. And of those that can, they’re so far away that I’d never be able to have a full on conversation with them from earth in real time. We are so far removed removed from any other form of life in the universe that &lt;em&gt;may &lt;/em&gt;exist as to make us alone.&lt;/p&gt;  &lt;p&gt;Couple that with our catastrophically short life span, and you should be able to see where I’m going with this.&lt;/p&gt;  &lt;p&gt;I don’t need God to explain the sanctity of life to me. All I have to do is look at the night sky.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2011/03/sanctity-of-life.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-3241565036782863608</guid><pubDate>Tue, 15 Mar 2011 02:46:00 +0000</pubDate><atom:updated>2011-03-14T22:46:08.497-04:00</atom:updated><title>Insurmountable Obstacles</title><description>&lt;p&gt;So here’s the thing. I’ve been living a fairly &lt;a title=&quot;hermetic&quot; href=&quot;http://dictionary.reference.com/browse/hermetic&quot; target=&quot;_blank&quot;&gt;hermetic&lt;/a&gt; lifestyle for a pretty long time now. (And that’s &lt;em&gt;hermetic &lt;/em&gt;as in the hermit, not the jar.) I don’t get out, I don’t socialize, I’m pretty much consumed by my work and the things I do at home that can be defined as one-person tasks: reading, writing, programming, and watching movies.&lt;/p&gt;  &lt;p&gt;Now, there’s a reason for the way my life is the way it is. A few years or more ago, my &lt;a title=&quot;epilepsy&quot; href=&quot;http://www.ncbi.nlm.nih.gov/pubmedhealth/PMH0001714/&quot; target=&quot;_blank&quot;&gt;epilepsy&lt;/a&gt; spiraled out of control. My body basically built up a tolerance to the medication I was on, and I started having &lt;a title=&quot;Grand mal seizure&quot; href=&quot;http://www.mayoclinic.com/health/grand-mal-seizure/DS00222&quot; target=&quot;_blank&quot;&gt;grand mal seizures&lt;/a&gt; with no warning and at an alarming rate. At one point, I had them &lt;em&gt;every week &lt;/em&gt;without fail. During that time period, I had an active social life. I went out every weekend, I had a circle of friends, and things were going pretty well. &lt;/p&gt;  &lt;p&gt;Well, when the seizures started acting up, I realized that having a grand mal seizure at a gay club (or any social venue, for that matter) is a real buzz-killer. 911 is called. With that, the police, fire, and emergency responders are dispatched. Any fun you may be having comes to a grinding halt. Once the dust settles, and I’m all healed up, if I ever walk back into the club after that, I’ll be “that guy who flopped around on the floor and ruined the fun for everyone.” I’ll also be “That guy who might do it again.”&lt;/p&gt;  &lt;p&gt;I’m not worried so much about my reputation. I’m a nerd. And a geek. (There is a difference. Subtle, but important.) I’ve dealt with those stigmas all my life. What I am worried about is ruining everyone else’s fun.&lt;/p&gt;  &lt;p&gt;And let’s be honest: most people have &lt;em&gt;no &lt;/em&gt;idea what to do when they see someone having a seizure. People still think you can swallow your tongue. I mean, really. It’s attached to the bottom of your mouth. Seriously, people. Have you never brushed your teeth and observed this for yourselves?&lt;/p&gt;  &lt;p&gt;Of course, television and movies don’t help. Just recently I watched a television show where a patient started having a seizure and the doctor ordered a &lt;em&gt;spinal tap STAT!&lt;/em&gt; During a seizure. Pray tell, why would you inject a foot-long needle into anyone’s spinal column while they were convulsing so violently that you’d likely paralyze them for the rest of their lives?&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Le sigh.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;So you can imagine all the horrifying things I can imagine people trying to do to me in their efforts to “help” while I’m having a seizure. I don’t blame them. It’s just that they don’t know any better.&lt;/p&gt;  &lt;p&gt;So the best thing that I can do is remove myself from the equation. Put myself where I can’t expose people to danger. Because believe me, I’m a danger to people when I’m seizing. Not only do I have epilepsy, I have HIV. As I’m seizing, I may bite my tongue. And if some hapless Samaritan decides to help me out by sticking his fingers in my mouth, I will likely &lt;em&gt;bite him&lt;/em&gt; and infect him with HIV. I won’t know it, because the truth of the matter is that &lt;em&gt;I am not there.&lt;/em&gt; And when I came to, I would live with that guilt for the rest of my life.&lt;/p&gt;  &lt;p&gt;And there you have it. To protect people, I stopped going out. I became a recluse. It was safer for everyone that way. My doctor changed my medications, and the seizures came back under control, but my confidence was badly shaken. And here I am, years later, still a recluse, sitting alone at 10:35 PM, typing this blog entry alone.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;And I’m tired of being alone.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;I feel like there’s this gaping void in my life. I don’t need a circle of admirers. I’ve never needed that. I think that what I need is some sort of &lt;em&gt;connection &lt;/em&gt;to the world that isn’t based on bytes flying through cyberspace. I want to discuss politics, religion, philosophy, science, books, and the arts. I want to be able to have my opinions challenged, to expand my horizons, to be lured out of my cave because someone makes me &lt;em&gt;want &lt;/em&gt;to do it. &lt;/p&gt;  &lt;p&gt;But I’m afraid to do it. I’ve grown so accustomed to being here, to hiding from the world, for a myriad of reasons, that I find that taking that first step is a seemingly insurmountable challenge. I find myself longing for someone to take my hand, tell me it will be okay, and help me take that first step. Because I don’t think I can do it by myself. As strong as I’ve always thought I was, I know now that I’m not. &lt;/p&gt;  &lt;p&gt;The funny thing is, I don’t even know why I’m writing this. My blog has no readership. Perhaps that &lt;em&gt;is &lt;/em&gt;why I’m writing it. Maybe I’m putting this here because it’s safe. Because my blog is a safe part of my isolated little world, and I don’t have to worry about anyone finding it. In which case nothing will change, and everything will remain the same.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2011/03/insurmountable-obstacles.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-9110100124037871210</guid><pubDate>Wed, 27 Oct 2010 09:05:00 +0000</pubDate><atom:updated>2010-10-27T05:05:38.226-04:00</atom:updated><title>Visual Studio 2008 Detaching from the Debugger</title><description>&lt;p&gt;At work, my machine has always been problematic. Getting Visual Studio 2008 to stay attached to the debugger has been an excercise in futility. I&#39;ve done everything that every site on Google suggested. And still, a few seconds into debugging an ASP.NET web app under IIS or WebDev, the debugger would detach.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This happens for me under Windows 7, against both IIS 7 and Visual Studio&#39;s WebDev.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;I was running Visual Studio as an administrator. I made sure of this by setting the shortcut properties, and even right-clicking the icon and selecting &amp;quot;Run as Administrator.&amp;quot; &lt;/li&gt;    &lt;li&gt;I set up exclusions in the antivirus software to tell it not to scan my web project&#39;s folders. &lt;/li&gt;    &lt;li&gt;I disabled protected mode in Internet Explorer. &lt;/li&gt;    &lt;li&gt;I added localhost to the trusted sites in IE. &lt;/li&gt;    &lt;li&gt;I set the TabProcGrowth setting to 0 in the registry to disable IE&#39;s LCIE. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Still, the debugger would predictably detach. And then, the day before yesterday, I stumbled across something very, very curious. &lt;em&gt;Windows Defender was still running on my machine.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Now that struck me as very odd, because my understanding is that you&#39;re not supposed to run two different antivirus packages at the same time: they&#39;ll wreak havoc with each other. So, I contacted IT and we decided it was time to shut that blasted thing off in favor of our preferred antivirus application. (Note that the antivirus application &lt;em&gt;should&lt;/em&gt; have shut it off when it installed, but didn&#39;t for some reason.)&lt;/p&gt;  &lt;p&gt;Once I did, Visual Studio fired up, and for the first time the word &amp;quot;(Administrator)&amp;quot; appeared in the title bar. That was the first clue that something drastic had changed. And the best news is that I haven&#39;t had a single disconnect from the debugger since.&lt;/p&gt;  &lt;p&gt;I can&#39;t guarantee that this is the problem that you&#39;re having, but you might want to look at it. If you&#39;re running an antivirus application on your machine, &lt;em&gt;Windows Defender should not be running at the same time.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;To Disable Windows Defender&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Right click on My Computer. &lt;/li&gt;    &lt;li&gt;Select Manage. &lt;/li&gt;    &lt;li&gt;Click Services and Applications. &lt;/li&gt;    &lt;li&gt;Click Services. &lt;/li&gt;    &lt;li&gt;In the services list, double-click Windows Defender. &lt;/li&gt;    &lt;li&gt;In the Windows Defender Properties dialog, change the settings as follows:      &lt;ol&gt;       &lt;li&gt;Change the Startup Type to Disabled. &lt;/li&gt;        &lt;li&gt;Click the Stop button. &lt;/li&gt;     &lt;/ol&gt;      &lt;p&gt;Click OK to close the dialog. &lt;/p&gt;   &lt;/li&gt;    &lt;li&gt;Close Computer Management. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I hope this helps someone besides me, who&#39;s been battling this issue for months.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2010/10/visual-studio-2008-detaching-from.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-3806091432528807501</guid><pubDate>Mon, 16 Aug 2010 02:57:00 +0000</pubDate><atom:updated>2010-08-15T22:57:49.722-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">CodeQuality</category><category domain="http://www.blogger.com/atom/ns#">JavaScript</category><category domain="http://www.blogger.com/atom/ns#">SoftwareDevelopment</category><title>JavaScript...For Good or Ill</title><description>So, I&#39;ve been spending a lot of time working with JavaScript, lately. For whatever it&#39;s worth, I&#39;ve been thrust into a role in which I find myself working with a large volume of JavaScript code that needs to be maintained and it falls on me to do that. &lt;br /&gt;&lt;br /&gt;Now, generally speaking, in my eyes, code is code. I don&#39;t really care what language you&#39;re writing in, but some things are just generally true regardless of the language. Cryptic code is to be shunned At All Costs™. A coding standard--even a minimal standard--should apply. Variable names should be clear. The code should document itself, mitigating the need for comments. Every variable should be predeclared. And so on, and so on, and so on.&lt;br /&gt;&lt;br /&gt;But over the long course of my career, I&#39;ve observed something about scripting languages like JavaScript and VBScript. There&#39;s just something about them that seems to encourage people to write bad code.&lt;br /&gt;&lt;br /&gt;I&#39;ve seen and had to debug a lot of script code in my lifetime. And that code tends to be riddled with subtle and not-so-subtle defects that could easily have been avoided if we simply treated scripting languages like they were real languages and not &lt;span style=&quot;font-style: italic;&quot;&gt;toys&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Don&#39;t Blame the Browser.&lt;/span&gt; One could argue that many of the defects that crop up in script code are due to browser incompatibilities. But let&#39;s be honest with ourselves: it&#39;s our job to know what those incompatibilities are and write the software to take them into account so that script errors don&#39;t occur. If script errors are occurring &quot;due to a browser incompatibility,&quot; that&#39;s not really the reason: they&#39;re occurring because the developers didn&#39;t account for the browser incompatibility.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Functions, Formal Parameters, and Arguments. &lt;/span&gt;How many times have you seen a function that takes a set of arguments and then starts working with them without performing any sort of argument validation? How much time have you spent scratching your head, trying to figure out what &lt;span style=&quot;font-style: italic;&quot;&gt;type &lt;/span&gt;of data the function expected to receive for any given formal parameter? And have you ever wondered what guarantee the function has that it is going to receive arguments of the correct type, or that it will behave correctly if it doesn&#39;t?&lt;br /&gt;&lt;br /&gt;The truth is, the vast majority of the functions in script code never check their arguments to ensure that they are what they expect them to be. They don&#39;t check to ensure that the values are present, that they&#39;re of the correct data type, that they fall within the allowed ranges or have the right formats. Any number of errors that occur in the browser in front of end-users in production could be avoided if those checks were put in place early on, when the functions were first written, and a developer found out about them during development.&lt;br /&gt;&lt;br /&gt;But we&#39;re lazy, and scripting languages somehow encourage us to be even lazier. I&#39;m not sure why this is so, it just seems to be so. Now, when ou consider a language like JavaScript, where &lt;span style=&quot;font-style: italic;&quot;&gt;any &lt;/span&gt;variable, object, or function can be modified at any time by anyone, it&#39;s not a good idea to assume that the arguments you&#39;ve received are what you expect them to be. To quote a classic mantra:&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;margin-left: 0.5in; font-style: italic;&quot;&gt;Assert, assert, assert.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Assume Nothing.&lt;/span&gt; Too often I&#39;m presented with code that grabs an element from the document using &lt;code&gt;document.getElementById&lt;/code&gt;. This code then proceeds to use the control as if there was never any doubt in the world that the element existed.&lt;br /&gt;&lt;br /&gt;If you&#39;re writing code like this, &lt;em&gt;stop it right now.&lt;/em&gt; What if the content of the page unexpectedly changed on you (a write to &lt;code&gt;document.innerHTML&lt;/code&gt;), or you&#39;re reading from an &lt;code&gt;iframe&lt;/code&gt; and it doesn&#39;t have the correct document loaded into it? What if the control you&#39;re after was never created? &lt;em&gt;If you aren&#39;t checking for these conditions yourself early in the development cycle, the customer is bound to find out for you.&lt;/em&gt;&lt;br /&gt;&lt;pre style=&quot;margin-left: 0.5in;&quot;&gt;&lt;code&gt;&lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; theElement = document.getElementById(&lt;span style=&quot;color: red;&quot;&gt;&quot;myElement&quot;&lt;/span&gt;);&lt;br /&gt;&lt;span style=&quot;color: blue;&quot;&gt;if&lt;/span&gt;(theElement === &lt;span style=&quot;color: blue;&quot;&gt;null&lt;/span&gt;)&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: blue;&quot;&gt;throw new&lt;/span&gt; Error(&lt;span style=&quot;color: red;&quot;&gt;&quot;myElement was not found.&quot;&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;span style=&quot;color: blue;&quot;&gt;else&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span style=&quot;color: green;&quot;&gt;// Code to work with the control.&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt; &lt;br /&gt;We tend to make these kinds of assumptions all the time in scripting languages. We assume that a property or method exists on an object, that a given variable is an array, that a variable is not undefined or null, that a variable has not been preinitialized by someone else to hold a value that is different from what we want to store in it. All of these are unsafe assumptions. Unsafe assumptions lead to subtle defects that are notoriously difficult to track down and correct. We need to make it a priority to ruthlessly eliminate them by adopting a Zero-Assumption policy.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;What Happened to Black Box Programming?&lt;/strong&gt; Remember the idea behind black box programming? The basic principle is simple:&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;margin-left: 0.5in; font-style: italic;&quot;&gt;A function or object knows nothing about the outside world except what is passed into it.&lt;/div&gt;&lt;br /&gt;At some point in your career, you should have been introduced to this fundamental concept. &lt;em&gt;Functions and objects don&#39;t rely on global variables.&lt;/em&gt; They just don&#39;t. Everything they need to know is passed to them through their formal parameter list. In this way, the function has an opportunity to validate that its arguments are sound, and it is &lt;em&gt;decoupled&lt;/em&gt; from its host so that it can be tested more easily.&lt;br /&gt;&lt;br /&gt;These days, we push the notions of &lt;a href=&quot;http://en.wikipedia.org/wiki/Loose_coupling&quot; target=&quot;_top&quot;&gt;loose coupling&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Cohesion_%28computer_science%29&quot; target=&quot;_top&quot;&gt;high cohesion&lt;/a&gt; to explain black box development in greater detail. We also talk about things like &lt;a href=&quot;http://en.wikipedia.org/wiki/Inversion_of_control&quot; target=&quot;_top&quot;&gt;inversion of control&lt;/a&gt;, which should be nothing new to anyone who&#39;s ever written an event handler before. In short, the function &lt;em&gt;assumes nothing&lt;/em&gt; about its external environment (sound familiar?); we pass it everything it needs to know to get its job done.&lt;br /&gt;&lt;br /&gt;But if you look at JavaScript or VBScript code you will be inundated be vast swaths of code that references global variables with complete abandon. Of course it does. Scripting languages embrace global variables like flies embrace a fertilizer factory. &lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;History Lesson #1: global variables are a loaded weapon with a hairpin trigger. When you give that many sketchy loaded weapons to people with no training, Bad Things Will Happen.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;History Lesson #2: Humans frequently fail to learn from history.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I implore you. I beg you. Please, please stop using global variables. It is, of course, necessary atthe topmost layer of your application, but once you&#39;re past that, there&#39;s no reason whatsoever for your functions and objects to have any knowledge of global objects (unless they&#39;re provided by JavaScript or VBScript itself). Do not assume &lt;em&gt;anything&lt;/em&gt; about the global,&lt;code&gt;document&lt;/code&gt; or &lt;code&gt;top&lt;/code&gt; objects. When you write a function, if it needs some piece of information to do its work, insist that your callers pass it to you.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;In Closing...&lt;/strong&gt; I think you can see where I&#39;m going with this. We&#39;ve got decades of script code out there, and a lot of it is really badly written. But if we want to be perfectly honest about it, we have no one to blame for its state but ourselves. We look at what JavaScript &lt;em&gt;can&lt;/em&gt; do, and we never stop to ask ourselves if what it &lt;em&gt;can&lt;/em&gt; do is somethig we &lt;em&gt;should&lt;/em&gt; do.&lt;br /&gt;&lt;br /&gt;Making a bad situation worse, we don&#39;t apply the same disciplined coding practices to JavaScript that we do to languages like C++, C#, Java, or even VB.NET. And that&#39;s a shame, because there&#39;s nor real reason we shouldn&#39;t or couldn&#39;t. Perhaps, in the near future, we&#39;ll see things like code contracts, automated unit tests, argument validaton frameworks, StyleCop for JavaScript, and so on. Pipe dreams, probably, but it would be nice if we could have all of that and take a huge, collective leap forward in improving the quality of the script code we have to maintain every day.&lt;div class=&quot;flockcredit&quot; style=&quot;text-align: right; color: #CCC; font-size: x-small;&quot;&gt;Blogged with the &lt;a href=&quot;http://www.flock.com/blogged-with-flock&quot; style=&quot;color: #999; font-weight: bold;&quot; target=&quot;_new&quot; title=&quot;Flock Browser&quot;&gt;Flock Browser&lt;/a&gt;&lt;/div&gt;</description><link>http://mikehofer.blogspot.com/2010/08/javascriptfor-good-or-ill.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-5319203068101310100</guid><pubDate>Wed, 30 Jun 2010 17:28:00 +0000</pubDate><atom:updated>2010-06-30T13:29:58.491-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Musings</category><category domain="http://www.blogger.com/atom/ns#">Productivity</category><category domain="http://www.blogger.com/atom/ns#">Quality</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><category domain="http://www.blogger.com/atom/ns#">Technology</category><title>Knowing How is Not Enough</title><description>&lt;p&gt;There’s an old adage that I heard once, and it’s stuck with me through the years:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;He who knows how to do a thing is a good employee. He who knows why is his boss.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I’m also fond of this one:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;If you can’t explain it, you don’t understand it.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;So I’ve been ramping up on some technology that I’ve really not had an opportunity to &lt;em&gt;really &lt;/em&gt;use before, and I’m very excited about it. To make sure I understand it, I’ve decided to go back to the MSDN examples, reproduce them one line at a time, and then document the source code &lt;em&gt;as I understand it&lt;/em&gt;. It’s a great way to learn, and sheds a great deal of light on what you think is happening, versus what’s actually happening.&lt;/p&gt;  &lt;p&gt;To be perfectly honest, the technology is AJAX. Over the last few years, I’ve predominantly worked for companies that haven’t had any use for Web services, so there’s been no compelling need for it. I’m starting a new job soon and it will rely heavily on Web services, and I really want to make sure I understand them well before I set my foot in the door. It has never been enough for me to know that you just drag a control onto a form or page, set a few properties and press F5. To me, that degree of abstraction is a double-edged sword.&lt;/p&gt;  &lt;p&gt;When abstraction reaches the level that it has with Microsoft AJAX, you start to run into some fairly significant issues when it comes time to test and debug the application. The MS AJAX framework is no small accomplishment, and it hides a &lt;em&gt;lot &lt;/em&gt;of complexity from you. It makes it &lt;em&gt;so &lt;/em&gt;easy to write AJAX applications that you really don’t need to understand the underlying fundamentals of Asynchronous Javascript and XML that make the whole thing work. Consequently, when things go wrong, you could very well be left scratching your head, without a clue, and no idea where to begin looking. &lt;/p&gt;  &lt;p&gt;Where, in all of this enormously layered abstraction did something go wrong? Was it my code? Was it the compiler? Was it IIS? Was it permissions? Was it an update? Was it a configuration setting? Was it a misunderstanding of the protocol? Did the Web service go down or &lt;em&gt;move&lt;/em&gt;? Was the proxy even generated? If it was, was it generated correctly? Do I even know what a proxy is and why I need it?!&lt;/p&gt;  &lt;p&gt;When I started learning about AJAX, we coded simple calls against pages that could return &lt;em&gt;anything &lt;/em&gt;to you in an HTTP request using the XMLHTTPRequest object. Sure, it was supposed to be XML, but that was by convention only. The stuff I wrote back then (and I only wrote this stuff on extremely rare occasions, thank the gods), returned the smallest piece of data possible: a single field of data in flat text. It was enough to satisfy the business need, and didn’t require XML DOM parsing. &lt;/p&gt;  &lt;p&gt;But even with DOM parsing, the code to make a request and get its data back via XMLHTTPRequest was a lot smaller than all the scaffolding you have to erect now. You might argue that you don’t have create a lot of code now, but that is just an illusion. You’re not writing it, but Microsoft is. Just because you don’t see it doesn’t mean it’s not there. Do you know what that code is doing?&lt;/p&gt;  &lt;p&gt;In theory, the Why of Microsoft AJAX, or any AJAX library is to make our lives easier when it comes time to write dynamic Web applications that behave more like desktop applications. To a certain degree, they have. When they work. But when they don’t, I wonder if the enormous degree of abstraction they’ve introduced hasn’t dumbed us down to the point where we’ve ignored essential knowledge that we should have. &lt;/p&gt;  &lt;p&gt;If you’re going to write Web services, or consume them, you should, at a minimum, understand what they are, and how they work. You should understand their history, how they evolved, and the problem that AJAX tries to solve. It’s not enough to know how to write a Web service, you have to know why you’re doing it, and why you’re doing it the way you are. That sort of knowledge can be crucial in making the right choices about algorithms, protocols, frameworks, caching, security, and so on.&lt;/p&gt;  &lt;p&gt;But this could be true of any technology or practice we learn. AJAX, LINQ, design patterns, TDD, continuous integration, pair programming, and so on. Know why. &lt;/p&gt;  &lt;p&gt;Try this simple litmus test. Explain something you think you know to one of your peers. If you can’t explain it clearly without having to pull out a reference or go online, you don’t understand it the way you think you did. Consider relearning it. It’ll only improve your value to yourself, your peers, and your employer.&lt;/p&gt;  &lt;div style=&quot;padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:f5d335c5-ea23-44a5-9802-bb8ee543aa84&quot; class=&quot;wlWriterEditableSmartContent&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/Productivity&quot; rel=&quot;tag&quot;&gt;Productivity&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/Software+Development&quot; rel=&quot;tag&quot;&gt;Software Development&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/Technology&quot; rel=&quot;tag&quot;&gt;Technology&lt;/a&gt;&lt;/div&gt;  </description><link>http://mikehofer.blogspot.com/2010/06/knowing-how-is-not-enough.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-8877898803441006286</guid><pubDate>Tue, 29 Jun 2010 13:53:00 +0000</pubDate><atom:updated>2010-06-29T09:53:38.783-04:00</atom:updated><title>64-bit Browsers: Useless, but not for the reasons you think</title><description>&lt;p&gt;I was really stoked when I recently upgraded from a 32-bit OS to a 64-bit OS. I was even more pleased to learn than IE came in a 64-bit flavor. Then, the &lt;em&gt;reality &lt;/em&gt;hit me.&lt;/p&gt;  &lt;p&gt;Broad-based support for 64-bit browser addons still hasn’t arrived. Silverlight, Flash, Adobe Acrobat, and all their ilk are not 64-bit compatible. So, you can view generic HTML, but that’s pretty much it.&lt;/p&gt;  &lt;p&gt;So I have this spiffy 64-bit browser that’s (theoretically) faster and can (theoretically) address far more memory, but it’s fairly useless to me because I can’t view a vast amount of content on the Web.&lt;/p&gt;  &lt;p&gt;Sure, there’s content I can view, but having to switch back and forth between 64-bit and 32-bit versions of a browser—and that’s &lt;em&gt;any &lt;/em&gt;browser—is a pain: a useless time sink. &lt;/p&gt;  &lt;p&gt;So, it looks like it’s back to 32-bit browsers for me. As a web developer, that’s fairly sad, because it means that I won’t be testing any really cool, dynamic “flashy” content in 64-bit browsers for a long time. And that’s fairly sad. User demand is what drives the corporations to get these things fixed, and if we all have to set those 64-bit browsers aside because there’s just no support for them, well, those corporations feel less compelled to provide support for them with any kind of urgency. &lt;/p&gt;  &lt;p&gt;It’s a vicious circle, really. They aren’t caught up, we can’t use it, so we go back to older tech, so they relax on the implementation, so it’s not done as quickly as we might like, so we remain entrenched in 32-bit technology longer.&lt;/p&gt;  &lt;p&gt;Now, 32-bit technology is fine, if that’s all you really need. But software is not getting any smaller. Nor are operating systems, or corporate computing needs. Eventually, the amount of memory we can address effectively with 32-bit operating systems and software will fail to be sufficient. That day may be far off, but it may not. The truth is, you’re better off being ahead of the curve than behind it. That’s not always possible, but if you can, you should.&lt;/p&gt;  &lt;p&gt;In the meanwhile, I’m back to a 32-bit browser, because it’s the only way I can view Silverlight, Flash, and PDF online. Here’s hoping that all changes sometime in the near future.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2010/06/64-bit-browsers-useless-but-not-for.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-2926106626007890812</guid><pubDate>Sun, 27 Jun 2010 02:33:00 +0000</pubDate><atom:updated>2010-07-02T12:27:08.603-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">BCL</category><category domain="http://www.blogger.com/atom/ns#">Generics</category><category domain="http://www.blogger.com/atom/ns#">Microsoft</category><category domain="http://www.blogger.com/atom/ns#">NValidate</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><title>Generics, Value Types, and Six Years of Silence</title><description>&lt;p&gt;It’s been a long time since I worked on the code for NValidate, but in a fit of creative zeal I decided to dust it off and take a look at it. &lt;/p&gt; &lt;p&gt;As one of the posters on the old NValidate forums pointed out, it was full of duplicate code. Granted, that was a conscious design choice at the time: it was written well before generics came out, and performance was a key consideration. I didn’t want a lot of boxing and unboxing going on, and since a lot of the tests dealt with value types, the only way I could see to get that stuff done was to duplicate the test code for specific types.&lt;/p&gt; &lt;p&gt;Well, time marches on and languages advance. .NET 2.0 came out, and along with it came generics. I figured that they would provide a fantastic way for me to eliminate a lot of the duplicate code. I mean, it would be awesome if we could just write a single validator class for all the numeric data types and be done with it. And that’s where I hit the Infamous Brick Wall&amp;amp;tm;.&lt;/p&gt; &lt;p&gt;It turns out that generics and ValueType objects do not play well together. At all. Consider the following piece of code:&lt;/p&gt; &lt;pre&gt;public class IntegralValidatr&amp;lt;T&amp;gt; where T : ValueType&lt;br /&gt;{&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;This, as it turns out, is forbidden. For some reason, the compiler treats ValueType as a “special class” that cannot be used as the constraint for a generic class. Fascinating. The end result is that you cannot create a generic class that requires that its parameters are derived from ValueType. You know: Boolean, Byte, Char, DateTime, Decimal, Double, Int, SByte, Short, Single, UInt, and ULong. Types you might actually want to work with on a daily basis, for all kinds of reasons.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The workaround, they say, is to specify struct. The problem is that struct is a pretty loose constraint. Lots of things are structs but aren&#39;t necessarily the types you want. I assume that&#39;s why they call it a &lt;em&gt;workaround&lt;/em&gt; and not a &lt;em&gt;solution&lt;/em&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So, anyway, here I am with a basic class definition. I can at least admit to myself that I can build the class outline as follows:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;public class IntegralValidator&amp;lt;T&amp;gt; where T : struct&lt;br /&gt;{&lt;br /&gt;  public T ActualValue { get; internal set; }&lt;br /&gt;  public string Name { get; internal set; }&lt;br /&gt;  public IntegralValidator (string name, T actualValue)&lt;br /&gt;  {&lt;br /&gt;    this.Name = name;&lt;br /&gt;    this.ActualValue = actualValue;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;But now it’s time to create a test. The problem is determining how to perform basic comparisons between value types when you can’t seem to get to the value types now that they’ve been genericized. Understand that NValidate needs to be able to do the following with numeric values:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Compare two values for equality and inequality &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Compare a value to a range, and fail if it falls outside that range &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Compare a value to zero, and fail if it isn’t zero &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Compare a value to zero, and fail if it is zero. &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Compare a value to the Max value for its type, and fail if it is or isn’t equal to that value. &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Compare a value to the Min value for its type, and fail if it is or isn’t equal to that value. &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Compare a value to a second value, and fail if it is less than than the second value. &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Compare a value to a second value and fail if it is greater than the second value. &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;You get the picture.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The problem I’m experiencing is that it’s become clear to me that it’s really very difficult to convert a genericized value type back to its original value type. Consider the following code:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;private byte ToByte(){&lt;br /&gt;  if (ActualValue is byte&amp;gt;)&lt;br /&gt;    // The as operator must be used with a reference type or&lt;br /&gt;    // nullable type (&#39;byte&#39; is a non-nullable value type)&lt;br /&gt;    return ActualValue as byte;&lt;br /&gt;  if (ActualValue is byte)&lt;br /&gt;    // Cannot convert type &#39;T&#39; to &#39;byte&#39;&lt;br /&gt;    return byte ActualValue; &lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;So, if neither of these approaches works, how do I get to the original values? Generics appear to &lt;em&gt;demand &lt;/em&gt;an actual object, which would, in turn, demand boxing and unboxing of value types (which I’m staunchly opposed to for performance reasons).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So, we go back to the drawing board, and eventually we discover that you can, in fact, get to the type through a bit of trickery with the System.Convert class:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;private byte ToByte() {&lt;br /&gt;  if (ActualValue is byte)&lt;br /&gt;    // The as operator must be used with a reference type or&lt;br /&gt;    // nullable type (&#39;byte&#39; is a non-nullable value type)&lt;br /&gt;    return Convert.ChangeType(ActualValue, TypeCode.Byte);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Well, the problem I’m faced with now, upon careful reflection is this: &lt;em&gt;If I’m drilling down to the original data type, I’m kind of defeating the whole point of generics in the first place&lt;/em&gt;. And that brings us to the whole point of this article.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I should be able to write a line of code like this:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;Demand.That(x).IsNonZero().IsBetween(-45, 45);&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;And that code should be handled by generics that correctly infer the type of x and select the right code to execute, but I can’t. And the reason I can’t is because (1) you can’t use ValueType as a constraint for generics and (2) there is no common interface for numeric types in the BCL.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This is an egregious oversight in the Framework. Worse, &lt;a href=&quot;https://connect.microsoft.com/VisualStudio/feedback/details/94264/arithmetic-types-like-int-double-decimal-should-implement-iarithmetic-t?wa=wsignin1.0&quot; target=&quot;_blank&quot;&gt;it’s been an outstanding complaint on Microsoft Connect since 2004&lt;/a&gt;. Through multiple iterations of the Framework, despite numerous postings on the site and clamorings for the oversight to be corrected, Microsoft has yet to do anything about it. For some reason, they seem to think it’s less important than things like Office Integration, UI overhauls, destroying the usability of online help, and making Web services as difficult and unpredictable to use as possible.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;It baffles me that Microsoft’s own responses to the issue have been questions like “How would you use this functionality?” Are they kidding me? There are so many uses for this it’s not even funny.&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;What happens when you have an array or list of heterogenous numeric types and need to work with them in some meaningful way using a generic (possibly a delegate)? &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;What happens when you want to write a program that converts 16-bit data to 32-bit data, or floating point data to Long data, or work with both at the same time using a common algorithm? &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;What happens when you need to work with graphics algorithms common to photo processing software? &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;What happens when you need to work with the many different types of value types and convert them back and forth quickly and efficiently as you would in, say, an online game? &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Or, as in my case, what happens when you’re writing a reusable framework for validation and boxing and unboxing are simply not an option, and a generic solution would handily solve the problem, but you &lt;em&gt;can’t &lt;/em&gt;because there’s no common interface – no One Ring that binds them all together? &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;It’s about time this issue was resolved. And this isn’t something the open source community can fix. This is something Microsoft has to fix, in the BCL, for the good of all humanity. Six years is far too long to leave something this painfully obvious outstanding.&lt;/p&gt;&lt;br /&gt;&lt;div style=&quot;padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:f65d13f7-03c9-4fd1-a03f-1d7425f58ea3&quot; class=&quot;wlWriterSmartContent&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/.NET&quot; rel=&quot;tag&quot;&gt;.NET&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/NValidate&quot; rel=&quot;tag&quot;&gt;NValidate&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Software+Development&quot; rel=&quot;tag&quot;&gt;Software Development&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/BCL&quot; rel=&quot;tag&quot;&gt;BCL&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Microsoft&quot; rel=&quot;tag&quot;&gt;Microsoft&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Generics&quot; rel=&quot;tag&quot;&gt;Generics&lt;/a&gt;&lt;/div&gt;  </description><link>http://mikehofer.blogspot.com/2010/06/generics-value-types-and-six-years-of.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-5084227255052825135</guid><pubDate>Thu, 10 Jun 2010 19:22:00 +0000</pubDate><atom:updated>2010-06-10T15:22:57.758-04:00</atom:updated><title>On Work at Home Programs</title><description>&lt;p&gt;In his article, &lt;a title=&quot;Work from home. Save the Planet&quot; href=&quot;http://www.zdnet.com/blog/government/work-from-home-save-the-planet/8788?tag=main;footer&quot; target=&quot;_blank&quot;&gt;Work from home. Save the Planet&lt;/a&gt;, David Gewirtz lays out numerous benefits for embracing Work at Home programs throughout the country. I find some of the author&#39;s arguments questionable, but I haven&#39;t read his book, either. &lt;/p&gt;  &lt;p&gt;I do know, living in New England, that the vast majority of road repairs are not due to traffic, but seasonal weather changes. So that argument goes flying out the window. &lt;/p&gt;  &lt;p&gt;Also, it&#39;s quite evident that many jobs simply cannot be done from home. Let&#39;s be realistic. Security, plumbing, firefighting, surgery, shop keeping, termite control, landscaping, road repair, construction, and so on simply cannot be done from your home. &lt;/p&gt;  &lt;p&gt;On the other hand, densely populated urban areas packed with office buildings and utilizing the latest technologies can reap the benefits of work-at-home programs. We are not bereft of the technologies that make this possible: instant messaging, email, online Web applications, video conferencing, VPN networks, and the ever growing &amp;quot;Cloud&amp;quot; enable us to get more done from geographically separate locations than ever before. &lt;/p&gt;  &lt;p&gt;The trick is to ensure that the work is actually getting done with as much zeal as it would if people were in the office, where they are observed by their coworkers. Let&#39;s be honest: people tend to be more disciplined about getting the work done if their peers are able to walk in on a moment&#39;s notice and see whatever it is they&#39;re doing. That&#39;s not the case when you&#39;re working from home. &lt;/p&gt;  &lt;p&gt;At home workers must possess a greater amount of self-discipline than workers in the office, by simple virtue of the fact that they must manage their own time and not be distracted by daily annoyances that might be present in the home. &lt;/p&gt;  &lt;p&gt;And yet, if this program can be made to work, the benefits to the community (and the planet) can be numerous. Reductions in carbon emissions, fossil fuel consumption, traffic jams, traffic fatalities, and overall travel expenses are virtually (but not necessarily) a given. &lt;/p&gt;  &lt;p&gt;In any event, it&#39;s not a simple case of black and white. No issue ever is.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2010/06/on-work-at-home-programs.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-946201308329447848</guid><pubDate>Mon, 15 Mar 2010 19:59:00 +0000</pubDate><atom:updated>2010-03-15T15:59:38.164-04:00</atom:updated><title>Strange Days</title><description>&lt;p&gt;These are strange days.&lt;/p&gt; &lt;p&gt;The pundits and economists claim that the economy is on the rebound. But for those of us down here in the trenches, those of us whore are jobless, with bills to pay and families to feed, there&#39;s no economic recovery in sight. The bills are piling up, the job offers aren&#39;t materializing, and money is getting harder and harder to come by. All the while, the fat cats in Washington bicker over health care reform while getting &lt;em&gt;nothing &lt;/em&gt;done aside from playing the blame game, trying to decide who was responsible for the economic disaster in the first place.&lt;/p&gt; &lt;p&gt;My dad, dead now ten years or more, used to say that the more things changed, the more they stayed the same. He was right. Things are no different today than they were ten, twenty, fifty years ago. Politicians, in their luxurious offices, with their limos and travel budgets and vastly superior health care plans, have &lt;em&gt;no real idea &lt;/em&gt;what those of us in the trenches are going through on a day by day basis. We have very basic needs. We have to be able to pay the rent. We have to be able to clothe our kids. We have to be able to pay for things like gas, electricity, and hot water. We have to be able to pay for public transportation or gas to get to work every day. We have to be able to afford decent medical care and prescriptions when we need them—which isn&#39;t always a planned thing. &lt;/p&gt; &lt;p&gt;But if you&#39;re rich, you likely don&#39;t even have to think about those things. They&#39;re just taken care of. Someone handles all that stuff for you. It&#39;s inconsequential, beneath your notice. You might stand there on television and claim to be a man of the people, but after a little while in office with that big salary and all those incredible benefits, your memories of what it was like to be one of us will quickly fade. &lt;/p&gt; &lt;p&gt;But we are your constituents. We&#39;re the ones you&#39;re supposed to be helping. We&#39;re the ones having to decide, day in and day out, what we&#39;re going to have to cut out of our lives to be able to afford food or rent. Not because we want to, but because we have to. We make little choices, and lots of them. &lt;/p&gt; &lt;p&gt;We turn off our cell phones because it&#39;s not necessary, and the phone service that anchors us to the house through our cable service is cheaper. Sure, we&#39;re screwed if we get stuck on the side of the road, but we have to make that choice because we can&#39;t afford it&lt;em&gt;.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;We choose to give our pets up for adoption, because we can&#39;t afford to feed or care for them anymore. Sure, they&#39;ll likely be euthanized, because no one else can care for them either. But we do it, because we can&#39;t afford it&lt;em&gt;.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;We choose to cut our automobile insurance, because we can&#39;t afford the egregious rates we&#39;re being charged. Sure, we&#39;re out a vehicle if something really bad happens. But we do it. And you know why.&lt;/p&gt; &lt;p&gt;We choose to endure pain and suffering without visiting a doctor, or to try alternative therapies which are either ineffective or potentially dangerous, because we can&#39;t afford the copays. &lt;/p&gt; &lt;p&gt;We choose to buy cheap, processed foods to feed our families, rather than fresh meat and produce. Sure, it&#39;ll have a longer term impact on our overall health. But the price difference makes you wonder if they&#39;re trying to discourage you from eating healthy. And we simply can&#39;t afford to eat well.&lt;/p&gt; &lt;p&gt;We use up our savings, dive into college funds, remortgage our homes, do anything to survive. We sell our cherished belongings. We move into smaller apartments, crammed with multiple roommates trying to pool their resources against the financial crush. And even then, we struggle.&lt;/p&gt; &lt;p&gt;Those of us who have jobs hold onto them for dear life, afraid of what might happen to us if we lost them. It doesn&#39;t matter if we &lt;em&gt;hate &lt;/em&gt;the work we&#39;re doing, who we&#39;re working with, the hours we keep. The world outside that job is far, far worse.&lt;/p&gt; &lt;p&gt;And yet, to hear the news, the economy is in a rebound, and things are looking up. Consumer spending is on the rise. You wouldn&#39;t know it at my house, or the homes of any of the people I know. We&#39;re all feeling the pinch. And this pinch leaves major bruises that aren&#39;t going to heal any time soon.&lt;/p&gt; &lt;p&gt;Washington, and all the local politicians, need to take off their blinders and remember that the world does not live like they do. In the real world, the vast majority of the population is poor, and struggling to survive from one day to the next. Sure, the rich line your pockets. We all know that. But the poor cast the votes. Step out of that bright light that blinds you to the realities of life that every day people face, and look at it with an unfettered vision for once. And then, without just dismissing what you&#39;ve seen and heard, &lt;em&gt;do something about it. &lt;/em&gt;&lt;/p&gt; &lt;p&gt;Stop bickering. Party lines should be irrelevant in this crisis. And it doesn&#39;t matter who started it. What matters is what we&#39;re going to do about it.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2010/03/strange-days.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-7115096440250080622</guid><pubDate>Wed, 03 Mar 2010 20:20:00 +0000</pubDate><atom:updated>2010-03-03T15:20:15.634-05:00</atom:updated><title>Farewell to Software Development</title><description>&lt;p&gt;So here I am, staring at this screen, thinking about what to say. It&#39;s been a long time since I blogged. It&#39;s been funny, in a way, that my blog was never really very &lt;em&gt;technical. &lt;/em&gt;I always blogged about the esoteric aspects of software development. About personal improvement, about striving to become a better software developer, about questioning the status quo, about reevaluating yourself at every step of the way. And now, I find that those words come back to haunt me. But not in any way that I would ever have expected.&lt;/p&gt; &lt;p&gt;I&#39;ve been unemployed since December 1st. I&#39;ve been seeking employment since then, and the experience has been eye-opening. In the past, getting work was never difficult. I like to consider myself both a competent developer and a proficient interviewer. In the past, it&#39;s &lt;em&gt;never &lt;/em&gt;been difficult to find work. Within the first three or four interviews I had an offer on the table--usually several, and I could take my pick from them. But this time, I&#39;m finding myself faced by rejections for reasons that escape me. One company refused to hire me because I hesitated when asked to describe the difference between natural and left joins. They thought a senior level developer should have provided an immediate response, without hesitation. I thought a senior level developer would have thought his answer through, worded his response carefully, and not just blurted out the first thing that leapt to mind. Apparently, it was irrelevant that my answer was correct.&lt;/p&gt; &lt;p&gt;I&#39;m also faced by the prospect that technology is passing me by. This has been a growing concern of mine for years. There&#39;s a conundrum we all face when we seek long-term employment with any company. You see, companies seek candidates who want to stay with them for years. The problem is, companies tend to be entrenched in a particular technology stack. They have a vested interest in maintaining whatever software they&#39;ve developed with that stack, and once you&#39;ve invested yourself in the maintenance of that software, you&#39;re pretty much mired in it for the long haul. Whatever tools and technology were used in its initial development tend to become a ball and chain that anchor you where you are for years at a shot. Technology moves forward, but the product likely does not. And you, as the maintenance developer, stay tethered to that product and its associated technologies as everyone else moves forward.&lt;/p&gt; &lt;p&gt;New technologies emerge all the time. There are so many technologies out there right now that no one could possibly grasp them all, let alone consider himself an expert in them all. And yet, interviewers expect you to have this commanding expertise in such a wide variety of technologies that their expectations can be considered unreasonable. A jack of all trades is master of none. The truth of the matter is that most of us will never learn a new technology until a particular project demands exposure to it. Only then will we learn it. And then, we&#39;ll only learn enough of it to get by. Few companies have the budget to send their development staff to seminars or their ilk to receive formal training. Few developers make enough money to seek out and pay for formal training out of pocket. And few companies that provide that training are motivated to lower their prices to make it accessible to dirt-poor developers hungry for the knowledge.&lt;/p&gt; &lt;p&gt;And so it&#39;s a vicious cycle. Technology moves forward. Developers are stuck with the old technology, and cling to their jobs because, in this economy, they know it could be really difficult to find new work. Further, they know any new work they find could be worse than the work they&#39;re doing now. It&#39;s a buyer&#39;s market. Wages have declined, benefits are being cut, and the work still has to get done.&lt;/p&gt; &lt;p&gt;Over the last few years, I&#39;ve been stuck in this vicious cycle. But since December, as I&#39;ve been interviewing, one thing has started to become increasingly clear to me: software development is leaving me behind. &lt;/p&gt; &lt;p&gt;It doesn&#39;t matter how much I love it. It doesn&#39;t matter how good I am at it. It doesn&#39;t matter how passionate I am about quality, good design, team cohesion, self improvement, or any of those things. What matters is that I am tired of playing this catch-up game, of trying to appease people with unreasonable expectations, of being expected to know everything about everything, and being held accountable when I don&#39;t.&lt;/p&gt; &lt;p&gt;I know my limitations. It&#39;s time to get out. It&#39;s time to leave an industry behind that is full of falsified estimates, rushed deliveries, power grinds to meet deadlines, badly defined requirements, insane amounts of finger pointing, and unreasonable expectations. The days when developing software was fun are long gone. Somewhere along the road, it became work. And for me, that&#39;s the day it died.&lt;/p&gt; &lt;p&gt;So I&#39;ll turn from that path, now, and find a new path. I&#39;m not sure what it is yet, but with any luck, it will be far less stressful. &lt;/p&gt; &lt;p&gt;To all of you still in the quagmire, I wish you well and good luck. Software can be tons of fun, if you keep it in the proper perspective. Somewhere along the way, I suppose I just lost mine. Try to keep yours. But for me, this is farewell to software development.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2010/03/farewell-to-software-development.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-5070550850881892397</guid><pubDate>Fri, 30 Oct 2009 16:58:00 +0000</pubDate><atom:updated>2009-10-30T12:58:17.277-04:00</atom:updated><title>Oracle SQL Coding Standards, Or the Dearth of Them</title><description>&lt;p&gt;So here I am, laboring furiously to get my refactoring tools polished up for &lt;em&gt;Insight&lt;/em&gt;, and the one feature that I would really like to get implemented is a spiffy coding-standards compliance tool for SQL. One would think that it would be a simple matter of digging up the most widely accepted standard, allowing the user to modify that standard to suit their firm’s needs, and then applying it to the script in question. And that isn’t really rocket science. Except for one thing.&lt;/p&gt; &lt;p&gt;&lt;em&gt;There isn’t really one widely-accepted PL-SQL coding standard.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Now, I’m not going to just come out and say that Oracle is horrible at documentation. No, wait, I &lt;em&gt;am &lt;/em&gt;going to say that Oracle is horrible at documentation. Aside from the fact that the vast majority of it is nearly incomprehensible, incomplete, and badly formatted, they tend to gloss over things that concern the really important folks: &lt;em&gt;those who have to use the damned thing.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;A coding standard is a really important thing. Without it, you end up with ten-year-old databases that have passed through a plethora of hands and no two sets of hands agree about how the code should be laid out, how the variables and objects should be named, how things should be cased, and where commas should be placed. Sounds trivial, I know. But when you have to come in ten years later and try to reconcile all those competing non-standards into a single, cohesive “product” that makes sense so that you can maintain it, it’s a nightmare. &lt;/p&gt; &lt;p&gt;We &lt;em&gt;need &lt;/em&gt;a driving vision for a SQL coding standard. And we need it from a single source, with some authority behind it. But it can’t just establish a standard that comes down with some heavy-handed practice that isn’t thought out. As much as I hate to admit it, Oracle has been doing this a &lt;em&gt;long &lt;/em&gt;time, and they’re the logical choice to start this movement, with lots of input from the community.&lt;/p&gt; &lt;p&gt;On the other hand, this could be an entirely community-driven thing, a grass-roots effort to establish a common SQL coding standard. &lt;a href=&quot;http://it.toolbox.com/blogs/oracle-guide/sql-and-plsql-free-and-open-coding-standards-33039&quot; target=&quot;_blank&quot;&gt;On this blog&lt;/a&gt;, Lewis Cunningham discusses such a project, but it doesn’t appear to have taken off. It’s a pity, because I think it’d be well worth the effort.&lt;/p&gt; &lt;p&gt;Who knows, maybe I’ll slide on over to Google Apps and see what I can do to start such a grassroots effort myself. I’m tired of sitting around waiting for a consensus to just pop up out of thin air. You’ve got to start somewhere, right?&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2009/10/oracle-sql-coding-standards-or-dearth.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-554861834031791448</guid><pubDate>Wed, 21 Oct 2009 04:29:00 +0000</pubDate><atom:updated>2009-10-21T00:29:05.957-04:00</atom:updated><title>Smug Bastards, Toy Databases, and Ease of Use</title><description>&lt;p&gt;Alarmingly, I cannot find anything in &lt;a title=&quot;All those years in marketing taught me nothing&quot; href=&quot;http://hestia.typepad.com/flatlander/2009/08/those-years-in-marketing-taught-me-nothing.html&quot; target=&quot;_blank&quot;&gt;this post&lt;/a&gt; that I disagree with. I don&#39;t know whether that makes me proud, smug, or ashamed. Either way, I laughed my ass off.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2009/10/smug-bastards-toy-databases-and-ease-of.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-7934404789072806591</guid><pubDate>Wed, 14 Oct 2009 18:44:00 +0000</pubDate><atom:updated>2009-10-14T14:44:10.205-04:00</atom:updated><title>The Cost of a Quick Second</title><description>&lt;p&gt;So, here I am, cleaning up a rather large code base, and I find myself in the throes of &lt;em&gt;retrofitting properties with attributes&lt;/em&gt;. Now, when I wrote these properties, the prevalent thought at the time was that I just had a crap-load of properties to write, and tons of business code that needed them. So, in a bug hurry, I slapped together some C# code that spit them out. You know, kind of like this:&lt;/p&gt;&lt;pre&gt;&lt;span style=&quot;color: blue&quot;&gt;public string&lt;/span&gt; Owner { &lt;span style=&quot;color: blue&quot;&gt;get&lt;/span&gt;; &lt;span style=&quot;color: blue&quot;&gt;protected set&lt;/span&gt;; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Now, at the time, that’s all well and good, because at some point, the work just has to get done. But then, I realized that the software I’ve been working on is actually &lt;em&gt;very useful &lt;/em&gt;and that I want to polish it up and get it ready to release it to the masses. But I discover, to my utter horror, that the source code is an absolute disaster because, well, I didn’t write it with the intention that anyone else was going to actually look at the source code.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Sure, the thing looks beautiful from the outside. And it does what it’s supposed to do (by and large). And it’s fast. Very fast. But please, &lt;em&gt;please &lt;/em&gt;do not look at the plumbing. Or the wiring. The vinyl siding is Fabulous. But don’t look underneath it.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Hence, the retrofitting.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I’m sure you’ve been there. Don’t look at me like that. I &lt;em&gt;know &lt;/em&gt;we’ve all written crap code slapped together in a hurry because we needed something &lt;em&gt;just this second &lt;/em&gt;and &lt;em&gt;it will only take a second to do.&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Which leads me to my point: &lt;strong&gt;A quick second now will cost you hours later.&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This particular project involves two separate assemblies. A Class Library DLL, which houses all the logic, and a Windows Forms Application which references the Class Library. The problem is that the class library is missing the bulk of its XML documentation comments, and the properties aren’t properly marked with attributes. Silly me.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So now, I have to go back through the code, one file at a time, and mark up my source code. Trust me, this is no picnic. Fortunately, I believe in good, clean names, so the code is largely self-documenting. But there have been a few surprises here and there. But going back through any source file and adding the comments after-the-fact is slow and tedious work. You shouldn’t put yourself in a position to do it in the first place. Comment up front when the purpose of the property or method is fresh in your mind.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;When it comes to property attributes, you’d be amazed at how many there are:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;DefaultProperty&lt;/strong&gt;. This attribute doesn’t go on a property, but marks up the class to indicate the name of the property that should be treated as the default. &lt;br /&gt;&lt;li&gt;&lt;strong&gt;ReadOnly&lt;/strong&gt;. Use this attribute to specify that a property is read-only in the property grid. &lt;br /&gt;&lt;li&gt;&lt;strong&gt;Description&lt;/strong&gt;. Use this attribute to specify the description that appears in the property grid, or in the tooltip that appears when the user hovers over the property in the editor. &lt;br /&gt;&lt;li&gt;&lt;strong&gt;Category&lt;/strong&gt;. Use this attribute to specify the category that the property is grouped under when the property appears in the property grid.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;These are the few that I’m primarily interested in. So, for each property, I have to move along as follows:&lt;/p&gt;&lt;pre&gt;&lt;span style=&quot;color: gray&quot;&gt;/// &amp;lt;sumary&amp;gt;&lt;br /&gt;///   &lt;span style=&quot;color: green&quot;&gt;Gets the owner of the view.&lt;/span&gt;&lt;br /&gt;/// &amp;lt;/sumary&amp;gt;&lt;/span&gt;&lt;br /&gt;[&lt;span style=&quot;color: maroon&quot;&gt;ReadOnly&lt;/span&gt;(&lt;span style=&quot;color: blue&quot;&gt;true&lt;/span&gt;), &lt;span style=&quot;color: maroon&quot;&gt;Description&lt;/span&gt;(&lt;span style=&quot;color: red&quot;&gt;&quot;Gets the owner of the view.&quot;&lt;/span&gt;), &lt;span style=&quot;color: maroon&quot;&gt;Category&lt;/span&gt;(&lt;span style=&quot;color: red&quot;&gt;&quot;Schema&quot;&lt;/span&gt;)]&lt;br /&gt;&lt;span style=&quot;color: blue&quot;&gt;string&lt;/span&gt; Owner { &lt;span style=&quot;color: blue&quot;&gt;get&lt;/span&gt;; &lt;span style=&quot;color: blue&quot;&gt;protected set&lt;/span&gt;; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;This gets a lot more complicated if I’m documenting a method, as you can imagine. Then we’re dealing with parameters, return values, and all that other hooplah because &lt;em&gt;the consumer isn’t familiar with the code like I am.&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Refactoring tools can simplify some of this stuff. Some software tools boast the ability to generate documentation comments for you, but my experience with them have been less than rosy. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;So take some advice. Spare yourself a little effort down the road. Document and mark up your code as you go along. It’s worth the time to do it up front. I have to go through this code base and get this stuff cleaned up now. The only good thing I can say about it is that it’s giving me a really good chance to go through the code with a fine-toothed comb and clean it up, remove dead code (oh, for an open-source tool for that!), and eliminate some redundancies. Aside from that, I’ll be kicking myself in the future for taking hasty shortcuts like these.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You should be too.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2009/10/cost-of-quick-second.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-8869835094663542337</guid><pubDate>Sun, 02 Aug 2009 01:05:00 +0000</pubDate><atom:updated>2009-08-01T21:05:49.427-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">City of Heroes</category><category domain="http://www.blogger.com/atom/ns#">Musings</category><title>The Perfect Villain</title><description>&lt;p&gt;I play &lt;a href=&quot;http://www.cityofheroes.com/&quot; target=&quot;_blank&quot;&gt;City of Heroes&lt;/a&gt; quite a bit. Okay, so that&#39;s an understatement. I play it a lot. After five years in the game, my addiction runs so deep it&#39;s threaded its way through my genetic makeup. You&#39;d be hard-pressed to separate me from it.&lt;/p&gt; &lt;p&gt;I&#39;ve always had a love of comic books. What&#39;s not to love? Sure, they&#39;re the domain of geeks, nerds, and all their ilk. But let&#39;s face it: who wouldn&#39;t love to fly? To have virtually god-like power at their disposal? To have a body so ripped you wouldn&#39;t think twice about showing up in public in a spandex body suit?&lt;/p&gt; &lt;p&gt;But one thing has started to really bug me about the villains in my game of choice. Now, I laud the writers for COH. As the game has aged, the stories have grown more compelling, more twisted, more convoluted. Sure, we have some dangling plot threats, gaping plot holes, and all that jazz, but they&#39;ve fleshed out some of the characters quite nicely. In a world full of super-powered beings, that&#39;s frequently no mean feat. It&#39;s not easy fleshing out characters in a story about normal humans; try fleshing out a character who can incinerate you with a look, or teleport across vast distances, or summon the dead--and &lt;em&gt;justify their reasons for doing what they do&lt;/em&gt;. That&#39;s a lot easier said than done.&lt;/p&gt; &lt;p&gt;The budding writer in me understands their desire to do just that. I think that the armchair psychiatrist in all of us would tend to agree that any villain who embarks on a life of crime does so for a reason. Greed, revenge, betrayal, power, lust, all the standard reasons are there. &lt;/p&gt; &lt;p&gt;But I&#39;ve watched those foundation villains in City of Heroes for some time now, and I&#39;ve discovered something about them that disturbs me.&lt;/p&gt; &lt;p&gt;&lt;em&gt;They are all too distracted.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Give me any villain from the COH Universe and I can likely show you how that villain is too distracted. They all lack focus. A clear vision of what it is that motivates them. What Paragon City, indeed the COH Universe, needs is a villain who is so absolutely single-minded that he (or she) is utterly unstoppable and incapable of being distracted.&lt;/p&gt; &lt;p&gt;Imagine, if you will, a villain whom you &lt;em&gt;never see. &lt;/em&gt;He is adept at keeping his identity and location concealed from &lt;em&gt;everyone&lt;/em&gt;, including those with psychic and magical abilities. He does not want money, power, fame, or legions of followers. What he does want is to watch people suffer. He does not care, particularly, how he does it. He just cares that the world is filled with pain, anguish, misery, and death, and that it was his hand that brought it to pass.&lt;/p&gt; &lt;p&gt;He is not a god. He is not inhuman. He is not even super-powered. He is simply intelligent, and possessed of a single-minded determination to bring mass chaos to the world around him. He loathes the other villains because they are weakened by the petty squabbles they engage in between themselves. He will kill heroes, villains and civilians with merciless abandon.&lt;/p&gt; &lt;p&gt;While he has no followers of his own, there are those who have heard of him, and rally to his cause. These &lt;em&gt;copy-cats &lt;/em&gt;seek to emulate him. They spread his anarchist agenda with a ruthlessness on par with his own. They could be anyone: civilians, members of known factions, heroes teetering on the brink of villainy. But &lt;em&gt;none of them &lt;/em&gt;knows who he is or has ever seen him.&lt;/p&gt; &lt;p&gt;The only reason that anyone knows he exists is because he occasionally forewarns people of upcoming tragedies he will inflict, only to incite more terror. His mastery of indirection will sometimes lead heroes to one site in an attempt to avert disaster, only to realize that his real target was some other heavily populated target.&lt;/p&gt; &lt;p&gt;His targets of choice are &lt;em&gt;always &lt;/em&gt;large population centers: hospitals, police departments, large office buildings, schools, and so on. Given any choice where he can inflict damage, he will inflict as much damage as is humanly possible.&lt;/p&gt; &lt;p&gt;Yes, this is the kind of villain that the COH Universe needs. A Black Mask, completely unpredictable, untraceable, never brought to justice, enemy to both hero and villain, and incapable of being distracted from the one thing that he seeks the most: the pain and suffering of others.&lt;/p&gt; &lt;p&gt;I highly doubt that this sort of a villain could be brought to pass and maintain the T for Teen rating that the game enjoys in its current incarnation. But one could dream. And if you&#39;re going to dream, dream big.&lt;/p&gt; &lt;div style=&quot;padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:1f9b130e-434b-433a-ba3f-5d8849de8cec&quot; class=&quot;wlWriterSmartContent&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/City%20of%20Heroes&quot; rel=&quot;tag&quot;&gt;City of Heroes&lt;/a&gt;&lt;/div&gt;  </description><link>http://mikehofer.blogspot.com/2009/08/perfect-villain.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-5050924731870968856</guid><pubDate>Thu, 16 Jul 2009 18:59:00 +0000</pubDate><atom:updated>2009-07-16T14:59:22.859-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">C#</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><category domain="http://www.blogger.com/atom/ns#">VB.NET</category><title>InternalsVisibleTo and Chasing Down Public Keys</title><description>&lt;p&gt;Sometimes, just getting assemblies to cooperate the way you want them to is a real pain in the neck. &lt;/p&gt; &lt;p&gt;Today, I wanted to make one assembly (which we’ll call Foo) to be able to access the &lt;font face=&quot;Courier New&quot;&gt;internal&lt;/font&gt; (Friend for all us VB geeks) members of another assembly (which we’ll call Bar). Now, the documented way to achieve this is by adding the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx&quot;&gt;InternalsVisibleTo&lt;/a&gt; attribute to your project. The code sample on MSDN looks like this:&lt;/p&gt;&lt;pre&gt;[assembly:InternalsVisibleTo(&quot;AssemblyB, PublicKey=32ab4ba45e0a69a1&quot;)]&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;For a Visual Basic application, that statement goes into the AssemblyInfo.vb file, and looks like this:&lt;/p&gt;&lt;pre&gt;&amp;lt;Assembly:InternalsVisibleTo(&quot;AssemblyB, PublicKey=32ab4ba45e0a69a1&quot;)&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;No big deal. It’s not rocket science. You just need a strong name. To generate a strong name, you fire up the Visual Studio Command Prompt, and execute the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/k5b5tt23(VS.71).aspx&quot;&gt;Strong Name tool (sn.exe)&lt;/a&gt; and execute it as follows:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC&amp;gt;sn.exe -k bar.snk &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Microsoft (R) .NET Framework Strong Name Utility&amp;nbsp; Version 3.5.30729.1&lt;br&gt;Copyright (c) Microsoft Corporation.&amp;nbsp; All rights reserved. &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Key pair written to bar.snk&lt;/font&gt; &lt;br /&gt;&lt;p&gt;As you can see, this creates a .SNK file, which contains a public and a private key. However, its contents are not human readable. Further, the InternalsVisibleTo attribute requires that you provide the public key in the constructor. (Don’t even think about trying it without it.)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Here’s where things get tricky: The code samples on MSDN do not provide a public key to the constructor; they provide a public key &lt;em&gt;token&lt;/em&gt;. There’s a &lt;em&gt;huge &lt;/em&gt;difference between the two, and it’s very misleading. A strong name token is much shorter than a public key; the former is only about 16 characters long, the other well in excess of 140 characters. If you rely on the code sample from MSDN to get you where you want to be, you’ll be pulling your hair out in no time.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;But how do you get the public key token?&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You can retrieve the public key token as follows:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;sn –p foo.snk barpublic.snk&lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This creates a new file that contains &lt;em&gt;only the public key. &lt;/em&gt;It removes the private key information from the file. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;sn –tp &amp;gt; barkey.txt &lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This creates a text file that contains the full dump of the key information, including the public key. We redirect it to a text file so that you can open it in the editor of your choice (because you’ll have to do some cleanup to get the key onto one line). You’ll want to select the public key and paste it into the PublicKey portion of the constructor for the InternalsVisible attribute.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So here’s everything we did at the command prompt:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC&amp;gt;sn -k bar.snk &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Microsoft (R) .NET Framework Strong Name Utility&amp;nbsp; Version 3.5.30729.1&lt;br&gt;Copyright (c) Microsoft Corporation.&amp;nbsp; All rights reserved. &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Key pair written to bar.snk &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC&amp;gt;sn -p bar.snk barpublic.snk &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Microsoft (R) .NET Framework Strong Name Utility&amp;nbsp; Version 3.5.30729.1&lt;br&gt;Copyright (c) Microsoft Corporation.&amp;nbsp; All rights reserved. &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Public key written to barpublic.snk &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC&amp;gt;sn -tp barpublic.snk &amp;gt; bar.txt &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC&amp;gt;&lt;/font&gt; &lt;br /&gt;&lt;p&gt;And here’s the contents of our text file:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Microsoft (R) .NET Framework Strong Name Utility&amp;nbsp; Version 3.5.30729.1&lt;br&gt;Copyright (c) Microsoft Corporation.&amp;nbsp; All rights reserved. &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Public key is&lt;br&gt;0024000004800000940000000602000000240000525341310004000001000100e13cb392af5437279736fc3c33fe237242d0f6301fafb01c5cbc719d84102c2d8b30a148600997ed53d99624b5d0eab37fd6b24cca3ce7f7b62ae99f961e148d5421576bade0ac8ab1187a3eee318ca20026ffe9b56b8a63156f817cef49998633867ae547684e8e59c0fe0b68ab29dffa749340dc6cfdd18071f1b69c6772ac &lt;/font&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Public key token is db218359dd8997df&lt;/font&gt; &lt;br /&gt;&lt;p&gt;So, when we finally add that attribute to our AssemblyInfo.vb file, it looks like this: &lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;&amp;lt;Assembly:InternalsVisibleTo(&quot;Bar, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e13cb392af5437279736fc3c33fe237242d0f6301fafb01c5cbc719d84102c2d8b30a148600997ed53d99624b5d0eab37fd6b24cca3ce7f7b62ae99f961e148d5421576bade0ac8ab1187a3eee318ca20026ffe9b56b8a63156f817cef49998633867ae547684e8e59c0fe0b68ab29dffa749340dc6cfdd18071f1b69c6772ac&quot;)&amp;gt;&lt;/font&gt; &lt;br /&gt;&lt;p&gt;Once this stuff is in place, Bar should be able to access any members in Foo that are marked &lt;font face=&quot;courier new&quot;&gt;internal&lt;/font&gt;/&lt;font face=&quot;courier new&quot;&gt;Friend&lt;/font&gt;. It should be smooth sailing from there. &lt;br /&gt;&lt;p&gt;Good luck!&lt;/p&gt;&lt;br /&gt;&lt;div style=&quot;padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:eb7fea41-f012-4a01-8702-fd596492b6c9&quot; class=&quot;wlWriterEditableSmartContent&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/Software+Development&quot; rel=&quot;tag&quot;&gt;Software Development&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/.NET&quot; rel=&quot;tag&quot;&gt;.NET&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/Visual+Basic&quot; rel=&quot;tag&quot;&gt;Visual Basic&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/C%23&quot; rel=&quot;tag&quot;&gt;C#&lt;/a&gt;&lt;/div&gt;  </description><link>http://mikehofer.blogspot.com/2009/07/internalsvisibleto-and-chasing-down.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-7617410303835850372</guid><pubDate>Wed, 15 Jul 2009 03:12:00 +0000</pubDate><atom:updated>2009-07-14T23:12:44.712-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Musings</category><category domain="http://www.blogger.com/atom/ns#">Quality</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><category domain="http://www.blogger.com/atom/ns#">Software Maintenance</category><title>On Legacy Software Maintenance</title><description>&lt;p&gt;In the mad, mad, mad, mad world of software development, we are faced with the trying task of maintaining legacy systems. In an ideal world, that wouldn&#39;t be the case. We&#39;d all be developing brand new systems from the ground up, writing ground-breaking code that no one has ever seen before, without the hassles that arise when you have to worry about things like backwards compatibility and maximum system uptime.&lt;/p&gt; &lt;p&gt;But this isn&#39;t an ideal world. The vast majority of us don&#39;t have the luxury of developing completely new systems. Instead, our lives are fraught with the perils of correcting defects and adding new features to systems that have been around for ages and, occasionally, decades. Those systems have usually passed through a number of hands and they tend to be poorly documented. They sometimes have sprawling feature sets, support technologies that have long since fallen by the wayside, bloated with code that doesn&#39;t appear to be invoked by anyone, and riddled with obscure and seemingly nonsensical comments.&lt;/p&gt; &lt;p&gt;Your job, as a maintenance developer, is to massage that seemingly horrific beast into a thing of beauty. Real people doing real jobs depend on it to get their work done in a timely manner. As much as we might loathe an ancient codebase, the language it was written in, or the tools we have to use to get the job done, truth is, a legacy application is maintained for a reason: it has intrinsic value to the bottom line of the business. When the folks who depend on that system can get their jobs done on time, in a productive manner, they can continue to draw a decent paycheck. That means that they can continue to pay the rent, put food on the table for their families, afford healthcare, and all those other essentials. &lt;/p&gt; &lt;p&gt;So tread lightly when you delve into the code of a legacy system. It&#39;s far more important than you think. We just take it for granted that it&#39;s a dirty, loathsome job and someone has to do it. We just happen to be the unlucky bastard who drew the short straw. Not so: you happen to be the &lt;em&gt;lucky &lt;/em&gt;one who drew that straw. People depend on you to help them keep their families safe, warm, and well-fed. &lt;/p&gt; &lt;p&gt;My point isn&#39;t that every legacy application is manna from heaven. My point is that legacy applications exist for a reason, that they&#39;re maintained for a reason. They have long, varied histories for a reason. They have endured because they have value; they&#39;ve grown beyond their original specification because the company sees real value in them, and doesn&#39;t want to lose that investment. The problem for you, as a developer, is in ensuring that you do not destroy that investment.&lt;/p&gt; &lt;p&gt;When we are first introduced to a legacy system, we have a tendency to look at the source code and view it as though it were written by a blind deaf quadriplegic with Tourette&#39;s syndrome. No one in their right mind would have written a system that way. What could they possibly have been thinking? You certainly wouldn&#39;t have! I certainly wouldn&#39;t have. &lt;/p&gt; &lt;p&gt;But then, over time, we start to learn things about it. The code is old; &lt;em&gt;very &lt;/em&gt;old. There&#39;s been a high turnover rate, and the code has passed through lots of hands. The companies that published third-party components went out of business when the dot-com bubble burst. They used to use Novell for security, and then switched to Active Directory. When this thing was released, Windows 95 was still popular. They upgraded the database about two years ago, and had to make some emergency revisions to the code.&lt;/p&gt; &lt;p&gt;There are reasons that things like this happen in a legacy system that&#39;s old enough to qualify for Medicare. Many of those reasons are valid, and many of them are the product of a lack of time and budget. Sometimes, sadly, it&#39;s a result of a lack of skilled developers (but that&#39;s something for someone else to blog about). The point, in short, is that systems grow from an original vision into large, cumbersome, bloated systems because &lt;em&gt;developers respond to the needs and demands of the business.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;Now, here you are, present day, and you&#39;re tasked with maintaining that source code. You have two primary responsibilities: 1.) Fix the defects, and 2.) Add new features. Keep in mind that while you are doing both, you must not at any point in time break backwards compatibility or bring down the system. People rely on this system. It&#39;s the bread and butter (or part of it) of the business. And it&#39;s your baby now.&lt;/p&gt; &lt;p&gt;It is absolutely crucial that you treat legacy software with its due gravity. If you view it like it&#39;s some recurring annoyance, &lt;em&gt;stop that. &lt;/em&gt;If you leap to hasty conclusions about the cause of problems in the system, &lt;em&gt;&lt;u&gt;stop that immediately&lt;/u&gt;&lt;/em&gt;. This is a system that many people rely on. Get it into your head that you need to treat this thing delicately, as if it were your pride and joy. Once you fix a defect, once you put a new feature into it, &lt;em&gt;your name is associated with that software. &lt;/em&gt;Take pride in it. Do it right. Take your time. &lt;/p&gt; &lt;p&gt;Over time, the legacy system stops being the horrific beast associated with all those who preceded you. It becomes the creature that &lt;em&gt;you &lt;/em&gt;have molded it into. And then, people will associate it with you, for better or worse. &lt;/p&gt; &lt;div style=&quot;padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:4da5cf2f-f6a3-40bb-85a6-8d52851960de&quot; class=&quot;wlWriterSmartContent&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/Quality&quot; rel=&quot;tag&quot;&gt;Quality&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Software%20Development&quot; rel=&quot;tag&quot;&gt;Software Development&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Legacy%20Software&quot; rel=&quot;tag&quot;&gt;Legacy Software&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Software%20Maintenance&quot; rel=&quot;tag&quot;&gt;Software Maintenance&lt;/a&gt;&lt;/div&gt;  </description><link>http://mikehofer.blogspot.com/2009/07/on-legacy-software-maintenance.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-2021629880948974737</guid><pubDate>Mon, 13 Jul 2009 14:02:00 +0000</pubDate><atom:updated>2009-07-13T10:02:37.496-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Best Practices</category><category domain="http://www.blogger.com/atom/ns#">Musings</category><category domain="http://www.blogger.com/atom/ns#">Productivity</category><category domain="http://www.blogger.com/atom/ns#">Quality</category><category domain="http://www.blogger.com/atom/ns#">Refactoring</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>The Sad State of SQL Refactoring</title><description>&lt;p&gt;I love refactoring tools.&lt;/p&gt; &lt;p&gt;The ability to select a variable in code, right-click on it, choose the Rename command from a context menu, and then safely rename that variable in every location in which it appears is a boon to my programming productivity. Similarly, the ability to take a large block of complex logic and extract it to its own method is really handy. Or, the ability to reorder parameters, and know that every piece of code that calls that method will be updated appropriately saves me tons of time and improves my confidence in the quality of the code.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://c2.com/cgi/wiki?WhatIsRefactoring&quot; target=&quot;_blank&quot;&gt;When you refactor code of any kind, you enhance its readability without changing the way it works&lt;/a&gt;. But refactoring by hand is frequently difficult, tedious, and error-prone. That&#39;s why refactoring tools exist and why the essential service they provide is important. They allow us to improve the maintainability of code, hopefully reducing maintenance costs, quickly and efficiently. &lt;/p&gt; &lt;p&gt;Enter SQL languages. &lt;/p&gt; &lt;p&gt;In theory, there is a standard for SQL languages: &lt;a title=&quot;The ANSI SQL-92 standard&quot; href=&quot;http://en.wikipedia.org/wiki/SQL-92&quot; target=&quot;_blank&quot;&gt;the ANSI SQL-92 standard&lt;/a&gt;. One would like to think that it would be a simple matter to create refactoring tools for any SQL based on the ANSI standard for SQL. One would be wrong. You can&#39;t use the standard as the sole basis of a refactoring tool. &lt;/p&gt; &lt;p&gt;Any given database vender wants to strive to make their product unique, to stand out from the crowd. And so, they don&#39;t &lt;em&gt;entirely &lt;/em&gt;conform to the standard. They have additional features that separate them from each other. For example: Oracle organizes functions and procedures into packages. Microsoft does not. Microsoft allows a bit data type on columns. Oracle does not. And, although we all loathe to think of Access as a real database, Access provides a &lt;em&gt;boolean &lt;/em&gt;data type that you can use in columns, while Oracle does not.&lt;/p&gt; &lt;p&gt;Now, let&#39;s also talk about legacy support. Oracle has been around for a &lt;em&gt;very long time. &lt;/em&gt;Version 2 came out in 1979, from what I gather. Their legacy join syntax looks nothing like the ANSI standard (and that&#39;s not a criticism, just a simple statement of fact):&lt;/p&gt; &lt;p&gt;&lt;code&gt;SELECT Customers.CustomerId, Company, OrderID&lt;br&gt;FROM Customers C, Orders O&lt;br&gt;WHERE C.CustomerID (+) = O.CustomerID&lt;br&gt;UNION&lt;br&gt;SELECT Customers.CustomerId, Company, OrderID&lt;br&gt;FROM Customers C, Orders O&lt;br&gt;WHERE C.CustomerID = O.CustomerID (+) &lt;/code&gt;&lt;/p&gt; &lt;p&gt;In ANSI SQL, this is :&lt;/p&gt; &lt;p&gt;&lt;code&gt;SELECT Customers.CustomerId, Company, OrderId&lt;br&gt;FROM Customers C FULL OUTER JOIN Orders O ON&lt;br&gt;(C.CustomerId = O.CustomerId)&lt;/code&gt;&lt;/p&gt; &lt;p&gt;Now, we could add in all the different SQL variations that we know that are out there:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;ANSI standard&lt;/li&gt; &lt;li&gt;Interbase/Firebird&lt;/li&gt; &lt;li&gt;IBM&amp;nbsp; SQL&lt;/li&gt; &lt;li&gt;Microsoft Transact SQL&lt;/li&gt; &lt;li&gt;MySQL&lt;/li&gt; &lt;li&gt;Oracle PL/SQL&lt;/li&gt; &lt;li&gt;PostgreSQL &lt;/li&gt; &lt;li&gt;Access&lt;/li&gt; &lt;li&gt;FoxPro&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;...and on and on and on, but you get the point. There are a lot of SQL variants out there. And their goal is to accomplish the same thing: &lt;/p&gt; &lt;ul&gt; &lt;li&gt;Create a data store.&lt;/li&gt; &lt;li&gt;Occasionally, modify the structure of the data store.&lt;/li&gt; &lt;li&gt;Get data out of a data store.&lt;/li&gt; &lt;li&gt;Put data into a data store.&lt;/li&gt; &lt;li&gt;If supported, execute code within the confines of the data store and (optionally) return a result.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Behold, SQL in a nutshell.&lt;/p&gt; &lt;p&gt;Over the lifetime of these various products, they have added features that they have to maintain for legacy support. Somewhere out there there&#39;s a business that absolutely &lt;em&gt;must &lt;/em&gt;have that feature in place or their whole process will come crashing down. Don&#39;t you dare remove it. It doesn&#39;t matter that there are better features (likely based on a standard); there are applications out there for which they don&#39;t have the source code anymore, or which no one understands, and they&#39;re too afraid to touch.&lt;/p&gt; &lt;p&gt;Now, all these reasons have led us to a scenario where we have vastly different implementations of SQL. Sure, they share a lot in common, but they also have radically different feature sets and syntax. And that situation, in and of itself, has led us to one frightening and sad conclusion:&lt;/p&gt; &lt;p&gt;We will likely never have a tool that is able to connect to &lt;em&gt;any &lt;/em&gt;database and be able to correctly refactor its SQL. &lt;/p&gt; &lt;p&gt;And that&#39;s just a damned shame. Because there&#39;s a lot of SQL out there. Stored procedures, functions, views, triggers, even inline SQL in applications and all that other jazz. But the amount of work it would take to get us to a point where a refactoring tool could recognize &lt;em&gt;any &lt;/em&gt;variant of SQL and correctly parse it, refactor it, and not hose the code is enormous. &lt;/p&gt; &lt;p&gt;It&#39;s a pity, really. I could see tons of use for a tool like this. In my own office, we work with SQL Server, Oracle, and Atomix databases. What I wouldn&#39;t give for a tool that could refactor SQL to enhance its readability without changing the way it worked. &lt;/p&gt; &lt;p&gt;And who knows? Down the road, we may be working with something else. &lt;/p&gt; &lt;p&gt;But this is the world we live in. If we want to refactor SQL, it looks like we&#39;ll have to settle for separate refactoring tools for each language. And then each will come with its own quirks. That might be good or bad, but it&#39;s likely the best we can hope for for now.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt; &lt;div style=&quot;padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:138fc9b2-2cbe-4553-a8b7-329cbdd0dab2&quot; class=&quot;wlWriterSmartContent&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/SQL&quot; rel=&quot;tag&quot;&gt;SQL&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Best%20Practices&quot; rel=&quot;tag&quot;&gt;Best Practices&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Productivity&quot; rel=&quot;tag&quot;&gt;Productivity&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Code%20Quality&quot; rel=&quot;tag&quot;&gt;Code Quality&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Refactoring&quot; rel=&quot;tag&quot;&gt;Refactoring&lt;/a&gt;, &lt;a href=&quot;http://technorati.com/tags/Software%20Development&quot; rel=&quot;tag&quot;&gt;Software Development&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2009/07/sad-state-of-sql-refactoring.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-1303251255226116726</guid><pubDate>Sun, 12 Jul 2009 00:14:00 +0000</pubDate><atom:updated>2009-07-11T20:14:03.071-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Best Practices</category><category domain="http://www.blogger.com/atom/ns#">Quality</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><title>Defects and the Scientific Method</title><description>&lt;p&gt;Let&#39;s leap back a few years to that frightening time in Junior High School. Remember those years? September, possibly October. It was still hot, and the air conditioning didn&#39;t work. Your science teacher was standing in the back of the room, with an overhead projector and had a slide up for you to copy down. On it, he had this information:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;THE SCIENTIFIC METHOD&lt;/p&gt; &lt;li&gt;Ask and define the question.  &lt;li&gt;Gather information and resources through observation.  &lt;li&gt;Form a hypothesis.  &lt;li&gt;Perform one or more experiments and collect and sort data.  &lt;li&gt;Analyze the data .  &lt;li&gt;Interpret the data and make conclusions that point to a hypothesis.  &lt;li&gt;Formulate a &quot;final&quot; or &quot;finished&quot; hypothesis.&lt;/li&gt;&lt;/blockquote&gt; &lt;p&gt;Ah, remember those days? Remember how boring it was? Remember thinking to yourself, &quot;I&#39;ll never use this?&quot;&lt;/p&gt; &lt;p&gt;Well, as a software developer who is tasked with maintaining software that is virtually &lt;em&gt;guaranteed &lt;/em&gt;to contain defects, you can be certain that you need to be intimately familiar with The Scientific Method.&lt;/p&gt; &lt;p&gt;The Scientific Method provides a clear roadmap for defect isolation. In fact, anyone who has any real experience isolating defects without disturbing the rest of the system has (whether he&#39;s aware of it or not) used the Scientific Method to do so. Here&#39;s how it breaks down:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Ask and define the question.&lt;/strong&gt; The software should behave in this manner, but it does not. What is the cause of this problem, and how do we fix it?  &lt;li&gt;&lt;strong&gt;Gather information and resources through observation.&lt;/strong&gt; In a controlled environment that mimics production as closely as possible, reproduce the defect. If possible, step through the code and observe its behavior.  &lt;li&gt;&lt;strong&gt;Form a hypothesis.&lt;/strong&gt; The defect is caused by this behavior in the system (or by the behavior of this external system).  &lt;li&gt;&lt;strong&gt;Perform one or more experiments and collect and sort data.&lt;/strong&gt; Implement a code fix; attempt to reproduce the defect using the fixed code. Observe the results.  &lt;li&gt;&lt;strong&gt;Analyze the data.&lt;/strong&gt; Did the code fix have the desired effect? If so, how?  &lt;li&gt;&lt;strong&gt;Interpret the data and make conclusions that point to a hypothesis.&lt;/strong&gt; Was the code that was modified the &lt;em&gt;cause &lt;/em&gt;of the defect, or was it merely a symptom of an underlying problem requiring further resolution?  &lt;li&gt;&lt;strong&gt;Formulate a &quot;final&quot; or &quot;finished&quot; hypothesis.&lt;/strong&gt; If the defect is fully repaired, check all code into the repository. Otherwise, continue the analysis until you have rooted out the underlying cause of the defect.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Simply put, there&#39;s no guesswork in defect resolution. It is a rational, thinking process, much like a game of Sodoku. If you approach any defect and just yank an answer out of thin air, &lt;em&gt;You&#39;re Doing It Wrong. &lt;/em&gt;&lt;/p&gt; &lt;p&gt;Instant answers to defects are a dangerous game. Your first, instinctive answer to any problem is likely to be wrong; the chances of this being true will only rise as your code base grows in size. As your product gains features, you&#39;ll want to take greater care to make sure that you have taken the time to disturb absolutely &lt;em&gt;nothing &lt;/em&gt;outside of the defect you&#39;re trying to correct. In that case, take some advice: Keep your grubby fingers to yourself. Touch only the code in the defect domain. The best way to do that is to have a plan for defect resolution, and I strongly encourage you to apply The Scientific Method.&lt;/p&gt; &lt;p&gt;Developing software is a task for those who can think. It is not a task for the simple-minded, the lazy, or the inattentive. You have to be willing to pay attention to the details, and to invest the time it takes to hunt down a defect in painstaking detail to get to the root of a problem. &lt;/p&gt; &lt;p&gt;A good software developer knows the difference between a &lt;em&gt;symptom &lt;/em&gt;and a &lt;em&gt;disease&lt;/em&gt;, and how that correlates to software defects. Sure, you have a NullReferenceException, and your code is missing a handler for that. But is the problem the missing exception handler, or is the problem that a null somehow got into a table that should never have had it, or that a stored procedure in the database returned nulls when they were never expected? Which one is the symptom? Which is the disease? Make sure you&#39;re fixing the right defect. Don&#39;t just prescribe aspirin when the software needs invasive surgery. To find that out, you need to think critically. You need to apply the Scientific Method.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2009/07/defects-and-scientific-method.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-2686329691345596872</guid><pubDate>Sun, 10 Aug 2008 22:47:00 +0000</pubDate><atom:updated>2008-08-10T18:49:04.827-04:00</atom:updated><title>Top 10 Signs You&amp;#39;ve Become Indispensable (and Are Therefore About to Be Fired)</title><description>&lt;p&gt;A wise man once told me that when someone becomes indispensable the very best thing you can do is get rid of them as soon as possible. I&#39;ve always thought that was sage advice. I&#39;ve tried to keep that in mind. So I&#39;m always keeping an eye out for habits that &quot;indispensable&quot; coders have. These are the guys I want eliminated, even if one of those guys is me.&lt;/p&gt; &lt;p&gt;What it comes down to is whether or not one guy on the team can hold an entire project hostage. No company can reasonably afford to be in that position. I certainly wouldn&#39;t want to put a company in that position. It&#39;s about risk, and managing that risk, and doing so proactively. &lt;/p&gt; &lt;p&gt;So, without further adieu, the Top 10 Signs You&#39;ve Become Indispensable (and Are Therefore About to Be Fired):&lt;/p&gt; &lt;ol&gt; &lt;li&gt;You&#39;re the only one who can work on the particular tasks assigned to you, because you&#39;re the only one who understands them.  &lt;li&gt;You believe in or practice job security through code obscurity.  &lt;li&gt;You don&#39;t communicate, and hoard valuable information that other members of the team need to get their jobs done.  &lt;li&gt;You make technology decisions, implement them, and expect everyone to follow suit, whether they understand them or not.  &lt;li&gt;You frequently make vast, sweeping changes to the underlying architecture of the system, without first discussing those changes or their impact with others on the team.  &lt;li&gt;You don&#39;t &lt;em&gt;really &lt;/em&gt;understand object oriented analysis and design, but you act like you do.  &lt;li&gt;You resist any suggestions for better, proven ways to implement solutions, simply because someone tried it that way before and it left a bad taste in your mouth.  &lt;li&gt;You use source code control like a backup device, rather than a version control system.  &lt;li&gt;When designing a system, your first thought is the code or data model and not the problem domain.  &lt;li&gt;You have no interest in being a member of the team, and would rather do it your way all the time.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&lt;font size=&quot;1&quot;&gt;(This is, of course, completely unscientific and totally subjective. Take it or leave it.)&lt;/font&gt;&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2008/08/top-10-signs-you-become-indispensable.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-3852946543640307109</guid><pubDate>Thu, 07 Aug 2008 12:02:00 +0000</pubDate><atom:updated>2008-08-08T14:10:41.929-04:00</atom:updated><title>Why Censor the Internet (Language Warning)</title><description>&lt;div style=&quot;border-right: gray 1px solid; border-top: gray 1px solid; border-left: gray 1px solid; border-bottom: gray 1px solid; background-color: lemonchiffon&quot;&gt; &lt;p&gt;A poster on Digg offered this eloquent response to the article, &lt;a href=&quot;http://digg.com/security/Internet_Censorship_is_On_it_s_Way_The_i_Patriot_Act&quot;&gt;Internet Censorship is On it&#39;s Way. The i-Patriot Act&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;WHY THE FUCK ARE THEY CONCERNED ABOUT THE FUCKING INTERNET?!?!&lt;/p&gt; &lt;p&gt;I mean seriously there are much bigger issues in the whole fucking world then the internet. We cannot be in our on privacy doing our own thing without the people watching over us. I mean come on its such bullshit. Soon it will be like the movie Demolition Man and we will get fined when we fucking curse at home! We are slowly creeping into a government who has complete control over everything we do.&lt;/p&gt; &lt;p&gt;Censor the internet... Give me a fucking break.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;My apologies for the language, but this impassioned question deserves an equally impassioned answer. Why, indeed?&lt;/p&gt;&lt;/div&gt; &lt;p&gt;In a fascist state, the last thing you want is for people to be able to express themselves and speak out against the government. It&#39;s all about control. And people who can speak freely can&#39;t be controlled. Neither can those who listen to those who speak freely.&lt;/p&gt; &lt;p&gt;Anyone who&#39;s been raptly paying attention to what&#39;s been going on in our country (particularly over the last 8 years or so) knows that we&#39;ve been becoming a fascist state. But it&#39;s by our own choosing. We elected these people to power, either by choice or by sheer apathy. We refused to entertain the notion of deviating from a two party system, and we allowed them to strip us of our rights and freedoms. We did not cry out in protest when the Patriot Act was put into place; rather, many of us celebrated it, embracing it as a necessary evil in order to hunt down the vile terrorists who had dared to attack us on our own soil.&lt;/p&gt; &lt;p&gt;Thus, &lt;em&gt;we&lt;/em&gt; surrendered our rights, our freedoms, our liberties in order to gain a false sense of security and chase after demons that never really existed. And from that day forward our government, whom we put into power and have kept in power, have continued to play upon our fears in order to further strip us of any vestige of the Constitutional rights we had before. They can do what they want, when they want, to whomever they want, and there is little that any of us can do about it.&lt;/p&gt; &lt;p&gt;But we chose this path. We elected it. Sixty percent of the population failed to vote in the last presidential election. It was far more important to watch reality television than it was to secure a meaningful future for our nation, and we allowed the same criminals to maintain their stranglehold on what was once a powerful, respectable democracy. But those same people maintain that their government fails them, that they have no rights, that the economy is in the toilet, that we&#39;re sending our troops to senseless deaths overseas in a war we should never have been involved in, and a myriad of other complaints. When asked, though, they&#39;ll tell you that they didn&#39;t vote because their vote didn&#39;t count. Of course it didn&#39;t. No uncast vote counts.&lt;/p&gt; &lt;p&gt;But we&#39;ve learned nothing. Even now we entertain the absurd notion of effecting change by maintaining the status quo. We&#39;re going to elect either Obama or McCain. Yet another pawn from a two-party system. Neither will be able to revolutionize the country and restore what it was. Neither will break the back of the military industrial complex. Neither will do what must be done to fix what must be fixed.&lt;/p&gt; &lt;p&gt;That responsibility rests with you and me. Right here. Right now. Every day. But it means getting off our asses, turning off our televisions, and getting involved. We must DEMAND change, DEMAND our rights, and DEMAND the restoration of the Constitution.&lt;/p&gt; &lt;p&gt;You see? A fascist would &lt;em&gt;never&lt;/em&gt; want words like these uttered on any medium. And the Internet makes it all too easy to make such statements in a forum where hundreds, thousands, even millions of people can read it.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2008/08/why-censor-internet-language-warning.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-1608832651648852400</guid><pubDate>Mon, 07 Apr 2008 03:10:00 +0000</pubDate><atom:updated>2008-04-06T23:10:48.066-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">.NET</category><category domain="http://www.blogger.com/atom/ns#">Best Practices</category><category domain="http://www.blogger.com/atom/ns#">Musings</category><category domain="http://www.blogger.com/atom/ns#">Productivity</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><category domain="http://www.blogger.com/atom/ns#">Technology</category><title>The Absurdity of &amp;quot;Don&amp;#39;t Reinvent the Wheel&amp;quot;</title><description>&lt;p&gt;As developers, we&#39;ve had this adage drilled into us from the beginning: Don&#39;t reinvent the wheel. In short, don&#39;t rewrite what&#39;s already been written. The idea is sound, in theory. You can save yourself time and money if you&#39;ll simply reuse existing code and/or components rather than writing them yourself from scratch. This time and money is saved up front when you write it (or would have written it), and down the road, when you have to maintain your system.&lt;/p&gt; &lt;p&gt;However, I&#39;d like to point out another, equally applicable adage: &lt;em&gt;There&#39;s nothing new under the sun. &lt;/em&gt;Anyone who&#39;s ever tried to write a novel, a short story, a play, a movie, a song, or a piece of software, will know this one simple truth: somewhere, at some point in time, it&#39;s already been written.&lt;/p&gt; &lt;p&gt;Every algorithm, every piece of code that we will ever attempt to write has already been written somewhere, at some point in time, by someone. Only the names have been changed. You&#39;re not inventing anything that is completely new, that&#39;s never been seen before. You should wisely disabuse yourself of that notion as quickly as possible.&lt;/p&gt; &lt;p&gt;In the grand scheme of things, at the application level, you may very well have an idea for a system that is unlike anything that has been done to date. But the algorithms that drive it have already been written. Bubble sorts, hashes, exception handlers, encryption, data access, socket management, shopping carts, entire application frameworks, date management, document management, serialization, port I/O, and all that other stuff has already been done. Further, it&#39;s already been done several times over in many different languages to varying degrees of success.&lt;/p&gt; &lt;p&gt;Tragically, if you&#39;re using a large application framework, like Java&#39;s EE or Microsoft&#39;s .NET, the chances are good that the functionality you&#39;re looking for is built right into the framework itself. The problem is that the framework is so vast that you&#39;ll spend more time looking for it, and determining whether or not it works the way you need it to work than you would just rewriting it yourself. &lt;/p&gt; &lt;p&gt;Application frameworks are stunningly afflicted with feature creep. They must do everything under the sun, must meet every possible need. The problem, then, is that their scope becomes so broad, so vast, that no one in their right mind could possibly grasp the totality of all that they can do. It is inevitable that anyone using them will reinvent some of their functionality. The scale of that functionality might be small (reformatting dates) or it might be substantial (pooled database connections).&lt;/p&gt; &lt;p&gt;In the end, it&#39;s absurd to think that we can possibly avoid reinventing the wheel. Of course we&#39;re going to reinvent it. Every application we write is a reinvention of someone else&#39;s wheel. It just so happens that our wheel is a custom wheel. All this paranoia about reinventing the wheel is blown out of proportion. A proper buy vs. build decision should never be neglected; but don&#39;t ever think for one minute that what you&#39;re creating hasn&#39;t been created before. &lt;/p&gt; &lt;p&gt;Consider the scenario where you&#39;re under the gun to get a product out the door. And I mean it&#39;s a really tight schedule. And don&#39;t act like it&#39;s a perfect world, and you have leverage over the schedule. This is reality here. In the real world, the &lt;em&gt;customer &lt;/em&gt;controls the schedule, because it&#39;s tied to when the product is released, and that&#39;s tied to this big, huge monstrosity in another state or another country. The product&#39;s delivery schedule is a train barreling down the track at 120mph and no one short of God can stop it. Now, you have a &lt;em&gt;very &lt;/em&gt;finite amount of time to work in. You need an algorithm. You know you could write it. Or you could look to see if someone else has written it. &lt;/p&gt; &lt;p&gt;If you do the whole Web search thing, you have to ask yourself a few questions: Is it from a source you trust? Is it in the language you&#39;re using, or do you have to convert it? &lt;em&gt;Does it work? &lt;/em&gt;Does it need to be tweaked? If any of these fail, you&#39;re back to the drawing board. Time&#39;s wasting here, and that train&#39;s getting closer to its destination. If all the answers pass, you have to make sure you don&#39;t run into any copyright or licensing issues with that code. (You are paying attention to that, aren&#39;t you?)&lt;/p&gt; &lt;p&gt;If you decide to peruse your application&#39;s framework, you&#39;d better hope it&#39;s well documented, and very easy to search. Good luck using the search features in .NET. It&#39;s not like the ASK.COM interface, where you can ask, &quot;How do I convert a date in DOD format to Gregorian format?&quot; Yeah. Good luck with that. On the other hand, you could ask your coworkers. They might know. Then again, they might not. If they don&#39;t, you&#39;re off to Google to get the information. Here&#39;s hoping you get a timely and accurate response.&lt;/p&gt; &lt;p&gt;Sure, this is an extreme example. But it makes my point: At some point, the work has to get done. You can&#39;t afford to spend days or weeks scratching your head about whether or not that wheel&#39;s already been invented. Believe me, it has. The problem is, there are a countless number of wheels, and none of them are labeled, and you don&#39;t know where to find the wheel you&#39;re looking for.&lt;/p&gt; &lt;p&gt;Stop wasting time, and invent your own damned wheel. &lt;/p&gt; &lt;p&gt;After all, whatever code you might reuse, is just someone else&#39;s reinvention of the same wheel.&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2008/04/absurdity-of-reinvent-wheel.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-2749576790831204299</guid><pubDate>Fri, 28 Mar 2008 02:43:00 +0000</pubDate><atom:updated>2008-03-27T22:43:13.126-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Musings</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><title>My First Time: Software Passion</title><description>&lt;p&gt;I remember when I was first bitten by the computer programming &quot;Bug.&quot;&lt;/p&gt; &lt;p&gt;I was young: still in high school, in fact. At my particular high school (in &lt;a title=&quot;Fontana, California article on WikiPedia&quot; href=&quot;http://en.wikipedia.org/wiki/Fontana,_California&quot; target=&quot;_blank&quot;&gt;Fontana, California&lt;/a&gt;), we had an Indian Education Department. That small department was lucky enough to have a &lt;a title=&quot;TRS-80 article on WkiPedia&quot; href=&quot;http://en.wikipedia.org/wiki/TRS-80&quot; target=&quot;_blank&quot;&gt;TRS-80&lt;/a&gt; computer for the kids in the Indian Club to play on. I dare say that the computer itself drew a few kids to the club; we were misfits, outcasts, by and large, but we were drawn to that thing like moths to a flame.&lt;/p&gt; &lt;p&gt;It was nothing to look at really. It was just an old monochrome monitor, with a keyboard, and a tape drive. Our model didn&#39;t even have a floppy disk. Everything was on tapes. But we were mesmerized by that thing. I remember watching one of the other kids, Dan, fire up ZORK, and typing, &quot;go north&quot; into the computer. It responded to his simple command, and described the next room to him. &lt;em&gt;It amazed me. &lt;/em&gt;I remember sitting there and thinking, &quot;How did they &lt;em&gt;do &lt;/em&gt;that?&quot;&lt;/p&gt; &lt;p&gt;I mean, it was just a stupid box, with a keyboard and a cassette drive. It couldn&#39;t think. But there it was, responding to him as if it &lt;em&gt;could &lt;/em&gt;think. And he could type commands that were, for the day, fairly close to English. &quot;Eat food.&quot; &quot;Quaff potion.&quot; &quot;Open door.&quot;&lt;/p&gt; &lt;p&gt;I remember sitting there, thinking about that and being relentlessly tormented by it. I had to know. How could an inanimate box like that do things like that? How did it know what room he was in? How come the rooms changed every time we played the game? How did it decide if the potion killed him, healed him, or made him sick? How did it decide what color the potion was? How did it decide what was in the room? For a stupid box with no brain, this thing was pretty damned smart.&lt;/p&gt; &lt;p&gt;And then, one day, Dan got stumped by the game. Something, apparently was wrong. A few years later, I&#39;d realize he&#39;d found a bug. So, he fired up a program, and cracked open the game&#39;s source code. And there, before my eyes, was the big secret. It was line after line after line of &lt;em&gt;source code: &lt;/em&gt;carefully written instructions that told the stupid box exactly what to do. From those cryptic instructions, written in some obscure language called BASIC, you could make that TRS-80 do &lt;em&gt;amazing &lt;/em&gt;things!&lt;/p&gt; &lt;p&gt;That was the beginning of the end for me. I had to master that language. I had to know how I, too, could command a stupid, brain-dead box and make it do amazing things. It wasn&#39;t long before I had obtained a copy of the language reference for BASIC and taken a computer programming course at our High School. (Yes, we had them, even out in the sticks in Fontana.)&lt;/p&gt; &lt;p&gt;So, in a way, ZORK made me a programmer. &lt;/p&gt; &lt;p&gt;It&#39;s been about twenty-five years since I watched Dan crack open the source code to ZORK, and the path of my life was irrevocably altered. Up until that point, I didn&#39;t really have any real aspirations. I don&#39;t think I really did after that, either. But one thing became very clear: more than any other endeavor to which I applied myself, computer programming proved itself to be my one enduring passion. All these years later, I still have those moments reminiscent of that first day. I&#39;ll see a beautiful piece of code, a website design, or an application, and I&#39;ll think, &quot;How did they &lt;em&gt;do that&lt;/em&gt;?&quot; Any ideas I may have had about leaving software development will be blown away and my passion for software will be rekindled.&lt;/p&gt; &lt;p&gt;It&#39;s because I have to know. I can&#39;t walk away from these damned stupid boxes without being able to make them do amazing things. &lt;/p&gt; &lt;p&gt;There&#39;s a certain, childish delight in figuring out the solution to a problem, or finding a new way to do something. For me, it&#39;s like Christmas, and I want to share that joy with others. Sadly, a lot of folks don&#39;t understand it--especially if they&#39;re not in the same field. But anyone who&#39;s done this work, and ever had a &lt;em&gt;EUREKA! &lt;/em&gt;moment knows &lt;em&gt;exactly &lt;/em&gt;what I&#39;m talking about. &lt;/p&gt; &lt;p&gt;Somewhere, right now, a budding young developer is experiencing his or her first time. They&#39;re being bitten by the bug. It&#39;s an infection that will take hold and set in for life. For most of us, it&#39;s a turbulent ride, filled with ups and downs, and we frequently consider leaving the field. For others, it&#39;s pure hell, and we leave it too quickly; for a lucky few, it&#39;s nirvana all the way through. I&#39;m not sure I envy the lucky few; I rather like the way my challenges have tempered me over the years.&lt;/p&gt; &lt;p&gt;When you face challenges, think back on what it was about software that caught you in the first place. Think back to your first time. Then think about the many times you&#39;ve been lured back to it by &lt;em&gt;your own passion. &lt;/em&gt;Not because someone offered you money, or material goods, or power, or prestige; think back to those times that your personal passion for software kept you in the game. Then ask yourself why you feel so passionate about software. The answer for me was surprising: I&#39;m not really doing it for anyone else, but because &lt;em&gt;I have to know, and because I have to conquer the stupid box. &lt;/em&gt;&lt;/p&gt; &lt;p&gt;For all my noble aspirations, that&#39;s a humbling admission.&lt;/p&gt; &lt;p&gt;But that passion is still there. It keeps me in the game. And, in retrospect, it&#39;s likely why I feel so passionately about software quality. It&#39;s not enough that it works, it has to work well.&lt;/p&gt; &lt;p&gt;What was your first time like? &lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2008/03/my-first-time-software-passion.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-2927138587287918798</guid><pubDate>Mon, 24 Mar 2008 14:10:00 +0000</pubDate><atom:updated>2008-03-24T10:10:30.043-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Musings</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><category domain="http://www.blogger.com/atom/ns#">Usability</category><title>You are Not the Average Computer User</title><description>&lt;p&gt;John Lilly, the CEO of Mozilla, recently blogged about Apple&#39;s practice of including a new installation of Safari in Apple&#39;s Software Update service, even if you didn&#39;t have the application installed in the first place. You can read the full article &lt;a title=&quot;Apple Software Update&quot; href=&quot;http://john.jubjubs.net/2008/03/21/apple-software-update/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. His main point was this: As a matter of trust, update software should update previously installed applications, and not install new applications. Apple pretty much violated that trust when it presented users with this handy little dialog box:&lt;/p&gt; &lt;div style=&quot;text-align: center&quot;&gt;&lt;img src=&quot;http://i.i.com.com/cnwk.1d/i/bto/20080321/apple.JPG&quot;&gt;&lt;/div&gt; &lt;p&gt;The main issue here is that Safari is not already installed on the end-user&#39;s machine. So, the option is not an update, but a fresh download of brand new software. Further, the option is checked by default, and the button in the lower right hand corner clearly says &quot;Install 2 items&quot;.&lt;/p&gt; &lt;p&gt;Now, I&#39;m not going to rehash the pros and cons of Apple&#39;s tactics in this matter, because that argument has been debated endlessly on John&#39;s blog and on &lt;a title=&quot;Comments on programming.reddit.com&quot; href=&quot;http://reddit.com/r/programming/info/6cy1v/comments/&quot; target=&quot;_blank&quot;&gt;Reddit&lt;/a&gt;. What I am going to take issue with is the &lt;em&gt;arrogant presumption &lt;/em&gt;that many commenters take when they make these sorts of statements:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&quot;I don’t see what the problem is here. If you don’t want the software, you uncheck the box. The product description is listed very clearly in the window, no extra clicking required.&quot;&lt;/p&gt; &lt;p align=&quot;right&quot;&gt;Omar&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&quot;I don’t see the big deal. They are promoting their software through their software update program. It’s automatically checked…ok, so? Lots of update programs automatically check everything anyway, not just apple.&lt;/p&gt; &lt;p&gt;&quot;If FF is better then people will use FF. If they like safari then they will switch. These browser “loyalty” wars are getting old. IE came with windows by default and FF is still gaining ground. It is gaining ground because it is better. Just keep making a better browser and stop worrying about this. ppl will flock to the best. We’re not stupid.&quot;  &lt;p align=&quot;right&quot;&gt;Chris  &lt;p&gt;&quot;Oh fer heaven’s sake, uncheck the box and get over it. Are you saying the majority of Windows users of iTunes are too clueless to look and see what they’re downloading? OK, I’ll admit it’s a bit pushy of Apple but beyond that I fail to see what all the fuss is about.&quot;  &lt;p align=&quot;right&quot;&gt;Anne  &lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;These are knee-jerk responses. The last one, in particular, is an exemplary case of a poster who clearly doesn&#39;t understand the idea that &lt;em&gt;users who read or post to tech blogs or forums are not typical computer users&lt;/em&gt;. If you&#39;re reading this blog, you&#39;re not a typical computer user. (I&#39;m not sure what you are, exactly, but you&#39;re not typical.) &lt;/p&gt; &lt;p&gt;Apple&#39;s case is interesting because of the enormous success of the iPod, and the vast number of iPod owners who use Windows. Those users will download iTunes so that they can use their iPod with their computer to purchase music and manage their playlists. However, the vast majority of those people are not what we would classify as &lt;em&gt;tech savvy users. &lt;/em&gt;Rather, I&#39;d call them &lt;em&gt;click-through users&lt;/em&gt;, who implicitly trust the software vendor to make decisions for them. Think about your mom, your dad, your sister, your brother, your aunt, your uncle, the kids at school, the clerks at the nearest retail outlet or fast food joint, your fellow students, or your nontechnical coworkers.&lt;/p&gt; &lt;p&gt;&lt;em&gt;Those people represent the average computer user. They are click-through users.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;A couple times a year, I get calls from my family members about their computers. Inevitably, they&#39;ll tell me that the computer is suddenly horrifically slow, and that they need me to fix it. So they bring it to me, and I look at it, and it has tons of mystery software on it. I like to have them sit with me when I&#39;m going through it, so that I don&#39;t remove anything that they might actually need or use. Nine times out of ten, they&#39;ll tell me, &quot;I don&#39;t know where that came from.&quot; Apple&#39;s software update for Safari is likely going to produce an awful lot of these scenarios, because the the average computer user will have just clicked through the dialog, trusting that Apple knew what was best for them.&lt;/p&gt; &lt;p&gt;A tech savvy user isn&#39;t likely to just click through that dialog box because they know what can happen, and they&#39;re pretty darned picky about what goes on their machine. They don&#39;t blindly trust the vendor to make those decisions for them. But the number of users like that is relatively small, and is hardly representative of the world&#39;s population. &lt;/p&gt; &lt;p&gt;But the world is full of click-through users. There are far more of them than there are of us. Thinking for one minute that everyone thinks and/or behaves as we do is naive, shortsighted, arrogant and presumptuous. &lt;/p&gt; &lt;p&gt;Again, my point here isn&#39;t that Apple was right or wrong. My point is this: &lt;em&gt;never assume for one minute that YOU represent the average computer user. You don&#39;t. &lt;/em&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;If you&#39;re smart enough to competently read or post an a technical blog or forum, you&#39;re not an average computer user.  &lt;li&gt;If you know how to &lt;em&gt;correctly&lt;/em&gt; fix someone else&#39;s machine after they&#39;ve borked it, you&#39;re not an average computer user.  &lt;li&gt;If you know the difference between a hash table, a binary tree, and a linked list, you are not an average computer user.  &lt;li&gt;If you know what recursion is, you are not an average computer user.  &lt;li&gt;If you know how to safely overclock your machine, you&#39;re not an average computer user.  &lt;li&gt;If you read technical books like they&#39;re gripping, fast-paced murder mysteries, you&#39;re not an average computer user.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;This list is undoubtedly incomplete, but I haven&#39;t had enough coffee yet. But you get the point.&lt;/p&gt; &lt;p&gt;So, enough with this arrogant presumption. Stop assuming that all users behave as we do. Because the simple truth is that the vast majority of users do not behave or think as we do. They trust; we suspect. &lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2008/03/you-are-not-average-computer-user.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-5542134311456577119</guid><pubDate>Sun, 23 Mar 2008 22:11:00 +0000</pubDate><atom:updated>2008-03-23T18:11:37.376-04:00</atom:updated><title>LINQ to SQL and the Coming Apocalypse</title><description>&lt;p&gt;I&#39;m going to say it, and I&#39;m going to say it for everyone to see: LINQ TO SQL SCARES THE HELL OUT OF ME.&lt;/p&gt; &lt;p&gt;Does anyone remember &lt;a title=&quot;Database Connectivity with ASP and ADO&quot; href=&quot;http://www.abiglime.com/webmaster/articles/frontpage/122697.htm&quot; target=&quot;_blank&quot;&gt;this&lt;/a&gt; from classic ASP?&lt;/p&gt; &lt;div style=&quot;padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre style=&quot;border-right: silver 1px solid; padding-right: 0px; border-top: silver 1px solid; padding-left: 0px; padding-bottom: 0px; border-left: silver 1px solid; padding-top: 0px; border-bottom: silver 1px solid; background-color: lemonchiffon&quot;&gt;&lt;p&gt;&lt;font face=&quot;Courier&quot; size=&quot;1&quot;&gt;&amp;lt;%&lt;/font&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;font face=&quot;Courier&quot; size=&quot;1&quot;&gt;Set rs = Server.CreateObject(&quot;ADODB.RecordSet&quot;)&lt;br&gt;param = Request.Form(&quot;lastname&quot;)&lt;br&gt;q = &quot;SELECT * FROM personnel WHERE lastname LIKE &#39;&quot; &amp;amp; param &amp;amp; &quot;&#39;&quot;&lt;br&gt;rs.Open q, &quot;DSN=mydsn;&quot;&lt;/font&gt; &lt;br /&gt;&lt;p&gt;&lt;font face=&quot;Courier&quot; size=&quot;1&quot;&gt;if NOT rs.EOF then&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; while NOT rs.EOF&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Response.Write rs(&quot;firstname&quot;) &amp;amp; &quot; &quot; &amp;amp; rs(&quot;lastname&quot;) &amp;amp; &quot;&amp;lt;BR&amp;gt;&quot;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rs.MoveNext&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; wend&lt;br&gt;end if&lt;/font&gt; &lt;br /&gt;&lt;p&gt;&lt;font face=&quot;Courier&quot; size=&quot;1&quot;&gt;%&amp;gt;&lt;/font&gt;&lt;/p&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;LINQ to SQL is giving me flashbacks to this kind of code. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;No, of course code written in LINQ to SQL won&#39;t look anything like that. But it will look like &lt;a title=&quot;LINQ to SQL - 5 Minute Overview&quot; href=&quot;http://www.hookedonlinq.com/Default.aspx?Page=LINQtoSQL5MinuteOverview&amp;amp;AspxAutoDetectCookieSupport=1&quot; target=&quot;_blank&quot;&gt;this&lt;/a&gt;:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;pre style=&quot;border-right: silver 1px solid; border-top: silver 1px solid; border-left: silver 1px solid; border-bottom: silver 1px solid; background-color: lemonchiffon&quot;&gt;HookedOnLINQ db = &lt;br /&gt;     &lt;a href=&quot;http://www.google.com/search?q=new+msdn.microsoft.com&quot;&gt;&lt;span style=&quot;color: #008000&quot;&gt;new&lt;/span&gt;&lt;/a&gt; HookedOnLINQ&lt;span style=&quot;color: #000000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #808080&quot;&gt;&quot;Data Source=(local);Initial Catalog=HookedOnLINQ&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;)&lt;/span&gt;;&amp;nbsp;&amp;nbsp; &lt;br&gt;     var q = from c &lt;span style=&quot;color: #0600ff&quot;&gt;in&lt;/span&gt; db.&lt;span style=&quot;color: #0000ff&quot;&gt;Contact&lt;/span&gt;&lt;br /&gt;           where c.&lt;span style=&quot;color: #0000ff&quot;&gt;DateOfBirth&lt;/span&gt;.&lt;span style=&quot;color: #0000ff&quot;&gt;AddYears&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #ff0000&quot;&gt;35&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;)&lt;/span&gt; &amp;gt; DateTime.&lt;span style=&quot;color: #0000ff&quot;&gt;Now&lt;/span&gt;&lt;br /&gt;           orderby c.&lt;span style=&quot;color: #0000ff&quot;&gt;DateOfBirth&lt;/span&gt; descending&lt;br /&gt;           select c;&amp;nbsp;&amp;nbsp; &lt;br&gt;     &lt;span style=&quot;color: #0600ff&quot;&gt;foreach&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;(&lt;/span&gt;var c &lt;span style=&quot;color: #0600ff&quot;&gt;in&lt;/span&gt; q&lt;span style=&quot;color: #000000&quot;&gt;)&lt;/span&gt;&lt;br /&gt;       Console.&lt;span style=&quot;color: #0000ff&quot;&gt;WriteLine&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #808080&quot;&gt;&quot;{0} {1} b.{2}&quot;&lt;/span&gt;,&lt;br /&gt;                   c.&lt;span style=&quot;color: #0000ff&quot;&gt;FirstName&lt;/span&gt;.&lt;span style=&quot;color: #0000ff&quot;&gt;Trim&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;)&lt;/span&gt;,&lt;br /&gt;                   c.&lt;span style=&quot;color: #0000ff&quot;&gt;LastName&lt;/span&gt;.&lt;span style=&quot;color: #0000ff&quot;&gt;Trim&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;)&lt;/span&gt;,c.&lt;span style=&quot;color: #0000ff&quot;&gt;DateOfBirth&lt;/span&gt;.&lt;span style=&quot;color: #0000ff&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #808080&quot;&gt;&quot;dd-MMM-yyyy&quot;&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color: #000000&quot;&gt;)&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So, what we potentially have here is database code mixed in with our business code. Further, we have no guarantee that this code will &lt;em&gt;not &lt;/em&gt;appear in the .aspx page. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;What really disturbs me about LINQ to SQL is that it looks like people will begin to use it to do things that really should be left to the database. Looking at the specific code example above, is there any good reason that this couldn&#39;t have been done with a stored procedure? I mean, after all, stored procedures are compiled, provide additional security, and aren&#39;t subject to some sleepy programmer doing a global search and replace in the IDE and &lt;a title=&quot;&amp;quot;borked&amp;quot; in the Urban Dictionary&quot; href=&quot;http://www.urbandictionary.com/define.php?term=bork&quot; target=&quot;_blank&quot;&gt;borking&lt;/a&gt; the code.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now, I realize that LINQ to SQL has support for stored procedures. But I&#39;m willing to bet that the vast majority of organizations are going to use that support in conjunction with the syntax shown above to produce truly horrendous code that completely negates the tremendous power available to them in the database.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Database technology has evolved over decades to be &lt;em&gt;extremely &lt;/em&gt;efficient at what it does: indexing, sorting, selecting, inserting, updating, and so on. We will &lt;em&gt;never &lt;/em&gt;be as efficient doing it client side as the database will be on the server side. Ignoring that power and trying to do it in code is an exercise in futility. The lesson we need to bear in mind here is this: &lt;em&gt;let the database do what it does best, and let the code do what it does best.&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Sadly, I don&#39;t have a whole lot of confidence that this is going to be the case in many places, because LINQ to SQL makes it far too easy to do the database&#39;s job. For crying out loud, you can do a WHERE and an ORDER BY--which should happen in the database so you can take advantage of the indexes--in the code. (Perhaps, under the hood this gets done by generating SQL. Fine. But &lt;em&gt;why &lt;/em&gt;am I essentially writing SQL statements in code again?! WHY!? Get that SQL out of the damned code! It doesn&#39;t belong there! SQL belongs in the database!)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now, suppose, for instance, that LINQ to SQL is 100% bug free on its first iteration. Let&#39;s assume that it generates flawless SQL to query your database when you write that code. &lt;em&gt;It still has to pass dynamic SQL. &lt;/em&gt;That means you can&#39;t take advantage of compiled stored procedures. It also means that you have to repeat that code if you want to reuse it--unless, of course, you&#39;re savvy enough to &lt;a title=&quot;Code Refactoring on WikiPedia&quot; href=&quot;http://en.wikipedia.org/wiki/Refactoring&quot; target=&quot;_blank&quot;&gt;refactor&lt;/a&gt; your code base to do so. But let&#39;s be honest: the folks I&#39;m worried about here probably aren&#39;t smart enough to refactor their code base because they&#39;re likely in a rush to get the code out as quickly as possible, and refactoring isn&#39;t a big ticket item for them. The &lt;a title=&quot;Single Responsibility Principle on WikiPedia&quot; href=&quot;http://en.wikipedia.org/wiki/Single_responsibility_principle&quot; target=&quot;_blank&quot;&gt;Single Responsibility Principle&lt;/a&gt; likely hasn&#39;t bubbled to the top of their list of grave concerns yet.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Why this becomes a serious concern is simple: &lt;em&gt;Eventually, someone has to maintain that code. &lt;/em&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;How many of us have nightmares about working with someone else&#39;s lamentably bad ASP code that had embedded SQL statements in it? Remember how horrible that was? Remember trying to search all the files to figure out where the SQL was? Which files touched which tables? &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Why on earth do we want to go back to that?&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Sure, sure; someone, somewhere, has an utterly compelling need for LINQ to SQL. They absolutely, positively must have it. Their business will collapse if they don&#39;t have it. Problem is, as I see it, this is going to be abused like a box of needles and a ton of heroin at a recovery clinic. And it&#39;s everyone else who&#39;s going to pay the price.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So, in closing, I&#39;ll just say this:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;em&gt;DOOOOOOOOOOM!&lt;/em&gt;&lt;/p&gt;  </description><link>http://mikehofer.blogspot.com/2008/03/linq-to-sql-and-coming-apocalypse.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-2088901786978801075.post-45525920050056430</guid><pubDate>Fri, 14 Mar 2008 02:29:00 +0000</pubDate><atom:updated>2008-03-14T07:54:10.002-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">NValidate</category><category domain="http://www.blogger.com/atom/ns#">Open Source</category><category domain="http://www.blogger.com/atom/ns#">Quality</category><category domain="http://www.blogger.com/atom/ns#">Software Development</category><title>NValidate: Misunderstood from the Outset</title><description>&lt;p&gt;Occasionally, I will post questions about the design or feature set of &lt;a href=&quot;http://www.nvalidate.org&quot; target=&quot;_blank&quot;&gt;NValidate&lt;/a&gt; on &lt;a href=&quot;http://groups.googl.com&quot; target=&quot;_blank&quot;&gt;Google Newsgroups&lt;/a&gt;. More recently, I posted a question about it to &lt;a href=&quot;http://www.linkedin.com&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt;. Almost immediately, I got this response:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;I&#39;d suggesting looking at the Validation Application Block portion of the Enterprise Library from the Microsoft Patterns and Practices group. &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Now, I&#39;m not belittling the response, because it&#39;s perfectly valid, and the Validation Application Block attempts to solve essentially the same problem. But when I talk about NValidate, which I find myself doing &lt;em&gt;a lot &lt;/em&gt;as I interview for jobs (it&#39;s listed on my résumé), people often ask me questions like it:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;How is that any different from the &lt;a title=&quot;Validation ASP.NET Controls&quot; href=&quot;http://msdn2.microsoft.com/en-us/library/debza5t0.aspx&quot; target=&quot;_blank&quot;&gt;Validator controls in ASP.NET&lt;/a&gt;?  &lt;li&gt;Why don&#39;t you just use the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/bb410105.aspx&quot; target=&quot;_blank&quot;&gt;Validation Application Block&lt;/a&gt;?  &lt;li&gt;Why didn&#39;t you go with attributes instead?  &lt;li&gt;Why didn&#39;t you use interfaces in the design?  &lt;li&gt;Why not just use assertions instead of throwing exceptions?&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;These days, I find myself answering these questions with alarming frequency. It occurs to me that I should probably get around to answering them, so I&#39;m going to address them here and now.&lt;/p&gt; &lt;p&gt;It helps, before starting, to understand the problem that NValidate is trying to solve: &lt;em&gt;Most programmers don&#39;t write consistent, correct parameter validation code because it&#39;s tedious, boring, and a pain in the neck. We&#39;d rather be working on something else (like the business logic). Writing parameter validation code is just too difficult. NValidate tries to solve that problem by making it as easy as possible, with a minimal amount of overhead.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q. How is NValidate any different from the Validator controls in ASP.NET?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;A. The Validator controls in ASP.NET can only be used on pages. But what if I&#39;m designing a class library? Isn&#39;t it vitally important that I make sure I test the parameters on my public interface to ensure that the caller passes me valid arguments? If I&#39;m not, I&#39;m going to fail spectacularly, and not in a pretty way. You can&#39;t use the Validator controls (&lt;font face=&quot;courier new&quot;&gt;RangeValidator&lt;/font&gt;, &lt;font face=&quot;courier new&quot;&gt;CompareValidator&lt;/font&gt;, and so on) in a class library you&#39;re writing that&#39;s intended to be invoked from your Web application.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q. Why don&#39;t you just use the Validation Application Block?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;A. This one&#39;s pretty easy to answer. NValidate is designed to accommodate &lt;em&gt;lazy programmers &lt;/em&gt;(like me).&lt;/p&gt; &lt;p&gt;Here&#39;s the theory that essentially drives the design of NValidate: Developers don&#39;t write parameter validation code with any sort of consistency because it&#39;s a pain in the neck to write it, and because we&#39;re in a big hurry to get to the business logic (the meat and potatoes of the software). Let&#39;s face it: if the first chunk of the code has to be two to twenty lines of you checking parameters and throwing exceptions, and doing it all over the place, you&#39;d get tired of doing it, too. Especially if that code is &lt;em&gt;extremely repetitive. &lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;if(null == foo) throw new ArgumentNullException(foo);&lt;br&gt;if(string.Empty == foo) throw new ArgumentException(&quot;foo cannot be empty.&quot;);&lt;br&gt;if(foo.length != 5) throw new ArgumentException(&quot;foo must be 5 characters.&quot;);&lt;/font&gt;&lt;/p&gt; &lt;p&gt;We hate writing this stuff. So we skip it, thinking we&#39;ll come back to it later and write it. But it never gets done, because we get all wrapped up in the business logic, and we simply forget. Then we&#39;re fixing bugs, going to meetings, putting out fires, reading blogs, and it gets overlooked. And the root cause is because it&#39;s tedious and boring.&lt;/p&gt; &lt;p&gt;I&#39;m not making this up, folks. I&#39;ve talked to lots of other developers and they&#39;ve all admitted (however reluctantly), that it&#39;s pretty much the truth. We&#39;re all guilty of it. Bugs creep in because we fail to erect that impenetrable wall that prevents invalid parameter values from slipping through. Then, we have to go in after the fact and add the code after we&#39;ve got egg on our face and fix it, at increased cost.&lt;/p&gt; &lt;p&gt;So, if you want to make sure that developers will write the parameter validation code, or are at least more likely to do it, you have to make it as easy as possible to do so. That means &lt;em&gt;writing as little code as possible. &lt;/em&gt;&lt;/p&gt; &lt;p&gt;Now, if we look at the code sample provided by Microsoft on their page for the &lt;a href=&quot;http://msdn2.microsoft.com/en-us/library/bb410105.aspx&quot; target=&quot;_blank&quot;&gt;Validation Application Block&lt;/a&gt;, we see this:&lt;/p&gt; &lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;using Microsoft.Practices.EnterpriseLibrary.Validation;&lt;br&gt;using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;&lt;br&gt;public class Customer&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [StringLengthValidator(0, 20)]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string CustomerName;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Customer(string customerName)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.CustomerName = customerName;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;} &lt;/font&gt; &lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;public class MyExample&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static void Main() &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Customer myCustomer = new Customer(&quot;A name that is too long&quot;);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ValidationResults r = Validation.Validate&amp;lt;Customer&amp;gt;(myCustomer);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!r.IsValid)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new InvalidOperationException(&quot;Validation error found.&quot;);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}&lt;/font&gt;  &lt;p&gt;A couple of things worth noting:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;You have to import two namespaces.  &lt;li&gt;You have to apply a separate attribute for each test.  &lt;li&gt;In your code that invokes the test, you need to do the following:  &lt;ol&gt; &lt;li&gt;Declare a &lt;font face=&quot;courier new&quot;&gt;ValidationResults&lt;/font&gt; variable.  &lt;li&gt;Execute the Validate method on your &lt;font face=&quot;courier new&quot;&gt;ValidationResults&lt;/font&gt; variable.  &lt;li&gt;Potentially do a cast.  &lt;li&gt;Check the &lt;font face=&quot;courier new&quot;&gt;IsValid&lt;/font&gt; result on your &lt;font face=&quot;courier new&quot;&gt;ValidationResults&lt;/font&gt; variable.  &lt;li&gt;If &lt;font face=&quot;courier new&quot;&gt;IsValid&lt;/font&gt; returned &lt;font face=&quot;courier new&quot;&gt;false&lt;/font&gt;, take the appropriate action.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;That&#39;s a lot of work. If you&#39;re trying to get lazy programmers to rigorously validate parameters, that&#39;s not going to encourage them a whole lot.&lt;/p&gt; &lt;p&gt;On the other hand, this is the same sample, done in NValidate:&lt;/p&gt; &lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;using NValidate.Framework;&lt;br&gt;public class Customer&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public string CustomerName;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Customer(string customerName)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&lt;/font&gt;&lt;font face=&quot;Courier New&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Demand.That(customerName, &quot;customerName&quot;).HasLength(0, 20);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; this.CustomerName = customerName;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;} &lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;public class MyExample&lt;br&gt;{&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static void Main() &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/font&gt;&lt;br&gt;&lt;font face=&quot;Courier New&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/font&gt;&lt;font face=&quot;Courier New&quot;&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Customer myCustomer = new Customer(&quot;A name that is too long&quot;);&lt;/font&gt;&lt;br&gt;&lt;font face=&quot;Courier New&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/font&gt;&lt;br&gt;&lt;font face=&quot;Courier New&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; catch(ArgumentException e)&lt;/font&gt;&lt;br&gt;&lt;font face=&quot;Courier New&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new InvalidOperationException(&quot;Validation error found.&quot;);&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;}&lt;/font&gt;&lt;/p&gt; &lt;p&gt;A couple of things worth noting:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;You only have to import one namespace.  &lt;li&gt;In the property, you simply &lt;font face=&quot;courier new&quot;&gt;Demand.That&lt;/font&gt; your parameter is valid.  &lt;li&gt;In your code that invokes the test, you need to do the following:  &lt;ol&gt; &lt;li&gt;Wrap the code in a &lt;font face=&quot;courier new&quot;&gt;try...catch&lt;/font&gt; block.  &lt;li&gt;Catch the exception and handle it, if appropriate. &lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;See the difference? You don&#39;t have to write a lot of code to validate the parameter, and your clients don&#39;t have to write a lot of code to use your class, either.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q. Why didn&#39;t you go with attributes instead?&lt;/strong&gt; &lt;/p&gt; &lt;p&gt;A. I considered attributes in the original design of NValidate. But I ruled them out for a number of reasons:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Using them would have meant introducing a run-time dependency on reflection. While reflection isn&#39;t horrendously slow, it is slower than direct method invocation, and I wanted NValidate to be as fast as possible.  &lt;li&gt;I wanted the learning curve for adoption to be as small as possible. I modeled the public interface for NValidate after a product I thought was pretty well known: NUnit. You&#39;ll note that &lt;font face=&quot;Courier New&quot;&gt;Demand.That(param, paramName).IsNotNull()&lt;/font&gt; is remarkably similar to NUnit&#39;s &lt;font face=&quot;courier new&quot;&gt;Assert.IsNotNull(someTestCondition)&lt;/font&gt; syntax.  &lt;li&gt; &lt;p&gt;In NValidate, readability and performance are king. Consequently, it uses a fluent interface that allows you to chain the tests together, like so:  &lt;p&gt; &lt;p&gt;&lt;font face=&quot;courier new&quot;&gt;Demand.That(foo, &quot;foo&quot;).IsNotNull().HasLength(5).Matches(&quot;\\d5&quot;);&lt;/font&gt;&lt;/p&gt; &lt;p&gt;This is a performance optimization that results in fewer objects created at runtime. It also allows you to do the tests in a smaller vertical space.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;My concerns about attributes and reflection may not seem readily apparent until you consider the following: it&#39;s conceivable (in theory) that zealous developers could begin validating parameters in every frame of the stack. If the stack frame is sufficiently deep, the costs of invoking reflection to parse the metadata begins to add up. It may not seem significant yet, but consider the scenario where any one of those methods is recursive; perhaps it walks a binary tree, a DOM object, an XML document, or a directory containing lots of files and folders. When that happens, the costs of reflection can become prohibitively expensive.&lt;/p&gt; &lt;p&gt;In my book, that&#39;s simply not acceptable. And since, as a framework developer, I cannot predict or constrain where a user might invoke these methods, I must endeavor to make it as fast as possible. In other words, take the parameter information, create the appropriately typed validator, execute the test, and get the hell out as quickly as possible. Avoid any additional overhead at all costs. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q. Why didn&#39;t you use interfaces in the design? &lt;/strong&gt;&lt;/p&gt; &lt;p&gt;A. I go back and forth over this one all the time, and I keep coming back to the same answer: Interfaces would tie my hands.&lt;/p&gt; &lt;p&gt;Lets assume, for a moment, that we published NValidate using nothing but interfaces. Now, in a subsequent release, we decided we wanted to add new tests. Now we have a problem. We can&#39;t extend the interfaces without breaking the contract with clients who are built against NValidate. Sure, they&#39;ll likely have to recompile anyway; but if I add new methods to interfaces, they might have to recompile &lt;em&gt;lots &lt;/em&gt;of assemblies. That&#39;s something I&#39;d rather not force them to do.&lt;/p&gt; &lt;p&gt;On the other hand, abstract base classes allow me to extend classes and add new tests and new strongly typed validators fairly easily. Further, it eliminates casting (because that&#39;s handled by the factory). If, however, the system is using interfaces, some methods will return references to an interface, and some will return references to strongly typed validators, and some casting will have to be done at the point of call. I want to eliminate manual casting whenever I can, to keep that call to &lt;font face=&quot;courier new&quot;&gt;Demand.That&lt;/font&gt; as clean as possible: the cleaner it is, the more likely someone is to use it, because it&#39;s easy to do.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Q. Why not just use assertions instead of throwing exceptions?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;A. This should be fairly obvious: Assertions don&#39;t survive into the release version of your software. Additionally, they don&#39;t work as you&#39;d expect them to in a Web application (and rightly so, since they&#39;d kill the ASP.NET worker process, and abort every session connected to it. [For a truly educational experience, set up a test web server, and issue a Visual Basic &lt;font face=&quot;courier new&quot;&gt;Stop&lt;/font&gt; statement from a DLL in your Web App. You&#39;ll kill the worker process, and it will be reset on the next request. Nifty.]). &lt;/p&gt; &lt;p&gt;Wisdom teaches us that the best laid plans of mice and men frequently fail. Your most thorough testing will miss some points of your code. The chances of achieving 100% code coverage are pretty remote; if you do it with a high degree of frequency, I&#39;m duly impressed (and I&#39;d like to submit my resume). But for the rest of us, we know that some code never gets executed during testing, and some code gets executed, but doesn&#39;t get executed under the precise conditions that might reveal a subtle defect. That&#39;s why you want to leave those checks in the code. Yes, it&#39;s additional overhead. But wouldn&#39;t you rather know?&lt;/p&gt; &lt;p&gt;&lt;strong&gt;In Summary&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;Sure, these are tradeoffs in the design. But let&#39;s keep in mind who I&#39;m targeting here: &lt;em&gt;lazy programmers&lt;/em&gt; who are typically disinclined to write lots of code to validate their parameters. The idea is that we want to make it so easy that they&#39;re more likely to do it. In this case, less code hopefully leads to more, which (I hope) leads to fewer defects, and higher quality software.&lt;/p&gt;</description><link>http://mikehofer.blogspot.com/2008/03/nvalidate-misunderstood-from-outset.html</link><author>noreply@blogger.com (Mike Hofer)</author><thr:total>0</thr:total></item></channel></rss>