Tuesday, June 22, 2010 #

On the state of ASP.NET development

There's an interesting discussion at Rob Conery's blog about the differences and divisions between .NET development and other (mainly web) technologies.

There's always a little bit of me that despairs when I see these sort of discussions, in which the ALT.NET community in particular have a habit of indulging. It often brings out the worst kind of "I've escaped from the cave because I use this platform, and the rest of you squares are just too dumb to see that you're still stuck in the dark watching the flickering shadows of what's out here" nonsense. MVC guys have this attitude to WebForms guys. Rails guys who've moved from .NET have this attitude to .NET (and if they moved from Java, they have the same attitude to Java). Everyone has this attitude to PHP.

I left a comment which I feel sums up better than I have managed elsewhere my thoughts on why the WebForms/MVC debate is, and always was, not relevant to any discussion about the merits of the .NET platform, or even to ASP.NET, as a whole.

posted @ Tuesday, June 22, 2010 3:30 PM | Feedback (10)

Friday, August 14, 2009 #

Dysfunctional JavaScript

jQuery is, quite rightly, lauded for providing a way of coding JavaScript for web browsers that just works. It pushes you relentlessly towards the pit of success, making simple things easy and difficult things possible. But if there's one niggle I have with coding jQuery, it's the anonymous function noise level. Every block of jQuery code is wrapped up in

$(function() {
	...
});

and inside that you're constantly having to nest yet more anonymous blocks:

$(function() {
	$('div.clickable').click(function() { ... }).
};
(Aside: I see a lot of people coding jQuery who don't use the $(function) shorthand to hook up document ready handlers. There's NO NEED to write $(document).ready(function() { ... }) - $(function() {}) is exactly the same, and way shorter.)

To be fair, it's largely the fault of JavaScript. Given that it's the basic unit of scope in the language, the amount of syntax you need to wrap around a function in JS is excessive. We can't do much about that directly, but there might be something we can do to help in some of jQuery's cases. Let's use some higher-ordered functional programming tricks and see if we can eliminate some functions - if that makes any sense.

Here's the theory:

Most of the time, what you end up doing inside each of these anonymous functions is creating a new jQuery object with a call to the $() function, passing it a selector, or frequently 'this', then chain a series of function calls onto that. Here's a simple example:

$(function() {
	$('.clickMe').click(function() {
			$(this).toggleClass('clicked');
		});
	});

There's two event handler functions here - one handling document.ready, and one handling a click.

Let's start with a little refactoring. Let's pull the functions out into variables, so we can look at them:

var handleClick = function() {
		$(this).toggleClass('clicked');
	};

var setupClickHandler = function() {
		$('.clickMe').click(handleClick);
	};

$(setupClickHandler);

That is (modulo some scope variations that aren't relevant) exactly equivalent to the inline anonymous function version.

But it seems to me that those two functions have a very similar structure to one another. Both of them call $(), then call a method on the result. Would it be possible, perhaps to have some sort of clever function that can build functions like that for us?

With JavaScript's support for first-class functions, the answer is 'yes, absolutely'. Let's build one. Here's step one:

var magicFunctionBuilder = function(selector) {
	return function() {
		$(selector || this);
	};
};

This is just a starting point, to get us into the idea of a function that builds a function for us. Look closely at what is does: it returns a function that calls the jQuery function passing either the selector we give it, or 'this' if we omitted the selector.

So if we call it thus:

var f = magicFunctionBuilder('.clickMe');

f now contains a function, which, when called, calls $('.clickMe'). It's equivalent to our having written:

var f = function() { $('.clickMe'); };

only with a lot less curly braces.

Similarly:

var g = magicFunctionBuilder();

is equivalent to

var g = function() { $(this); };

But we need our magically-built function to not only call the $() function for us; we need it to chain on the subsequent series of calls we need to perform on the jQuery object. How can we tell it what series of function calls to make?

Well, we could describe calling .toggleClass('clicked') with an object, like this:

var call = {
	method: 'toggleClass',
	args: ['clicked']
};

Given an object, o, and an array of call objects like that, calls, we can persuade JavaScript to call them in sequence, chaining the return value in as the 'this' for the next call. Here's how:

var executeCalls = function(o, calls) {
	for (var i = 0; i < calls.length; i++) {
		var call = calls[i];
		var fn = o[call.method];
		o = fn.apply(o, call.args);
	}
	return o;
};

This uses the apply method, which all JavaScript functions possess, which calls the function as a method of the supplied object, with the supplied argument list.

Now, if our magicFunctionBuilder had access to an array of calls, it could build us a more sophisticated function. Let's try it:

var magicFunctionBuilder = function(selector, calls) {
	return function() {
		var o = $(selector || this);
		executeCalls(o, calls);
	};
};

Now, we can write this:

var handleClick = magicFunctionBuilder(null, [{	method: 'toggleClass', args: ['clicked'] }]);

That is exactly equivalent to our original

var handleClick = function() { $(this).toggleClass('clicked'); };

But we've clearly swapped one complexity for another one here. What's needed is a better way to build that array of call objects.

JavaScript functions all have access to an arguments object. It contains a few interesting properties, but usefully it also provides indexed access to all the arguments supplied to the function. You can extract the values into an array very easily:

var argArray = function(args) {
	var arr = [];
	for (var i = 0; i < args.length; i++) arr[i] = args[i];
	return arr;
};

Now imagine a function like this:

var createToggleClassCall = function() {
	return {
		method: 'toggleClass',
		args: argArray(arguments)
	};
};

Now our handleClick creation could be a little cleaner:

var handleClick = magicFunctionBuilder(null, [createToggleClassCall('clicked')]);

Now for the clever bit. Instead of passing in a fully-formed array of calls to the magicFunctionBuilder, we can instead add methods onto the function it returns (yes, we can add methods onto a function object - welcome to the crazy world of Extreme JavaScript) that add calls for us. For example, we could do this:

var magicFunctionBuilder = function(selector) {
	var calls = [];
	
	var fn =  function() {
		var o = $(selector || this);
		executeCalls(o, calls);
	};
	
	fn.toggleClass = function() {
		calls.push({
			method: 'toggleClass',
			args: argArray(arguments)
		});
	};
	
	return fn;
};

Let's just rename magicFunctionBuilder to something a little more terse:

var $$ = magicFunctionBuilder;

and NOW we can create handleClick like this:

var handleClick = $$().toggleClass('clicked');

which is, remember, equivalent to our original

var handleClick = function() { $(this).toggleClass('clicked'); };

So all that's left to do now is to provide more than just a toggleClass method. It would be nice to provide all the methods that the user will expect to find on the actual jQuery object itself, don't you think? Well, conveniently, we can find those by enumerating $.fn's members - the members of the jQuery object prototype - finding all the functions, and making dummy 'recorder' versions of our own:

var $$ = function(selector) {
	var calls = [];
	
	var fn =  function() {
		var o = $(selector || this);
		executeCalls(o, calls);
	};
	
	for (var member in $.fn)
	{
		if (! ($.fn[member] instanceof Function)) continue;
		(function(method) {
			fn[method] = function() {
				calls.push({
					method: method,
					args: argArray(arguments)
				});
				return fn;
			};
		})(member);
	}
	
	return fn;
};

So now, as well as handleClick, we can build our other function, which you may remember, looked like this:

var setupClickHandler = function() {
		$('.clickMe').click(handleClick);
	};

Rewritten with our magic builder:

var setupClickHandler = $$('.clickMe').click(handleClick);

And we can now remove our original refactoring out of the variables, since our code's so much terser:

$(function() {
	$('.clickMe').click(function() {
			$(this).toggleClass('clicked');
		});
	});
	

becomes

$(
	$$('.clickMe').click(
		$$().toggleClass('clicked')
	)
);	

And to show some of the power of it, let's do something more complicated, including some chaining and animation completion callbacks:

$(
	$$('.clickMe').click(
		$$().toggleClass('clicked')
				.hide('slow', 
			$$().show('slow', 
				$$().toggleClass('clicked')))
	)
);

with anonymous functions, this becomes the monstrous:

$(function() {
	$('.clickMe').click(function() {
		$(this).toggleClass('clicked')
					 .hide('slow', function() {
			$(this).show('slow', function() {
					$(this).toggleClass('clicked');
				});
			});		
		});
	});

We can even make $$() Visual Studio intellisense friendly by lying to intellisense and telling it it returns a jQuery object; we'll get full intellisense on all the functions we can access.

I can't be sure this is an original idea, and I'm sure I've missed some subtlety that means this breaks in some common scenarios. I'm also not 1oo% happy with the $$ naming choice, nor sure I'd actually use this in a live dev environment (the maintenance coders would likely kill me). But it's certainly food for thought.

posted @ Friday, August 14, 2009 10:16 PM | Feedback (6)

Wednesday, July 15, 2009 #

Azure Prices Announced

Microsoft finally announced the commercial pricing model for Azure.

The numbers all look small at first glance, quoted at a very fine granularity of hours and gigs and kilotransactions, but it’s worth doing some multiplication to get real numbers out. $0.12/hour is £646 a year, by Google’s reckoning. That’s slightly more than the cost of a basic dedicated server from one random hosting provider I picked out of the air.

Amazon’s EC2 is $0.10/h for their smallest VM, but the next step up is $0.40/h, so you could have three compute units on Azure for less than Amazon’s mid-range VM.

So it’s largely in the same ballpark as standard hosting, with the granular scaling benefits you’d expect from utility cloud rental. Assuming once Azure compute unit is about one little server’s worth of CPU, which is, I suppose, a big assumption – but most application deployments are handled on a ‘one function per box’ basis regardless of the actual computing requirement.

So in summary: Everybody who thought it would be crazy expensive was wrong, everybody who thought it would be really cheap was kidding themselves. No surprise.

But there’s one key benefit that – I think – is underestimated in assessing Azure, though: it takes the entire system management layer out from under your software. Every dedicated or virtual host you operate in a conventional hosting environment, you’re responsible for patching the OS, managing reboots, clearing out log files, managing backup strategy, and so on. An Azure ‘compute unit’ box is isolated from OS and hardware concerns. If the hard drive in the server MS is currently running it on dies, an identical compute unit in a different box should pop up to replace it right away. And it’s the scaling cost of the additional overhead of managing extra server instances that limits the appeal of even utility computing solutions like EC2.

So while the pricing may be comparable to dedicated or virtual-dedicated hosting, the granularity and the administrative scalability suggest that MS is doing something genuinely interesting.

posted @ Wednesday, July 15, 2009 9:44 AM | Feedback (6)

Wednesday, June 03, 2009 #

Hunt the Class

Popquiz - in which .NET assembly is System.Drawing.Design.UITypeEditor?

1) System.Design
2) System.Windows.Forms
3) System.ComponentModel
4) System.Drawing
5) System.Drawing.Design

A little background to help you choose:

When you want to make a property of a custom type editable via a modal dialog from within a PropertyGrid control (from the System.Windows.Forms assembly), you need to decorate the type with an EditorAttribute (from the System.ComponentModel assembly), to which you must pass the type of a class that inherits from UITypeEditor.

Your UITypeEditor class must use the IWindowsFormsEditorService (again, from the System.Windows.Forms assembly, but located in the System.Windows.Forms.Design namespace) so that it may supply a WinForms Form object (System.Windows.Forms again) to display the edit UI.

The answer? In their infinite wisdom, the .NET elves hid UITypeEditor in the System.Drawing.Design namespace to begin with - but then decided not to put it in the System.Drawing.Design assembly (oh no, that is for concrete implementations of type editors). They didn't put it in System.ComponentModel, where the EditorAttribute lives; nor in System.Windows.Forms, where it could sit beside the components upon which it relies to provide the UI services it offers (and the PropertyGrid control to which it is subservient). No, the pin-the-class-on-the-assembly game in the WinForms dev team office that Friday afternoon landed on:

System.Drawing, of course.

With all the GDI+ library tools for pushing pixels around.

A natural fit, clearly. I can't imagine why I didn't think to look there sooner.


posted @ Wednesday, June 03, 2009 10:01 PM | Feedback (3)

Friday, January 16, 2009 #

Named Format Strings

Phil Haack’s post about named format strings a week or so ago, and the followup discussion on Phil’s blog this week, got me intrigued at lunchtime today – intrigued enough to have a play. As Phil says, it’s a fairly simple problem space, but it does have some gnarly edge cases, and he’d put together a fairly thorough set of unit tests which tripped up some alternative implementations he’d come across.

As it happens, I’ve been nursing some thoughts about string formatting in the back of my mind ever since I came across F#’s strongly typed format expressions, which are actually parsed and typechecked by the compiler. Obviously C# can’t be hacked to do anything that clever at compile time, but it did make me think that it must be possible to do a one-time parse of a format string to turn it into a function that could subsequently be executed to generate format output for a particular set of variables.

So, for example, Phil’s sample expression "{pi} first, {date} second" would be compiled into a function which, given an object obj with properties ‘pi’ and ‘date’, returns, essentially, obj.pi + “ first, “ + obj.date + “ second” (although in reality, it should use a stringbuilder).

Compiling functions dynamically would, until recently, have meant delving into Reflection.Emit and brushing up on IL syntax. In .NET 3.5, however, it sounds like a job for System.Linq.Expressions, and so this looked like a perfect opportunity to have a hack around with dynamically constructing expression trees.

So, armed with Phil’s test suite, I set out to throw together a solution to see whether this approach was viable. Once I’d got the tests passing, and mindful of Phil’s admonition that this isn’t a speed contest, for a laugh I threw my implementation’s hat in the ring in Phil’s benchmark testbed. I was expecting my lambda generator to crawl in behind the rest, but was astonished instead when the results came in:

Hanselformat took 0.17128 ms
OskarFormat took 0.22646 ms
JamesFormat took 0.1473 ms
HenriFormat took 0.1085 ms
HaackFormat took 0.1262 ms
HartFormat took 0.04908 ms

Now, it’s not a speed contest, obviously, until you’re winning.

The thing that amazed me about this result was that in this version of the benchmark test, I wasn’t reusing the ‘compiled’ parsed format – I was parsing the format string every time through (though there was some upfront precompilation and reflection caching that I’ll come to later)

Reusing the same precompiled formatter each time round, the result looks almost unbelievable:

HartFormat - precompiled took 0.0076 ms

This even compares favourably (i.e., it’s in the same order of magnitude of execution time) with these alternatives:

ConcatFormat took 0.00476 ms
StringFormatFormat took 0.00582 ms
StringBuilderFormat took 0.00474 ms

The source for which is as follows:

MeasureFormatTime("ConcatFormat", 
        () => o.foo + " is a " + o.bar + " is a " + o.baz 
                + " is a " + o.qux.ToString("#.#") 
                + " is a really big " + o.fizzle);
 MeasureFormatTime("StringFormatFormat", 
        () => String.Format("{0} is a {1} is a {2} is a {3:#.#} is a really big {4}", 
                o.foo, o.bar, o.baz, o.qux, o.fizzle));
 MeasureFormatTime("StringBuilderFormat", () => new StringBuilder(o.foo, 128)
                .Append(" is a ")
                .Append(o.bar)
                .Append(" is a ")
                .Append(o.baz)
                .Append(" is a ")
                .Append(o.qux.ToString("#.#"))
                .Append(" is a really big ")
                .Append(o.fizzle)
                .ToString());

So, what are the ingredients of my formatter that mean it’s able to be so fast? I think there are three:

  1. It uses an efficient regex search strategy to parse the format string
  2. It pre-analyses the datatype of the object that it’s going to have to extract property values from, and pregenerates and caches fast property accessors for it
  3. It uses the format string parse information and precompiled property accessors to generate a lambda expression whose compiled execution path is not dissimilar from the StringBuilderFormat example above, which had the fastest execution time of any strategy.

Regex

The regex I used solves all my parsing issues in one go – it handles format expressions, escaped braces, and also picks up loose unmatched braces, all in one go:

    (?<escapedOpenBrace>      {{       )
|   (?<escapedCloseBrace>     }}       )
|                             {
                                  (?<name>[A-Za-z_][A-Za-z0-9_]*)
                                  (?<propertyChain>\.(([A-Za-z_][A-Za-z0-9_]*\.)*[A-Za-z_][A-Za-z0-9_]*))?
                                  (:(?<fmt>[^}]+))?
                              }
|   (?<mismatchedBrace>       {     )

 

This is a useful regex pattern to know. Picking up all the matches for this regex in the format string tells me all the places I need to do anything special, and I can distinguish between those cases by examining whether particular named match groups succeeded:

if (match.Groups["mismatchedBrace"].Success) 
    throw new FormatException("Mismatched brace in format expression at " + match.Index);
else if (match.Groups["escapedOpenBrace"].Success) yield return OpenBrace;
else if (match.Groups["escapedCloseBrace"].Success) yield return CloseBrace;

Letting the regex engine handle parsing takes a lot of responsibility off my shoulders; I don’t have to implement my own state machine (the regex engine is excellent at doing precisely that), or my own lookahead/backtrack strategy (the regex engine handles that too). The expression is generally quite conservative in what it matches (except for format values, but those are relatively rare) so should be pretty quick in most cases – including non-matching scenarios, which is typically where a lot of regexes fall down.

Precaching Reflected Property Accessors

This is probably the biggest win, since it keeps reflection code out of the loop. We make sure that we only reflect over the properties of any type once, and when we do so we generate a fast property accessor that formats that property’s value as a string without going via a reflective invocation.

The logic for this is encapsulated in the static initialiser of a generic class. A static field in a generic type is a great way to essentially create a lookup from a type to a value – in this case, from a type to a dictionary of its property names, and compiled lambdas for reading from them:

public class Formatter<T>
{
    // statically, for the type T, generate a dictionary of name -> formatting lambdas
    // This will happen once per type, so multiple format operations on the same type will benefit.
    static Formatter()
    {
        _parameters = new Dictionary<string, Func<T, string, IFormatProvider, string>>();
        foreach (PropertyInfo prop in typeof(T).GetProperties(bindingFlags.Instance | bindingFlags.Public)
                                           .Where(p => p.CanRead))
        {
            ParameterExpression t = Expression.Parameter(typeof(T), "t" + prop.Name);
            parameterExpression fmt = Expression.Parameter(typeof(string), "fmt" + prop.Name);
            parameterExpression fmtr = Expression.Parameter(typeof(IFormatProvider), "fmtr" + prop.Name);
            Expression<Func<object, string, IFormatProvider, string>> toStringMethod;
    
            toStringMethod = typeof(IFormattable).IsAssignableFrom(prop.PropertyType) 
                ? _IFormattableToString 
                : _objToString;

            Expression<Func<T, string, IFormatProvider, string>> formatLambda = 
                Expression.Lambda<Func<T, string, IFormatProvider, string>>(
                    Expression.Invoke(
                            toStringMethod, 
                            Expression.Convert(Expression.Property(t, prop), typeof(object)), 
                            fmt, 
                            fmtr
                        ), 
                    t, 
                    fmt, 
                    fmtr
                );
            _parameters.Add(prop.Name, formatLambda.Compile());
        }
    }

    private static Dictionary<string, Func<T, string, IFormatProvider, string>> _parameters;
}

Build a Fast Format Function

So with the parsing done, and the type pre-reflected, building up a fast formatter is just a case of stitching together the function calls:

public Formatter(string format)
{
    if (format == null) throw new ArgumentNullException("format");
    _generators = GetTokenGenerators(format).ToList(); // note, GetTokenGenerators() is 
                                                       // enumerated now, at construction time, 
                                                       // allowing same format string to be reused 
                                                       // without further regex hits
}


public string Format(T dictionary, IFormatProvider formatProvider)
{
    if (dictionary == null) throw new ArgumentNullException("dictionary");
    return _generators.Aggregate(new StringBuilder(), 
                                 (builder, val) => builder.Append(val(dictionary, formatProvider)), 
                                 builder => builder.ToString()
                                );
}
// parses the format and returns a set of functions that output part of the format result
private static IEnumerable<Func<T, IFormatProvider, string>> GetTokenGenerators(string format)
{
    int index = 0;

    foreach (Match match in _re.Matches(format))
    {
        if (match.Index > index) // don't bother returning for an empty string
        {
            string previousText = format.SubString(index, match.Index - index);
            yield return (t, fmtr) => previousText;
        }

        if (match.Groups["mismatchedBrace"].Success) 
                throw new FormatException("Mismatched brace in format expression at " + match.Index);
        else if (match.Groups["escapedOpenBrace"].Success) yield return OpenBrace;
        else if (match.Groups["escapedCloseBrace"].success) yield return CloseBrace;
        else
        {
            debug.Assert(match.Groups["name"].Success);

            string name = match.Groups["name"].Value;

            Func<T, string, IFormatProvider, string> formatLambda;
            if (!_parameters.TryGetValue(name, out formatLambda)) 
                    throw new FormatException("No such value in dictionary type: " + name 
                                            + " in format expression at " + match.Groups["name"].Index);

            string specifiedFormat = null;
            if (match.Groups["fmt"].Success) specifiedFormat = match.Groups["fmt"].Value;

            if (match.Groups["propertyChain"].Success)
            {
                // take a slower path
                yield return (t, fmtr) => System.Web.Ui.DataBinder.Eval(t, name 
                                       + match.Groups["propertyChain"].Value, "{0:" + specifiedFormat + "}");
            }
            else
            {
                yield return (t, fmtr) => formatLambda(t, specifiedFormat, fmtr);
            }
        }

        index = match.Index + match.Length;
    }

    if (format.Length > index)
    {
        string previousText = format.SubString(index, format.Length - index);
        yield return (t, fmtr) => previousText;
    }
}

It’s prebuilding this formatter that explains the massive performance improvement in the compiled version of the benchmark. The formatter is strongly typed to deal with values coming in from a specific type, to be formatted with a particular string.

So, i should stress: this was a quick lunchbreak hack; it’s not been deliberately optimized, nor deliberately made particularly pretty. It’s probably got some pretty hairy edges. On the plus side, it passes Phil’s test suite.

Speaking of test suites, I should mention Peli’s findings when he pointed Pex at the various implementations Phil posted. As should be expected, mine is also fully incompatible with all the others. In particular, mine aggressively throws FormatExceptions when it finds mismatched braces, more so than any of the others. But I will certainly  be having more of a play with Pex – it looks an amazing tool.

Caveats aside, if you want to play with my code, it’s here. Drop it in Phil’s NamedStringFormatSolution and have a play.

posted @ Friday, January 16, 2009 10:38 AM | Feedback (36)

Wednesday, January 14, 2009 #

JQuery 1.3 and Visual Studio 2008 IntelliSense

Time for an update on the JQuery IntelliSense story.

Since I last updated the blog on this subject, things have moved on enormously:

  • Microsoft started shipping JQuery 1.2.6 with ASP.NET MVC, and announced their intention to do the same with VS 2010.
  • Alongside that, they handed over their own annotated intellisense file to the JQuery project to support intellisense in VS 2008
  • To make that even easier to use, they released a patch for VS2008 SP1 that allows the intellisense parser to read an alternate –vsdoc.js file instead of a real .js file to get intellisense hints.
  • Then today, John Resig announced the release of JQuery 1.3. Great news!

But then, not-so-great news: reference JQuery 1.3 from a file in VS2008, and intellisense falls over in a heap. Looks like there’s something in the new Sizzle CSS selector library component of JQuery that VS just doesn’t like. That disables all JavaScript intellisense in the referencing file. It’s a real shame; MS went above and beyond releasing a pre-SP1 hotfix that enabled intellisense to be compatible with jQuery 1.2, and I know the VS guys have a completely overhauled intellisense engine coming in the next version of VS. But right now, it looks like something in Sizzle’s capability detection code throws the current VS2008SP1 code for a wobbler.

Luckily, if you’re using a –vsdoc.js file to augment jQuery, intellisense doesn’t fail because it ignores the actual jQuery source file. Unfortunately, there’s no intellisense file for JQuery 1.3.

Until now.

Thanks to the fact that up to date API docs have been published immediately on http://api.jquery.com/, I’ve updated the generator script and posted a new JQuery 1.3 intellisense header file up, so you can drop in a jquery–vsdoc.js beside your jquery.js file and get fully-functional, chainable intellisense, including all the latest function signatures.

Note that my file is slightly different to Microsoft’s 1.2.6 file in its structure, and contains no actual jQuery code; it’s likely mine won’t function as well in co-ordination with jQuery extensions, for example. No warranty express or implied, your mileage may vary, etc.

If you need more information on getting JavaScript intellisense working in visual studio, Jeff King’s FAQ is a must-read.

posted @ Wednesday, January 14, 2009 5:31 PM | Feedback (79)

Thursday, October 30, 2008 #

On C#’s Newest Keyword

Finally got to see Anders Hejlsberg reveal the new features in C# 4.0 today. As expected, nothing hugely radical. But the new ‘dynamic’ keyword did inspire one thought that I shared with a couple of guys in the ask-the-experts session and Dave Remy suggested I should blog it, so I shall…

Three years ago as part of the LINQ wave of announcements for C# 3.0, Anders introduced anonymous types and this necessitated the ‘var’ keyword. Now we all know this is just a static inferred type declaration, we’re all cool with it now, but at the time there was a lot of panicking and wailing and misunderstanding about what this new ‘var’ word really meant, much of it around the fear that C# had introduced a variant type. This turned out not to be true, and the panic subsided.

Now, with the new ‘dynamic’ keyword… guess what? C# has variants. And nobody’s noticed, and nobody’s panicking.

Yet…

posted @ Thursday, October 30, 2008 5:20 AM | Feedback (2)

Wednesday, October 29, 2008 #

PDC 2008 thoughts so far

With a combination of jetlag and a persistent cough keeping me from sleeping, it seems like a pretty good moment to jot down some thoughts on the first couple of days of the 2008 Microsoft Professional Developers Conference, “the first PDC in the history of PDCs”, as Don Box said, “where Microsoft has not launched a new data access stack”.

My overall feeling about this PDC is that MS has fluffed the marketing angle really badly. There doesn’t feel like there’s a coherent story behind this PDC launch wave. MS will tell you this is the “Software + Services” PDC, but they’ve failed to convince that that’s a central driving philosophy, rather than a generic term they’ve applied to try to categorise what they’re about.

The pitch of the keynotes has felt slightly wrong, and I think the main reason for that is that so much of what could have been the big splashy announcements to get the crowd on their feet had already been announced prior to PDC. The last month has seen a whole raft of things trickle out of microsoft not with a bang but with a whimper: the Windows 7 name; the fact that MS was launching what Ballmer called an ‘OS for the Cloud’; Silverlight 2.0. Even a couple of developer crowdpleasers, like ASP.NET MVC hitting beta and the deal where MS will start shipping JQuery sneaked out via the blogosphere rather than being saved a couple of weeks for the big event.

When the ‘Azure’ name leaked out (via a Microsoft RSS feed) before the Monday morning keynote, all the wind was taken out of the sails of that keynote. It wasn’t helped by the fact that Ray Ozzie feels too corporate as a presenter to engage a dev crowd. The crux of the Azure announcement really comes down to Microsoft going into web hosting, and while the cloud provisioning model is qualitatively different to your classic rackspace offering, it doesn’t demo any differently. The point of Azure is to make scaling transparent; transparency doesn’t demo well.

And my overall impression of Azure is… well, ‘meh’. Google and Amazon offer cloud hosting platforms; now so does MS. Each has proprietary management APIs, proprietary storage, proprietary hosting APIs. Developing a system for any one of these cloud services locks you in to that vendor’s offering. I’d expected Microsoft to, well, act like Microsoft, and make a platform play. Release Azure as a platform for cloud hosting services, let third party ‘hosting partners’ take up the hosting part of the problem, and change the cloud service hosting market. I could commit to building Windows-Azure-based apps if I knew that I had competition among hosting providers, just as I am happy now to build ASP.NET web apps knowing I can go to a range of hosts to get my app out on the net. With MS as the sole provider, I can’t commit to their platform, when it could turn out to just be another .NET MyServices and disappear quietly into the sunset in 12 months. No game-changer, so… ‘meh’.

Of course, MS wanted to use the day 1 keynote to set the message that will go out in the non-specialist press about their plans; the audience for the cloud announcement was the business world looking at Microsoft’s positioning relative to Google, not the crowd in the hall. But come on, the leak of the name and the foreshadowing done by Ballmer a few weeks back, this barely deserved to be called an announcement.

Meanwhile, while I was stuck in that keynote fighting to get a slice of WiFi bandwidth and failing, out on the net, Microsoft shipped the .NET 4.0 and Visual Studio 2010 CTP, and the Oslo SDK CTP. I didn’t know about this until I got back out of the PDC keynote hall. Frankly, if Microsoft is releasing a new version of Visual Studio but not making a big deal of it in the PDC conference hall, something has gone seriously wrong. It almost feels like there was originally a different plan, but that the Azure keynote took centre stage at the last minute, too late to change the scheduled VS and Oslo releases.

Something has definitely gone wrong with the Oslo launch. Oslo incorporates a new language, new tools, and represents a new development paradigm; it’s exactly the kind of stuff you can hang a PDC on. The Oslo team have come with a ton of marketing collateral, they’ve got branding, they’ve got t-shirts, they’ve got balloons… in the Microsoft pavilion, this is a big coming out party for a big technology, but if you’re looking to learn about what MS is releasing from sitting in the keynote hall, well you wouldn’t even know about it. Even after Don Box and Chris Anderson did their keynote – they slipped in a tiny demo of IntelliPad, an Oslo tool, but it felt almost like guerrilla marketing, not part of the message they were there to sell.

Day two keynote, we got some real meat, and felt like this was more like what we expect from PDC. But still the foreshadowing announcements had stolen half the thunder. YES we got to see the first ever public demo of the Windows 7 desktop (the first EVER DEMO! Steve Jobs would’ve had us eating out of his hands…), but imagine how much bigger that presentation would’ve been if it had also been the first time MS had confirmed that the product name was Windows 7 (or even if they’d chosen a better name).

As it was, the biggest cheers Microsoft squeezed out of the PDC crowd were for demoing Windows 7 multi-monitor remote desktop, and the announcement that VS2010 was being rebuilt in WPF (and would support multiple monitors too… spotting a theme here?) – other than that, polite ripples of applause greeted a few nice features, but there was no ovation. ScottGu’s demo of customising the WPF-based VS editor was incredibly well-received (it’s always great to watch Scott throw out code on a keynote stage), though the momentum was short-lived.

With the right staging, they could have whipped up the crowd with VS2010 multitargeting support; .NET 4.0/2.0 side-by-side in process; foreshadowing Anders’ C# 4.0 announcements… And what was that tantalising ‘SilverLight running outside the browser’ hint? Was that iPlayer app they demoed really SilverLight acting like Adobe Air? did they just forget to announce that one too?

Failing to keep Azure secret enough; failing to announce Oslo; failing to announce .NET 4.0, VS 2010, C# 4.0 (a language Eric Lippert has been carefully describing as ‘a potential hypothetical future language’ for the past three years) and VB10; failing to use this as a platform to properly launch Windows 7; there’s a lot of fail in the PDC marketing machinery.

But away from the keynotes, that marketing failure doesn’t take away from the fact that MS is launching all that technology here. Real stuff is being announced during every session slot, and I’m having to catch up on the news via twitter and the blogs from the sessions I’m not in. In many ways, it feels like I’d be better informed if I wasn’t actually here on site, but that would mean missing out on the chance to meet up and talk to the teams and get some real insight. I had a great catch up with Jeff King, who’s the guy behind the JQuery intellisense file you can now get hold of; he showed me a few cool new capabilities coming up in VS JavaScript intellisense capability. I also had some great opportunities to chat with guys from the Oslo group, to see how their tools fit with my apps. I’m looking forward to more of the same today, especially tonight at the Ask the Experts session. I’ll also be trying to take in the repeat of Anders’ C# 4.0 talk.

So I’m disappointed in Microsoft’s lack of control over the proceedings, its seeming lack of self-awareness and co-ordination. But I’m not disappointed in the tech, the content I’m seeing, or the people I’m meeting. PDC’s still worthwhile in a blog-driven age because of the connections you can make on site, and no leakage of codenames changes that.

posted @ Wednesday, October 29, 2008 1:58 PM | Feedback (8)

Tuesday, August 05, 2008 #

JQuery VS2008 IntelliSense Update

UPDATED January 19 2009: This post predates several important developments in the world of JQuery intellisense, not least the release by Microsoft of the ‘official’ JQuery 1.2.6 intellisense file. I’ve also updated my intellisense file for JQuery 1.3.0. More Information

 

Just a quick post to (belatedly) announce that I've updated the JQuery VS2008 IntelliSense 'Header file' and generator script. The generator supports the 'newer' style documentation XML, produces a better (more compatible) header file, and the version available on the site is now up to date for JQuery 1.2.6. You can use the script to generate headers for older versions yourself - download the zip file and replace the jquery.js and jquery-docs-xml.xml files, and then run the index.htm generator page.

You can read about the purpose and origins of this file on my original blog post.

There's been a lot of buzz since my original posting about the header file.

  • My post was linked from Scott Guthrie's blog
  • Brad Vincent posted his updated version (he tweaks some of the return types for methods that sometimes return jQuery objects to get more intellisense - I'll have to see about making that an option on the generator; at the moment it prioritises being correct, possibly at the expense of being helpful). Brad's post includes a great se tof clear instructions as to how to get up and running with the header file.
  • Brad's file featured in Scott Guthrie's later post about Visual Studio 2008 SP1 features (it was great to see 'jquery.intellisense.js' turn up in a scottgu screen capture - he commented about where he got it here).

The basic adaptations to support the newer XML format were posted on the jQuery forum by Jeffrey Kretz. I've tried to get in touch with Jeffrey about including his adaptations in my download; I've had no response, so I'm hoping that the included credit for his work is acceptable.

If you just want to download the latest JQuery 1.2.6 header file, it's here.

posted @ Tuesday, August 05, 2008 11:10 AM | Feedback (22)

Monday, July 21, 2008 #

On Titling Programming Books

Jon Skeet (author of the truly excellent C# In Depth - I mean truly excellent, the best book I've read in the .NET sphere, bar none) blogged recently about the mess of version numbers in book titles about current versions of C# and .NET technology. He's right, Microsoft's fast-and-loose interpretation of the major/minor version number convention and its separation of language versioning from framework versioning has made a mess that's especially visible in the pages of Amazon's programming section. But I believe Jon's wrong to complain quite so much about the publishers who've elected to title books with the '2008' moniker; it may not be pedantically correct, but it's a darn sight better than most alternatives. The titling of these books is way more complicated than it looks; there are more subtle dynamics than mere precision at play here.

I've been here before, you see. Back in the days before it became a Wiley imprint, I was a kind of series-commissioning-technical-editor-cum-technical-reviewer-cum-author at Wrox Press, so I've got some experience of titling programming books in the face of pathological version numbering disasters. In particular, I cut my editorial teeth in Java books just as Sun, in their wisdom, decided to call the version of the Java platform that they shipped with version 1.2 of the SDK "Java 2". At that point, it wasn't too bad. We were able to bring out books with Java 2 in the title, and everybody could see that they were about a newer technology than those old books about Java 1.1. So far, so rosy.

Then Sun decided to release a new SDK version, 1.3. Suddenly, not so rosy. We needed to sell books that were:

  1. clearly about a newer technology than older books - the ones with Java 2 in the title - you want a punter in a bookshop with your new book, next to one of your competitor's older books, to pick your new one. "Hmm - Learn Java 2 in 123 microseconds, or Beginning JDK 1.3? I'll take the version 2 book, please!"
  2. clearly about version 1.3 of the SDK - you want punters who know they want a 1.3 book to find your book. It has to come up when they search for... whatever it is they're going to type when they search for it.

In the editorial team, we had to pick titles and convince the sales team that they could convince the book buyers in Amazon and Barnes & Noble and Borders that the title covered a new technology, would appeal to customers, and justified its place on the shelf instead of all those old books (Chainstore book buyers don't like clearing books that have a good sales history off their shelves, even if you tell them that the technology they cover is obsolete. They know that book sells; they don't trust this new book yet.)

The sales channel is a crucial part of the titling dynamic, because even more than the customer they buy based on title alone. And they shelve by title. A badly titled book will end up in the wrong bookcase entirely. A lot of early C# books wound up under 'C++', while general .NET titles ended up under 'networking' because bookstores didn't have a .NET category yet, and it looked like a networky word.

In the case of Java's 1.3 naming crisis, we tried to title books as new 'JDK 1.3 Editions' of existing Java 2 titles, which worked reasonably. The problem didn't get much better when Sun - in its wisdom - decided to title the next release 'Java 2 SDK 1.4'; My name (and part of my face) appears on a couple of differently-titled books that reflect the uncertainty that name switch caused:

Seriously. We called the technology an abbreviation of "Java Java Two Standard Edition One-Point-Four". And I stand by that - it was the right thing to do from a search optimisation and version clarity perspective, even though it was, pedantically, a mess. But it was Sun's mess. Sun's term - J2SDK 1.4 - was never going to fly in a book title for the sales channel. They knew J2SE (because J2EE titles had been such a success), they new Java, they wanted something bigger than 1.3.

Microsoft have put publishers in a similar position with .NET. In fact, they've put publishers in a worse position, by releasing .NET 3.0 with so few actual changes. Publishers updated general C# and VB.NET books to match the version number - and of course, nobody bought them. People bought WCF, WF and WPF books if they had an interest in those fields, I'm sure, but who would buy a .NET 3.0 update of a generic .NET book? Only newcomers picking up a first title, and only because the 3.0 book had obsoleted the old 2.0 one.

Then 3.5 comes along, and there are genuine changes, and for once people do want to buy books on C# and VB.NET again that cover all these new features, and... the book buyers say "A point release? You saw the sales figures for version 3.0, and that was a major update. The .NET book market is dead. You can't seriously expect us to buy new books for a point release."

Or worse, you come to them with a book claiming to be on C# 3. "Three-dot-oh is DEAD, I told you. What are you doing bringing us new books on last year's tech, when we couldn't even sell books on last year's tech last year? Come back when it's four-dot-oh and we'll talk."

Yeah, you try telling the sales guys it's C# 3 not .NET 3.0... see how well that meeting goes.

Bear in mind that these conversations with book buyers are all going on early in the pre-release cycle; books are announced and ordered six months ahead of release. And all the publishers are trying to pick the same naming convention as each other, because it's critical that if you're going to position your book as a competitor for one of the big players' books, you need to pick the same name for the technology. No book buyer will believe your Crazy C# 3 Tricks book competes with the market-leading Dull Business Applications with C# .NET 3.5 - the titles are totally different. And besides, C# 3 - that must be older than this competing .NET 3.5 book, right? Who cares if they got the title technically wrong, and you're right - what matters on the shelf - or in the search results - is that you're the same.

So what do sensible publishers do? They tie the new release books to the new Visual Studio version. Put 2008 on a book and it looks a lot sharper and more interesting to a book buyer than that tired old 2005 edition (albeit with the 'Covers .NET 3.0!' flash on the cover). You can make up for the version number chaos in the subtitle (because even though nobody reads it, it'll help with search results). So you wind up with Serious C# 2008 Edn: .NET 3.5 Development With C# 3.

Now, not all of the publishers have played this game all that well, I'll admit, and I'm far enough out of the publishing loop that I'm sure my intuitions about how the market influenced the book titles in this release cycle is a mile off the mark, but even if I'm wrong about how it works nowadays, I think it's particularly unfair to criticise them for not using C# 3 in the book titles. That was never going to fly after the .NET 3.0 release.

Still, I guess with the way computer book publishing's been going in the years since I left the industry (that's a correlation, not a causation), optimising book titles is probably a case of rearranging the deckchairs on the beachfront at Atlantis, but I just wanted to point out that in the list of people I considered when I was choosing book titles, version number pedants came pretty low down.

Probably just below the ill-informed marketing people who tried to persuade us that using non-trademarked names instead of the Official Name™ when referring to their product was somehow a trademark violation...

posted @ Monday, July 21, 2008 11:07 PM | Feedback (1)