Wednesday, January 30, 2008

Competence != Compensation

In America we are conditioned to believe that working hard, being diligent, and producing great work is the road to fiscal success.  Anyone who has really worked here will tell you that is simply not the case.  Prima facie, you must recognize that you are not paid what you are "worth"; that is, your personal worth has nothing to do with your income.  One must never forget this simple fact.  Despite the fact that you may do three times the work of your peers, you will not be compensated even twice as much.

Witness the Home Depot CEO who purposefully runs his stock in the ground, knowing well that a golden parachute awaits for him once the board of directors requests that he "step down."  Negative output results in a cash payout worth over $200 million dollars.  In America, you are worth what someone will pay you.  There is no such thing as intrinsic value, only assessed value.  In software development there are two ways of having your value assessed, by managers and by investors.

Make sure you don't hang your hopes on managers.

Continuous Integration with TFS: Pre-compiling a Web Application Project

If you are looking to pre-compile your web application projects with TFS 2008 Team Build, here are some tips.

First, you'll want to add the following to your TFSBuild.proj:

<Target Name="AfterDropBuild">
<
AspNetCompiler
PhysicalPath="$(DropLocation)\$(BuildNumber)\Release\_PublishedWebsites\web_project_name"
Debug="false"
Force="true"
TargetPath="C:\path_to_copy_precompiled_web_to"
VirtualPath="/Path_to_your_web"
/>
</
Target>


There a few things to note here.  First, the Target Name is crucial; this Target will get executed after the drop is made, i.e. after the build successfully runs and your files are copied to the drop folder you specified when you created the build.  Secondly, remember that this is running from the machine where your build agent runs.  The AspNetCompiler MSBuild tag shown here will launch aspnet_compiler.exe on that build agent machine, and so "/Path_to_your_web" points to the virtual directory on the default web site of your build agent machine.  Please note that "/Path_to_your_web" would be "/" in the case of your application being in the root directory.  Finally, the Force parameter is required since we will be writing over the existing pre-compiled web on subsequent builds.



If you want setup a build agent on another machine, perhaps a development web server where you would prefer to deploy the pre-compiled web application, you'll need to configure that agent according to these instructions.  This is a good idea when running verification tests that drive the web UI.



Happy Coding!

Saturday, January 26, 2008

On a Positive Note

Jean-Paul Boodhoo is a developer and consultant who used to work at ThoughtWorks and has been featured on the Polymorphic Podcast and DNRtv.  He recently posted a very encouraging post about dreams, risk, and reward.

Here's an excerpt.

I was speaking with a friend yesterday who made an interesting comment:

“You seem to regularly take on more stress than most other people would ever think to take on”

I corrected him and made this statement. I don’t feel like I am stressed out that much. In all honesty, the times that I feel stressed out almost always constitute a failure to plan on my part. I did say that what I do take on regularly is: Challenge and Risk. I am not afraid of the opportunity to fall flat on my face taking a risk, because I now that it is in the times of struggle/pain that growth happens.

Bravo.  That's well said.  Paul Graham (all your Lisp are belong to us) wrote a year ago explaining: How to Do What You Love.  Here's a quote, emphasis added:

Once, when I was about 9 or 10, my father told me I could be whatever I wanted when I grew up, so long as I enjoyed it. I remember that precisely because it seemed so anomalous. It was like being told to use dry water. Whatever I thought he meant, I didn't think he meant work could literally be fun—fun like playing. It took me years to grasp that.

Sure, sure, I heard you saying... do what you love, right?  Well, I love vacations, the ocean, playing guitar, and chasing my puppy--how do I get paid to do that?  The truth is you don't; you won't; and you shouldn't.  Again, from Mr. Graham:

Unproductive pleasures pall eventually. After a while you get tired of lying on the beach. If you want to stay happy, you have to do something.

I can't tell you how invigorating working in the yard can be or how exciting solving some mildly difficult programming problem can be.  It's enough to make people blog about their experiences.  But, even these are just short-term examples, what is it that you would love to do over the long haul?  Is there some sort of heuristic that we can apply to help use decide?  Here's Graham's idea:

I think the best test is one Gino Lee taught me: to try to do things that would make your friends say wow.

If you hate what you do, I cannot convince you that trying to impress your friends with it is going to make it fun.  So, think of the things you do that you do try to impress your friends with?  Do you love to cook?  Master the art, learn the language, hone your technique, and blog about the experience.  Start a in-home cooking class consultancy.  Do you love to take photographs?  Practice, learn, take your camera everywhere, make it your first thought.  Do you love it enough to do it for free?

The test of whether people love what they do is whether they'd do it even if they weren't paid for it—even if they had to work at another job to make a living. How many corporate lawyers would do their current work if they had to do it for free, in their spare time, and take day jobs as waiters to support themselves?

If you don't have enough passion to work hard at something and get better, then you either don't love it or you don't have an audience.  You might just need new friends.  Seek them out in classes or online discussion groups.  But seek them out.

If you are worried about money, if you're worried about being responsible for the well-being of your children or spouse, remember that you have a responsibility to them.  You are responsible for loving them, for inspiring them, for trying to be the best person you can for them.  Those are your true responsibilities; you can find a way to pay the really important bills.  Don't let fear admit apathy.  Don't use your family as an excuse.

If you don't already know what you love to do--and so few of us really do--Graham has further advice:

It's hard to find work you love; it must be, if so few do. So don't underestimate this task. And don't feel bad if you haven't succeeded yet. In fact, if you admit to yourself that you're discontented, you're a step ahead of most people, who are still in denial. [..] Finding great work you love does usually require discipline.  Is there some test you can use to keep yourself honest? One is to try to do a good job at whatever you're doing, even if you don't like it. [...] Another test you can use is: always produce.

If you are telling yourself that you hate your day job, and one day you will be set free to do what you love, then you better being doing what you love and consistently.  Otherwise, you're lying to yourself and everyone around you.  The hardest thing to admit is that at age 20, 30, 40, or 50 is that you don't know what you love; you don't know what you want to do when you grow up.  My point here is that you must do something; you must produce.  Even if you prove to be rather amateurish in all you attempt, but you really gave it your best, you will be happier--and much more interesting.  The worst thing you can be in your work-life, truly, is be a dilettante.

I will close by leaving you with these further words from Graham's essay (please read it):

"Always produce" is also a heuristic for finding the work you love. If you subject yourself to that constraint, it will automatically push you away from things you think you're supposed to work on, toward things you actually like. "Always produce" will discover your life's work the way water, with the aid of gravity, finds the hole in your roof.

One last note before parting that I have is simply this: seek out good teachers.  My wife recently told me what the tuition for a four-year degree at local technical college is: nearly $84,000.  Most of their students do not finish, and most of them are there because they want to make more money.  And, sadly, most of them don't learn a thing--because they're not there to learn, they're there to make more money (via a diploma).  This is not the road to happiness.  It would be much better for those people to find work they love and to see out the best teachers.  I guarantee you that those technical colleges do not have the best teachers.

Thursday, January 24, 2008

IndyTFS January Meeting: These Guys Rawk!

Jamie Kurtz of Open Solutions presented on TFS Work Items.  Now, I really hate going to user group meetings in the midwest, because most of the time the speakers are not really all that knowledgeable about their topic.  This session, however, could have been entitled, "TFS: All Questions Answered."  Between Paul Hacker and Jamie Kurtz, not one question was a stumper.  I learned more about TFS in that two hours than I could have in two days on my own.  It was truly fantastic; they had a great attitude!

Here are some of the things we learned.

  • Customizing Work Item types: workflow, states, custom form fields, custom field controls
  • Details and gotchas on how to get business users setup to edit work items from Excel
  • Details about securing fields and work items
  • Editing MSBuild files to work appropriately with WorkItems

Kudos to both gentlemen.  I encourage anyone using or considering using TFS to member up and start attending meetings.

Saturday, January 12, 2008

List of Links for Learning LINQ

Since I often use this blog as a brain back-up device.  I will add another list of links, this time for learning LINQ.

Building a LINQ Provider

Links to LINQ (another link-post)

How LINQ Works: Creating Queries (part of a series of great posts on LINQ internals)

The .NET Standard Query Operators (slightly out-of-date, but very relevant)

Standard Query Operator Translation (LINQ to SQL)

Friday, January 11, 2008

Happy 70th Birthday to Don Knuth

I still haven't read The Art of Computer Programming, Volume 1, but I'm definitely an admirer of this man.  Here's to many, many more years where we are blessed to have him among us.

Don Knuth is my homeboy

Thursday, January 10, 2008

A Twitter-style Blog Post from a User Group

Larry Clarkin is a developer evangelist for Microsoft based out of Milwaukee.  He gave a talk this evening to the IndyNDA group at the Junior Achievement center on Keystone.  He spent the first twenty minutes of his talk showing us Microsoft's Virtual Earth maps site.  To use the Virtual Earth client libraries you need to include their script library and create a DIV to contain the map renderings.  A very informative site for learning Virtual Earth was demonstrated; it's called "The Virtual Earth Interactive SDK".  Very cool.

He's showed us a pretty tame example of overlaying a Silverlight control on a Virtual Earth map.  The Silverlight control references the map via Javascript.  Pretty simple, but I believe the concept is solid.  You could really have a lot of fun with this approach.

7:09pm and we've been enlightened that SOAP has lost the battle to REST on the public web.  Now we're getting some of the Twitter hype...  boring.  More Twitter, more boring.  I guess I just don't get Twitter. It seems like a way to fill the gaps when you are alone with yourself.  What's next--a microphone for your thoughts?  I will never waste my time reading that crap.

7:23pm and we're learning that RSS is gee-wowie!  "We need more things like RSS."  Good to know.  Larry likes Flickr.

The guy sitting behind me has returned to his seat and reeks of cigarette smoke.  Joy!

Oooh, now I'm learning how to get an ugly slideshow in Blend from a Flickr RSS feed.  It's 7:37pm and he's done--felt longer but under an hour.

The highlight was hearing guys get excited about being able to update Twitter via SMS.  They thought, "Wow, I can point my applications at that feed and then send control codes via SMS."  It feels like you should probably skip the middle-man.  Though, a free SMS to RSS gateway is a fun idea for homebrew mash-ups.

Well, the pizza was better this time.

Wednesday, January 9, 2008

TFS Build Failure: MSBuild Tool missing sgen.exe

We're running TFS 2008 now at my client.  I installed the trial edition just to expedite things, as I'm not the one who works with the licenses.  (You can do an in-place upgrade of the trial to a live license.)  As I was getting the continuous integration build setup for our pilot project, I kept getting a build error similar to the following. 

error MSB3091: Task failed because "sgen.exe" was not found, or the correct Microsoft Windows SDK is not installed. The task is looking for "sgen.exe" in the "bin" subdirectory beneath the location specified in the InstallationFolder value of the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0A. You may be able to solve the problem by doing one of the following:  1) Install the Microsoft Windows SDK for Windows Server 2008 and .NET Framework 3.5.  2) Install Visual Studio 2008.  3) Manually set the above registry key to the correct location.  4) Pass the correct location into the "ToolPath" parameter of the task.


Some extensive searching only yielded this post, but I ignored the suggestion that followed the original posting... at first.  Turns out, it works quite fine.  Basically, you should have two registry keys under HKLM\SOFTWARE\Microsoft\Microsoft SDKs



image



The InstallationFolder value in the .NETFramework\v2.0 subkey is the thing we're after in the case.  Make an exact copy of that value under the Windows\V6.0A key.  I did this, as the previously mentioned post suggested, and things worked fine!



Mas Importante!  You may need to install the .NET Framework 2.0 SDK onto your TFS Server/Build Agent machine in order to do the above.

Saturday, January 5, 2008

Lambdas & Closures in C# 3.0

Here's some code the exhibits the creation of a closure in C#.  This was possible with the advent of anonymous delegates in C# 2.0, but it looks a lot cleaner in C# 3.0.

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
public static void Main(string[] args)
{
ClosuresWithLambdas a = new ClosuresWithLambdas();

List<Func<int>> fs = a.GetNumberFunctions();

Func<int> increments_i_func = fs[0];
Func<int> just_returns_i_func = fs[1];

//prints 1
a.PrintReturnValue(increments_i_func);
//prints 2
a.PrintReturnValue(just_returns_i_func);
}

public class ClosuresWithLambdas
{
public List<Func<int>> GetNumberFunctions()
{
//this variable gets included in the closure
int j = 1;

//we use this to return two functions
List<Func<int>> fs = new List<Func<int>>(2);

//don't get confused by the postfix operator
//the f lambda returns j BEFORE incrementing it
Func<int> f = () => j++;

//g just returns the variable j
Func<int> g = () => j;

//add the two functions to the list and return it
fs.Add(f);
fs.Add(g);
return fs;
}

public void PrintReturnValue(Func<int> f)
{
Console.WriteLine(f());
}
}
}


This closure of which I speak is not immediately evident to the untrained eye.  The basic concept in this example is that the variable "j" has to survive past the end of its normal scope, i.e. the execution of GetNumberFunctions.  It has to survive because the two functions passed out of GetNumberFunctions--the lambdas "f" and "g"--refer to "j" outside of the function in which they were defined.  The compiler detects this (perfectly legal) reference as a lexical closure; it generates a class to contain these functions and the variable "j".  Here is that generated helper class viewed from Lutz Roeder's Reflector.



[CompilerGenerated]
private sealed class <>c__DisplayClass2
{
// Fields
public int j;

// Methods
public int <GetNumberFunctions>b__0()
{
return this.j++;
}

public int <GetNumberFunctions>b__1()
{
return this.j;
}
}


As you can probably gather b__0 is "f" and b__1 is "g" (or, "increments_i_func" and "just_returns_i_func" respectively).  They share "j" in the scope of an instance of this compiler generated sealed class instance.  There are other ways for language and compiler to implement closures, but this generated inner class works just fine.  For a practical example of using closures, please see my previous article on doing asynchronous network I/O with closures.