<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Developer Journey</title><link>http://devjourney.com/</link><description>languages, tools and techniques for the modern software developer</description><generator>Graffiti CMS 1.2 (build 1.2.0.2308)</generator><lastBuildDate>Thu, 24 Feb 2011 05:01:00 GMT</lastBuildDate><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/DevJourney" /><feedburner:info uri="devjourney" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><title>Stupid Cartoon Bears</title><link>http://feedproxy.google.com/~r/DevJourney/~3/M2jeXA52gic/</link><pubDate>Thu, 24 Feb 2011 05:01:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/blog/stupid-cartoon-bears/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>2</slash:comments><category domain="http://devjourney.com/blog/">Blog</category><description>&lt;p&gt;Rahm Emanuel's use of a famous Yogi Berra quote during a recent Chicago Mayoral debate got me thinking about unfair history has been to arguably the best catcher in the history of baseball.&lt;/p&gt;&lt;p&gt;You don't have to agree with me that Yogi Berra was the best catcher in baseball history. Johnny Bench was a great catcher but there are many statisticians on my side who say&amp;nbsp;that Yogi&amp;nbsp;was better. And statistics never lie, right? Combined with my own well-conceived prejudices, I feel quite comfortable with my claim.&lt;/p&gt;
&lt;p&gt;I was having a conversation with a twenty-something fellow at work recently when I mentioned Yogi Berra after quoting him in context. The youngster, ostensibly a baseball follower if not a fan, asked me if I was quoting that &amp;quot;stupid cartoon bear&amp;quot;. It was funny until I realized he wasn't joking. Now close your eyes for a moment and imagine if you:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Were arguably the best catcher in the history of baseball&lt;/li&gt;
    &lt;li&gt;Played in and/or coached 18 All-Star games and 13 World Series&lt;/li&gt;
    &lt;li&gt;Played for the Yankees and Mets and won the American League MVP award 3 times over 19 years of play&lt;/li&gt;
    &lt;li&gt;Went on to coach the Yankees and Mets for 20 more years&lt;/li&gt;
    &lt;li&gt;Were inducted in to the Baseball Hall of Fame&lt;/li&gt;
    &lt;li&gt;Were elected by fans as 1 of 2 catchers&amp;nbsp;on the Major League Baseball All-Century Team (guess who else?)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and your entire career was lost to generations of baseball fans because of a stupid cartoon bear. The Yogi Berra quote that seems most appropriate here: &amp;quot;If the world was perfect, it wouldn't be.&amp;quot; True, Yogi. So true.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/M2jeXA52gic" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/blog/stupid-cartoon-bears/</feedburner:origLink></item><item><title>Free Alternatives to Reflector</title><link>http://feedproxy.google.com/~r/DevJourney/~3/6Mg_mQBLudE/</link><pubDate>Wed, 23 Feb 2011 12:00:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/blog/free-alternatives-to-reflector/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>8</slash:comments><category domain="http://devjourney.com/blog/">Blog</category><description>&lt;p&gt;Thanks to my friend Mike Etheridge for this news bit. A few days ago, I &lt;a target="_blank" href="http://devjourney.com/blog/red-gate-s-decision-to-commercialize-reflector/"&gt;blogged about&lt;/a&gt; Red Gate's decision to make Reflector a commercial-only product. In other words, there will be no free version of Reflector when version 7 is released in late February of 2011. The developer community responded quickly.&lt;/p&gt;&lt;p&gt;On 17 February, about a week after my blog post concerning Red Gate's decision, &lt;a target="_blank" href="http://blogs.jetbrains.com/dotnet/2011/02/resharper-6-bundles-decompiler-free-standalone-tool-to-follow/"&gt;JetBrains announced&lt;/a&gt; that they will be bundling a decompiler with ReSharper 6 after it launches. JetBrains hasn't released ReSharper 6 yet but you can get it via their &lt;a target="_blank" href="http://confluence.jetbrains.net/display/ReSharper/ReSharper+6.0+Nightly+Builds"&gt;Early Access Program&lt;/a&gt; nightly builds if you want to check it out. The decompiler looks quite good, at least the ways in which it's connected to the rest of the ReSharper suite: very well thought out and with the attention to detail that we've come to expect from the folks at JetBrains. The really good news from the announcement is that the decompiler will be unbundled and made available for free sometime after ReSharper 6 launches.&lt;/p&gt;
&lt;p&gt;Another free tool called &lt;a target="_blank" href="http://wiki.sharpdevelop.net/ilspy.ashx"&gt;ILSpy was announced&lt;/a&gt; by &lt;a target="_blank" href="http://community.sharpdevelop.net/blogs/danielgrunwald/default.aspx"&gt;Daniel Grunwald&lt;/a&gt; and &lt;a target="_blank" href="http://community.sharpdevelop.net/blogs/dsrbecky/default.aspx"&gt;David Srbecky&lt;/a&gt; on the &lt;a target="_blank" href="http://wiki.sharpdevelop.net/MainPage.ashx"&gt;SharpDevelop Wiki&lt;/a&gt; on 22 February. They claim that ILSpy development began after Red Gate's announcement just a few weeks ago which is somewhat amazing to me given the richness of what ILSpy can do in this initial release. A quick peek at &lt;a target="_blank" href="https://github.com/icsharpcode/ILSpy"&gt;the source code to ILSpy on github&lt;/a&gt;&amp;nbsp;shows that they are using the&amp;nbsp;&lt;a target="_blank" href="http://www.mono-project.com/Cecil"&gt;Cecil&lt;/a&gt; (pronounced see-sil) decompiler from the mono project which explains why they've been able to achieve such a steep initial trajectory with ILSpy.&amp;nbsp;I just hope that Daniel and David can find a way to &lt;em&gt;voluntarily monetize&lt;/em&gt; their open source project in ways that Lutz Roeder (the inventor of Reflector) and Red Gate never did. A simple &amp;quot;Donate via PayPal&amp;quot; link in the About dialog would go a long way to making this tool free and technically excellent perpetually.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/6Mg_mQBLudE" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/blog/free-alternatives-to-reflector/</feedburner:origLink></item><item><title>Richmond Code Camp XI</title><link>http://feedproxy.google.com/~r/DevJourney/~3/UzSxEoibOOw/</link><pubDate>Mon, 14 Feb 2011 13:00:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/community/richmond-code-camp-11/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>0</slash:comments><category domain="http://devjourney.com/community/">Community</category><description>&lt;p&gt;Richmond Code Camp XI will be held&amp;nbsp;on May 21, 2011. If you are interested in speaking at RCC XI, complete and submit &lt;a target="_blank" href="http://codecamp.wufoo.com/forms/richmond-code-camp-20111-speaker-submissions/"&gt;this form&lt;/a&gt;. You can also register as an attendee &lt;a target="_blank" href="http://richmondcodecamp.eventbrite.com/"&gt;here&lt;/a&gt;. Spread the word and direct people here for more information, please. Submitted talks should be geared to 75 minute-long slots. We expect to offer 50 of these talks during this one-day event.&lt;/p&gt;
&lt;p&gt;Richmond Code Camp is Microsoft-&lt;em&gt;leaning&lt;/em&gt; because it is, after all, a .NET Code Camp. However, we will accept talks that are not Microsoft-oriented, especially if they compare and contrast other technologies against Microsoft&amp;rsquo;s platform in an objective way.&amp;nbsp;Talks on security, language trends and techniques, emerging technologies, software development methodologies and communication frameworks are always popular, regardless of vendor. For whatever reason, we seem to be perpetually in need of more and deeper database-themed talks in particular, especially around database architecture, data modeling and business intelligence. We are also open to great talks on IT Pro (system administration &amp;amp; networking) topics, too.
&lt;p&gt;For speakers, here are some tips for getting your talk selected:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Give it a twist: something unique that will both attract &lt;em&gt;campers&lt;/em&gt;&amp;nbsp;&lt;strong&gt;and &lt;/strong&gt;promises to hold their interest for 75 minutes&lt;/li&gt;
    &lt;li&gt;Use a short, concise title that has marketing &lt;em&gt;punch&lt;/em&gt;; don't get too &lt;em&gt;cute&lt;/em&gt; when naming your talk&lt;/li&gt;
    &lt;li&gt;Make it relevant to work that people need to accomplish or to skills that people want to develop&lt;/li&gt;
    &lt;li&gt;In the abstract, sell your talk as conversational and code-focused&lt;/li&gt;
    &lt;li&gt;In the abstract, also let people know why you are qualified to be speaking about the topic&lt;/li&gt;
    &lt;li&gt;People don&amp;rsquo;t read bios as deeply as they do the abstracts so sell yourself in as few words as possible&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is our 11th Code Camp in Richmond as the name implies and we are expect attendance to be over 400 for this one-day, free event. Free WiFi, great parking, free breakfast, lunch and snacks. Great giveaways from our contributors. And we are known for hosting a really fun, totally gratis speaker dinner on the Friday evening before the Code Camp. Don't miss that! We expect to have our speakers and topics selected by April 1st so get your talks submitted soon. Directions to the campus and the selected topics list will be available on the &lt;a target="_blank" href="http://richmondcodecamp.org/"&gt;official Richmond Code Camp site&lt;/a&gt; after April 1st.&lt;/p&gt;
&lt;p&gt;Please remember to tell a few friends and colleagues about the Richmond Code Camp. Our number one complaint is that there are too many great talks. Bring tech-savvy friends and co-workers to divide and conquer! Thanks.&lt;/p&gt;
&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/UzSxEoibOOw" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/community/richmond-code-camp-11/</feedburner:origLink></item><item><title>Red Gate's Decision to Commercialize Reflector</title><link>http://feedproxy.google.com/~r/DevJourney/~3/WIHQ8jhiPXk/</link><pubDate>Wed, 09 Feb 2011 22:30:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/blog/red-gate-s-decision-to-commercialize-reflector/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>4</slash:comments><category domain="http://devjourney.com/blog/">Blog</category><description>&lt;p&gt;Red Gate's Co-CEO Neil Davidson announced in February 2011 that they would be making version 7 of the venerable Reflector product commercial-only. My thoughts are captured in this blog post and I hope that you'll take the opportunity to offer your insights and opinions as well.&lt;/p&gt;&lt;p&gt;When Neil made &lt;a target="_blank" href="http://www.red-gate.com/products/dotnet-development/reflector/announcement"&gt;the announcement&lt;/a&gt;, there was a lot of traffic on the Twittersphere about what the decision means to the .NET developer community. Most of what I saw was fairly negative. It seems that #2&amp;nbsp;on Scott Hanselman's &lt;a target="_blank" href="http://www.hanselman.com/blog/ScottHanselmans2007UltimateDeveloperAndPowerUsersToolListForWindows.aspx"&gt;Big Ten Life and Work-Changing Utilities&lt;/a&gt; was presumed by many to be a perpetually free utility with perpetual updates to deal with language changes, Framework revisions&amp;nbsp;and CLR changes, of course. Reflector also appeared prominently in James Avery's MSDN Magazine article entitled &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/magazine/cc300497.aspx"&gt;Ten Must-Have Tools That Every Developer Should Download Now&lt;/a&gt;. In that article, James says of his example, &amp;quot;it does not represent what I consider to be the best use of .NET Reflector, which is to examine .NET Framework assemblies and methods&amp;quot; which brings me around to my opinion on the subject.&lt;/p&gt;
&lt;p&gt;Since&amp;nbsp;2008, Microsoft has opened up much of the .NET Framework Class Library (FCL) source via the &lt;a target="_blank" href="http://support.microsoft.com/kb/319037/en-us"&gt;Microsoft Symbol Server&lt;/a&gt;. Setting up the symbol server in Visual Studio lets you literally step into Microsoft's code for much of the FCL. Of course, not everything's available but I've stepped into Microsoft's code hundreds, maybe thousands of times over the past few years and found what I needed at least 99 percent of the time. In 2007, if James was correct that the best use of Reflector is to examine (really to reverse engineer) .NET Framework assemblies and methods, how important is Reflector in a world where Microsoft's Framework code is simple to obtain, especially in the context of a debugger where parameters, results and side-effects can be evaluated as they occur? My opinion is that Reflector isn't all that useful anymore.&lt;/p&gt;
&lt;p&gt;My co-author of Metaprogramming in .NET, Jason Bock, and I were discussing the impact of Red Gate's decision on our book. Jason summed up the impact on him pretty well when he said to me, &amp;quot;To be honest, I really don't use it that much anymore. Decompiling code isn't something I need to do a lot of.&amp;quot; That's pretty telling coming from a hard-core metaprogrammer like Jason. If he doesn't need Reflector, who does? At my company, &lt;a target="_blank" href="http://www.captechconsulting.com/"&gt;CapTech Consulting&lt;/a&gt;, there was a lively discussion of the topic on one of our internal Microsoft-oriented mailing lists. Darrell Norton, a fellow Microsoft MVP and all-around genius, quickly reached the same conclusion that I did. When I can step into most of Microsoft's code, why do I need to disassemble it? David Catherman, another of my colleagues also offered up a tool called&amp;nbsp;&lt;a target="_blank" href="http://karlshifflett.wordpress.com/mole-for-visual-studio/"&gt;Mole by Karl Shifflett&lt;/a&gt; as an alternative to Reflector. I haven't used it yet but it looks very useful. I wish I had time to run down all the cool stuff I hear about. I'll put Mole in position 487 of the cool things I need to check out for now.&lt;/p&gt;
&lt;p&gt;In closing, I should say that my reckoning about Reflector's usefulness has nothing to do with the company Red Gate. Anyone who knows me knows that I just love Red Gate products. I use them at work every day and honestly, I just can't imagine doing my job without them. My work would be half as fulfilling and take me ten times longer to do it if it weren't for the &lt;a target="_blank" href="http://www.red-gate.com/products/sql-development/sql-toolbelt/"&gt;SQL Toolbelt&lt;/a&gt; and the &lt;a target="_blank" href="http://www.red-gate.com/products/dotnet-development/dotnet-developer-bundle/"&gt;.NET Developer Bundle&lt;/a&gt; products. When my clients see me using these tools, they're typically shocked with the kind of productivity I can achieve. They often buy the tools for their own staffs and I don't even get any kind of kick-back from Red Gate. Note to self... Besides being thoroughly conceived from a design perspective, the Red Gate tools are rock solid performers on the job, too. And when I have a problem, the &lt;a target="_blank" href="http://www.red-gate.com/messageboard/"&gt;online support forums&lt;/a&gt; are a good way to get the information I need. The Red Gate support staff are really good at monitoring the forums and responding with thorough and helpful responses. By making Reflector 7 a fully commercial product, perhaps we'll see that famous Red Gate&amp;nbsp;support and attention-to-detail start to shine through with features that make it more than just a good tool for disassembling Microsoft's Framework assemblies. For $35 US, it will most likely be a bargain, given Red Gate's track record. That's my opinion, anyhow. And if you don't want to spend the $35, try Mole or set up the Microsoft Symbol Server in Visual Studio to see what kind of utility you get out of those solutions.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/WIHQ8jhiPXk" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/blog/red-gate-s-decision-to-commercialize-reflector/</feedburner:origLink></item><item><title>Using T4 to Generate SQL Merge Scripts</title><link>http://feedproxy.google.com/~r/DevJourney/~3/2KgPL5wc5iY/</link><pubDate>Tue, 08 Feb 2011 17:30:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/blog/using-t4-to-generate-sql-merge-scripts/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>2</slash:comments><category domain="http://devjourney.com/blog/">Blog</category><description>&lt;p&gt;In the forthcoming book that Jason Bock and I are working on called Metaprogramming in .NET, we cover a lot of code generation techniques. Unfortunately, we weren&amp;rsquo;t able to fit a full chapter into the first version of the book concerning Microsoft&amp;rsquo;s Text Template Transformation Toolkit (T4) so I&amp;rsquo;ll dedicate some blog posts to the topic instead. In this post, I&amp;rsquo;ll show you how to use T4 to generate MERGE scripts in T-SQL.&lt;/p&gt;&lt;p&gt;The following T4 script requires that the Microsoft SQL Server 2008 (or 2005) SQL Management Objects (SMO) assemblies are installed in the Global Assembly Cache (GAC). It also assumes that I have the Northwind database installed in my &amp;ldquo;(local)&amp;rdquo; instance of SQL server and that there&amp;rsquo;s another instances called ReplicatedNorthwind. The idea here is that I&amp;rsquo;m going to use a T4 script to generate T-SQL code that uses the MERGE statement to &amp;ldquo;upsert&amp;rdquo; data from the Northwind Products table to the ReplicatedNorthwind Products table. Changed records will be updated. New records will be inserted and those records deleted from the source will also be deleted from the target. T-SQL&amp;rsquo;s MERGE statement wraps all this functionality up into a one logical operation:&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s look at the T4 script. If you're reading this directly on my blog (not via syndication), you can double-click the code and copy it with Ctrl-C:&lt;/p&gt;
&lt;pre class="brush: plain" translate="no"&gt;
&amp;lt;#@ template language=&amp;quot;C#&amp;quot; #&amp;gt;
&amp;lt;#@ output extension=&amp;quot;SQL&amp;quot;#&amp;gt;
&amp;lt;#@ assembly name=&amp;quot;Microsoft.SqlServer.Smo&amp;quot; #&amp;gt;
&amp;lt;#@ assembly name=&amp;quot;Microsoft.SqlServer.ConnectionInfo&amp;quot; #&amp;gt;
&amp;lt;#@ assembly name=&amp;quot;Microsoft.SqlServer.Management.Sdk.Sfc&amp;quot; #&amp;gt;
&amp;lt;#@ import namespace=&amp;quot;Microsoft.SqlServer.Management.Smo&amp;quot; #&amp;gt;
&amp;lt;#
  string serverName = &amp;quot;(local)&amp;quot;;
  string sourceDbName = &amp;quot;Northwind&amp;quot;;
  string targetDbName = &amp;quot;ReplicatedNorthwind&amp;quot;;
  string schemaName = &amp;quot;dbo&amp;quot;;
  string entityName = &amp;quot;Products&amp;quot;;

  Server server = new Server(serverName);
  Database targetDatabase = new Database(server, targetDbName);
  Table targetTable = new Table(targetDatabase, entityName, schemaName);
  targetTable.Refresh();

  int index = 0;
#&amp;gt;
BEGIN TRANSACTION;
BEGIN TRY
MERGE [&amp;lt;#= targetDbName #&amp;gt;].[&amp;lt;#= schemaName #&amp;gt;].[&amp;lt;#= entityName #&amp;gt;] AS [Target]
  USING [&amp;lt;#= sourceDbName #&amp;gt;].[&amp;lt;#= schemaName #&amp;gt;].[&amp;lt;#= entityName #&amp;gt;] AS [Source]
    ON
    (
      /* join on the primary key column(s) */
&amp;lt;#
  PushIndent(&amp;quot;\t\t\t&amp;quot;);
  index = 0;
  foreach (Column column in targetTable.Columns)
  {
    if (column.InPrimaryKey)
    {
      if (index &amp;gt; 0)
        Write(&amp;quot;AND &amp;quot;);
      WriteLine(&amp;quot;[Target].[&amp;quot; + column.Name + &amp;quot;] = [Source].[&amp;quot; + column.Name + &amp;quot;]&amp;quot;);
      index++;
    }
  }
  PopIndent();
#&amp;gt;
    )
  WHEN MATCHED
    AND
    (
      /* and compare all non-key column(s) for inequality */
&amp;lt;#
  PushIndent(&amp;quot;\t\t\t&amp;quot;);
  // This compares all the values to look for update-ability
  // which can slow down the merge. If you have an update date
  // or something like it in your schema, you can check for its
  // existence here and use that to make the merge efficient.
  index = 0;
  foreach (Column column in targetTable.Columns)
  {
    if (!column.InPrimaryKey)
    {
      if (index &amp;gt; 0)
        Write(&amp;quot;OR &amp;quot;);
      WriteLine(&amp;quot;[Target].[&amp;quot; + column.Name + &amp;quot;] &amp;lt;&amp;gt; [Source].[&amp;quot; + column.Name + &amp;quot;]&amp;quot;);
      index++;
    }
  }
  PopIndent();
#&amp;gt;
    )
    THEN UPDATE SET
&amp;lt;#
  PushIndent(&amp;quot;\t\t\t&amp;quot;);
  index = 0;
  foreach (Column column in targetTable.Columns)
  {
    if (!column.InPrimaryKey)
    {
      if (index &amp;gt; 0)
        Write(&amp;quot;, &amp;quot;);
      WriteLine(&amp;quot;[Target].[&amp;quot; + column.Name + &amp;quot;] = [Source].[&amp;quot; + column.Name + &amp;quot;]&amp;quot;);
      index++;
    }
  }
  PopIndent();
#&amp;gt;
  WHEN NOT MATCHED BY TARGET
    THEN INSERT
    (
&amp;lt;#
  PushIndent(&amp;quot;\t\t\t&amp;quot;);
  index = 0;
  foreach (Column column in targetTable.Columns)
  {
    if (index &amp;gt; 0)
      Write(&amp;quot;, &amp;quot;);
    WriteLine(&amp;quot;[&amp;quot; + column.Name + &amp;quot;]&amp;quot;);
    index++;
  }
  PopIndent();
#&amp;gt;
    )
    VALUES
    (
&amp;lt;#
  PushIndent(&amp;quot;\t\t\t&amp;quot;);
  index = 0;
  foreach (Column column in targetTable.Columns)
  {
    if (index &amp;gt; 0)
      Write(&amp;quot;, &amp;quot;);
    WriteLine(&amp;quot;[Source].[&amp;quot; + column.Name + &amp;quot;]&amp;quot;);
    index++;
  }
  PopIndent();
#&amp;gt;
    )
  WHEN NOT MATCHED BY SOURCE
    /* are you sure you want to delete? */
    /* this could be converted to a logical delete */
    /* by using an update on the target instead */
    THEN DELETE
  OUTPUT
    $action AS [Operation]
&amp;lt;#
  PushIndent(&amp;quot;\t\t&amp;quot;);
  foreach (Column column in targetTable.Columns)
  {
    if (column.InPrimaryKey)
      WriteLine(&amp;quot;, Inserted.[&amp;quot; + column.Name + &amp;quot;] AS [Merged&amp;quot; + column.Name + &amp;quot;]&amp;quot;);
  }
  PopIndent();
#&amp;gt;
&amp;lt;#
  PushIndent(&amp;quot;\t\t&amp;quot;);
  index = 0;
  foreach (Column column in targetTable.Columns)
  {
    if (index &amp;gt; 0)
      WriteLine(&amp;quot;&amp;quot;);
    if (column.InPrimaryKey)
      Write(&amp;quot;, Deleted.[&amp;quot; + column.Name + &amp;quot;] AS [Deleted&amp;quot; + column.Name + &amp;quot;]&amp;quot;);
  }
  WriteLine(&amp;quot;;&amp;quot;);
  PopIndent();
#&amp;gt;
END TRY
BEGIN CATCH
  IF @@TRANCOUNT &amp;gt; 0
  BEGIN
    ROLLBACK TRANSACTION;
    PRINT N'The transaction was rolled back because the merge failed.';
  END
  PRINT N'Error number = ' + CONVERT(NCHAR(10),ERROR_NUMBER());
  PRINT N'Error severity = ' + CONVERT(NCHAR(10),ERROR_SEVERITY());
  PRINT N'Error state = ' + CONVERT(NCHAR(10),ERROR_STATE());
  PRINT N'Error procedure = ' + ERROR_PROCEDURE();
  PRINT N'Error line = ' + CONVERT(NCHAR(10),ERROR_LINE());
  PRINT N'Error message = ' + ERROR_MESSAGE();
END CATCH

IF @@TRANCOUNT &amp;gt; 0
BEGIN
  COMMIT TRANSACTION;
  PRINT N'The transaction was committed with no errors.';
END&lt;/pre&gt;
&lt;p&gt;In the pre-amble, I specified that C# will be the scripting language and that we&amp;rsquo;re going to emit SQL code from it. Next, some assembly directives are used to load referenced assemblies into the script generator&amp;rsquo;s context. The three (3) SMO assemblies referenced here are expected to be in the GAC but they could optionally be placed in the script engine&amp;rsquo;s private assembly path, too. In a future post, I&amp;rsquo;ll show you how to resolve assemblies in a much more predictable way. For now, let&amp;rsquo;s depend on the GAC.&lt;/p&gt;
&lt;p&gt;Next comes an import directive. This is akin to the Import keyword in Visual Basic or the using &lt;em&gt;declaration&lt;/em&gt; in C#. Notice that I said using declaration, not using statement because in C# the using keyword can be used in both ways. A using declaration in C# is used to import the objects from a specified namespace. And that&amp;rsquo;s what I&amp;rsquo;m asking T4&amp;rsquo;s scripting engine to do here. I want to import the Microsoft.SqlServer.Management.Smo namespace for use throughout the script that follows.&lt;/p&gt;
&lt;p&gt;The remainder of the script is T-SQL code with bits of C# script sprinkled about using &amp;lt;# (or &amp;lt;#=) and #&amp;gt; tags. T4&amp;rsquo;s scripting engine will compile and execute the script from top to bottom, injecting literal T-SQL text and evaluating the C# expressions and injecting their output as well. The output, which shows up under the TT file in Visual Studio&amp;rsquo;s Solution Explorer looks like this:&lt;/p&gt;
&lt;pre class="brush: sql" translate="no"&gt;
BEGIN TRANSACTION;
BEGIN TRY
MERGE [ReplicatedNorthwind].[dbo].[Products] AS [Target]
  USING [Northwind].[dbo].[Products] AS [Source]
    ON
    (
      /* join on the primary key column(s) */
      [Target].[ProductID] = [Source].[ProductID]
    )
  WHEN MATCHED
    AND
    (
      /* and compare all non-key column(s) for inequality */
      [Target].[ProductName] &amp;lt;&amp;gt; [Source].[ProductName]
      OR [Target].[SupplierID] &amp;lt;&amp;gt; [Source].[SupplierID]
      OR [Target].[CategoryID] &amp;lt;&amp;gt; [Source].[CategoryID]
      OR [Target].[QuantityPerUnit] &amp;lt;&amp;gt; [Source].[QuantityPerUnit]
      OR [Target].[UnitPrice] &amp;lt;&amp;gt; [Source].[UnitPrice]
      OR [Target].[UnitsInStock] &amp;lt;&amp;gt; [Source].[UnitsInStock]
      OR [Target].[UnitsOnOrder] &amp;lt;&amp;gt; [Source].[UnitsOnOrder]
      OR [Target].[ReorderLevel] &amp;lt;&amp;gt; [Source].[ReorderLevel]
      OR [Target].[Discontinued] &amp;lt;&amp;gt; [Source].[Discontinued]
    )
    THEN UPDATE SET
      [Target].[ProductName] = [Source].[ProductName]
      , [Target].[SupplierID] = [Source].[SupplierID]
      , [Target].[CategoryID] = [Source].[CategoryID]
      , [Target].[QuantityPerUnit] = [Source].[QuantityPerUnit]
      , [Target].[UnitPrice] = [Source].[UnitPrice]
      , [Target].[UnitsInStock] = [Source].[UnitsInStock]
      , [Target].[UnitsOnOrder] = [Source].[UnitsOnOrder]
      , [Target].[ReorderLevel] = [Source].[ReorderLevel]
      , [Target].[Discontinued] = [Source].[Discontinued]
  WHEN NOT MATCHED BY TARGET
    THEN INSERT
    (
      [ProductID]
      , [ProductName]
      , [SupplierID]
      , [CategoryID]
      , [QuantityPerUnit]
      , [UnitPrice]
      , [UnitsInStock]
      , [UnitsOnOrder]
      , [ReorderLevel]
      , [Discontinued]
    )
    VALUES
    (
      [Source].[ProductID]
      , [Source].[ProductName]
      , [Source].[SupplierID]
      , [Source].[CategoryID]
      , [Source].[QuantityPerUnit]
      , [Source].[UnitPrice]
      , [Source].[UnitsInStock]
      , [Source].[UnitsOnOrder]
      , [Source].[ReorderLevel]
      , [Source].[Discontinued]
    )
  WHEN NOT MATCHED BY SOURCE
    /* are you sure you want to delete? */
    /* this could be converted to a logical delete */
    /* by using an update on the target instead */
    THEN DELETE
  OUTPUT
    $action AS [Operation]
    , Inserted.[ProductID] AS [MergedProductID]
    , Deleted.[ProductID] AS [DeletedProductID];
END TRY
BEGIN CATCH
  IF @@TRANCOUNT &amp;gt; 0
  BEGIN
    ROLLBACK TRANSACTION;
    PRINT N'The transaction was rolled back because the merge failed.';
  END
  PRINT N'Error number = ' + CONVERT(NCHAR(10),ERROR_NUMBER());
  PRINT N'Error severity = ' + CONVERT(NCHAR(10),ERROR_SEVERITY());
  PRINT N'Error state = ' + CONVERT(NCHAR(10),ERROR_STATE());
  PRINT N'Error procedure = ' + ERROR_PROCEDURE();
  PRINT N'Error line = ' + CONVERT(NCHAR(10),ERROR_LINE());
  PRINT N'Error message = ' + ERROR_MESSAGE();
END CATCH

IF @@TRANCOUNT &amp;gt; 0
BEGIN
  COMMIT TRANSACTION;
  PRINT N'The transaction was committed with no errors.';
END&lt;/pre&gt;
&lt;p&gt;If you have a Northwind database locally and another database locally named ReplicatedNorthwind that contains a Products table with the correct schema, the resulting SQL script will merge changes that occur in the Northwind Products table to the other table. Try inserting a product, updating a product and deleting a product in the source Products table and running the merge script. You&amp;rsquo;ll see that all three (3) changes are detected and executed for you to synchronize the tables. If you don&amp;rsquo;t have Northwind databases handy, try modifying the T4 script to work with two other databases of your choosing instead. The only real requirement is that the target table&amp;rsquo;s schema has to be a subset of the source table&amp;rsquo;s schema to function correctly.&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t dig into all the particulars of how T-SQL MERGE works. It&amp;rsquo;s a fairly clean syntax and there are plenty of resources on the net for learning about that. What I wanted to make clear in this post is how simple the code generation process is when using T4. You can see how simple it is to iterate over the targetTable.Columns collection and evaluate each Column object&amp;rsquo;s InPrimaryKey property to build up the MERGE statement.&lt;/p&gt;
&lt;p&gt;In my next post concerning the T4 code generator, I&amp;rsquo;ll show you how to pass parameters to the T4 script by implementing the ITextTemplatingEngineHost and ITextTemplatingSessionHost interfaces. In that post, I'll build one metaprogramming technique on another to create a customized script generator that can generically MERGE one entire database to another.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/2KgPL5wc5iY" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/blog/using-t4-to-generate-sql-merge-scripts/</feedburner:origLink></item><item><title>Metaprogramming in the .NET Micro Framework</title><link>http://feedproxy.google.com/~r/DevJourney/~3/Wb7RZiDEUsY/</link><pubDate>Sun, 06 Feb 2011 04:45:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/blog/metaprogramming-in-the-dotnet-micro-framework/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>2</slash:comments><category domain="http://devjourney.com/blog/">Blog</category><description>&lt;p&gt;Metaprogramming capability has been in the .NET Framework since day 1. So it&amp;rsquo;s no surprise that the .NET Micro Framework has some basic metaprogramming capabilities, too. Most of the introductory examples you see for working in the .NET Micro Framework involve blinking an LED. So, why not blink out &amp;ldquo;Hello world&amp;rdquo; on an LED in Morse code? And because we can, why not do it in metaprogramming style?&lt;/p&gt;&lt;p&gt;The basic metaprogamming functionality that we&amp;rsquo;ll take advantage of in this little application is the multicast delegate. &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Morse_code"&gt;Morse code&lt;/a&gt; letters can be expressed as a series of dots and dashes. The dots are short signals that are 1/3 the length of the dashes. And there are rules for intra-letter spacing, intra-word spacing and extra-word spacing. The word &amp;ldquo;HELLO&amp;rdquo; might be expressed as four dots or &amp;ldquo;....&amp;rdquo; for H, a single dot &amp;ldquo;.&amp;rdquo; for E, the sequence &amp;ldquo;.-..&amp;rdquo; for L and so on. With the appropriate spacing in between, of course. The goal is to blink the LED on my &lt;a target="_blank" href="http://www.netduino.com"&gt;Netduino&lt;/a&gt; to emit the correct Morse code sequence for a string.&lt;/p&gt;
&lt;pre translate="no" class="brush: csharp;"&gt;
private Hashtable _letters = new Hashtable();
public Morse(OutputPort led)
{
  _letters.Add(' ', &amp;quot;*&amp;quot;);
  _letters.Add('A', &amp;quot;.-&amp;quot;);
  _letters.Add('B', &amp;quot;-...&amp;quot;);
  _letters.Add('C', &amp;quot;-.-.&amp;quot;);
  // remainder omitted for brevity
&lt;/pre&gt;
&lt;p&gt;The first step is to insert each dot-dash sequence into a dictionary keyed by each letter of the alphabet. The .NET Micro Framework 4.1 doesn&amp;rsquo;t support generic collection classes so we have to use an old-fashioned Hashtable. That&amp;rsquo;s OK because I&amp;rsquo;ll take advantage of the weak typing in the Hashtable to demonstrate memoizing my dynamic Morse code sequences in the next section. Now that I&amp;rsquo;ve got the letters and their dot-dash sequences in a dictionary, now I need some functions for the dot, dash and space parts.&lt;/p&gt;
&lt;pre translate="no" class="brush: csharp;"&gt;
private int dotLength = 200;
private void dash()
{
  _led.Write(true);
  Thread.Sleep(dotLength * 3);
  _led.Write(false);
}

private void dot()
{
  _led.Write(true);
  Thread.Sleep(dotLength);
  _led.Write(false);
}

private void intraletterspace()
{
  Thread.Sleep(dotLength);
}

private void intrawordspace()
{
  Thread.Sleep(dotLength * 3);
}

private void extrawordspace()
{
  // this is actually 7 but we'll borrow
  // the intraword space from the end of
  // the last word
  Thread.Sleep(dotLength * 4);
}

public delegate void seq();
&lt;/pre&gt;
&lt;p&gt;Notice the seq delegate type declared here? The various dot, dash and space functions shown here will be assembled into a seq delegate depending on their formulations found in the _letters Hashtable. The function to do the conversion from string to multicast delegate looks like:&lt;/p&gt;
&lt;pre translate="no" class="brush: csharp;"&gt;
private seq ConvertToDelegate(string letterSeq)
{
  seq del = null;
  bool addIntraWordSpace = true;
  foreach (char c in letterSeq.ToCharArray())
  {
    switch (c)
    {
      default:
        break;
      case '*':
        del += extrawordspace;
        addIntraWordSpace = false;
        break;
      case '.':
        if (del == null)
          del = dot;
        else
        {
          del += intraletterspace;
          del += dot;
        }
        break;
      case '-':
        if (del == null)
          del = dash;
        else
        {
          del += intraletterspace;
          del += dash;
        }
        break;
    }
  }
  if (addIntraWordSpace)
    del += intrawordspace;
  return del;
}
&lt;/pre&gt;
&lt;p&gt;The conversion function evaluates each dot, dash or space in the source string and assembles a seq delegate that invokes each of the appropriate functions in order. Isn&amp;rsquo;t metaprogramming fun? We&amp;rsquo;re actually treating each symbol in the string like an instruction in a little programming language and converting them into function calls. The delegate type, which is really a MulticastDelegate from the Framework, does all the hard work. When we use the += operator to add a new function call, the MulticastDelegate adds a new function to the list of those to be invoked. The last step is to invoke the sequences as letters are encountered in a source string like &amp;ldquo;Hello world&amp;rdquo;.&lt;/p&gt;
&lt;pre translate="no" class="brush: csharp;"&gt;
public void Emit(string text)
{
  if (text == null)
    return;
  text = text.Trim().ToUpper();
  if (text.Length == 0)
    return;

  foreach (char c in text.ToCharArray())
  {
    char actual = c;
    if (!_letters.Contains(c))
      actual = ' ';
    object s = _letters[actual];
    if (s is string)
    {
      // memoize the multicast delegate for each letter
      _letters[actual] = s = ConvertToDelegate(s as string);
    }
    (s as seq)();
  }
}
&lt;/pre&gt;
&lt;p&gt;The code is simple enough. It just iterates over the characters in an input string, converts the associated sequence characters to seq delegates and invokes them. However, like any good metaprogramming application, we always look for chances to optimize the code generation steps. They are the most expensive so caching the results of our little &amp;ldquo;dot-dash compiler&amp;rdquo; is really important. The weak typing of the Hashtable makes this easy enough. When a new letter is encountered during emission of the phrase, it&amp;rsquo;s compiled into a seq delegate and cached in the Hashtable in place of the original string (source code) that was used to create it. A bit of reflection is used to determine whether or not the object in the value part of the Hashtable is a string (my dot-dash style source code) or a seq delegate that can actually be invoked to flash the LED on my Netduino. Once a letter has been compiled, it never has to be compiled again while the application is running.&lt;/p&gt;
&lt;p&gt;The single C# source code file for this fun, little application can be &lt;a target="_blank" href="http://devjourney.com/files/media/file/MorseCode.zip"&gt;downloaded here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/Wb7RZiDEUsY" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/blog/metaprogramming-in-the-dotnet-micro-framework/</feedburner:origLink></item><item><title>Common Table Expression Recursion</title><link>http://feedproxy.google.com/~r/DevJourney/~3/1oMyhPiJj6Y/</link><pubDate>Wed, 02 Feb 2011 03:00:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/blog/common-table-expression-recursion/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>0</slash:comments><category domain="http://devjourney.com/blog/">Blog</category><description>&lt;p&gt;I like using recursion when it helps to make an algorithm clearer. That's not always the case though. For many developers, recursion is difficult to understand. So I'm always on the hunt for code samples that make recursion easier to understand. One good example of this can be found in traversing the foriegn keys in a database using&amp;nbsp;a SQL Server Common Table Expression (CTE).&lt;/p&gt;&lt;p&gt;When I load data into a database, I'd like to know the order I must use to load the tables. Some tables will be at Level Zero (0). Those are the ones that have no dependencies on other tables. They're typically type tables that contain reference data and they&amp;nbsp;can be loaded at any time&amp;nbsp;because&amp;nbsp;they have no&amp;nbsp;foreign keys in them. The next level, Level One (1), are those tables that depend on the Level Zero (0) tables. And so on, and so on. If I knew the load order, my Extract, Transform and Load (ETL) packages could be scripted to run level by level starting at Level Zero (0). A Common Table Expression (CTE) can be used to find that load order using recursion. Let's look at the code first, then I'll describe it.&lt;/p&gt;
&lt;pre class="brush: sql" translate="no"&gt;
WITH
[key_info] AS
(
  SELECT
    OBJECT_SCHEMA_NAME([sfk].[parent_object_id]) AS [from_schema]
    , OBJECT_NAME([sfk].[parent_object_id]) AS [from_table]
    , OBJECT_SCHEMA_NAME([sfk].[referenced_object_id]) AS [to_schema]
    , OBJECT_NAME([sfk].[referenced_object_id]) AS [to_table]
  FROM [sys].[foreign_keys] AS [sfk]
  WHERE [sfk].[parent_object_id] &amp;lt;&amp;gt; [sfk].[referenced_object_id]
)
, [level_info] AS 
(
  -- the anchor part
  SELECT
    [ss].[name] AS [SchemaName]
    , [st].[name] AS [TableName]
    , 0 AS [ReferenceLevel]
  FROM [sys].[tables] AS [st]
  INNER JOIN [sys].[schemas] AS [ss]
    ON [st].[schema_id] = [ss].[schema_id]
  LEFT OUTER JOIN [key_info] AS [ki]
    ON [ss].[name] = [ki].[from_schema]
      AND [st].[name] = [ki].[from_table]
  WHERE [ki].[from_schema] IS NULL

  UNION ALL

  -- the recursive part
  SELECT
    [ki].[from_schema]
    , [ki].[from_table]
    , [li].[ReferenceLevel] + 1
  FROM [key_info] AS [ki]
  INNER JOIN [level_info] AS [li]
    ON [ki].[to_schema] = [li].[SchemaName]
      AND [ki].[to_table] = [li].[TableName]
)
SELECT
  [li].[SchemaName]
  , [li].[TableName]
  , MAX([li].[ReferenceLevel]) AS [LoadLevel]
FROM [level_info] AS [li]
GROUP BY [li].[SchemaName], [li].[TableName]
ORDER BY MAX([li].[ReferenceLevel]), [li].[TableName];
&lt;/pre&gt;
&lt;p&gt;The WITH statement kicks off the CTE by establishing two data elements that will be used later on. The first one is called [key_info] and it's just a dump of the foreign keys in the database, capturing parent (from)&amp;nbsp;tables to referenced (to) tables. Care must be taken not to include those keys that refer back to the same table. We don't need them for discovering the load levels and they will cause the recursion to become infinite. More on that in a moment.&lt;/p&gt;
&lt;p&gt;The [key_info] part of the WITH statement isn't recursive but the next part named [level_info] is. You can tell it's a recursive CTE by finding the UNION ALL statement in the middle of the [level_info] definition. The part of the query before the UNION ALL is called the anchor part. The part following it is the recursive part. The anchor part of [level_info] builds a list of schemas and tables then LEFT OUTER JOINs them to the [key_info]&amp;nbsp;using the parent (from) side of the keys. The trick to understanding this is in realizing (A) that it's a LEFT OUTER JOIN to the key data and that (B) it uses a WHERE clause that includes only those tables with&amp;nbsp;NULL keys on the parent (from) side of the LEFT OUTER JOIN. In other words, I'm including only those tables that have no foreign key references. Also notice how the [ReferenceLevel] is hard-coded to zero (0) in this anchor part? These are our Level Zero (0) tables: the ones that can be loaded at any time because they don't depend on anything else.&lt;/p&gt;
&lt;p&gt;After the anchor part establishes the Level Zero (0) tables, the recursive part below the UNION ALL finishes the job. SQL will execute the recursive part over and over again until no new data is unioned in to the results. That's how it knows when to stop so it's important to make sure that you write the recursive part in such a way that it will actually finish. Had we included self-referencing (same table) keys in the [key_info], we'd have&amp;nbsp;had a real problem getting the recursive part to finish.&lt;/p&gt;
&lt;p&gt;The recursive part&amp;nbsp;of this query&amp;nbsp;will finish because the referenced (to) values in the [key_info] are joined with&amp;nbsp;the schema&amp;nbsp;and table combinations in [level_info] from the&amp;nbsp;last recursion pass (or the anchor results if it's the first call to the recursive part, of course). Joining on the referenced (to) side of the key is important because we want to find all the tables already in the [level_info] list that have references &amp;quot;to&amp;quot; them. Then, in the [level_info] data&amp;nbsp;in this&amp;nbsp;pass,&amp;nbsp;we capture the parent (from) data on the matches and increment the [ReferenceLevel]&amp;nbsp;to one greater than the last known value. This could result in the same schema/table combination being included in the recursive results more than once, potentially at different levels. But that's OK. We take care of the duplicates in the last part of the query.&lt;/p&gt;
&lt;p&gt;Following the CTE that does all the recursive work is the consumption part of the query. It can be a SELECT statement or an INSERT that selects from the CTE as its source. In this case, we simply select out the data, grouping by the schema and table name and picking off the MAX([ReferenceLevel]). It's important to pick the maximum reference level that was recorded for any table because it may refererence tables at varying load levels. As an example, imagine a table named C&amp;nbsp;that&amp;nbsp;references another&amp;nbsp;table A directly&amp;nbsp;using a foreign key.&amp;nbsp;Table C may&amp;nbsp;also reference a table named B that in turn references table A. In our ungrouped [level_info] results, Table A would appear twice: once as a Level One (1) table and again as a Level Two (2) table. We need to select the Level Two (2) row to make sure that we don't try to load table C before table B is fully loaded;&amp;nbsp;hence the use of the MAX function in the final SELECT statement.&lt;/p&gt;
&lt;p&gt;Running this query on the AdventureWorks database, for example, shows that there are eight (8) layers of data to be loaded into this database. In Level Zero (0), we find basic&amp;nbsp;lookup tables like [Person].[AddressType] and [Sales].[SalesReason]. Tables like that don't depend on anything else so they can be updated first. At the other end of the spectrum are the tables&amp;nbsp;at Level Seven (7). These are highly dependent tables like [Sales].[SalesOrderDetails] and [Sales].[SalesOrderHeaderSalesReason]. And, of course, there are dozens of tables in the six (6) layers in between. Try this query on your own databases to see what it reveals about the organization of your data. Missing foreign keys might become more apparent to you by examining the results.&lt;/p&gt;
&lt;p&gt;Hopefully, this query helps you to wrap your brain around recursion a bit better, too. Enjoy.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/1oMyhPiJj6Y" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/blog/common-table-expression-recursion/</feedburner:origLink></item><item><title>Server Side JavaScript</title><link>http://feedproxy.google.com/~r/DevJourney/~3/uS04ERCslQM/</link><pubDate>Wed, 19 Jan 2011 12:00:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/blog/server-side-javascript/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>14</slash:comments><category domain="http://devjourney.com/blog/">Blog</category><description>&lt;p&gt;I&amp;rsquo;m going to warn you that this is a rant. I just can&amp;rsquo;t take it anymore. Microsoft is a great company but there are some things going on at Microsoft these days that are very, very unsettling, in my opinion. I am going to address one of those issues in as graceful and as courteous a manner as I can muster. At a minimum, I promise not to go all Bellware on them. Here it is.&lt;/p&gt;&lt;p&gt;JavaScript is arguably the most popular programming language on planet Earth. I&amp;rsquo;m not sure what the Alpha Centaurians code in but it probably looks a lot like JavaScript, too. JavaScript isn&amp;rsquo;t perfect but it&amp;rsquo;s deliciously dynamic and declarative and just as functional as most people really desire in a general purpose programming language. I totally appreciate the great things that Microsoft is doing on the client side to make JavaScript faster, more standards (meaning jQuery) compliant and to provide better tooling. But don&amp;rsquo;t we deserve the power and flexibility of JavaScript on the server side, too?&lt;/p&gt;
&lt;p&gt;Back in the day, I coded using Server Side JavaScript (SSJS) on Netscape Web Servers running on Solaris. It wasn&amp;rsquo;t that great an experience as I recall. It was OK but the development tool support was pretty weak and the debugging story was just awful. But JavaScript has matured a lot over the past 15 years since control was handed over to ECMA. Development environment support for JavaScript is very good now, even from Microsoft which seemed to be doing everything possible to make the JavaScript experience for developers and end-users poor until a few years ago. After so much noise, I suppose they couldn't ignore us any longer. And it&amp;rsquo;s a good thing, too. Without a fast, highly-compliant scripting language in Internet Explorer 9, that browser version would be doomed to be Microsoft&amp;rsquo;s last, in my opinion. Microsoft really does&amp;nbsp;&lt;em&gt;get it&lt;/em&gt;&amp;nbsp;now about JavaScript in the browser. Hiring someone like&amp;nbsp;&lt;a target="_blank" href="http://twitter.com/reybango"&gt;Rey Bango&lt;/a&gt;&amp;nbsp;is a testament to their understanding. Microsoft simply must have an excellent JavaScript story to tell with IE9. It&amp;rsquo;s got to pass all the benchmarks and compatibility tests with the highest possible marks. And the Visual Studio integration has to be tight, especially with respect to debugging. I have no doubt that Microsoft will do everything that they need to do to make JavaScript a first-class citizen within Internet Explorer from now on.&lt;/p&gt;
&lt;p&gt;Microsoft&amp;rsquo;s JavaScript story on the server side isn&amp;rsquo;t all that rosy, however. In fact, other than a nascent, very limited version that showed up in some DLR alpha bits, there is no SSJS story from Microsoft. My repeated attempts to get Microsoft programming language product managers to engage in meaningful conversation about SSJS have fallen on deaf ears. They usually just stare at me when I say that we really need a good SSJS story as if I&amp;rsquo;m speaking Alpha Centaurian. They usually nod and say something like, &amp;ldquo;Yeah, well that&amp;rsquo;s nice but um&amp;hellip; I need to go. My little brother got his arm stuck in the microwave so my mom had to take him to the hospital&amp;hellip; And my grandmother freaked out and hijacked a busload of penguins. So, it&amp;rsquo;s kind of a family crisis. Buh-bye.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Unfortunately, this is pretty much in line with the dynamic language story that we&amp;rsquo;re seeing from Microsoft across the board. The IronPython implementation got just up to the point of near perfection and BOOM! They dropped it. I think it&amp;rsquo;s somewhat noble of Microsoft to turn support of IronPython and IronRuby over to the community as they did. They didn&amp;rsquo;t just abandon it. But let&amp;rsquo;s be honest. You don&amp;rsquo;t give control away to the community if you&amp;rsquo;re invested. The community will do good things with both of the Iron languages but some problems require a company at Microsoft&amp;rsquo;s scale to get the mindshare they need to succeed. Microsoft&amp;rsquo;s decision to give up (for all intents and purposes) on IronPython and IronRuby is just a bad business decision, in my opinion, no matter what other irons (pardon the pun) Microsoft has in the fire. I know that Microsoft has other priorities but they made a huge mistake within the developer community with those decisions.&lt;/p&gt;
&lt;p&gt;When I first met &lt;a href="http://devhawk.net/" target="_blank"&gt;Harry Pierson&lt;/a&gt; of Microsoft a few years ago, his enthusiasm for the Python language rubbed off on me. I already loved Python from having worked around the RocketMail guys many years before when I was at Intel (before the Yahoo! acquisition of RocketMail). I could tell after swapping ideas about IronPython and the DLR around for a few hours that Harry and I were kindred spirits. Harry&amp;rsquo;s love for the Python language is totally infectious. I&amp;rsquo;ve always had a penchant for dynamic languages and Python, in particular, really rung my bell, so to speak. Python&amp;rsquo;s syntax is so light and clean and fluent. There&amp;rsquo;s little or no ceremony required to get truly wonderful work done with a few lines of code. And the standard library is very rich: &amp;ldquo;Batteries Included&amp;rdquo; we say in the Python world. Best of all, Python has excellent support for my other language love affair: functional programming. So much so that when I started working with the F# language, it felt Pythonic to me. It&amp;rsquo;s no wonder that a couple of years later, &lt;a href="http://blogs.msdn.com/b/lukeh/" target="_blank"&gt;Luke Hoban&lt;/a&gt; (from Microsoft&amp;rsquo;s F# team) revealed to me that the F# programming language was deliberately designed to attract Python developers. From a statically-typed versus dynamically-typed perspective, these two languages couldn&amp;rsquo;t be more in opposition to one another. But the feel of working in F# is authentically Pythonic. And according to Luke, that feeling was embedded there quite deliberately.&lt;/p&gt;
&lt;p&gt;Recently, I&amp;rsquo;ve been thinking about the state of things in the language world. My one biggest regret is failing to tell Microsoft how important dynamic languages are to me. I blogged about IronPython a lot. I gave dozens of user group and Code Camp presentations on integrating static and dynamic languages using .NET technologies. I even have a book coming out this year called Metaprogramming in .NET from Manning that contains a hundred plus pages on the Dynamic Language Runtime and all the great metaprogramming things that can be done with it. The DLR is firmly in place in the .NET Framework so I&amp;rsquo;m not worried about that. But seeing what&amp;rsquo;s happened to IronPython and IronRuby over the past few months, I lay awake at night sometimes wondering what else I could have done to make influential fellows like&amp;nbsp;&lt;a target="_blank" href="http://weblogs.asp.net/scottgu/"&gt;Scott Guthrie&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a target="_blank" href="http://www.hanselman.com/blog/"&gt;Scott Hanselman&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a target="_blank" href="http://blogs.msdn.com/b/somasegar/"&gt;Somasegar&lt;/a&gt;&amp;nbsp;understand why they should be showing their support publicly and within Microsoft for dynamic languages. I honestly feel like I failed my developer colleagues by not being a better spokesperson for Python and Ruby on .NET. Moreover, my grief about the subject spills over into other languages that should have been. Those that could have been. Server Side JavaScript is chief among them.&lt;/p&gt;
&lt;p&gt;My reasons for wanting Server Side JavaScript running on the DLR are pretty simple. Today, I write in a multitude of &amp;ldquo;languages&amp;rdquo;: C#, F#, T-SQL, PL/SQL, JavaScript, CSS, XHTML, XSLT and a handful of other XML dialects that come in handy on occasion. It&amp;rsquo;s all too much really. As I use each of these &amp;ldquo;tools&amp;rdquo;, I ponder why they fit well for solving particular problems. Each of these languages is appropriately domain-specific which then leads me to wonder why I work in so many domains. Setting that question aside for a moment, I can&amp;rsquo;t help but think that if all the genius floating about in Microsoft&amp;rsquo;s Building 41 were aimed at creating a world-class Server Side JavaScript implementation on the DLR, we could rest our heads on our pillows at night enjoying a common language between at least two of our important domains.&lt;/p&gt;
&lt;p&gt;I imagine a world where I might write JavaScript to render an MVC application, for example. The tooling in the environment I envision is so tight that emitting JavaScript to run on either side of the &amp;ldquo;pipe&amp;rdquo; is simply a matter of choosing the correct namespace. Better still, the JavaScript I&amp;rsquo;m thinking of has a runtime engine that decides where the code should execute. On a slower connection, the engine might decide to remote some of the code to the client side to provide a better user experience. On faster connections, it might decide to generate more AJAX callbacks from the client and run more of the code on the server to speed up the application or to enhance security. Emitting minified or pre-compiled versions of types and functions in my library would also be totally invisible to me. It would be automatic. Intrinsic. Creating markup from this system would be completely integrated, too. Calling an application a web app or a desktop client would be a thing of the past. There would only be apps. Making mental distinctions about where or how code must run would seem totally foreign to developers in this environment. Code in this dream becomes pure intent: homogenized, universal and sufficiently abstracted from any implementation constraints to become properly focused on solving problems first and foremost. List comprehension and query comprehension would eventually give way to a fully declarative&amp;nbsp;&lt;em&gt;intent realization model&lt;/em&gt;, arguably the goal of any universal computer. I did say this was a dream, didn&amp;rsquo;t I?&lt;/p&gt;
&lt;p&gt;I know it may sound crazy. Some of the things I envision probably won&amp;rsquo;t be achieved in my lifetime. But think for a moment about the kinds of innovations that would come out of the process if the languages team at Microsoft utterly embraced JavaScript on the server side. Think about the developer experience they would craft in Visual Studio. It would be no less than stunning. Think about the editor and debugger and designer experiences. Imagine how IIS would evolve to support such a unified JavaScript execution model. Ponder for a moment how the JavaScript language itself might evolve if Microsoft put all of their mental and marketplace muscle behind it as both a server and client language of choice. Over time, languages like Python and Ruby would actually suffer from that kind of dedication as developers flocked to JavaScript as the common language on both sides of the average Internet connection. Silverlight, as much as I admire it for what it needs to be in 2011, would simply evaporate if my vision were to become real. And in that sort of scenario, Silverlight&amp;rsquo;s retirement wouldn&amp;rsquo;t be seen as a bad thing at all. Rather, it would just be a natural part of the evolution toward a better, more unified web for everyone.&lt;/p&gt;
&lt;p&gt;&lt;a target="_blank" href="http://www.codethinked.com/"&gt;Justin Etheredge&lt;/a&gt;&amp;nbsp;turned me onto&amp;nbsp;&lt;a target="_blank" href="http://nodejs.org/"&gt;node.js&lt;/a&gt;&amp;nbsp;at&amp;nbsp;&lt;a target="_blank" href="http://codemash.org/"&gt;CodeMash&lt;/a&gt;&amp;nbsp;2011. It does evented I/O on Google&amp;rsquo;s&amp;nbsp;&lt;a target="_blank" href="http://code.google.com/p/v8/"&gt;V8 JavaScript Engine&lt;/a&gt;. Extremely cool stuff for building web services and definitely a step in the right direction, in my opinion. Google is a great company but I wish it were my trusted friend and partner Microsoft taking this step with me. Say what you will about Microsoft but my corporate and government clients trust them. And that&amp;rsquo;s why I&amp;rsquo;ve invested so much of my career in making Microsoft technologies successful. If I have to start migrating toward other vendors, I will do so. But I lament that decision in my heart of hearts. I can only hope that some of you who read this will agree with me and echo my sentiments in your own way.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/uS04ERCslQM" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/blog/server-side-javascript/</feedburner:origLink></item><item><title>Exploring LINQPad Talk at RDNUG January 2011</title><link>http://feedproxy.google.com/~r/DevJourney/~3/i6rW1U3EBi8/</link><pubDate>Mon, 17 Jan 2011 16:39:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/blog/exploring-linqpad-talk-at-rdnug-january-2011/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>0</slash:comments><category domain="http://devjourney.com/blog/">Blog</category><description>&lt;p&gt;Here are the &lt;a href="http://devjourney.com/files/media/file/Exploring%20LINQPad.pptx"&gt;slides&lt;/a&gt; from my Exploring LINQ with LINQPad talk at Richmond .NET User Group on January 6, 2011.&lt;/p&gt;
&lt;p&gt;&lt;font color="#ff0000"&gt;UPDATE 1/26:&lt;/font&gt; Here is the &lt;a href="http://devjourney.com/files/media/file/ExploringLINQPadJanuary2011.zip"&gt;code&lt;/a&gt; from the presentation.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/i6rW1U3EBi8" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/blog/exploring-linqpad-talk-at-rdnug-january-2011/</feedburner:origLink></item><item><title>Embedding IronPython Talk at CodeMash 2011</title><link>http://feedproxy.google.com/~r/DevJourney/~3/vST5zonx9_0/</link><pubDate>Mon, 17 Jan 2011 16:26:00 GMT</pubDate><guid isPermaLink="false">http://devjourney.com/blog/embedding-ironpython-talk-at-codemash-2011/</guid><dc:creator>Kevin Hazzard</dc:creator><slash:comments>0</slash:comments><category domain="http://devjourney.com/blog/">Blog</category><description>&lt;p&gt;Here are the &lt;a href="http://devjourney.com/files/media/file/EmbeddingIronPython.pptx"&gt;slides&lt;/a&gt; and &lt;a href="http://devjourney.com/files/media/file/EmbeddingIronPythonJanuary2011.zip"&gt;code&lt;/a&gt; from my embedding IronPython talk at CodeMash 2011 entitled &amp;ldquo;Embedding IronPython as Your Application&amp;rsquo;s Scripting Language&amp;rdquo;. I&amp;rsquo;ve given versions of this talk over the past couple of years but this one&amp;rsquo;s up-to-date with all of the latest information from the &lt;a target="_blank" href="http://dlr.codeplex.com/wikipage?title=Docs%20and%20specs"&gt;Dynamic Language Runtime (DLR) hosting specification&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/DevJourney/~4/vST5zonx9_0" height="1" width="1"/&gt;</description><feedburner:origLink>http://devjourney.com/blog/embedding-ironpython-talk-at-codemash-2011/</feedburner:origLink></item></channel></rss>

