2001-2004
Thursday, November 4th, 2004
On an internal mailing list the other day, there was a question asking for how to make a tray notification icon come back up on the try after explorer.exe died and came back to life. Good notification icons do this and the asker wanted to know how to do it for Windows Forms. I had had a dearth of technical work at the time, so decided to dig into the problem and see if I could answer it.
I started with a dim memory of a piece in MSJ by Paul Dilascia on the subject. Searching on msdn.com, I found Paul DiLascia's 2/99 MSJ C++ Q&A (http://www.microsoft.com/msj/0299/c/c0299.aspx) (emphasis added by me):
"…provided you have Windows 98 or the Microsoft Internet Explorer 4.0 desktop installed. Whenever Internet Explorer 4.0 starts the taskbar, it broadcasts a registered message TaskbarCreated to all top-level parent windows. This is your cue to recreate the icons. If you're using MFC, all you have to do is define a global variable to hold the registered message and implement an ON_REGISTERED_MESSAGE handler for it."
From there, I dug through the SDK docs on ON_REGISTERED_MESSAGE (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_mfc_on_registered_message.asp) and found:
// example for ON_REGISTERED_MESSAGE
const UINT wm_Find = RegisterWindowMessage( FINDMSGSTRING )BEGIN_MESSAGE_MAP( CMyWnd, CMyParentWndClass )
//{{AFX_MSG_MAP( CMyWnd )
ON_REGISTERED_MESSAGE( wm_Find, OnFind )
// ... Possibly more entries to handle additional messages
//}}AFX_MSG_MAP
END_MESSAGE_MAP( )
Figuring I'd have to be able to call RegisterWindowsMessage from managed code, I surfed to pinvoke.net and found RegisterWindowMessage (http://pinvoke.net/default.aspx/user32.RegisterWindowMessage):
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
Now that I knew how to figure out the Window message value for which to watch, I looked back into the MSDN documentation on System.Windows.Forms.Control, the base class of Form and all other HWND-based classes in Windows Forms (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformscontrolclasswndproctopic.asp) and the WndProc method I would have to override to catch the message, finding:
protected virtual void WndProc(
ref Message m
);
and:
"All messages are sent to the WndProc method after getting filtered through the PreProcessMessage method.
"The WndProc method corresponds exactly to the Windows WindowProc function. For more information about processing Windows messages, see the WindowProc function documentation in the Windows Platform SDK reference located in the MSDN Library.
"Notes to Inheritors: Inheriting controls should call the base class's WndProc method to process any messages that they do not handle."
Putting this together, I figured you could add "re-awakening" to notification icons in the following way (some compiler errors left in to keep readers on their toes : ):
using System.Windows.Forms;
using System.Runtime.InteropServices;
class MyMainForm : Form {
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
static uint taskbarCreatedMessage = RegisterWindowMessage("TaskbarCreated");
protected override void WndProc(ref Message m) {
if( (uint)m.Msg == taskbarCreatedMessage ) {
// re-show your notify icon
}
base.WndProc(ref m);
}
…
}
After posting this answer to the list, I couldn't help but crank up a quick app to test it (after fixing the compiler errors of course : ). To my satisfaction, it worked immediately. I put up a notify icon in Windows Forms, killed explorer.exe and was pleased to see my icon show back up again when explorer.exe was restarted.
However, just to make sure, I commented out my code to see my icon not be restored. Those of you familiar with the internals of Windows Forms know what happened next, of course, because my notify icon was restored properly to the tray even without my code, as illustrated by Reflector against the .NET 1.1 Windows Forms implementation:
public sealed class NotifyIcon : Component {
...
static NotifyIcon() {
NotifyIcon.WM_TASKBARCREATED =
SafeNativeMethods.RegisterWindowMessage("TaskbarCreated");
}
private void WmTaskbarCreated(ref Message m) {
this.added = false;
this.UpdateIcon(this.visible);
}
private void WndProc(ref Message msg) {
...
if (msg.Msg == NotifyIcon.WM_TASKBARCREATED) {
this.WmTaskbarCreated(ref msg);
}
...
}
...
private static int WM_TASKBARCREATED;
...
}
What? Why would someone post a question about how to make something work that already worked? I figured that the questioner was referring to .NET 1.0 and I was digging through .NET 1.1 code.
However, reading through the 1.0 code showed the same support, meaning that neither the questioner nor I had bothered to check for this support before running off to add it. So, the lesson? Write your tests first!
Still, I learned a bit along the way and that was fun. : )
Thursday, November 4th, 2004
My youngest son was called into the office today for pantsing a kid on the school playground. That is not at all like my son (he's the sweetest kid you'd ever want to meet), but the principal was new, so she was talking about suspension. Luckily, the secretaries knew my boy, so they were able to point out the inconsistency of that behavior with the reputation he had built in 4 years at the school. It turns out that the pantsed boy was cutting in line in front of my son, who didn't like it, so pushed him right back out of line again. The "cutter" took a swing, my boy swung back and in the process (they're only 9) they both fell. My son reached out to grab the boy's shirt to catch himself, not knowing that the other boy was also falling and got the pants instead, causing the aforementioned "pantsing."
The moral of this story is an old saying I heard when I was a kid and have lived by since: "If you rise at dawn, you can sleep 'til noon." In other words, if you build yourself a reputation for good things, when occasionally you stray, folks will cut you some slack. The converse of this rule is that if build yourself a reputation for bad things, that could well stick with you for a long, long time..
Thursday, October 7th, 2004
I was working with a potential author on an article he'd like to write covering some ground I left uncovered in my original No-Touch Deployment piece for MSDN Mag. Anyway, he sent me the list of topics and then said the following:
"There is a fair amount of material here it might benefit from being broken into chunks. I think I will write about small chunks at a time and then we see how much belongs in one article. Rereading your original article it struck me that you had [a] story that held it together, I need to find one for me."
I've heard this kind of thing before, i.e. people ask how I turn a seemingly random set of topics into "a story." I'm all for that, but it's not really such a chore. In fact, here's the essence of every technical piece I've ever written:
"So, I want to build this thing that needs to do this, that and the other. I started with this, did it this way and it worked. Now I need to do that. Oops. That didn't work the way I thought it should. Here's what I need to do to work around the problem. OK, now I want to do the other... [repeat]"
The secret is really building up from what the reader already knows with some minimal new, interesting thing and keep on like that 'til you've covered the ground you want to cover, stringing things together with transitions that give the reader the impression of one contiguous story. If you really want to get fancy, put a personal anecdote at the front that you use as an analogy, bring it up a few times during the piece and then wrap up with something clever that ties the your anecdote together with the ground you've covered by extending the analogy in a humorous way (but that's optional).
Thursday, October 7th, 2004
I sat down to write a new Windows Forms application in .NET 1.1 the other day, but the Visual Studio 2005 beta 1 called to me with its "menu strips" and its "user settings" and most especially its "generics," and I just couldn't resist.
To start with, it was such a pleasure to add a menu strip, add in the standard menu items (including graphics), then just strip it down to just the menu items I wanted. Then, as I added new menu items, the menu item object names were set for me based on the menu item text, e.g. startRetrievalToolStripMenuItem instead of menuItem1, which was fabulous. Not everything was wonderful, e.g. I couldn't drag and drop menu items or use Alt+arrows to rearrange them , but overall the new menu control was a pleasant experience.
Even more pleasant was the app/user settings model. To add a setting to my application, all I had to do was bring up the properties of my project, add a named setting of whatever type I wanted (more on this later) and choose whether it should be an Application setting or a User setting. Both kinds of settings are loaded automatically when the app starts and all I had to do to save them was call Properties.Settings.Value.Save() when my main form shut down. Then, with the settings in place, e.g. MyUserSetting, I could get to it after the app started from anyone in my app with a type-safe access, e.g. Properties.Settings.Value.MyUserSetting.
And this didn't just work for built-in simple strings and ints and such like. Oh, no. I was allowed to add custom and collection types like System.Collections.Generic.List<MyNamespace.MyType> as well. Plus, using generics, the underlying XML serialization mechanism worked great, because all of the types are known at compile-time (settings are stored in standard XML .config files @ c:\documents and settings\<user name>\Local Settings\Application Data\<company name>\<product name_hash>\<product version>\user.config). Being able to declaratively set app and user settings of any type and then just use them in a type-safe manner, saving them with one line of code, loading them with zero lines of code and not having to flatten my collections into comma-separated lists made things so pleasant until I hit the ugly realities of beta software, especially as new features interact with existing features and each other.
For example, because the default AssemblyVersion attribute is set to "1.0.*" in AssemblyInfo.cs (which has moved to below the Properties folder of your VS05 project), every time I compiled, all of my settings were lost. That seems very counterintuitive to me. Why should a user lose all of their settings with the new version of the application? To work around this, I changed my AssemblyVersion attribute to a hard-coded string that I now have to remember to change manually, blowing the benefit of having a version number that changes automatically with each build.
As another example, like C++ "const" of old, generics infect your code; use them in one place and you find yourself using them all over. That was fine with me (the generic Predicate<T> for finding things in a List<T> was so handy!) except that as of b1, the Windows Forms Designer gets all unhappy when you use generics. I have every hope that this will be fixed by b2, but as of right now, if I wanted to use the Designer (and it's so sweet, how could I not want to use it?!?), I had to strip out any methods or properties in my visual code that exposed generics (although method and property implementations with generics works just fine).
Stripping out List<T> brought me to the use of ArrayList instead. That worked just fine (System.Collections.ArrayList is even available via the Browse button when setting up app/user settings) until the XML serializer couldn't serialize instances of the custom type that I was using to populate my ArrayList. The error looked like this:
Could not use Xml serialization for setting: SelectedExchanges. ---> System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type MyNamespace.MyType was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
When I start up the debugger to see the line of code where the error is happening, I ended up in Main because the code is part of the Application start-up for which there is no source code, making this even more difficult to debug. The problem was that the underlying serialization engine didn't know what to do with this custom type. The clue was the mention of the XmlInclude attribute, which you can use to tell the serializer what types may be in the ArrayList, but you have to have somewhere to hang the attributes. In this case, that lead to a custom ArrayList type for the express purpose of informing the serializer (making me really miss the use of generics, where all of the types were specified at compile-type for me automatically):
[System.Xml.Serialization.XmlInclude(typeof(MyNamespace.MyType))]
public class MyList : System.Collections.ArrayList {
public override object Clone() {
MyList newList = new MyList();
newList.AddRange(this);
return newList;
}
}Notice also the Clone method. I added this later because the base ArrayList Clone method creates an instance of ArrayList, not my custom MyList type. Of course, since this was all run-time type errors, I couldn't let the compiler tell me about these problems; I had to run my app and find them. Very frustrating, especially when generics makes these problems all go away.
Still, I'm very much enjoying the new productivity features in VS05 and Windows Forms 2.0 and when they work better together, I'll be even more happy.
Monday, September 6th, 2004
I was just listing my activities for the week before Burning Man and amazed even myself:
Shopping for and celebrating my wife's 36th birthday
Helping to prepare for and then watching Sells brother #1 test for his Jr. Brown belt in karate (he was amazing)
Hosting my aunt and grandmother on a very rare 4-day trip
A day-trip to the beach
Celebrating the birthday of Sells brother #2
Coordinating the update, from my house and at the last possible moment, of more than 100 pages on microsoft.com to reflect the recent announcement of WinFX being made available on down-level versions of Windows (this included 3 all-nighters)
Preparing for and running a 2-day garage sale of the stuff I pulled out of my house over the last 8 months in my own personal episode of Clean Sweep
Packing for 5 days in the desert (I worried about survival and my wife worried about having enough costumes...)
Of course, after that I spent a week at Burning Man, and today we're cleaning the playa out of everything, preparing the boys for school, hanging out with the relatives for Labor Day and celebrating our 13th wedding anniversary. Starting tomorrow, I have to figure out what to do with the Longhorn Developer Center now that WinFX will be available on down-level windows, co-author two Avalon books and one Windows Forms book and run the Applied XML Developer's Conference 5. Should be fun. : )
Tuesday, July 27th, 2004
I got an email today from a friend who wanted to know what he could do to make the book he had in his head successful. I've thought a lot about this topic in the genre of Windows programming (I don't have a clue how to make your bodice ripper successful), but had never verbalized it 'til now, so I thought I'd run it up the flag pole and see who burns it.
DISCLAIMER: I make no claim about whether following these guidelines will make your book successful. These are just things that I think about when I'm trying to make my own books successful.
Write a quality book. I know this one goes without saying, but given the state of most books that make their way to the shelves, I thought I'd say it anyway. Karen Gettman, my editor at Addison-Wesley, says it like this, "Be the first or be the best." I've never yet had any luck being first, so I really try to be "the" book in any given category. For example, I think the 6 guys who read the TAPI book would agree that I really nailed it. : )
For me, the crux of quality (besides being able to string sentences into paragraphs and chapters in pleasant ways) is writing a book that describes how to do your work with the technology instead of that describes how the technology works. The difference is subtle, but it's what separates, for example, a book that describes how to build real applications in WinForms using the appropriate tools from a book on the WinForms classes, methods and events. Likewise, the former fills in the gaps when a technology falls short whereas the latter is frustratingly silent on such topics.
Have a significant audience. This is the one that's killed me time and again. The Win95 user book was killed by Internet encyclopedias. The TAPI book was killed by the lack of PC/Telephony adoption. The ATL book was pretty well-received, but the audience was still not the audience size that you'd like (although it still sells nicely and we're planning on having a 2e in time for Visual Studio 2005 and ATL 8).
Having a significant audience was the thing that killed my friend's book dreams when he called. Before our call, he was all excited about his technology (passion is an important part of the writing process and it's the only thing that can get you through the murderous back-end of a quality book [on the other hand, I understand that people that write crappy books don't have this problem, so there's something to be said for that...]). After our call, he had to admit that the market just wasn't there for anyone to purchase his labor of love once he'd produced it.
Own the marketing. The truth is that even though publishers have full-time marketing folks, you are much more likely to know where your audience hangs out and how to reach them then they are. Plus, there are all kinds of "guerrilla marketing" things that you are much more able to do than any publishing company. For example, these are some of the things that I like to do:
Answer questions online in your area of expertise. I'm continually surprised by the number of authors that don't participate in the communities that support their technology. If you answer questions and then point folks to your book for more details enough times, folks will grow to appreciate your book without ever having picked it up (although don't just point folks at your book without answering their question -- that'll just make you look like an asshole).
Ask for Amazon reviews of your book. People often feel the need to say something nice about my book before asking me a related question. In that case, I always take the opportunity to ask them to post a review and give them the URL to do so (the difference between finding my book on Amazon and just clicking an URL can make all the difference between whether they do it or not). I never ask them to post a "nice review," btw. I just encourage them to write what they feel.
Why do I care about them posting their reviews? According to legend, the number of reviews a book has is a fair indicator of how well it sells, regardless of whether those reviews are good or not. I don't know if it's causal, but since I can only influence one of the variables, that's what I do. Plus, the reviews look good to your family and friends when they pull up your books and since you're not going to make any money writing a book, you might as well get something out of it. : )
Why so I want the reviews on Amazon instead of blogs, newsgroups or BookPool? Because everyone goes to Amazon to buy books and that's where I want them to see the reviews. In fact, if I see a review somewhere else besides Amazon, I'll ask the reviewer to copy and paste it on Amazon so that all of the reviews are in that one, critical place (providing them the URL, of course, to make it nice and easy for them : ).
Continue writing in your area of expertise.
There's no better free advertisement for your book than that tiny bio at the end
of an article that says "P. Grammer is the author of Essential EDI Programming in a Nutshell in 21 Days for Dummies." Of course, that pre-supposes that the article is good enough for folks to want to read more of your work, but if it isn't, you've got bigger fish to fry.
Bang on your publisher. Your publisher has a PR department and a marketing department. Talk to them. Ask them what they're doing for your book. Watch where they go and make sure your book is represented. Watch where they don't go and tell them to go there. Make sure your publisher signs you up to revise your book as the technology evolves.
Pick your publisher wisely. Speaking of publishers, make sure you choose one you're going to like. It's easy to fall into the money trap, especially since every publisher on the planet can provide numbers about how they're the #1 publisher in some way for your book and you'd be a fool to go anywhere else. Unfortunately, when you do the hourly math, most authors make poverty level money, so why not pick the publisher you'll like the best? To find out which publisher fits you, you can either write for/flirt seriously with them or ask around. To save you the trouble of the former, I'll give a brief overview of the publishers with which I'm familiar:
Microsoft Press. This is the big dog that all the other publishers a) think is given an unfair advantage and b) are constantly trying to get within striking distance of. MS Press is so far ahead on sales volumes that the rest of the publishers are scrambling for #2. I've never written for MS Press, but have seriously flirted with them enough to be scared by them. This was years ago before the great opening of MS and things may be different now, but at the time, MS Press seemed keen to "fix" my writing to fit the "official" story and to be very firm about schedules, neither of which made me happy (I was used to a more loving, lax environment : ). Plus, MS Press is famous for little clauses in their contracts for which authors need to watch (although all publishers do this -- watch out for the one called "Right Of First Refusal").
Addison-Wesley. I've written all but one of my real books for Addison-Wesley and they have set the author environment standard against which I measure all others. In the old days, they'd throw advances and even grants at anyone with a pulse and then expect you to take 23.5 months to deliver on a 9-month contract while leaving you free to say pretty much whatever you wanted. Sadly, those days are over, but the idea of letting the author be the ultimate arbiter of what goes on the page has stayed. This comes from editors that are more like project managers in that they send nag emails when you're late and send chapters off to reviews to gather feedback, but don't ever really read the chapters (most AW editors aren't technical). What this means is that you have a lot of freedom as an author until some reviewer you don't agree with brings up something silly that the editor takes as gospel and whacks you with it.
Luckily, if you're writing for an AW series, you'll have someone technical that can read and review your content, although in this case, you'll want to make very sure that you see eye to eye with your series editor or you'll find yourself butting heads.
O'Reilly & Associates. I've only written one book for them and it was a mixed experience. On the one hand, it was the wrong book (it should've been a Visual Studio Hacks book, but this was before the Hacks format was invented). On the other hand, ORA editors actually read the book and provide intelligent, thoughtful feedback. I really like that. On the gripping hand, ORA has built its reputation of steady quality by applying heavy copy editing to all of their authors to coerce those that aren't writers into the ORA "voice." Most of the time, this works nicely. If you pick up any ORA book in any series, you know what you're getting and lots of people love that (I love a lot of ORA books myself). However, if you're an arrogant author (like me) who thinks that he writes better than the copy editors, you may be surprised with what the copy editor does to your stuff.
Also, ORA doesn't really have series so much as formats, e.g. Nutshell, Hacks, Developer Notebook, etc., so make sure you like the gimmick associated with a format before you sign up for one. To maintain that steady level of quality, they're going to make sure you stick to the format closely.
APress. I don't know a thing about APress except that I like Dan Appleman, Gary Cornell is a character and a half, they seem to have some good books and I've never written for them, so naturally I'd like to write for them for some day (I mean, just because my wife doesn't allow me to fool around outside our marriage, why shouldn't I be able to fool around in another genre? : ).
BTW, a lot of these same principles can be applied to your article writing, too, but there you know what they're paying you up front. A bunch of my friends have done the math and for the same amount of work required to produce a book, they can produce articles that pay much better. But you're not writing for the money, right? (Please don't try to write for the money...)
Wednesday, June 30th, 2004
I just got word from my publisher that, according to the industry-wide metrics they use, Windows Forms Programming in C# is the #1 seller in it's category week-to-week by a wide margin over everyone but Petzold (who I'm still beating, but by a smaller margin). And while Petzold has sold more copies overall, he had a 2-year head start on me and I'm gaining. Further, earlier today, Amazon.com had the book listed as the #5 best selling computer book (although it's at #10 right now with a sales rank of 459 and a ranking of 5 out of 5 with 52 reviews).
I normally try to toot my own horn a little more subtly than this, but the idea that I could learn Windows programming from the best-selling Windows book author of all time and then, 10 years later, beat his sales numbers makes me damn proud. Thanks to all the reviewers and folks that gave me feedback on the materials in my articles, to Shawn Wildermuth and Mike Weinhardt, who actually contributed material to the book and to Addison-Wesley for printing it (and then re-printing it, and then re-printing it... : ).
Saturday, June 26th, 2004
Can't come up with a better palindrome than "a man, a plan, a canal, Panama!"? Write a program and come up with one that's 17,000+ words. I love computers and what people do with them.
The most extreme thing I ever did along these lines is when my airplane was circling an airport for some unknown reason and the United flight attendant announced a contest to keep our minds off the dwindling fuel and the terrorists on the ground (oh, wait, that's Die Hard...). Anyway, she offered a free bag of peanuts (or something of equal value) to the person that could come up with the most words of 3 or more letters from the letters in the word "united" (Always Be Closing...).
Did I put my Tim Ewald-expanded vocabulary to work? Did I scratch words onto a cocktail napkin as fast as I could think of them?
No. In the limited time I had, I wrote a program that would come up with random combinations of letters in brute force fashion, then dumped the unique ones to a file so that I could use Word's spell checker to find the real words. I came up with 32. Did I win?
No. A librarian, using her own expanded vocabulary beat me with 34 (I had been running the program to generate 1000 possibilities to speed testing but forgot to flip it back to 10,000 when it came time to run it for real).
Did I stop there? Did I accept defeat gracefully, especially since it's pretty clear I had cheated in the first place?
No. I went home and learned the STL permutation algorithm and wrote a program that compared against a dictionary from the web to find the 72 words of 3 or more letters in "united" (including asynchronous updates to the UI as possibilities are checked [it takes a little longer, but it's worth it...]).

Now I carry that program on my laptop wherever I go, just in case I run into that damn librarian again...
P.S. I did get to use my program one more time against my mother playing Scrabble. I got my all-time high Scrabble score ever on that day. She still beat me. Did I mention she's got a bachelor's degree in library science? Damn librarians...
Friday, June 25, 2004
Because I'm a rarity at Microsoft, a remote employee, I've been conducting experiments in social video to increase my presence from afar.
My first experiment was a dedicated laptop for IM audio and video that sits on my desk in building 5. The idea was that anyone that wanted to chat with me could wander by my office and start an a/v chat w/ me nearly as easily if I was actually in the office. And then, when I'm supposed to be in a meeting, instead of requiring someone to bring their laptop, with a web-cam installed, and give it up to me for the duration of the meeting so that I could see folks, they could just grab the "mini-me" laptop from my desk and bring it to the meeting.
Sounds nice, eh?
Doesn't work.
The reason mini-me doesn't work as a stand-in for me in my office is because there's no standard account I can login with on my desktop, e.g. redmond\guest. The reason a standard account would be nice is so that I can leave it logged in all the time, tie its own .NET Passport to the account and put a shortcut on the desktop to make it IM me in video conference mode (I actually wrote an app that does just that). Unfortunately, it has to be an MS domain account so it has network access and if I leave an anonymous domain account logged in on a laptop all the time, that's an enormous security hole. And if I make folks that want a quick chat with me log in themselves, they'll will have to wait for their domain settings to migrate to the laptop, they'll have to login with their own IM account, they'll have to configure the web cam before using it and they'll have to remember to logout when they leave for the next person. Frankly, I'm not worth all that trouble when they could just call, IM or email me.
So, the mini-me laptop is a bust unless I can figure out a way to get Internet access without Intranet access inside the MS corporate Intranet without requiring everyone to log in w/ their own account to get it. Oh, and it has to be in a way that works with wireless so that they can haul mini-me to a meeting without having to haul along a cable, too.
My 2nd experiment in social video
went quite a bit better. Last week I gave two 1-hour talks back to back to the
AZ .NET User Group, but the trick was, I gave them from my house. The setup was
two computers on each side. One was for NetMeeting app-sharing (using MSN
Messenger to request Remote Assistance works, too, but I can never get MSN
Messenger app-sharing going). The second is for the video (the CPU load was too
heavy to do both on one computer). Voice was done over the phone, which they put
through their PA system. They also had two computers, both attached to video
projectors, broadcasting my screen using one projector and my image using
another (can you imagine how disturbing it must have been to see the giant,
pixelated maxi-me? I shudder at the thought… : ).
The app-sharing worked
well, as I was able to easily switch between PowerPoint and a Terminal Services
session to my Longhorn box. The audio worked well because I insisted on 2-way
audio so I could hear them ask questions (I hate talking into silence). The
video was cool, because I could see them raise their hands, drift off, laugh,
etc, but it required somebody sweeping the room on their end periodically
(talking without seeing your audience is slow death).
Overall, it seems
like folks were able to enjoy a remote presenter without too much trouble. Once
I got 'em warmed up, the speaker phone and roving camera made Q&A very natural.
I would try maxi-me again, although I'd love it if I could get mini-me working,
too.
In general, I believe that ubiquitous a/v conferencing is inevitable. I just I'm just a bit ahead of the curve. : )
Friday, June 25, 2004
I spent most of Thursday in a seminar given by Edward Tufte, the author of several seminal books in the area of data analysis and presentation (with another, Beautiful Evidence, in the works). I enjoyed it thoroughly and here's what I was able to capture:
The goal of good information design is to minimize the amount of time spent figuring out the design of the presentation of information (or even admiring it) and maximize the time spent reasoning about the information. Good designs should be as nearly invisible as possible.
Tufte: "The point of an information display is to assist thinking. Good design is clear thinking made visible. Bad design is stupidity in action. Chart junk is a good sign of statistical stupidity."
My favorite Tufte term is what he calls designers brought in to make boring numbers look interesting: "chartoonists."
Tufte: "Don't let the marketing people corrupt your presentations by eliminating detail. Chances are, the people looking at the information know more than the marketing people. People haven't suddenly gotten stupid just because they come to hear you talk. If people can read the financial tables and the sports tables from the paper, they can get read data from you." (The last point assumes a good design.)
In my own work, I often remove detail for clarity, but I'm very careful to leave enough details to keep context. I admit, it's a fine like to walk and hard to get right.
As a way to pack more data into a small space (and in an attempt to secure his immortality, imo), Tufte was inspired by Galileo's work to create a new kind of graphic meant to be integrated into a sentence as yet another word. He calls them "sparklines" (the sparkline is the graphic before each word):

Sparklines pack a lot of information into a small space and are a cool alternative to graphics that break the flow of thought and need to be called out with a phrase like "as seen in Figure 3." I have a mind to implement them in Avalon when I get a chance.
Tufte hates most kinds of user interfaces because they spend too much of the already low resolution screen on "fluff," e.g. menu bars, captions, navigation, etc, and too little on the content itself. As an example, he showed a screenshot of a photo display app that used only 18% of the screen for the actual photos. He wants nearly invisible operating systems and apps and 90% of the screen used for the content. He's a big fan of Google News as a way to pack in a lot of information and he's a big fan of scrolling. For web sites, Tufte recommends only a small set of links at the top of each page for navigation and nothing else. His own site is like this and I have to admit, I like it.
Ed hates low resolution. He wants everyone to design for high resolution to be viewed at 22 inches so you can pack a lot of information in, showing comparisons and causality. He hates PowerPoint because it's made to be viewed from 22 feet and doesn't provide a lot of room for showing dense data, comparisons or causality. It's far easier for humans to make judgments when they can see everything at once instead of sequenced one slide after another (or "one damn thing after another," as Tufte says : ). In general, he believes everything should be printed and that PowerPoint should only be used for showing pictures to an art class. I see his point, but ironically, when he wrote a paper on the problem of PowerPoint to be read at 22", after 3 pages of him blaming PowerPoint for sloppy thinking, I put it down in disgust. If he had had his thoughts put together into PowerPoint-style format, I could have skipped ahead to find his real point, i.e. low resolution makes it hard to do serious analysis.
As a point for Tufte, when producing this summary of my day listening to him, I'm mixing prose, images and references, but I'm not producing it in PowerPoint. According to Tufte, 4 pages of prose is equivalent to between 50-250 PowerPoint slides and I have to admit, it would be hard to convey what I want to say about him in a PowerPoint deck without using a lot of slides and throwing away the subtleties. In general, I believe that PowerPoint is best for reminding the presenter what they want to say and is very poor for the audience. Instead of a slide presentation, Tufte recommends providing the audience 4 pages of prose, which they read 3-5x as fast as you could say it, and then having a conversation. Interestingly, he allowed no conversation during his own presentation but instead talked to various parts of his books and hand-outs.
On the other hand, has anyone even read this far? Would you have gotten farther if I'd have summarized everything in slides, skipping ahead to the juicy bits when you got bored?
Tufte has a great deal of advice about how to prepare for and give presentations. To prepare, you must have great content (no amount of design or practice will fix bad content) and spend a great deal of time practicing (especially important if you're not using PPT to remind you what to say). When presenting, follow these rules (these aren't all of my rules, but I agree with them):
I think that Ed has enough good things to say about how to approach the presentation and analysis of data that I would recommend that pretty much anyone involved in the presentation and analysis of information take the time and attend his day-long seminar.
Monday, June 7, 2004
Wednesday was a good day. Not only did I get birthday wishes from all over the internet (thank you, Orkut), but I got to give my first presentation to a Distinguished Engineer (or DE, as we call them in humble tones). A DE is the top end of the individual contributor ladder that technical folks who want to stay technical -- aka avoid becoming management -- are on. Architects, e.g. Don, are one step down on that ladder and Program Managers (PMs), e.g. me, are even further down. In this case, the DE to whom I was presenting is someone that I've long respected and who invented and continues to guide my favorite programming language: Anders Hejlsberg.
A couple of weeks ago, Anders was digging through our docs on a topic in which he was interested because of the future directions he's got in mind for C#. However, the particular information that Anders was looking for wasn't in our documentation. So, he mentioned that he'd like someone to look into it and get the information for him. As a percentage of the 56K employees at MS, there are a very few DEs, so when one of them mentions that they'd like to see something done, that's what happens. This doesn't happens because a DE is your boss or because they decide whether you get a raise or not. This happens because smart technical folks get respect at MS and the smarter you are, the more respect you get. So, when Anders mentioned to BradA that he would like a brief on this technology, Brad found someone to give that brief: me.
Why me? Well, lately I've been talking to Brad about me doing some more technical work on WinFX and Longhorn. In the past, I've written and spoken a great deal about the good and the bad of various technologies and my thinking was that if I could get into a feedback loop with the product teams so that I could help prevent some the worse bits from making it out the door, giving me the opportunity to write only nice things about our technologies. Brad already runs the WinFX review team that's in charge of making WinFX a nice place for developers to play, so when I volunteered to help with some of that work, it didn't take long for him to take me up on it. And, after a few moments of hesitation when I realized that I only knew a little more than Anders about this particular topic, I jumped at it, digging into the technology, sending "tell me more" and "review these slides, please" emails to the various product groups in charge of those technologies (it's amazing how quickly you get a response when you put "I'm writing a presentation on your technology for Anders and..." into an email : ), revised the slides, woke up in the middle of the night with the perfect set of pictures to illustrate things, etc. In short, it was a blast and I learned a ton (which you know I like : ).
And the actual presentation was even more fun than the preparation. There are three kinds of talks. One kind of talk, which happens 80% of the time, is the kind of talk that doesn't really affect you one way or the other. It kind of blends in with all of the other talks you've given and doesn't really make an impact on you.
One kind of talk drains you completely. This is the talk where you just can't get anyone to notice you at the front of the room and you pour all of your energy into it to make it acceptable at all.
And one kind of talk, my favorite, is when the juices are really flowing and you walk out of the meeting all excited and energized. This is the kind of talk that drives me and my colleagues to all-night diners for a debrief session. This last talk was the kind that I had this time with Anders and a couple of the product teams from around the company. I was really just guiding the discussion, with Anders leading and peppering all of us with wonderful, insightful questions. I had 20+ slides with overview, pictures, details and recommendations, but I only showed 4 of them (3 of pictures and 1 of recommendations). My inability to get through all of the slides didn't matter: Anders got it all. He was interested in some of what I had to say, but also brought up points I'd never considered. What I think should be in our platform was changed by just listening to Anders ask questions. I could feel the synapses in my brain realign. It was amazing.
Things will absolutely change in our platform because of the desires that Anders expressed during my presentation. What a privilege.
Friday, May 28, 2004
Today was the first time that I was called to jury duty, even though I've been eligible for almost half of my life. I always dreaded being called when I was a consultant because the $10/day didn't cover a day's meals, let along the revenue I would miss as the sole breadwinner of the family. However, much like the body puts off illness when you just can't afford to take the time (stress has its uses), my dread seems to have put off my jury duty 'til I had a full-time job with enough redundancy to live w/o me for a day or so.
Even when your job pays, most folks seem to want to get out of jury duty in any way possible. George Carlin says that the best way to get out of it is to admit to the judge that you know how to tell if someone is guilty, "It's all in the distance between their eyes..." Personally, I'm a believer in America's system of justice (I've often fantasized about a life as a prosecuting attorney and as a judge), so I didn't mind serving my turn on a jury. Unfortunately, it was not to be. While I went down to the court house, my number wasn't even called to appear on one of the two juries needed today.
Doing a little math, I found out that the overall odds of me actually being on a jury were actually pretty low. Here are the stats:
47 people showed as potential jurors on 2 juries
28 were called for the 1st jury, of which 12 were needed
15 were called for the 2nd jury, of which 6 were needed
According to the State of Oregon Washington County Jury Director, 70% of people that show up for a trial see the assembled jury and decide to take the plea bargain after all
Therefore:
Folks called to jury duty that were actually put on a potential jury: 91.5%
Percent of juries, once formed, that are used: 30%
People called for a jury actually placed on that jury: 42%
My chance of actually serving on a jury today: 11.5% or less than 1 chance out of 8
The opportunity to make the US justice system real for the brothers Sells w/o them actually committing a crime: priceless
Friday, May 21, 2004
I took a Gallup questionnaire and 3-hour seminar on the philosophy of strength-based development. The central idea is to identify one's strengths and concentrate on those. This is opposed to general thinking which says that you should work on your weaknesses. According to Gallup, no one can really change their weaknesses much, but if you focus on your strengths, you can really make a difference in yourself.
As evidence of this claim, Gallup sites a study of teaching speed reading to average and above average readers. The average readers started at 90wpm and the speed reading course increased their speed to 150wpm, an increase of 67%. The above average readers started at 350wpm and increased by more than 800% to 2900wpm. Or, to put it another way, it was 10x more effective to concentrate on a strength than to try to improve a weakness.
The dark subtext of the strength-based point of view is that if I can't really fix my weaknesses, then I can only really do well in certain kinds of ways. I don't like this idea. It sounds too much like fate, which just pisses me off because I don't like the idea that it's my nature and not my effort that determines how well I do at something.
When I mentioned this to one of instructions of the seminar, she looked at my strengths and said, "Oh, I see why you want to think it's you that governs how well you do," which didn't make me feel any better. My strengths, in order, are Achievement, Command, Communication, Learner and Intellection. In other words, I like to get things done, tell people what I think, learn new things and think about them. This set of strengths wasn't really a surprise, but here's one: I think DevelopMentor was speed reading for my particular strengths. DM was an environment that encouraged all of my strengths and I stumbled onto it by pure, dumb luck.
On the other hand, before DM, I wasn't nearly the Communicator that I am now. In fact, I think it would've been one of my weaknesses had I taken the Gallup questionnaire 10 years ago. And if that's the case, I would have been discouraged from spending too much time working on it by, for example, teaching, presenting at conferences and writing courses, articles and books, which I think would've been a shame, because I really love to write.
So, while I like the idea of concentrating on one's strengths, I still don't like the idea of ignoring one's weaknesses.
Friday, May 21, 2004
At the last Applied XML Dev.Conf., I went ga-ga over Amazon's use of web services in their business and called it the "killer app for web services." Now I'd like to revise my statement: it think that it's one of the killer apps for web services.
Here's another one: exposing the functionality of all of those internal corporate services apps that are now exposed as web sites as web services instead.
Now that I've been back inside of a giant corp. adrift in a sea of sites to "help" me with the various "business processes" that I have to execute, I yearn for them all to be exposed as web services. There are several problems with the internal business-processes-as-web-apps morass that we're stuck in:
The web apps are generic for all uses across all companies, which means that there are tons of options for other uses then mine, but I still have to deal with the UI for all of the options
To get my business tasks accomplished, I have to string together several of these web apps in series, manually moving the data from one to the other
Just going from one page of a web app to another, even in a corp. intranet, is so slow when you are always going to pick the same options and your fingers want to be far ahead of what the server can handle when generating the UI a page at a time
For example, here at MSDN, we have package source code sent to us by authors into an MSI with a EULA, code sign it with the Microsoft key and submit it for download to the MS download site. A year ago, it took me an hour of instruction to understand the process and it involved using VS.NET to build the MSI and two separate web sites, both with several pages and tons of fields to get a folder of files available for download by our good readers. This took me 30-60 minutes to do each time I had to do it, which made me cranky, so I built this:

This tool takes the minimum number of fields necessary to turn the source files provided by the author into a signed MSI. Plus, it's a smart client, so the UI is snappy and I can make it smart about what specifically it should remember between sessions for our own uses. And, I can provide a single UI for multiple back-end services, duplicating the data between them as necessary w/o requiring the user to duplicate the data for me.
The way I was able to minimize the number of fields was to build all kinds of assumptions into the app based on how MSDN does things, aka the business rules, and build my own app that programmatically generates when I need. In other words, my app combines business rules with programmatic interfaces to save me and my friends all kinds of time (the process is now about 10x faster than it used to be and 100x less tedious and less error prone).
And that's the beauty of allowing programmatic access to internal business processes: it allows each group in the company to build specific apps that meet their needs more specifically, letting them consolidate the processes into their own group-specific tasks. Not only does this speed things up and increase consistency for our customers, but it also removes the tedium and lowers the possibility of human error. If you could gain all those benefits, would you do it? That's the promise of web services and SOA when applied internally, because it allows the groups that provide the services to be general-purpose, meeting the needs of all groups, but lets each group be specific when they apply it, instead of forcing a web interface that requires everyone to be general.
Am I alone in getting aroused when thinking about this kind of thing? : )
Sunday, May 16, 2004
Yesterday was my 3rd anniversary of The Sells Spout. It's hard to remember back that far, but this was before any wide-spread blogging software, either client or server, before RSS and before personal email addresses were rendered nearly useless by 157 messages/day about how to enlarge our genitalia, necessitating the eventual move away from newsletters.
At the time, I used FrontPage and <a name> tags to run my blog. I still use FrontPage + <a name> tags, but I also use web forms and SQL Server to track comments and generate RSS. In general, I see my site as a giant, categorized blog, e.g. Tools, Fun, Spout, etc, with a front page of descriptions of the items I add to my site and of interesting things I find in the world. Towards that end, I'd like to rebuild my site from scratch using some kind of content management system so that I can get a bunch of flexibility that I don't have now, e.g. referral logs, auto-archive pages, comment notifications for me, rich comments, a smart client front end for reading from -- and adding content to -- the site, etc. I could add all of that to my own homebrew software, but I'd prefer to use something like .Text. In fact, assuming ScottW integrates .Text into ASP.NET 2.0, rebuilding my site with both is something that I've very likely to do.
The site itself is 9 years old, but my normal outlet of tools, code samples and technical writing wasn't enough for me, so 3 years ago, I started editorializing on The Sells Spout. I don't know what my site traffic was 3 years ago, but I know it's grown ridiculously since then for no reason that I can discern. For example, last month my site served 885K sessions and 2.5GB in small pages, zip files and RSS feeds. While full 55% of the page hits were the RSS feeds (quite a number of you are keeping a close eye on me, apparently), that left 398K people/month visiting my site to read or respond to a topic from my blog (18.7% of the total), read about interviewing at Microsoft (10.6% of the total) or download a tool (4% of the total).
BTW, for those of you who would point out that my RSS feed is syndicated as the Editor's Blog for the Longhorn Developer Center, throwing off my site stats because of the traffic on the DevCenter itself, I'll counter with one word: caching. Kent Sharkey, the editor of the ASP.NET Developer Center and expert in all things ASP.NET, has built caching into the control that displays the Editor's Blog from my RSS feed. Since it's set to 60 minutes of cache per server and hosted on the 11-server MSDN web farm, that's at most 8184 sessions/month to serve my RSS feed on msdn.com.
I don't really know what draws that many people to my site, but 3 years ago, I stated my rules of engagement as follows:
After 3 years, my agenda remains the same. I find that strangely comforting.
Friday, May 14, 2004
Being a Midwesterner, my father is a fairly stoic man and, unlike his son, doesn't often speak just to hear the sound of his own voice. Still, I've managed to pick up a few gems over the years that my own sons are now forced to hear often, like "If something is worth doing, it's worth doing well," "It's the hard things that are worth doing," and "It's easy to figure out the right thing to do -- it's the hardest" (do you detect the Midwest work ethic in any of these sayings? : ).
When I was having trouble with a pair of 6th graders (I was a 3rd grader), he said, "Don't start a fight, but make sure that you end it" (that was hard to implement...).
When I went off to college, he said, "Don't go to bed drunk" (I always regret it when I ignore this piece of advise...).
When I broke something of my wife's and wasn't contrite enough, my father, working on wife #3 at the time, said to me, "You've got to be nice to your wife!"
But the one that sticks with me most, the one I hear in my head almost every time I make a sandwich (and the one that caused me to write these words) is "Don't get the God Damn jelly in the God Damn peanut butter!" To this day, with my father 1500 miles away in Fargo, I still make sure that there's no jelly on my knife when I reach for the peanut butter.
It's funny what unintended impressions you leave on people. I wonder what about me will haunt my children?
Sunday, April 25, 2004
Newsgroups, mailing lists, web forums and blogs (with comments) are all very similar. Fundamentally, they'll all about posts and replies. Sometimes the posts are replicated to servers around the world, acccepting replies in the same way. Sometimes the posts are replicated to a set of subscribers via SMTP and replies come in via POP3. Sometimes the posts are part of a web page and provided via HTTP, using HTML forms to take replies. Sometimes the posts are served up via a centralized server using HTTP + RSS or HTML, accepting responses via HTML forms or the CommentAPI. Fundamentally, it's all the same thing, though: posts and replies. Why do I have to suffer with the limitations of any one of these protocols just to hang out with my friends to talk shop?
I don't like newsgroups because I don't like having a separate reader outside of my mail reader (and NewsGator ain't anywhere close to what I want yet). Plus, newsgroups are very susceptible to spam, although the MS newsgroups are carefully patrolled to kill it before it spreads.
I don't like web forums because I either have to poll the site (which RSS has cured me of) or the integration of the forum into my mail reader is limited to notification only. Plus, every single web forum has a vastly different UI and set of features and the inconsistencies bug me. On the other hand, web forums are pushing the envelope on features that I really want, like author and content ratings.
I love mailing lists, but don't want to duplicate any of the WinFX newsgroups in mailing lists just yet to avoid fracturing the budding developer community.
Blogs are wonderful, of course, and RSS is the only thing that's worth me spinning up a whole separate reader than my mail reader, but it's impossible to follow a thread of conversation between blogs or comments on other people's blogs. On the other hand, the server-per-poster model is great because I can just subscribe to the posters that I like, increasing the signal to noise ratio substantially.
I think we should pack all of the features of mailing lists, newsgroups, web forums and blogs into a single backend and expose it via HTTP, NNTP, SMTP/POP3 and RSS as appropriate. Is it time for a new protocol that can be dumbed down to the existing protocols for the diehards that won't give up their readers of choice? Personally, I'd like to get everything via SMTP/POP3 except for my RSS feeds (although I don't know why -- maybe it's just that I can't seem to get a handle on a keyboard-only mode for RSS reading in NewsGator the way I can in SharpReader...).
Saturday, April 24, 2004
I'm a sucker for new experiences. It's not that I believe that "you only go around once," because I don't believe that. I believe that our job on this plane of existence is to raise our level of consciousness to the next level and that our souls are recycled from life to life on this plane 'til we're ready for the next. So, I figure that anything I don't get to do in this life, I can do in the next.
And yet, I'm still a sucker for new experiences. In any given 10 years, most folks get 1 year of experience 10 times, but I think I've done pretty well at squeezing quite a bit out of my last 10 years. And I hope to continue to do that. For example, this year my wife and I will be attending Burning Man. We'd never been, but a couple of my friends from MSDN are helping us find our footing at what promises to be a very unique experience indeed.
MSDN is, in fact, a haven for unique folks willing and able to help me try new things. As another example, last week I had a private meditation lesson from Henry Borys, MSDN editor, book author and meditation teacher for the last 30 years (he's been teaching meditation since I was 4!). He runs weekend seminars and even a yearly trek to the Himalayas and while both sound attractive, my Redmond travel schedule almost never brings me there over a weekend (let alone to the Himalayas : ), so he invited me up to his place for a private lesson. It was beautiful. It was 30 minutes north of the hustle and bustle of the MS campus and right on the shores of the Puget Sound. We sat on his back porch, watching the sun set over the water and talking about his experiences in meditation (mostly in variations of transcendental meditation [TM in meditation speak]) and my experiences applying what I'd picked up on my own reading Meditation for Dummies (I have come to love the Dummies books).
We spent almost two hours meditation and discussing meditation. Here's what I learned:
Meditation should be effortless. If you're working at it, you're not getting it.
Don't fight the thoughts to "clear your mind." That's a sure way to keep them bubbling in your head. Instead, think of thoughts as the by-product of the purification of the mind that happens when you meditate and let them happen w/o paying them any attention.
When you find yourself dwelling on your thoughts, go back to your mental mantra. Henry, as is traditional in the meditation teacher-student relationship, assigned me a mantra. Mine is a general-purpose and commonly shared amongst TM parishioners, but is still darn exotic to me, being in Sanskrit. The mere sound of it helps me and, since I don't really know what it means (although I'm hoping it's not "send Henry money" in some subliminal form : ), it doesn't distract me from the meditation (unlike my previous, self-chosen mantra "free your mind," which, while very meaningful to me, did tend to hinder).
You're not meditating for the act of meditation itself, but the benefits it adds to your life when you're not meditating. While I've grown to like the act itself, I have also been enjoying a more peaceful, less stressed perception of life since I started (although it's still too early to tell if this is merely the placebo effect).
Don't judge your meditation. Let it happen how it happens.
Your meditation may uncover some deep-seated sleep that's necessary for your body to experience, so if you feel yourself falling asleep while you meditate, that's OK.
Take 3+ minutes to come out of your meditation to "avoid the bends." Otherwise, you could easily come out of it too quickly, giving yourself headaches and/or making yourself irritable. I find that 60 seconds is enough for me, but I'm sure I don't get anywhere near as deep as an expert, so I always take this process as slowly as I can.
And one of the most fun techniques that Henry introduced was to realize that thoughts are merely interactions with your consciousness. This realization can make your thoughts abstract, which can actually push you deeper into the meditation itself. In other words, when you think of thoughts this way, the more you have of them, the better, which was non-intuitive to my previous understanding of meditation. Hearing this was a very "there is no spoon" kind of moment to me.
I was actually looking for some kind of introduction to meditation for months before I learned that Henry was a teacher, even though I've known him for more than a year, showing that once again, when the student is ready, the teacher will appear. I look at this experience as help along the way to a higher plane of existence, which I believe is defined within. And while I'm not a practitioner of any religion (I'm ex-Catholic), I do see this as a spiritual pursuit, blending the beliefs I've picked up with my brief brushes with Gnosticism and Buddhism and as popularized in The Matrix (although lost again in those stupid sequels). Free your mind, indeed.
Wednesday, April 14, 2004
You're remember the last installment in my continued quest to find the next big leap in program producing productivity (the last two were OO and managed environments), where I thought I had it all figured out with generic algorithms. All we need is a sophisticated enough environment and wham self-writing, self-maintaining, self-debugging algorithms baby. However, after this evening's Portland Nerd Dinner (you didn't pass up a chance to meet Ward Cunningham, did you?), I'm thinking there's one step in the middle (at least : ).
So, picture the scene. After hearing about a guy that has a "fob" on which he has to enter a password to get a 6-digit number that changes every 60 seconds to that he could log into his company's VPN, declaring that that's what happens when you let Keith Brown run the world (I love you, man : ), and describing the CSSM (the Chris Sells Security Model -- which I can not only implement under .NET, but actually apply to code [maybe I'll start a workspace...]), I turned to Ward and asked him the same question that I had asked the group from the last PND, i.e. "What's the next big leap away in development?", being careful not to give him my thinking from last time.
Ward went a whole other way.
And he got me thinking it's a good idea.
So, Ward starts describing how to use loose typing (as in computer science "types" and what you do with your 101-Key Text Wizard) and TDD-style tests to infer types for your loose typing and I'm shaking my head, 'cuz I still gotta write the code.
Then a long-haired guy to my left who's name I never lernt (I meant to!), starts talking about how each leap in the past came from handling one detail that you don't care about, e.g. register allocation, memory management, etc, and I think that has the possibility of helping me, 'cept the thing I want to get rid of is the code (I mean, if I can't make a business on generating the stuff, then let's kill it altogether : ).
Then Jim Blizzard starts asking an interesting line of questions about whether a leap is really a leap 'til we're passed it and we can look back and decide it was a leap. While I think a leap is a leap because you can feel it (I can still remember the joy of my first program [leap 1], hear the ping in my head when I understood OO [leap 2] and feel the rush in my veins when I got managed programming [leap 3]), I was very interested in Jim's point because I think he was leading me somewhere [leap 4?].
Then, Ward jumped in again with another scenario where you start from nothing and have a programmer at your elbow to translate the next thing you want as you desire it (the first such scenario was Ward's Adventure Diet where you start with nothing, then add one kind of food/day 'til you pass the unit tests I guess [Ward actually put himself on this diet for a while -- man, we are nerds]) and that's when I nearly leap across the table so that I can get my own words in edgewise, literally telling Warm that he had to stop talking now so that I could.
Because that's when it all hit me.
What I want is X1 for programs. I've fallen in love with X1 because it gives me immediate gratification. It still finds the same things that Outlook search and Explorer Search finds for me, but X1 does it in such real time that I can narrow in several fields at once based on what I know about what I'm looking for, e.g. some of the body content and/or who it's from and/or what folder it's filed in and/or when I got it, etc, until I see a small number of choices from which to pick and I can click on one and say "aha! that's the one!"
I want X1 for programs. I want to start with nothing and keep refining it with commands like, "I want an app," "I want a grid" and "the data should come from here" and have my computer say, "Would you like an app like this, this or this" and "would you like the grid to look like this, this or this." And I want my computer to know about every feature that ever been built into 3 or more programs, e.g. from remembering the spot my window was the app last ran to dropping in pivot tables, from reading/writing to/from databases to providing theming. Anything that doesn't work in 3-6 choices, e.g. color themes do but individual colors don't, I want a Property Browser/Windows Forms Designer-like experience and only when I get to implementing something that hasn't already been implemented 3 times do I even want to think about writing a line of code.
'cuz here's the thing. I don't want to give up writing code. I love writing code. I just hate writing code that's already been written. What I want is for a customer to go through all of the stuff in the Codeless, Human-enabled, Realtime, Interactive System (or CHRIS*, if you will : ) as described in the previous paragraph, get to an actual working system except that it doesn't do some cool, unique thing that no one's ever thought of before and then send it to me in an email along with a PO for how much they're willing to pay for me to do the last bit.
When the last bit's been written 2 more times, it goes into the CHRIS and around we go again.
And I was all happy with that answer and I presented it the PND crowd just before the Sells Brothers (who had come along and been absolute angels for more than 2 hours while I geeked out with my friends), lost it and started throwing their shoes at each other in the Washington Square Mall food court, at which point I had to leave, before hearing what Jim's point was or what Ward was going to say after he said, "OK, wait, what about this..." which is usually what he says just before he tells you that he's already built what he's been warming up to for the last 30 minutes and you find that it rocks.
So, you guys damn well better tell me what happened after I left, especially if it's better then the CHRIS!
BTW, why isn't anyone filming these PNDs? They're the best techie conversations I have all month...
* I swear that 90% of that acronym (abbreviation?) came out naturally and was only tweaked slightly at the end for marketing appeal. : )
Saturday, April 10, 2004
I enjoyed the annotations in The .NET Framework Standard Library Annotated Reference so much that I read them all in one sitting (in the bathtub, if you must know...). The annotations are where the authors put in their 2 cents about a particular class, method or property and it was very interesting. Here's what I learned just from that part of the book:
class Enum : IEnumerator {
object IEnumerator.Current { get { return this.foo; } }
...
}
This syntax hides an interface method from general use unless you
cast to the interface base class:Enum enum = new Enum();The thing I never thought of that this enables is that it lets you override based on return type, which isn't normally allowed in C#:
object obj1 = enum.Current(); // compile-time error
object obj2 = (IEnumerator)enum.Current(); // this works
class Enum : IEnumerator {
object IEnumerator.Current { get { return this.foo; }
Foo Current { get { return this.foo; } }
...
}
This private method implementation syntax lets you return the
generic type as part of the interface implementation so that you can plug
into standard idioms, e.g. foreach, but a more specific type for users of
the type directly, saving the cast:
Enum enum2 = new Enum();This will be less interesting as generics take over, but still, it's a useful trick.
Foo foo1 = (Foo)((IEnumerator)enum.Current());
Foo foo2 = enum.Current(); // no cast required
using System.Globalization; using System.Threading;...
If I can get that much out of just the annotations, imagine what I could learn if I read the whole thing. : )
Tuesday, April 6, 2004
Sometimes I get emails from folks that don't have a formal computer science knowledge and want the benefits of one w/o actually going back to college. Since I was disappointed in my own formal education (despite going on to "better" my BS in Computer Science with an MS), I can understand this desire.
My first thought was the MIT Open Courseware, which has a full course of computer science curriculum. However, while the course material is all there, unless there are officially sanctioned forums for each course, there's really no place to ask questions even of fellow students.
After thinking on it for a while, I thought I'd go right to my favorite source. Prof. Joe Hummel is a professor of computer science at Lake Forest College in Illinois and has spent a lot of time thinking about how to fill in missing CS knowledge in professional programmers (VB programmers, mostly) at DevelopMentor. Here's what he said:
For starters, I'd recommend a book by Brookshear called "Computer Science: an overview" (8th edition). It's written for those new to CS, but introduces lots of nice CS concepts like algorithm analysis, theory of computation (e.g. that some problems cannot be solved!), and other things like OS, networks, DBs, etc. It's a great starter book. After that, I'd recommend books on data structures and algorithms. After that, it really depends on what his interests are: Programming Languages? Theory? Operating Systems? Distributed Systems? Software Eng? AI?
Thursday, April 1, 2004
I wrote this at the beginning of 2002 while channeling my energies into the Windows Forms book. I never published it, but I liked it (and I'm in writer avoidance mode as day #2 past my due date rolls by), so I thought I'd share it:
The Dark Ages, a period of five centuries beginning in 5 AD, marked a time of intellectual darkness and barbarity. A ruling feudal class kept a firm grip on their over-worked peasants in small enclaves eking out a meager living from the soil. Only lonely, isolated monks were able to record knowledge using primitive tools to painstakingly inscribing it into hand-crafted volumes, each unique and each unavailable to their fellow man. Only pilgrims and adventures, willing to endure long journeys and brave many hardships, had the chance of obtaining this secret knowledge. Finally, the Renaissance, brought on by the spread of knowledge in approachable formats using inventions like the printing press, was able to rejuvenate a weary world and bring about a period of intellectual growth and achievement that continues to this day (interrupted only briefly by the Reagan years).
The Browser Age, a period of ten years beginning in 1991, marked a time of user-interface limitations and lowest common denominators. A ruling standards body kept a firm grip on their over-worked participating members in companies large and small, eking out a meager living from IPO wind-falls. Only lonely, isolated web masters were able to record knowledge, using primitive HTML to painstakingly code it into hand-crafted pages, each unique and each unavailable to their fellow programmers. Only Perl programmers and regular expressionists, willing to parse tangled byte streams and scrape many screens, had the chance of separating the data from the presentation. Finally, .NET, brought on by the spread of the information available programmatically to rich client applications using inventions like Web Services and Windows Forms [ed: and soon, Avalon], was able to rejuvenate a weary software world and bring about a period of productivity growth and achievement that will continue until long after we retire (interrupted only briefly by the Internet Bubble burst).
Thursday, March 25th, 2004
Even though Ward Cunningham and I have
been living only 4 miles away from each other for some years, I really didn't
know that he lived in in the same state 'til he sold his soul
hired on at Microsoft. Since then, we've been meeting at a local Starbucks on a
regular basis to shoot the shit in a very DevelopMentor/Tektronix-like way, i.e.
ramble on about whatever 'til we hit on something fun to try. In one of those
meetings, we were talking about requirements for a web services API that I'm
working on and he took us off on what I thought was a tangent, but turn out to
be very cool.
Before Ward set me straight, I thought that Test-Driven Development (TDD) was when I built a little console app to test my APIs. I routinely do this before I write an API so that I can imagine what I wish I had to program against without being encumbered with an existing implementation. Then, I run my console app(s) afterwards for testing and regression testing, but only sporadically. I knew that NAnt let me run these tests into my build process, but since I'm a VS.NET guy and I haven't done the NAnt/VS.NET integration work that I know I should do, I haven't done as much with this as I knew I should be. Plus, as it was only me, it didn't seem like such a big deal.
What makes TDD a big deal, however, is when you've got a team of folks. Of course, every developer is expected to check in tests for their stuff and those would be run as part of the nightly build. But that's not the cool part. The cool part is when another developer adopts my API and puts his tests into my build process. When someone adopts an API that I build, then make certain assumptions about how it works and what side effects they can expect. TDD lets Joe R. Programmer encode his assumptions as unit test code so that when I break his assumptions during an iteration of my API, I see it as part of my compiler output.

Until I get a build error, I don't need to know or care about Joe's test. But when I do, I look at Joe's unit test code and decide whether he was right. If Joe's unit test is valid, I need to either fix my breaking change or be prepared to help everyone that uses my API to rewrite and redeploy their code. If Joe's unit test isn't valid, I've got to help Joe fix his code and prepare to help everyone else that made "invalid" use of my API to begin with. The very nicest things about TDD is that "fixing breaking changes" becomes the least painful thing to do!
This is huge. In fact, it's so huge, that MS should provide an end point for people to submit their own unit tests against our Windows and .NET APIs so that when we make breaking changes, we can either fix them or know the proportion of folks affected by this breaking change.
Anyway, when Ward told me this, my eyes were opened and I was changed. But he was just getting warmed up. After showing me the power of formal unit tests across a team, he then went on to describe the power of putting the unit tests right into specifications themselves. For example, imagine a table in a spec laying out a series of inputs and expected outputs:

Now imagine a parser that could read through this table and execute the code being specified, checking expected output against actual output, lighting matching output green and mismatched output red:

This scheme lets designers define the spec long before it's implemented and then check it's progress as it's implemented. Likewise, a spec itself can be put into the build process as another set of unit tests. Plus, the readability and maintainability of specs in this format is much improved and very much more accessible then unit test code.
But wait, there's more. This isn't some pipe dream. Ward has a .NET implementation of it called the FIT Framework on the web and yesterday he and I played around with it in my kitchen. Our goal was to take Ward's .NET FIT implementation and add support to it for SOAP endpoints. We started with the ISBN Information web service that we found on xmethods.org and defined the following spec:

We specified the name of the FIT "fixture" (which is the class that implements the tests in FIT), as well as the WSDL URL, the service type and method we'd like to test, the arguments we'd like to test and the results we expected to get. We mixed in some of Christian Weyer's Dynamic Web Services Proxy and we got this:

Notice that we're not quite done yet, i.e. nothing is green and we're not reaching into the retrieved XML and pulling out the Author, Publisher, etc. Still, while FIT requires a matching piece of code for every spec, we dropped a bit more metadata into the tables for the SOAP version, leveraged WSDL and have narrowed the project to a single piece of generic code for any WSDL-described SOAP endpoint (so long as Christian's code can parse it).
Our plan is to finish up the extensions to FIT for SOAP and to put it into practice on the SOAP API that I'm currently designing and even to push it into our build process if I can. Further, I'd like to build another FIT fixture that, instead of executing the tests, generates sample code to demonstrate example usage and expected output (including expected errors). Rest assured, when we get it working well enough for public consumption, Ward and I will publish the SOAP extensions for your enjoyment.
But don't wait for that! You can do TDD with custom actions in VS.NET 2003 and with the FIT Framework today!
Thursday, March 11th, 2004
The .NET Global Assembly Cache (GAC) is a misunderstood and misused beast. For all intents and purposes, it provides what COM and windows\system32 do, i.e. a machine-wide place to drop shared DLLs. Of course, the problems with sharing DLLs in a machine-wide spot is that it leads to a set of well-known problems collectively called "DLL Hell." There are many problems, but the biggest is that when a shared DLL is updated, you're really updating an unknown set of applications. If the set of applications is unknown, how can you possible test them before making this change? And if you can't test them, you're likely to break them. What this boils down to is that any of the shared spots for updates, whether it's a COM CLSID, windows\system32 or the GAC, are dangerous and should be avoided. And this is why the preferred .NET deployment scenario is "xcopy deployment," i.e. having your own private copy of each DLL that you test and deploy with the rest of your application.
"Aha!" you say. "The GAC supports multiple version of an assembly! When a foo.dll is updated to v1.1, v1.0 sits right along side of it so that your app *doesn't* break!" Of course, that's absolutely true. But if that's the case, why do you care? I mean, if there's a new assembly available but your app isn't picking it up, what difference does it make?
"Aha again!, you say. "I can put a publisher policy into the GAC along with my assembly so that apps *are* updated automatically!" That's true, too, but now, like any of the machine-wide code replacement strategies of old, you're on the hook for an awesome responsibility: making sure that as close to 0% of apps, known to you or not, don't break. This is an awesome responsibility and one that takes MS hundreds of man-years at each new release of the .NET Framework. And even with those hundreds of man-years of testing, we still don't always get it right. If this is a testing responsibility that you're willing to live with, I admire you. Personally, I don't have the moral fortitude to shoulder this burden. For example, we do sign genghis.dll when we ship it so that folks can put it into the GAC if they want, but we make no promise of backwards compatibility between versions and therefore we do not ship publisher policy DLLs. Instead, we expect folks to use xcopy deployment and catch the problems at compile-time and test-time.
So, if the GAC represents such a massive burden, why do we even have it? It's for two things that I've been able to identify:
Fixing critical bugs without touching the affected apps (and without breaking anything!)
Sharing types at run-time between assemblies deployed separately
#1 is what you get when you install Windows hot fixes and service packs via Windows Update. A ton of design, implementation and testing time is spent to make sure that existing code won't break before shipping these fixes.
#2 is needed if you're going to be sharing types between assemblies that you can't deploy as a group but absolutely must keep to the same version of things. .NET Remoting peers are in this category, but only if they're deployed in separate directories so that they won't share the same set of types available via xcopy deployment. However, if .NET Remoting peers are deployed on difference machines, the GAC won't help you anyway as you'll be manually insuring the types are the same across machines. BTW, the responsibility of keeping multiple machines to the same set of types (and the same framework for hosting those types) spawned an entirely new way to talk between machines, i.e. web services, so .NET Remoting itself is something to avoid unless you can administer both ends of the pipe for simultaneous updates.
Another scenario that fits into #2 is the Primary Interop Assembly (PIA). A PIA is a COM interop assembly that's been pre-generated and dropped into the GAC so that everyone that adds a reference in VS.NET to mso.dll (the COM library for Office) gets office.dll instead (the .NET Office PIA). That way, everyone can talk to the same set of types instead of everyone getting their own incompatible interop types generated on the fly. However, PIAs are primarily a way to make sure that VS.NET has a central place to pick up the shared types without regenerating new incompatible types.
Notice that "Saving hard drive space" wasn't on my list of reasons to use the GAC. I just purchased a 60GB, 7200RPM hard drive for my laptop for a measly coupla hundred bucks. I don't want to hear about you jeopardizing the reliability of the applications on my machine to save a tiny percentage of that space. Hell, when I buy a HD, I give 50% of it over to apps anyway, so help yourself and keep my apps running by avoiding any machine-wide space for updating shared DLLs, including the GAC! Thanks.
Discuss (did I miss any reasons to use the GAC?)
Tuesday, February 24th, 2004
Don and I have an ongoing debate -- whether everyone was put on this planet for one purpose or whether a person gets to choose their path. This all started back in the middle of the bubble where we thought that we were so smart that we could take our success in training and turn our minds to anything we chose. We thought we could be anything, but used to talk most about politics (and Don even promised to get me elected as mayor of Beaverton) and religion (I'd like to get in on the ground floor of one of those "free love" cults : ).
Of course, the bubble burst, giving of us perspective on just what part of the success was us and what part was the go-go economy. Now, most of us that used to have those conversations work at Microsoft as a place to keep doing fun work without traveling to globe trying to keep up our old standards of living. These days Don talks about all of us having a specific place in the world and that he's pretty darn sure that he's found his (and you should see the guy; he's in there, fighting for what he thinks is best for the platform and building quite an impressive reputation base to extend his influence wider and wider). He's also of a firm mind that I've found my place and that I should be a s/w guy of some kind for the rest of my life.
So, I'm of two minds. On the one hand, I'm happy with the spot I've carved for myself in the Windows developer community and I think that there are plenty of fun s/w challenges to meet. Plus, my resume helps me get good gigs.
On the other hand, I'm not a big fan of being "predestined" to anything. I don't like the idea that fate or even my inborn predilections decides what I do and don't do in my life. I also still think that I'm smart enough and flexible enough that I could start another career. My latest fantasies revolve around moving into a place that my wife could afford on her nurse's salary while I write novels and spend my afternoons filling the public education gap my kids are experiencing. Previous fantasies include getting my jurist doctor at Harvard and becoming a courtroom prosecutor on my way to being a judge (I always know what's best for everyone : ). Also, the equities market calls my name and I've got a little property investment business on the side that could use more attention. So, I've got plenty of things I'd like to dig into before I die that have nothing whatever to do with my background or training. In fact, I've got so many other things to try that Lutz was making fun of me just last night, "Haven't you noticed that everyone in 2004 wants a new career?" Still, should I stick with what's safe because I may never achieve in other industries what I've achieved in this one or should I roll the dice and takes my chances, knowing that life is pretty short to spend it all doing the safe, comfortable thing?
Don't get me wrong; I'm not going anywhere just yet. I've started this Longhorn thing and I've got lots more to do there before I'm done. But I do think about hitting the reset button some day and starting over again from scratch. What do you guys think? Have any of you hit the reset button and ended up reading this post? Has anyone tried to escape from this industry only to end up back here and are happy they did? Does anything think that my hubris is going to get me into serious trouble? : )
Sunday, February 1st, 2004
I just got off the phone with my step-mother and boy are my arms tired. She way trying to do a mail merge. I told her about a month ago put data into an Excel spreadsheet in a data-like format (and I sent her an example spreadsheet to start from). Then, after entering the data into her spreadsheet, I recommended to her that she choose Mail Merge from the Tools menu in Word and she'd be home free.
Of course, she wasn't. For example, after choosing her Excel spreadsheet, she was asked if she wanted to use first name, Sheet1$, Sheet2$ or Sheet3$ as her data. Having zero idea what SheetN$ was, she chose something vaguely human-sounding, which was exactly what she didn't want, then was frustrated when her data didn't come up. Later, after going away to buy hundreds of dollars worth of books (none of them telling her how to do Mail Merge using words that she could understand, btw), she opened up her document and was presented with a dialog box asking whether it was OK to run an SQL statement. "What's SQL?" she asked. "Nothing that any normal human should ever have to see," I replied, growing more embarrassed about the state of the output of my industry by the minute.
Later, when we got the data working with the merge (Remote Assistance, even over a slow phone line to Fargo, ND, works *very* well, once I figured out how to take control of her computer [answer: Take Control in the upper left]), she turned her attention to reformatting her letter. For example, she'd pasted some text from the web, which, by default, left this weird web formatting instead of making it look like the rest of her letter, so the styles were very different. Luckily, selecting the text and turning off the bold was enough, otherwise I'd have either had to reformat her entire letter or talk her through doing it. And how did I tell her to turn off the bold? By selecting the text and pressing Ctrl+B? Why did I tell her that? Because Word had taken the Bold toolbar icon off the toolbar and I couldn't imagine describing to her what the little chevron was for so that she could get it back.
I've listed only a small percentage of issues I worked through with her, but lest you think otherwise, my step-mom is no idiot. She's a nurse anesthetist, so has to keep tons of details in her head all day long or people die. Also, she's trained her dogs to win first place obstacle courses in competitions around the country, one of whom was said to be untrainable. But when it came to Mail Merge, she worked for three weekends straight before giving up and calling me. It's clear to me that for anything but the simplest of tasks that computers are not even close to ready for normal humans. On behalf of the software engineers everywhere, I'd like to apologize to Charlene (my step-mom) and the rest of the normal humans everything who are merely trying to make computers actually work. Hopefully Longhorn will fix this problem, but until then, I recommended that she return her computer to the manufacturer and get herself a Nintendo. After working through this with her for over an hour, I was only half kidding.
Saturday, January 31st, 2004
On a recent thread on my favorite mailing list ever, Jon Kale answers the question "what would you save if your house was on fire," which triggered my own thoughts along this line.
Assuming I've already
made sure that the humans and the pets were out of the house, I'd make sure to
grab
my Omega X-33 (purchased during the bubble, of course), but since I go
almost nowhere without it, it's not likely to be burned up w/o its owner.
Also assuming I had a set of back-up CDs/DVDs for the last year in my safety
deposit box (which I don't have right now... please excuse the pause while I
purchase a DVD burner... OK, $155 got me
a top-reviewed DVD+R/DVD+RW drive with 30 blank DVD+RW disks delivered), the
thing I would most miss is my book collection. The computer books could be
replaced on demand, but my collection of just-for-fun books has literally taken
a lifetime to collect and cull down to just things that I really love (click on
the picture to get a closer look).
Often, when I want something comfortable to read, I'll scan the shelves 'til something pops out at me and re-read it. Also, when friends & family come to town, I often take them to Powell's City of Books and we play the "Top 5 Books of All Time" game, purchasing what they point out for me and writing their name in the book so that when I read it, I can talk about it with the recommender (man, I've gotten some wacky books that way...). Losing those books, especially the ones I haven't gotten to yet, would really hurt.
On the other hand, because you never know when you're going to need to jam, my goal is to fit my entire set of positions on a memory hypercube (or whatever). But how do I back up the books when the atoms themselves are so satisfying? I mean, how can I recapture the feel of my leather-bound The Complete Frank Miller Batman, the back-pocket-worn The Silicon Mage, my copy of The Hobbit and The Lord of The Rings signed by my mother when I received my Master's Degree because she read them to me when I was 10 or the ancient copy of The Complete Sherlock Holmes given to me by my father and to him by his father?
But even if I wanted a lossy digital backup of my books, how do I do it? I mean, I can scan all of my books and graphic novels, but only by destroying them. Why haven't books, which are produced in digital form, made the transition to electronic availability? Are we waiting for the Tablet PC to get to a point of ubiquity?
So, in summary:
Friday, January 30th, 2004
In response to my post yesterday (When In Doubt, Ignore Longhorn), Shaun asked whether he should be targeting Longhorn-only right now:
[ed: the following has been edited to remove identifying remarks at Shaun's request]
Thanks for all the great posts and community participation over the past year. Your recent 'Ignore Longhorn' post alarmed me a bit. I hope that was not born from some aspect of it being pushed past 2006.
Anyway, I know you are busy, so I will get to the point. We are mid-sized, established s/w company, and a Microsoft shop to the core (SQL Server, Analysis Services, VB, we embed VBA etc...). I am facing a huge decision regarding building our next gen app architecture. We need to ship in 1H 2006, and (IMO) we need to target rich and reach, so Longhorn is on my list of possible directions along with some ASP.NET 2.0 / ClickOnce combination.
I am enjoying working with Longhorn (XAML in particular), but I'm having a hard time shaking the feeling that I am taking too much of a gamble if I go Longhorn-Only, but some of the aspects are just so compelling. On the other hand, I'd hate to make a huge 2-3 year dev investment in ASP.NET only to ship something in 2006 that is not revolutionary/differentiated. I firmly believe our existing 3 million lines of solid COM code has plenty of life in it too.
Any insight or advice you might have would be greatly appreciated. I know it is probably difficult without understanding our company or market, but maybe some general advice to someone who is targeting a 2006 release. I guess my other worry surrounds the Longhorn adoption rate, but obviously none of us can predict that!
Here was my answer:
Shaun, if you think that Longhorn is going to help you build a differentiated product that'll help you be more successful, then great! That's why we're building it.
On the other hand, if I were you, I wouldn't put all my money into a single investment. Instead, I'd use some diversification strategies like you would with your financial portfolio. At this point, the ship date of Longhorn, along with the list of features it will support when it ships, is merely speculative. I won't put more than 10% of my available investment time/money/staff into it, leaving the rest of my portfolio for getting the most I can from my existing and/or near future technologies.
Specifically, you ask about ASP.NET 2.0 and Windows Forms/ClickOnce. Both of those technologies rock. ASP.NET is going to be the way to build web sites and services for the next decade at least, even after Longhorn's been out for years, since it has the reach across our existing OSes and competing OSes. Plus, ASP.NET 2.0 has a dizzying list of new features that people will spend years just taking full advantage of. For reach, you can't make a better investment than ASP.NET.
For rich, on the other hand, Windows Forms + ClickOnce is a killer combo. The updated Windows Forms in Whidbey along provides some amazing new capabilities, not the least of which is the new GridView, which you can read about in Michael's new Wonders of Windows Forms piece. Also, look for a "What's New in Whidbey Windows Forms" piece in MSDN Magazine RSN. ClickOnce (which you can learn more about in Duncan's ClickOnce piece and in Jamie's ClickOnce talk) is the way to deploy rich clients in Whidbey and in Longhorn, so digging into that technology is a very good idea.
As time goes on and Longhorn becomes a more solid development investment, you should put more of your portfolio into it. If you've got plenty of time/money/staff, than 10% now could mean an entire pilot project in Longhorn, which would be a good thing. But if you've got limited amounts of time/money/staff that you really need to yield a dividend now, Longhorn is dangerous for you and should only be something you dabble with at this point.
For you specifically, a mid-sized company, you should carve off a chunk of your dev. staff to build a pilot in Longhorn. This lets you dabble while the rest of your staff is busy with existing and near future technologies. And as you dabble and notice things that don't work at all as you expect or need, let us know! Operators are standing by to take your calls! We're at a stage in our development process where we're able to give much more attention to the fundamentals than we will be at beta, so the 10% you put into Longhorn now could yield large dividends in the future.
And as to your follow up comment, I'm happy that you enjoyed my response, but I'm pretty sure an autograph from Sting would be cooler. : )
Thursday, January 29th, 2004
A guy walks into an exotic car dealer and asks the salesman the price of the fancy new Ferrari in the corner. The salesman looks at him with a sad look on his face, shakes his head and says, "I'm afraid, sir, that if you have to ask, you won't be able to afford it."
If you're wondering whether you should be paying attention to the information on Longhorn that has appeared on the web and in the news lately, then you shouldn't be. Longhorn RTM is years away. This is the most lead time we've given on any Windows operating system ever. The reason we did it was so that we could get super early adopters to give us meaningful feedback while we still had enough of the development cycle left to make meaningful changes. If you're not a super early adopter, than Longhorn is just going to be noise that you should ignore 'til the beta hits.
For day-to-day development, you should pay attention to .NET 1.1 news sources. For the near future, you'll want to listen for Whidbey, the next version of the .NET Framework, which should work on all supported OSes when it ships. Here are a list of my favorite news sources for current information and near future information: