Wednesday, December 19, 2007

Design and Implementation - Episode 1

Update: I managed to mess up the permissions on the MP3 file, resulting in a few "access denied" errors. Ironically, I did this while trying to fix the Content-Type. Anyway, it should be working again. Sorry!

 

(For the impatient: link to episode 1 (MP3).)

 

For a long time now, Tim and I have called each other up on the phone whenever we have an interesting or difficult technological decision to make. The conversations have often been very interesting, and are in a large part responsible for the way I think about software. A while back, I was thinking to myself, "Man, we should record these - I bet other people would be interested in this stuff as well."

 

So we did.

 

Announcing the first episode of "Design and Implementation", a podcast by Craig Andera and Tim Ewald. You can grab the MP3 here. In our inaugural episode, we explore the topic of web service architectural styles, such as REST, SOAP, RPC, and Resource-Orientation. If you read our blogs, you'll know it's something we've both been thinking a lot about recently.

 

At some point in the future, we'll get a proper landing page together, with a feed and everything, but until then just watch here or on Tim's blog for announcement of new episodes.

 

We've already got a few more shows planned out, but with two and a half kids between us and the usual demands of life, I don't think we're going to be able to post more often than once a month. After all, (apparently unlike Scott Hansel(Super)man), I need to sleep. :)

 

We had a great time doing the first show, and I think you'll enjoy it. That said, I know we have a lot to learn about recording and producing a show, so if you have any advice/compliments/complaints, please drop a comment here!

 

Once again, here's the link to episode 1.

Wednesday, December 5, 2007

FlexWiki 2.0 Release Candidate 1 Available

I just posted the files for FlexWiki 2.0 Release Candidate 1. Woohoo! You can get it here.

 

Here are the release notes:

 

This is Release Candidate 1 of FlexWiki 2.0. Assuming we don't find any major bugs, this release will become the final FlexWiki 2.0 version: the Released To Web (RTW) version.

 

This version sports many, many improvements and enhancements over 2.0 Beta 2. Among these are:

 


  • Vastly improved performance

  • New tools for editing the configuration files via the web interface

  • Automated table-of-contents generation (via WikiTalk)

  • Page locking (a security feature)

  • Threaded message support for blog/forum-type behavior

  • An all-new default stylesheet for a fresh look

  • Support for file upload and page attachments

  • Improved XHTML compliance

  • Tons of bugfixes

 

This is not a complete list - there's lots more.

 

Thanks to Derek, John, and Nathan for all the great code, and to the FlexWiki community in general for all the excellent suggestions and feedback.

 

Enjoy!

 

Wednesday, November 21, 2007

Temporarily Bypass Popup Blocking in IE7

I read over on ZMan's blog the other day about how he was having some serious issues with downloading VS2008. The list of problems is extensive, but I'll quote a bit of it here:

 

You have to turn off your pop up blocker. "You will also need to allow pop-ups (at least temporarily)." - and they REALLY mean turn it off. You can't ctrl-click. You can't wait for the yellow bar and then say allow it because the site does multiple redirects and so you never get to see the page with the yellow bar. Remember that pop up blocker is ON by default in IE. You would think MS could make this a little easier in their own browser.

 

I rarely use IE myself (preferring Firefox), but I do know a few people on the MSDN team, so I made them aware of it. One of them posted this little workaround on ZMan's blog in response, but I think ZMan has comment moderation turned on and hasn't gotten around to approving the comment yet, so I'll put it here in case it saves someone some grief:

 

From your comments, it sounds like you are running IE7 on Vista.  If this is the case, to temporarily bypass the pop-up blocking functionality of IE7, you need to hold down Ctrl-Alt and click the link (Ctrl-click was how IE6 behaved). 

 

ZMan also had some issues with download location - read the rest of his post for the details. I'll reprint the response to that part here as well.

 

The second issue you had regarding the controlling of where downloads can be saved by an ActiveX control and the message prompts you received is a feature of IE7’s protected mode.  You can adjust these settings by clicking on the “Protected Mode” text in the lower right area of IE7.  Finally, to draw attention to the fact that downloads are being launched with a pop-up, our content team bolded the text on the download control to ensure it stands out a little better.

Friday, November 2, 2007

Simple Filename Wildcarding

I was writing a command-line application for a client the other day, and I found myself wanting to support syntax like this:

 

foobar *.foo *.bar foo*bar

 

which is to say, "run foobar against files that end with .foo, end with .bar, or that start with foo and end with bar." This is a fairly familiar thing for command-line apps to do.

 

One way to approach this is to interpret things like "*.foo" as regular expressions. I don't particularly like this solution, since a) it makes people learn regular expressions to use my app effectively, and b) the common patterns like *.foo don't really work like you want them to - "*.foo" is a regular expression meaning "anything that contains 'foo'" rather than "anything that ends with '.foo'".

 

Another way to deal with this is to use Directory.GetFiles. If you read the documentation, however, there are two issues. The first is that the caveats called out in the notes make the behavior pretty weird. For example, "*1*.txt" matches "LongFileNameHere.txt". Ick. The other issue is that this approach doesn't allow multiple patterns, so I have to scan the directory multiple times and merge the results to do the "*.foo *.bar foo*bar" example above.

 

I hit what I think is a fairly elegant solution, and I wanted to share it with you. The basic idea is to use string.Split, string.Join, and Regex.Escape to create a regular expression that supports exactly one "operator": the asterisk, which matches zero or more of any character. Here's the code:

internal static bool IsMatch(string name, string pattern)
{
// Short-circuit common cases
if (string.IsNullOrEmpty(pattern)) {
return false;
}
if (string.IsNullOrEmpty(name)) {
return false;
}
if (pattern.Equals("*")) {
return true;
}
if (pattern.Equals(name, StringComparison.CurrentCultureIgnoreCase)) {
return true;
}


// Bust the pattern apart at the asterisks
string[] parts = pattern.Split('*');
List patternParts = new List();
foreach (string part in parts) {
patternParts.Add(Regex.Escape(part));
}
// Then put it back together with .*, which matches
// any sequence of characters, and surround it with
// the start-of-string (^) and end-of-string ($) patterns
// so we don't match on things that only start or end
// with what we're after.
string newPattern = "^" + string.Join(".*", patternParts.ToArray()) + "$";
Regex expression = new Regex(newPattern, RegexOptions.IgnoreCase);
return expression.IsMatch(name);
}

Which, I think, is pretty nice, if I do say so myself. Best of all, it has semantics that make it match what I expect file patterns to do.

 

Using it is a simple matter of calling Directory.GetFiles to get all the files in the directory, and then filtering it via a looped call to this method.

 

You'll note that I haven't put in support for the ? operator (match exactly one character), because a) I hardly ever use this myself, and b) it would be pretty simple to bodge in if I ever needed to. It would just take a second call to Split/Join over each patternPart.

 

Hope this helps someone. It was fun to write.  

Thursday, October 11, 2007

How to Improve Collection Initializers

I think I'm starting to traverse the Linq/Orcas circle of (software) life, because I finally hit something that I don't like and that I couldn't work around. So far, anyway - maybe someone out there can tell me where I'm going wrong.

 

You may know that in the Orcas version of C#, they've added support for initializing collections via the funky new object initialization syntax. You can read about it here. The issue that I'm running into has to do with the fact that I'd like to initialize a collection in an object initialization expression, but I'm using XLinq to do it, and as a result I'm getting a compiler error.

 

See, I can get this to work:

 

Person craig = new Person

{

  Name = "Craig",

  Age = 35

  Children =

  {

     new Person

     {

        Name = "Ellen",

        Age = 2.9

     },

     new Person

     {

        Name = "TBD",

        Age = -0.4

     }

  }

}

 

But because this is just a simple example and in my real code I don't know the collection items at compile time, what I really want to do something is like this:

 

Person craig = new Person

{

  Name = "Craig",

  Age = 35,

  Children =

  {

     GetProgeny("Craig Andera")

  }

}

 

Where the Person class is the obvious implementation, and GetProgeny returns IEnumerable<Person>. Without doing anything else, I get a compiler error saying that Collection<Person> does not contain an overload of Add that accepts an IEnumerable<Person>, which makes perfect sense given that the collection initialization syntax is just shorthand for a bunch of calls to Add.

 

The part that sucks is that I can't get this to compose with extension methods to get what I want. That is, I'd like it if I were able to define an extension method like this:

 

public static void Add(this ICollection<Person> collection, IEnumerable<Person> items)

{

   foreach (Person item in items)

   {

      collection.Add(item);

   }

}

 

But that doesn't work. I'm not sure why, but here's the list of things I hope it is, in decreasing order of desirability:

 


  1. I'm doing something wrong.

  2. It doesn't work and there's a good reason.

  3. It doesn't work and there's no good reason.

 

Anyone have any idea which it is?

 

Update: I should have said right up front that Children is a read-only property of Person. I always make my collections read-only, and would prefer to do so in this case as well.

Tuesday, October 9, 2007

Add Using Statement in Visual Studio 2008

Update: Apparently this has been available since VS2005. Who knew? Other than the people that commented, of course. Certainly not me. :)

 

Update #2: So, the "organize usings" menu item that I happened to show in the screenshot alphabetizes the using statements. Also very nice, although I'd like it better if it didn't remove the line breaks I put between groupings. Still, nice. You can also remove unused using statements. Here's the menu:

 


 

Jon Flanders showed this to me the other day. In Visual Studio 2008, if you've just added a class for which you haven't yet added the corresponding using statement to bring the namespace into scope, you can hit control-dot, and up pops the following menu:

 


 

And sure it enough it pops a "using System.Collections;" in up at the top of the file. Very nice. Better still if it would put it in alphabetical order, but I seem to recall that the order of using statements is significant when Linq is in play, so maybe they couldn't do that.

 

You can also access it via the right-click menu:

 

Tuesday, September 25, 2007

HashSet&amp;lt;T&amp;gt; - Finally a Set Implementation in the .NET Class Libraries

Update: Despite what the documentation says, this class is new to .NET 3.5, and is not present in the .NET 3.0 libraries.

 

Update: Fixed typo - HashSet does not allow duplicate members, just as you'd expect.

 

I was poking around the other day and I noticed System.Collections.Generics.HashSet<T>. Sure enough, it's a collection class with the semantics of a set: there are no duplicates no matter how many times you add an item to the set, it is unordered, and it supports intersection, union, and subset operations.

 

It's part of .NET 3.0 3.5, so it's been around for a little while not quite out yet. I doubt I'm the last (although I'm even more sure I'm not the first :) to hear of it, though. Go check it out, because a set is one of those data structures that gets used all the time. If you've ever instantiated a Dictionary<T, bool> just to keep track of if you've seen something, you know what I mean.

 

Thanks, CLR team!

Wednesday, September 19, 2007

Parameterless Lambdas in C#

I'm liking Linq, but I think I like it more for the new language features it forced than for the query syntax itself. Lambdas and object initialization syntax - particularly collection initialization syntax - are extremely handy. Of course, I'm intentionally using them all I possibly can to find out where the cracks are. No doubt with experience I'll look at my current patterns as gross overuse. Nonetheless, it's fun. :)


I was writing some test code today in Visual Studio 2008 when I hit a good use case for lambdas. I wanted to execute a statement and compare the result to an expected value, but only if the expected value wasn't null. In that case I don't want to execute the statement at all, because it has unwanted side effects (specifically, it asserts something I know will be false).


I could have thrown a crateload of "if" statements in to check for null, but that wouldn't be very DRY. The solution I hit on was to use a parameterless lambda instead. It's passed to a method that evaluates the lambda if the thing it's being compared to isn't null. It works well. What I wanted to blog here was the syntax, because it wasn't immediately obvious to me, and it didn't really turn up anything in a few moments of Googling. So here it is for the record:


AssertEqualIfApplicable(

expected,

() => SomeMethodWithSideEffects(foo, bar))


private void AssertEqualIfApplicable(object expected, Func<object> actual)

{

if (expected != null)
{
Assert.AreEqual(actual());
}

}


So it's the "() =>" that defines a parameterless lambda. The syntax is a bit awkward, but not painfully so, IMO. The thing I especially like about this is that the lambda allows me to use lexical closures. Which is a fancy way of saying that foo and bar in my example above can be local variables, and their values will still be accessible when the lambda is invoked.


I must not have studied enough Lisp yet, because my reaction to this is "cool!" rather than "pfagh! Lisp has had that since 1827". Oh, and Keith, yes, I realize you are laughing at me, right now. :)

Thursday, September 13, 2007

I Can't Be the Only One (Re)Learning Lisp

It's funny how when you go down a new path, you suddenly see evidence that you're not alone. Here's some evidence (from the truly marvelous xkcd.com) that I can't be the only one that decided to spend more time with Lisp lately:

 

A God's Lament

 

and

 

A God's Lament

 

I found the latter especially amusing given that my official job title is "Jedi Master". Of course, given how bad the most recent movies were, I've been thinking of changing it to "Wizard". :)

 

By the way, if you're interested in Lisp, be sure to read the absolutely excellent book "Practical Common Lisp". Some of my readers pointed it out to me, so I've been reading it. Highly recommended, especially as it is available online in its entirety for free.

Wednesday, September 12, 2007

Linqing to Xhtml - Part 2

Update: Fixed minor bug in implementation of IsOfClass.

 

In a previous post, I talked about how I'm hoping to be able to use Linq for XML to allow me to process XHTML, my current favorite data serialization format. At the end of that post, I wrote code more or less like this:

var alternates = from ul
in document.Element(xhtmlns + "html").Element(xhtmlns + "body").Elements(xhtmlns + "ul")
where ul.Attribute("class").Value == "alternates"
select
from li
in ul.Elements(xhtmlns + "li")
select li.Value;

The idea was to be able to pull the values out of a bunch of XHTML list items. The problem with this code is that it doesn't really give me what I want. If you were to look at the type of the object referred to by alternates, you'd discover that it's a

 

System.Linq.Enumerable.SelectIterator<System.Xml.Linq.XElement,System.Collections.Generic.IEnumerable<string>>

Which - if you can read that expression without going blind - indicates that what I've got is essentially "a sequence of a sequence of strings". No, that's not a typo: it's a sequence of sequences, and iterating over it with a nested loop is sort of annoying.

 

Fortunately, it appears that Don Box reads this blog, or at least read that post. :) He's the co-author of the rather excellent article found here, and had I read it I would have known the solution. But even though I hadn't (I have now - you should, too), he was kind enough to drop by with a comment that made everything work. Here's the code I'm using now:

 

var alternates =
from ul
in document.Element(Xhtml.Tag("html")).Element(Xhtml.Tag("body")).Elements(Xhtml.Tag("ul"))
where ul.IsOfClass("alternates")
from li
in ul.Elements(Xhtml.Tag("li"))
where li.IsOfClass("alternate")
select li.Value;

I've made a few changes beyond just the Linq bits, but I'll explain those in a minute. The key to making the query work was removing the first "select". Having the second "from" clause follow without an intervening "select" results in a SelectMany method call (all the Linq keywords like select, from, where, etc. are just shorthand for method calls). And that's exactly what we want: SelectMany collapses the query to a single dimension. Read the article for a better explanation. With this change, the query now returns something we can iterate directly over with a "foreach (string alternate in alternates)". Nice.

 

As for the other changes, there were a couple. One was to create a class called Xhtml with a static method called Tag that creates my XNames. This just cleans up the code a little bit from all that "xhtmlns +" stuff I had before. I also created this extension method:

public static bool IsOfClass(this XElement element, string className)
{
    // TODO: this should really account for the fact that the class
    // attribute is multivalued - i.e. it's legal to have
// class="foo bar quux", and we should return true for any of
// foo, bar, or quux.
    return element.Attribute("class").Value.Equals(className);
}

to let me use IsOfClass on an XElement - I just think the syntax is cleaner, and as I do more and more XHTML processing, stuff like this should help contribute to my goal of a reasonable syntax.

Tuesday, September 11, 2007

Birthday Problem Variation - In Lisp

I get interesting email from my readers from time to time. The other day someone wrote me up asking me "What are the odds that exactly three people in a room of 19 have the same birthday?" Apparently his wife had challenged him with this one and it was bugging him. I suppose he must have found me via my post about the Birthday Problem. His problem was a bit different - the code I wrote will calculate the odds that at least two people in a room have the same birthday, not that exactly three do.

 

The way I approached the problem was to break it down. I realized that it's fairly easy to calculate the odds that the first three people in a room of 19 have the same birthday: it's just the odds that the first three have some birthday times the odds that everyone else has a different birthday. The odds that the first three people have the same birthday is (1/365)^2, since it doesn't matter what the first person's birthday is, and then the other two have to have the same birthday. The odds that the rest of them have a different birthday is (364/365 * 363/365 * … * (365-16)/365).

 

That tells us what the odds of the first three people having the same birthday and everyone else having the same birthday is. To compute the odds of any three people having the same birthday, we just need to figure out how many ways there are to arrange 3 people out of 19, without regard to order (i.e. we don’t care if it's Steve, Bob, and Alice or Alice, Bob and Steve). But that's just the combination operation, occasionally notated C(n, k), and it's just n!/(k! * (n-k)!). The odds for any three people are just the odds for the first three times C(19, 3).

 

As you know, I've been learning Lisp, and I figured this would be a great problem to get a little experience with. And it was. Here's the code:

(defun fact (n)
"Compute the factorial of n"
(if (= n 1)
1
(* n (fact (- n 1)))))
(defun combin (n k)
"The combination of n things taken k ways"
(/ (fact n) (* (fact k) (fact (- n k)))))
(defun odds-of-others (n)
"The odds that the other n-3 people in the room have some other birthday"
(* (/ (fact 364) (fact (- 364 (- n 3))) (expt 365 (- n 3)))))
(defun odds-of-first-three (n)
"The odds that the first three people in the room have the same birthday,
and that everyone else has a different birthday"
(* 1/365 1/365 (odds-of-others n)))
(float (* (odds-of-first-three 19) (combin 19 3)))

To my eye, this is a lovely, compact way to express the solution. Others may feel differently. :) Also, I've made no attempt to optimize the code.

 

If you're not familiar with Lisp, there are a few interesting things to point out here. First, note that the second line of each function definition (defun defines a function) is an optional documentation string. I just love that that sort of thing is built in to the language.

 

Second, one of the great things about using Lisp for this application is that it supports both rational numbers and big integers natively. That is, when you compute something like (/ 1 365) - the integer one divided by the integer 365 - the result is the rational number 1/365. If you multiply rationals, it continues to maintain the result as a rational. Plus, really large integers are also supported natively, including as the components of a rational. Which means that the expression (* (odds-of-first-three 19) (combin 19 3)) returns this:

 

105393858057485882391608381135063049633792/21153953378595625024923538729098931884765625

 

Which is pleasingly precise, but you can see why I cast it to a float. :) It's about 0.5%, in case you were wondering.

 

I should note that strictly speaking this calculates the odds that exactly three people in a room have the same birthday and that everyone else has a different birthday from everyone else. If you only care that three people have the same birthday and that no one else has the same birthday as them, the odds will be slightly higher, as we have to include the case where (for example) the first three were born on March 1st, and everyone else was born on March 2nd. That just means switching the term that looks like (364/365 * 363/365 * … * (365-16)/365) to one that looks like (364/365)^(n-3). That pushes the odds up to about 0.7%. The only code change we have to make to do that calculation is this:

(defun odds-of-first-three (n)
"The odds that the first three people in the room have the same birthday,
and that everyone else has a different birthday"
  (* 1/365 1/365 (expt 364/365 (- n 3))))

Anyway, it was a fun problem, particularly to stretch my (nascent) Lisp muscles.

 

Oh, and I should warn you that although I think I've gotten this right, there's every chance someone who's much better than I at probability and/or Lisp will find a mistake. Hopefully if so, they'll leave a comment.

Thursday, September 6, 2007

I Am &amp;quot;using System.Xml.Linq;&amp;quot;

As you know, I've come to believe that REST is the correct default way for me to program web services. (Whether it's the correct way for you to do so is an entirely separate question.) Part of my experimentation in this space has been to embrace the idea that "XHTML is the new XML". That is, that data should be encoded using standard XHTML tags rather than custom XML grammars wherever possible.

 

The idea has enormous potential due not least to the fact that it makes your browser a debugging environment for your web services. However, browsers aren't the real target: custom web service clients are. And in the .NET space, there hasn't been a great API for consuming XHTML as an object graph. Oh, you could use XPath, but that's a bit messy. XmlSerializer would be preferable, but unfortunately it's no good at deserializing based on things like the value of a class attribute of a tag.

 

Now, however, we have Linq. So given a document like this:

<html xmlns="xhtml namespace">
<body>
<ul class="alternates">
<li>3</li>
<li>4</li>
<li>5</li>

</ul>
</body>
</html>

we can do things like this:

 

XNamespace xhtmlns = "http://www.w3.org/1999/xhtml"; 

var alternates = from ul in document.Element(xhtmlns + "html").Element(xhtmlns + "body").Element(xhtmlns + "ul")
where ul.Attribute("class").Value == "alternates"
select from li in ul.Elements("li") select li.Value;
 

which is extremely damn cool. Of course, I can do something even more useful and initialize objects with the results of my query doing something like this instead:

var alternates = from ul
in document.Element(xhtmlns + "html").Element(xhtmlns + "body").Elements(xhtmlns + "ul")
where ul.Attribute("class").Value == "alternates"
select
from li
in ul.Elements("li")
select new Alternate { Value = li.Value } ;


where Alternate is a class I've defined with a public property called Value. I imagine you can get it to work with an anonymous type, too, but so far that hasn't worked for me. Anyway, it's wicked cool nonetheless.

Wednesday, September 5, 2007

And Then There Were…Three and a Third

Coming soon [1] to a crib [2] near us:

 


 

[1] Around the end of March.

[2] OK, probably right in the bed just like the last one.

Friday, August 3, 2007

How To (Start to) Learn Lisp in 21 Days

My quest to learn Lisp continues, but I've reached a major milestone: I'm ready to start writing code. For me, learning a new technology usually starts with reading about it for a while, trying to form a mental model of the landscape. It took a bit of searching, but with some help, I was able to find three resources that were just what I needed. I thought I'd post them here for anyone else interested in the language. All three of these are free and available online in their entirety.

 


  1. Common Lisp: A Gentle Introduction to Symbolic Computation. A really excellent beginner's book. Extremely approachable, good narrative style, describes the important bits and leaves out the advanced stuff. Highly recommended.

  2. Common Lisp the Language, 2nd Edition. The Lisp book. The style is rather dense, but once you've got the basics, that's just what you want.

  3. Common Lisp HyperSpec. As you might suspect, this is the spec. Always useful to know where the spec is.

 

I'd suggest reading the first, skimming the second with dives into areas that you think you might need, and browsing the third as appropriate.

 

As for me, I've got an interesting idea for a utility that I want to write. There's nothing like trying to solve a real problem to fill in the gaps academic exercises like reading a book leave. I'm sure you'll hear more about it here when I'm done.

Thursday, August 2, 2007

FlexWiki 2.0 Beta 2 Released

I just posted Beta 2 of FlexWiki 2.0 up on SourceForge. Major differences from Beta 1 include:

 


  • SQL Server once again supported as a store. 

  • Improved SPAM protection via optional CAPTCHA requirements. 

  • Added ability to require HTTPS on a namespace-by-namespace basis. 

  • Multiple bug fixes.

 

There's other good stuff in there, too - the release notes detail everything.

 

The major remaining issue is performance: 2.0 Beta 2 is significantly slower than the latest released version of FlexWiki 1.8, although still usable. Performance work is ongoing, and significant improvements are expected before 2.0 is released, but for now production deployment is not recommended. That said, we're running it at http://www.pluralsight.com/wiki because for us the new security features outweigh the slowness. And perf aside, I feel good about the stability of the code, and others have echoed that it seems pretty solid.

 

I'm very pleased by how quickly we've moved from Beta 1 to Beta 2, and even more happy about the fact that developer activity has picked up - Beta 2 sports input not just from me, but from Derek Lakin, John Davidson, and Keith Brown (apologies if I've forgotten anyone). I'd also like to thank all the users that gave us feedback on Beta 1 and the interim builds - we fixed a pretty good number of bugs thanks to their input.

 

Beta 2 is likely to be the last Beta before release. I'm currently working on the last major thing that I think needs to go into a full-up 2.0 release: reimplementing caching. My hope is that I can quickly implement a reasonable story there that will bring us back to FlexWiki 1.8 levels of performance. There will be a few cleanup things to do after that, but really, that's the bulk of the work. I won't be so stupid as to give a timeline for when I think that will happen - even if perf work were easy to estimate there's the fact that I've missed every estimate I've given for this project - but I will say that I'm pretty motivated to get this done. Devoting nearly three years of spare time to something will do that. :)

 

Anyway, download and enjoy, and watch for RC1 in the not-too-distant future!

Monday, July 30, 2007

Link to Rory

Apparently, Rory needs links. We lovable nutjobs (my insanity is better hidden…I think) have to stick together, so I'm obliging.

Thursday, July 5, 2007

Hello Lisp

I believe it's a good idea to learn at least one new programming language a year. If nothing else, it keeps me from getting bored. You might think I'd choose Ruby, as that's pretty hot right now (in certain circles). And in truth I'm interested. I've even read some of The Pickaxe Book. But the language I've decided to devote my time to is Common Lisp.

 

There are a number of reasons for this. I won't go into all of them, but here are a few:

 


  1. I've been meaning to really learn a Lisp for a long time. Probably since I took SICP as a freshman. (One of the more intimidating moments of my life: having Hal Abelson as a student in a class I taught. Really nice guy, fortunately.)

  2. I do a lot of work where I turn set-based data (from a database) into hierarchical data (XML). A language based on lists and conses seems worth investigating.

  3. Lisp has a pretty interesting reputation as "the most powerful and elegant programming language". That's quite a claim, and begs to be investigated.

  4. Every new feature that C# has sprouted has been available in Lisp for decades.

  5. I read this and was intrigued.

 

Of course, I'm going to continue to do my paying work in C#, if for no other reason than that no one in their right mind would pay me to write production Lisp code right now. But starting now, I'm going to make an effort to write all the code that I can in Lisp.

 

If you're interested in getting started yourself, it's as easy as going to download an implementation. I'm using CLISP, as it's free and seems to be pretty mature and broadly supported.  

 

Should be an interesting ride!

Monday, July 2, 2007

The Failure of SOAP

It may seem odd to see the title of this post, seeing as it immediately follows one entitled "The MTPS Content Service - A SOAP Success Story". But it was always my intention to write these two back-to-back, because my experience writing the MTPS service was a major part of my most recent revelation: SOAP is no longer my default choice for writing web services.

 

You've seen some of this story already. I said I've been thinking like Tim for a while now. That thinking has really solidified for me over the last few weeks, to the point where I'm ready to essentially walk away from ASMX/WCF/SOAP in all but a few edge cases.

 

There have been three main ingredients in this solidification of my "conversion". First, I managed to finish RESTful Web Services, by Sam Ruby and Leonard Richardson. This is a first-rate book. It is going on my shelf right next to Transactional COM+ as a "must read". Not that I necessarily agree with everything in it - in particular I'm not sure that PUT and DELETE are appropriate choices for most web services - but the way it helped me think about URL structure in particular puts it on the "must read" list for me.

 

The second ingredient was a series of conversations I had with John Elliot, one of the better-known posters on the Win Tech Off Topic list. He's been telling me for years about his ideas about web services, so I took the time to correspond with him to get clarification, and it really resonated. In a nutshell, his position is that web services should be accessible via a web browser, an idea I really like. This implies a read/execute bifurcation along GET/POST, metadata via HTML Forms, and XHTML as a the primary payload. Tasty. (Apologies to John if I've misstated or over-simplified his position.) 

 

The final (and key) ingredient was the realization that SOAP is the COM+ of the modern era. I did a lot of COM+ back in the day, even going so far as to teach classes about it and to write an MSDN article on it. So for some value of "expert", I was an expert on the technology. And yet, my main piece of advice to clients these days is: don't use it unless you have to.

 

Note that I'm not saying that either SOAP technologies or COM+ don't work. They do. If your problem fits the solution (e.g. multi-object transactions in COM+, single-URL RPC interfaces in SOAP, for example), then go ahead. It's just that I get enough benefits and avoid enough overhead from doing it at the lower (and simpler) level in each case that it's not my default choice any more.

 

It's also interesting to note that in both cases it was Microsoft - the vendor with a vested interest in me adopting the technology in question - that was the primary source of the information that led me to go down the SOAP/COM+ path. I'm not questioning anyone's integrity - it's just the nature of information that of course the COM+ message was going to be "use it for everything". And similarly SOAP. The failure to analyze whether the technology in question was the most appropriate for my problems was, of course, entirely mine. But hey, like Tim always says, "I reserve the right to get smarter." :)

 

If this seems like a repeat of things I've said already, well, I apologize. But I just had to share - the realization of the parallels between my personal journey with COM+ and my personal journey with SOAP just struck a real chord with me. Your mileage may vary.

Thursday, June 21, 2007

The MTPS Content Service - A SOAP Success Story

When I wrote the MTPS Content Service (was that a year ago already?) I didn't really expect people to use it much. I figured there'd be a few small and interesting apps - for instance, I wrote msdnman mostly for fun - but that it would largely be a useful but little-used service.

 

I was quite wrong.

 

The other day I found out the usage numbers for the service. The conversation went something like this:

 

Kim: "Hey, I wanted to tell you the stats are in for the content service."

Me: "Oh really? I'm curious - what are they like."

Kim: "Here, I'll email you the numbers."

Me: "Wow! It's only been a year and there's been 1.3 million hits - that's a lot!"

Kim: "No, that was for yesterday."

Me: "…"

 

I was quite literally speechless. Which, if you know me, you know is a rare thing. :) That's fifteen requests per second, so perhaps I can be forgiven my momentary surprise. (Traffic has since subsided to a mere 600K requests or so per day - an average of around seven requests per second.)

 

I have to say I'm fairly proud of having written a web service that can sustain those sorts of loads. Of course, the credit is not due all nor even (close to) mostly to me: the service is a fairly thin wrapper around the MTPS system, and I was only one part of the team that did that. Plus, without a crack ops team it doesn't matter how good your software is - you're not scaling. Kudos to those guys as well. All I had to do was not screw up the translation to SOAP. :)

 

We don't really have good data on what applications are creating all this traffic. We do know that the recently-released PackageThis is responsible for somewhere around a third of the traffic. We know that because PackageThis is the only app currently sending an AppID header with their requests. An AppID header is just a short string that identifies the application making the request. This is something we added rather late in the development cycle, never really documented, and made optional. So maybe it isn't surprising that it's not showing up in a lot of the requests. Hopefully we can fix that at some point.

 

Sandcastle also uses the service, and I wouldn't be too surprised if it accounts for the bulk of the remainder of the traffic. They're adding an AppID header soon, so we'll have better data then. It certainly will be interesting to see - personally I'd love it if there were still a whole bunch of unknown apps in the traffic pattern, as it would suggest that lots of people have found good ways to use the service. Which was our hope when we wrote it.

Monday, June 11, 2007

FlexWiki 2.0 Security Bug Alert

I noticed something weird on one of the wikis I’ve upgraded to FlexWiki 2.0. Even though I’d locked down a namespace to only allow authenticated users to edit, I was still seeing new topics getting created. Sure enough, when I tried it myself, I was able to create a new topic even though I wasn’t logged in. Fortunately, the problem only seems to manifest with new topics: editing of existing pages is still correctly prevented by the security provider.

 

After a bit of digging, I figured out that the problem is with the way permissions are handled for nonexistent topics. Basically, users were granted full control over nonexistent topics. The correct behavior is for nonexistent topics to be given the default permissions for the namespace, as once they are created, that’s what they’ll have (absent explicit permission statements). I’ve coded the fix and submitted it – it’s present in build 2.0.0.49 and forward.

 

Note that the fix makes the wiki secure by ensuring that unauthorized writes can't happen, but that the UI is still somewhat wanting: You're not told that the write is going to fail beforehand. I'll make that change soon. I just wanted to get a patch out to solve the underlying problem as quickly as possible.

 

If you’ve deployed FlexWiki 2.0 you should seriously consider upgrading to this latest build. Available here.

Thursday, May 31, 2007

Microsoft vs. TestDriven.Net Express

TestDriven.NET is the only Visual Studio extension I ever use. It's fantastic. So I was really bummed to read this, which tells about the legal trouble Jamie has been having with Microsoft over his truly useful product.

 

I'm no legal expert, so I have no idea which side is "right" here (assuming that it's even as black and white as that). All I know is it would suck if Jamie had to stop making TestDriven.Net, or even got so annoyed that he didn't feel like working on it any more, and that he has my sympathy. I've been in situations where legalities influenced technical decisions in distasteful ways many a time, and it always offends my sense of software aesthetics.

 

I wanted to blog this because I think people should be aware of it. It's days like this I seriously consider ditching as much proprietary software as I possibly can and living the free and open software lifestyle for real.

Tuesday, May 8, 2007

The Secret To Software Estimation: Lie Like Scotty

I see that Scott Hanselman posted about software estimation. Excellent advice, as usual. Here's my somewhat less serious advice, in the form of a quote from "Star Trek III: The Search for Spock":

 

Kirk: "How long to re-fit?"

Scotty: "Eight weeks. But you don't have eight weeks, so I'll do it for you in two."

Kirk: "Do you always multiply your repair estimates by a factor of four?"

Scotty: "How else to maintain my reputation as a miracle worker?"

Kirk: "Your reputation is safe with me."

 

I always multiply my initial gut-reaction estimate by four. So if I think it'll take a day, I tell the client it will take a week. If I think it'll take a week, I tell the client it'll take a month. This works really well for a couple of reasons:

 


  1. My initial gut-reaction estimate is almost always wrong by a factor of two or three.

  2. When I tell the client it's going to take a week and it takes three days, they're thrilled.

 

The funny thing about all this is that it still works even if I tell the client what I'm doing beforehand. Weird but true: I tell them a week, they know I actually think it'll take a day, but they're still happy when it's done in three.

 

Of course, this really only works after I've established a track record of delivering solutions to hard problems. And my miracle worker reputation gets a bigger jump from not telling them beforehand, so I usually don't. Except for the ones that read this blog.

Monday, May 7, 2007

FlexWiki 2.0 Beta 1 Released

I've just posted the latest FlexWiki bits on SourceForge. Get 'em here.

 

I seem to say this every few months, but this is a pretty major milestone on the long, long road to FlexWiki 2.0. Specifically, this is the first release where essentially everything from FlexWiki 1.8 works again. So the RSS feeds, the newsletters, and the administration pages have all been repaired, which is nice. The one thing that's still broken is the SqlProvider. Since most people use the FileSystemProvider, I don't think that's a huge deal. I'm fixing the SqlProvider even now, and it will be present in FlexWiki 2.0 Beta 2.

 

The major new feature in Beta 1 is the security infrastructure. FlexWiki now sports topic-level security. That means you can put something like this

 

AllowRead: user:candera

DenyEdit: anonymous

 

in a topic and it'll work. You can also do this sort of thing on a per-namespace basis, or wiki-wide. It works with either Windows or Forms authentication, and I've even thrown in a simple implementation of some login/logout pages for people that want to get something simple set up for Forms authentication.

 

If I seem excited about the security stuff, it's because I am: the whole reason I ripped FlexWiki apart (starting nearly two years ago!!) was to make it possible to add security in a maintainable fashion. Now it's done.

 

You can read more about the new security features here.

 

As far as the road ahead, there are really only two tasks remaining before I can shove FlexWiki 2.0 RTW out the door:

 


  1. Fix the SqlProvider.

  2. Analyze and tune performance.

 

I've already started the SqlProvider work, and I don't expect too many problems. Performance could be easy or could be hard - I'll need to start by comparing the performance of the 2.0 bits with the 1.8 baseline. That'll tell me how much work I have to do.

 

But any way you slice it, the release date for 2.0 RTW is a whole lot closer than it used to be.

Friday, April 27, 2007

Thinking Like Tim

I talk to Tim on a regular basis. So when he outed himself as a REST convert lately, it actually wasn't a huge surprise to me - we've been talking a lot lately about what the last few years have taught us about web service programming, and how more and more SOAP/WS-* just doesn't seem to be all that and a bag of chips. Still, the key part of the analysis in his latest post - that you can use HTTP as a way to publish application states and the transitions between them - really struck me as something significant, and brought a lot more clarity to the whole problem.

 

Here's where my thinking is at: Basically every SOAP web service I've written in the last four years could have been done just as well as a straight HTTP interface. And a several of them would have been significantly better. The ones that couldn't are very clearly RPC style, for better or for worse. I've been feeling this especially acutely lately as I try to optimize one of the services I've written. I found myself implementing HTTP over SOAP, which just seems stupid, not to mention clumsy.

 

For me it's really not about whether the thing is "REST" or not. I find the term REST to be too laden to be useful. I think more in terms of "SOAP via toolkits" (SVT?) versus Plain Old XML over HTTP (POX). After all, I'm perfectly willing to use a SOAP Envelope as long as I still get to use HTTP GET. But at the end of the day, ignoring particular terminology, I agree with Tim's analysis: SVT is for stuff I'd use DCOM for in the old days, not for putting up a large-scale, public-facing, web-based, programmatic interfaces.

 

I realize that programmers love their tools and toolkits, but honestly, when you build big giant systems sometimes you have to do things the "hard" way. It always surprises me when my clients complain that complex problems contain complexity in the solution. But in any case, I'm not even convinced that throwing away toolkits like WCF will raise the complexity level - there's a lot to be said for being closer to the wire. Plus, things like Linq for XML look really tasty when you consider how they might help with this style of programming.

 

I do really like the analysis of REST as Representational State *Transition*, as opposed to the T being for "Transfer". To me, viewing the design exercise as figuring out how to expose a connected state graph (i.e.

both transitions and states are explicit) brings a lot of mental order to what I already knew I wanted to do anyway. In particular, it helped me understand how a POX interface is useful for writes...because for reads it's dead obvious: GET kicks ass, especially if you care at all about performance. For a long time I was hung up on trying to figure out how to use SVT on write, and GET on read, because that seemed to make the most sense. But if the thing is just your application state where each state has an address, it's pretty obvious that it's okay to POST to a URL to cause a state transition. Or even for that state transition to significantly alter the URL space.

 

Of course, I have yet to build a large, real system using this new approach. I'd love to, though, because more and more it seems like the right thing. And no battle plan survives first contact with the enemy - witness SVT. The big question is whether the big concepts will prove out for me personally. Hence my eagerness to put my customers' money where my mouth is :).

 

And before you point it out in the comments, I should say that I'm aware of the efforts to make WCF more amenable to straight HTTP-style programming. It's just that I'm dubious about the viability of exposing transport semantics explicitly via an API that's all about abstracting transport semantics. It seems to me that if you're going to remove a layer of abstraction, you should actually remove a layer of abstraction. But again, I'll need to build something real with it before I can draw any supportable conclusions.

Tuesday, April 17, 2007

Converting Messages to Text in Outlook 2007

In Outlook 2003, you could open an email message and convert it from HTML to text by hitting Ctrl-Shift-O. That was handy, because I generally prefer to bottom-quote, and that's a pain in the ass when the email is HTML. So when I installed Outlook 2007 I was annoyed that Ctrl-Shift-O didn't work any more.

 

After a bunch of fumbling around, I finally discovered that if you open a message and edit it (Message->Other Actions->Edit), you can then change it to plain text (Options->Plain text). Well, being a keyboard guy, I got pretty tired of doing that, so now I have the following key sequence committed to muscle memory:

 

Enter (open message)

Alt H X E (edit message)

Alt P L (convert to plain text)

Alt H R P (reply)

 

Which, honestly, sucks, but is maybe 100 times as fast as doing the same thing with the mouse.

Wednesday, April 11, 2007

Fix Debugging QIs in ATL Code Under Vista

I think I have whiplash: in the space of a few hours I've gone from writing web services in C# to implementing COM stuff in C++. I don't do much C++ any more, so the adjustment has been somewhat extremely painful.

 

See, I'm trying to implement a new protocol handler to integrate with Windows Search. I have some content in a database, and I want to surface it along with other search results using Windows Desktop Search or the native Vista stuff. In the process, this set of posts has been an excellent resource. In fact, it's nearly the only resource for writing protocol handlers as far as I can tell.

 

While I was reading the posts and (slowly) implementing away, I decided that it would be a good idea to follow the suggestion turn on ATL QueryInterface debugging. Especially given that my code appeared to be doing nothing. So I was a bit annoyed to see output like this in DebugView:

 

[3552] CProtocolHandler
[3552]  -
[3552]  - failed

Those dashes are supposed to have interface names or IDs before them, and they're supposed to tell me what interfaces are being QueryInterfaced for. What's worse is that when I followed the link in the articles and read this, it looked as if the problem was fixed in VS2005, which I'm using. But it obviously wasn't.

 

Soon enough, I was down in the bowels of the ATL code (atlbase.h, no less), trying to figure out what's up. Well, eventually I spotted it: the code change they made to AtlDumpIID to fix the problem in VS2003 is still broken in the case where the registry keys can't be read. In that case, instead of dumping the raw ID, they dump…nothing.

 

I'm guessing that this is a Vista (which I'm using) problem that has to do with security being a lot more locked down. At any rate, if you encounter a similar problem, you'll want to change AtlDumpIID to something like the code below. I'm sure you can do better - this sometimes prints IDs twice, but it was the smallest change I could make to get the effect I wanted.

 

#if defined(_ATL_DEBUG_INTERFACES) || defined(_ATL_DEBUG_QI)
__forceinline HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr) throw()
{
        USES_CONVERSION_EX;
        CRegKey key;
        TCHAR szName[100];
        DWORD dwType;
        DWORD dw = sizeof(szName);

 

        LPOLESTR pszGUID = NULL;
        if (FAILED(StringFromCLSID(iid, &pszGUID)))
                return hr;

 

        OutputDebugString(pszClassName);
        OutputDebugString(_T(" - "));

 

        LPTSTR lpszGUID = OLE2T_EX(pszGUID, _ATL_SAFE_ALLOCA_DEF_THRESHOLD);
#ifndef _UNICODE
        if(lpszGUID == NULL)
        {
                CoTaskMemFree(pszGUID);
                return hr;
        }
#endif
        // Attempt to find it in the interfaces section
        if (key.Open(HKEY_CLASSES_ROOT, _T("Interface"), KEY_READ) == ERROR_SUCCESS)
        {
                if (key.Open(key, lpszGUID, KEY_READ) == ERROR_SUCCESS)
                {
                        *szName = 0;
                        if (RegQueryValueEx(key.m_hKey, (LPTSTR)NULL, NULL, &dwType, (LPBYTE)szName, &dw) == ERROR_SUCCESS)
                        {
                                OutputDebugString(szName);
                        }
            else
            {
                OutputDebugString(lpszGUID);
            }
  
      }
        else
        {
            OutputDebugString(lpszGUID);
        }
 
   }
    // Attempt to find it in the clsid section
    if (key.Open(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_READ) == ERROR_SUCCESS)
    {
        if (key.Open(key, lpszGUID, KEY_READ) == ERROR_SUCCESS)
        {
            *szName = 0;
            if (RegQueryValueEx(key.m_hKey, (LPTSTR)NULL, NULL, &dwType, (LPBYTE)szName, &dw) == ERROR_SUCCESS)
            {
                OutputDebugString(_T("(CLSID\?\?\?) "));
                OutputDebugString(szName);
            }
            else
            {
                OutputDebugString(lpszGUID);
            }

 

        }
        else
        {
            OutputDebugString(lpszGUID);
        }

 

    }
    else
        OutputDebugString(lpszGUID);

 

        if (hr != S_OK)
                OutputDebugString(_T(" - failed"));
        OutputDebugString(_T("\n"));
        CoTaskMemFree(pszGUID);

 

        return hr;
}
#endif  // _ATL_DEBUG_INTERFACES || _ATL_DEBUG_QI

 

Caveat Abstractor

Keith's recent post shows off an excellent use of anonymous delegates. There is, however, the fact that this is a bit weird to debug - as you step through you wind up jumping back and forth between contexts. Nothing that an experienced developer can't deal with, but anything that adds to the cognitive load required to maintain a piece of code needs to be carefully considered. The older I get, the more I realize that maintainability is the most consistently underserved of the five design tenets I like to remember. There's something to be said for having all the code right there in your face.

 

Syntactically, this gets a bit better with C# 3.0 due to the cleaner grammar for anonymous delegates, but I think it still has some of the same maintainability problems.

 

Of course, I've done this sort of thing myself. But I always think hard before I do it, and sometimes I feel a little dirty afterwards. Overused, this is a real maintenance nightmare.

 

Before someone jumps down my throat with a "so we should just repeat all that code, then?" I'll preemptively respond with two points:

 


  1. Well, it's what we did in .NET 1.1. How bad was it then?

  2. Every decision involves tradeoffs. Sometimes the tradeoffs involved make the decision easy. Sometimes they only seem to.

Monday, April 9, 2007

Yo, Package This!

I note that the cheekily-named Package This just went up on CodePlex. I had nothing to do with writing it, other than answering a couple of questions from the author.

 

The description from the project page:

 

Package This is a GUI tool written in C# for creating help files (.chm and .hxs) from the content obtained from the MSDN Library via the MSDN Content Service. You select the content you want from the table of contents, build a help file, and use the content offline. You are making personalized ebooks of MSDN content. Both help file formats also give full text search and keyword search.

The code illustrates how to use the MSDN Content Service to retrieve documentation from MSDN. It also shows how to build .hxs files and .chm files programmatically.

 

It's great to see interesting new applications making use of the web service!  


 

Thursday, March 29, 2007

'T' Is For &amp;quot;Too Cool&amp;quot;

I've mentioned here before that I was part of the original team that wrote MSDN2. I guess that's why I get occasional questions about the website. Of course, I was involved in writing the Microsoft/TechNet Publishing System (MTPS), the system behind the web pages, and not in the actual rendering stuff, but I try to help when I can. So the other day when someone asked me a question, I shot off an email to someone on the team to see if I could get him an answer. The response I got taught me something cool I didn't know about the website, so I thought I would share (with permission).

 

There are three new features to the MSDN2 website - two you may have noticed and one you probably haven't. The first one that's a bit more obvious is that the nav tree recently started loading asynchronously in its own iframe. What this means is that you no longer have to wait for the tree to load before you can view the content. As "I don't want to wait for the tree" is easily the number one complaint I have personally heard about the site - woohoo! Further changes are planned to make this even better.

 

Another one you might have picked up on is that the "trail of bread crumbs" navigation control along the top of the content (the internal MSDN term for it is "the eyebrow") has some added functionality. It now sports an AJAXy dropdown feature that makes it easy to navigate to siblings of the current node or any of the current node's ancestors. Go try it (for example, here) - you'll see what I mean.

 

The final, more subtle feature is that you can hit the 't' key to toggle visibility of the nav tree. I love this feature because I often just type in a URL to jump directly to a piece of documentation, so I don't need the tree at all. But whether I do or not, toggling the tree lets me use the full width of the screen for the content…very nice.

 

So kudos to the rendering team for making the MSDN2 site nicer to use!

Tuesday, March 20, 2007

Avalon (WPF) Application Not Closing

I've had a problem for the last few days that has been driving me nuts. I'm writing an Avalon (WPF) application, and the damn thing wouldn't shut down. Even though I was calling this.Close() in my File->Exit handler, the process would stick around. It was particularly insidious because the main window would close, making it look like the application had exited. Even though I knew it had this problem, I would still forget until the next time I would compile, when I'd get the error, "The compiler can't overwrite the file (dumbass)."

 

Mike Woodring and I spent what must have been close to an hour reviewing all my threading code to make sure it was correct. It wasn't, of course (it never is), but after we'd tried everything I ripped all that code out and it still wouldn't close.

 

It bugged me enough that it was the last thing I was thinking of as I fell asleep last night. And then - and I'm sure this has happened to most people reading this - I solved the problem in my sleep.

 

Here's the deal. I had a class that looks more or less like this:

 

public partial class MyWindow : Window {

  private readonly MyDialog _myDialog = new MyDialog();

 

  protected void OnFileExit(...) {

    this.Close();

  }

}

 

Where MyDialog is another Window. I like to use this pattern for dialogs that I'm going to pop up and down a lot: create it once during the constructor. That way they keep all their settings and whatnot when they're not visible. And in WinForms, this works great. However, in Avalon I needed to do this:

 

public partial class MyWindow : Window {

  private readonly MyDialog _myDialog = new MyDialog();

 

  protected void OnFileExit(...) {

    this.Close();

    _myDialog.Close();

  }

}

 

even if you never displayed the dialog! Because otherwise, you apparently still have a top-level window hanging out, and Avalon won't let you exit the process.

 

I haven't looked to see if there's some magic property that says "OK to nuke the process if this window is still around". You may want to check the comments on this post - given my level of knowledge of Avalon at this point, it's likely that someone out there knows better how to address this. Certainly, having to remember to Close all your subordinate Windows can't be the best way. But it beats having to run Process Explorer to kill the process every time.

Monday, March 19, 2007

Your Code May Be Suboptimal, But This T-Shirt Is Perfect

A few weeks ago, Eric Sink of SourceGear posted this article. I try to read everything Eric writes - he's one of the few guys on the business side with a background in the pointy end of the business he's managing, so he's got an interesting perspective. Plus, he seems damn smart.

 

Anyway, if you scroll down to the end of his article, you'll see a picture of the rockin' t-shirts they were giving away at SD West. I don't much make it to conferences any more, but I wanted a shirt. So, because Eric also seems like a nice guy, I emailed him to ask for one. I thought I'd offer to pump up the free advertising factor a bit by agreeing to post a picture of me wearing the shirt here. Nothing ventured, nothing gained.

 

Well, I ventured an email and gained a t-shirt. Here's my end of the bargain:

 


 

I'm not sure you can read it at this size (click the picture to jump to Flickr, where you can get the full-size version), but the evil mastermind robot dude is saying, "Your code is suboptimal".

 

My daughter wanted in on the act as well:

 


 

Thanks Eric!

 

Wednesday, March 14, 2007

InlineUIContainer and BlockUIContainer

I've been doing a project using Avalon (WPF, if you insist on using the sucky name), and have been learning a lot. I think it's the coolest of the .NET 3.0 family of technologies. Although I'm going to be attending Pluralsight's upcoming Workflow & WCF Double Feature in Waltham, so maybe more exposure will change my mind. I doubt it, though. :)

 

One of the areas that really interests me in Avalon is System.Windows.Documents. It interests me because it looks like it could make the next version of FlexWikiPad really easy to write - a well-thought-out model for text presentation that doesn't require messing around with a WebBrowser control. I'd even gone so far as to start writing a text editor control using .NET 1.1-era technologies. So I was happy when my current project gave me a chance to start dabbling in FlowDocument and friends.

 

One of the questions I ran across pretty quickly was "How do I include an image in a FlowDocument?" There's no Image element in System.Windows.Documents - just stuff like Paragraph, List, Bold, Span, etc. A quick question fired of to Ian (tired of my questions yet, dude?) revealed InlineUIContainer and BlockUIContainer, two wonderful classes that let you embed arbitrary Avalon controls inside a FlowDocument. All I had to do was wrap one of them around a System.Windows.Controls.Image control and I was off to the races.

 

Definitely a nice pair of bullets for the Avalon gun.

Tuesday, March 6, 2007

Outlook Feed Bug?

I ran into this today when I was fixing up FlexWiki 2.0's RSS mechanism to work with the new security provider. I finally got the page with the links to the RSS feeds to render, and I was a bit surprised when Outlook popped up showing what was obviously an ASP.NET error message. I was even more surprised that the same URL worked just fine in IE (I'd been testing with Firefox).

 

A little debugging and I think I figured out what's happening. Firefox appears to be launching Outlook as the registered application for RSS documents (presumably based on the ContentType, which is text/xml). Anyway, that's fine - I use Outlook to read RSS feeds, so great. What's not great is that Outlook decided to lowercase the URL.

 

Hello?! URLs are case-sensitive! Who thought it was a good idea to screw with the case of URL? I mean, it's fine to write a web application that accepts either case on the server side, but you can't just send either case as a client - you have to assume case sensitivity.

 

FlexWiki is highly case-sensitive as part of its design. So the lowercased namespace in the URL results in a failure to look up the right information. I'd write a fix for this into FlexWiki, but frankly I'm not sure that's a good idea. Outlook seems (to me) to be pretty clearly broken on this one.

 

I googled (lowercase intentional) for info on this but wasn't able to turn up much. Anyone know anything?

Thursday, February 22, 2007

Build Lights Done Right

I stole the idea, of course, but I've always sort of liked the build lights I did for a client of mine. However, I wish I had done it with as much style as this guy. Here's hoping he'll post a picture somewhere and drop a comment here with a link.

Tuesday, January 23, 2007

XAML and Error MC3074

I'm lucky. Really lucky. I have frequently had the fortune to get paid to play with new technologies. Right now I'm starting a project where I get to use WCF and WPF (curses on the Microsoft drone who dropped the far cooler names of "Indigo" and "Avalon"). It's fun.

 

Of course, life on the bleeding edge is not without challenges. For starters, there's the fact that I don't know what the hell I'm doing yet. That's usually the case anyway, but what's different now is that Google can't always save me. Usually I just type in some well-chosen search terms and lo and behold someone else has made the same mistake. Only it looks like I get to go first this time.

 

At any rate, I'm working on a project that makes use of the <WindowsFormsHost> control tag in XAML. This very cool tag, shown to me by Chris Sells, allows an Avalon form to host a Windows Forms control. In my case, it's the WebBrowser control, as Avalon (I'm going to keep calling it Avalon until no one can understand what I'm talking about) has no browser control in-built. However, when I went from the sample project that Chris sent me to my project, I kept getting build failures:

 

Error MC3074: Unrecognized tag 'WindowsFormsHost' in namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'.

 

After about half an hour of digging, I figured out that the problem is a missing reference. In my case, I was missing a reference to WindowsFormsIntegration, an assembly that can be found on my computer in C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0. Once I added it, all was well again.

 

Given what little I've been able to dig up on Google, I'm guessing this is going to be a common problem, so hopefully this post will help someone else at some point. Just be aware that it might not be WindowsFormsIntegration that you need to reference - I believe this error to be a general symptom of some missing reference, and not that assembly in particular. You'll have to do some detective work to figure out which one you need.

Wednesday, January 10, 2007

HoboCopy Fix: Side-By-Side Configuration Incorrect

So I was setting up one of my other machines with the new version of HoboCopy, when I got this error:

 

The application has failed to start because its side-by-side configuration is incorrect. Please see the application event log for more detail.

 

After doing a little digging, I realized that the problem was the version of the VC++ runtime I installed. I had run vcredist_x86.exe, but I had run the version that came with the RTM version of Visual Studio. Of course, HoboCopy was compiled with the SP1 version of Visual Studio, because a bug in the C++ compiler means it won't compile at all on the RTM version. Once I installed the updated vcredist_x86.exe, HoboCopy works again.

 

Of course, I had posted the wrong version up on SourceForge. I've fixed that - the version of vcredist_x86.exe available here now matches the one HoboCopy is expecting.

 

Sorry if this bit anyone other than me.

Monday, January 8, 2007

Announcing HoboCopy 1.0.0.0

Over the last few months, since I first released HoboCopy, I've been tinkering with it based on feedback from a few users, as well as my own experience using it daily. Today I posted the results of that tinkering: HoboCopy 1.0.0.0. Yes, it's stable and complete enough that I feel comfortable with the 1.0 label. You can download it from SourceForge here.

 

The highlights of the new release include the following:

 

Fixed a nasty bug. OK, you know how I said that HoboCopy would work with VSSAPI-aware applications like SQL Server to get you a consistent view of application state? Well, it turns out that I lied. I had a bug with the part of the process called component selection, and as a result the old version of HoboCopy was always giving you crash-consistent copies…i.e. whatever the hell was on the disk. That has been fixed, and SQL Server (and other VSS-aware applications) will now correctly flush their state before HoboCopy copies the files.

 

Vista compatibility. As Vista is now my main day-to-day OS, this was a must. Sadly but understandably, using the VSS API requires administrator privileges, so I had to add a manifest to HoboCopy so it'll give you that little secure "running elevated" prompt when you run HoboCopy under UAC. This sort of sucks for a command-line tool, since it launches another cmd.exe, meaning any errors immediately disappear when the process exits. Maybe I'll figure out a fix for that in a future version. In the meantime, running HoboCopy from an elevated cmd.exe is a reasonable workaround.

 

Default non-recursive processing and filename filters. You can now run hobocopy C:\sourcedir C:\targetdir *.txt *.foo to copy only files with the .txt or .foo suffixes. Recursive directory processing is off by default, so you need to run hobocopy /r C:\sourcedir C:\targetdir *.txt *.foo  if you want to include child directories as well.

 

There are a few more minor things I'd like to add to HoboCopy - specifically, to make it asymptotically approach robocopy's capabilities - but at this point it works pretty darn well for 99% of what I want to use it for, so I'm not sure it'll ever make it to the top of the project heap.

 

One more note: if you have any trouble running HoboCopy, it's probably because you don't have the VC++ runtime DLLs on your system. Run vcredist_x86.exe and try again. I've made vcredist_x86.exe available for download in the same place as HoboCopy itself.

 

Anyway, download and enjoy. Let me know if you have any problems.

Tuesday, January 2, 2007

Back and Forth

Here, as is my habit, is a review of 2006 and some thoughts on 2007.

 

I note first of all that it was a relatively light year for blogging for me. That's sort of unsurprising for a few reasons. First, I've been doing it for over three years now, so it's not quite as exciting as it was when I started. Hopefully, y'all still find it worth reading. Second, I have a toddler. Enough said. :)

 

2006 was a busy year for me, technically speaking. By my count, I was involved in at least nine different software projects. I even shipped a few of them, like the MTPS Content Service, msdnman, HoboCopy, and two releases of FlexWiki, including an alpha of version 2.0. And that's not to mention some of the work I did for some of my clients that I can't talk about.

 

Obviously, I've got more work to do in a few spots, including finishing FlexWiki 2.0 (oh ye gods, in the name of logic and mercy, please let me finish it in 2007) and shipping a new version of HoboCopy (this one's already in the can, I just need to post it).

 

The big stuff this year had nothing to do with the computer, though. First, Ellen turned two. Contrary to the popular stereotype of two-year-olds, she's been enormously fun and very well-behaved. I guess we're only two months into it at this point, but so far, two is my favorite age! But so were zero and one.

 

The other biggie was that Alice graduated. The positive impact of this on our personal lives cannot be overstated. Even more exciting than the graduation itself is that - even though I suspect she has her doubts from time to time - I'm certain than she's going to put her degree to good use in 2007, doing something really interesting.

 

As for me, I'm hoping that 2007 is a bit less busy than 2006, but just as interesting. From a work standpoint, I'm off to a good start on that one. I've got a project that I can't talk about just yet that pretty well ensures the "interesting" part, and I've finished up a few of the other ones on my list that should help with the "less busy" bit. But we'll see - I'm not historically very good at saying "no" to good opportunities.

 

In the near term, I'm very, very close to finishing my .NET architecture & design class for Pluralsight. It distills a lot of the lessons I've learned in my career - it's largely centered around the discussions I find myself having with clients over and over again as I move from gig to gig. So I think it'll be worthwhile for a lot of people. Maybe I'll see you in class sometime in 2007. :)

 

I'm not a big one for New Year's resolutions - I much prefer to strive for excellence all the time - so I'm not going to say, "I promise to blog more in 2007". More isn't generally better anyway. What I do hope is that I frequently learn new things that make me think, "Wow, I should share that with everyone" and that then I do.

 

See you around the feed.