Thursday, November 29, 2012

Decisions, Decisions - Which Windows 8 Programming Paradigm Should We Use

When Microsoft first announced that they would support three programming options for their Windows 8 Store apps – C#/XAML, C++/CX/XAML, and JavaScript/HTML – many organizations such as my benevolent employer, CTS, asked the question "which model is best?" After all, Microsoft has gone out of its way to declare all of them "First class citizens," and in the spirit of egalitarianism, we need to analyze each option. Our Chief Engineer asked us for our opinions, paying particular attention to three questions:
  • Does one platform perform better than another?
  • Which platform leverages our predominant actual skill-set as a company?
  • Do we have any insight into whether one of these methods will be an industry standard?
To answer our question of which model is right for us, it is important to understand how developing a Windows Store app is different than creating a traditional web app or .NET application, and why Microsoft decided to create the three different programming models. This will get a little geekier than some of my previous posts, so bear with me.

I've Programmed .NET for Years - No Big Whoop

One of the misconceptions I had when I first read about Windows 8 Store apps was that it was a .NET based platform - it isn't: Windows 8 Store apps are designed to be native to Windows. But if that is the case, then how on earth can I write my program in .NET? What does it compile to? An assembly? Does it bypass the IL/CLR tango altogether and compile into pure native code? As it turns out, our program compiles into a .NET exe assembly, but the assembly cannot be run directly on the desktop. It needs a Windows 8 Container.

The container wraps the CLR, and provides it access to the native Windows API through an adapter called WinMD (here is a great article explaining the interaction between .NET and native Windows in Store apps).  This functionality was put in place in order to lower the barrier of entry to Windows Store development for the hundreds of thousands of .NET developers Microsoft has cultivated over the past decade. The performance penalty is analogous to a standard .NET application since the code is compiled to IL and run within the Win RT “sandbox.” 

This Thing Runs HTML/JavaScript? All My Websites Are Now Apps!

When we first read that Microsoft was going to support programming Windows 8 Store apps in HTML/JavaScript we all had the same excited thought - Wow! I have tons of really cool web applications... I'll just drop those in a Windows Store project in Visual Studio, update my CSS to be all Metro-ey (oops, we're not supposed to say "Metro" anymore), and voila, I have a brand new Windows app that automatically mimics the style and functionality of my web site.  I just added a supported platform to my business in an afternoon, let's go drinking play golf!

Unfortunately for the drooling masses of developers, this is not quite the case. The point of creating an avenue for Windows Store app development through JavaScript was never portability - it was to lower the barrier to entry. Microsoft recognized that despite its best nefarious efforts there are lots and lots of developers out there who do not know .NET. Adding JavaScript with an HTML view engine allowed Microsoft to dip into the ample pool of web developers who have been happily humming along creating whiz-bang Web 2.0 applications and spending their days immersed in JavaScript, barely trifling with the antiquated drudgery of server side code. (Full disclaimer, I am one of the old trolls who much prefers writing code on the server to hours of browser based JavaScript, so this is not a knock on server side programming. More on this in a future post).

But it's not that simple. Yes, Windows store apps do a remarkable job of running Vanilla JS and rendering HTML 5, but web developers today use a complex diaspora of JavaScript libraries including the granddaddy of them all, jQuery. That's right, as of this writing, Windows 8 JavaScript apps do not support jQuery. There is a third party company called appendTo writing an adapter, but the support is not native to the framework, and requires some machinations to develop.

This obviously represents a significant departure from our standard web development models. Our fantastic web app using jQuery, Knockout JS, and custom control libraries cannot simply be ported. We have to completely rewrite them using raw JavaScript and WinJS - the Microsoft JavaScript library that handles data binding and the rendering of native Windows API controls.

The actual output of compiling your JavaScript app does not produce binaries (except for the resources PRI file), but instead groups all your HTML, JavaScript, images, and CSS into their own directories.

The reason we don't see binaries is because JavaScript is an interpreted language in Windows 8. The process that actually interprets, hosts, and runs your app is called WWAHost.exe. This could potentially mean a performance problem, which some early benchmarks do indicate for processor intensive code.

Code Side by Side

OK, enough of the talky-talk, let's look at some code to see what it all means for our actual solution.  Microsoft has written some outstanding project templates for Windows store apps for C++, C#, and JavaScript, which lets us make a direct, apples to apples (to apples) comparison between the three languages.

For starters, I created a project in each language using the "Grid App" template, and took a look at the markup and code of the GroupDetailPage. Here's what the page looks like when it runs in the simulator:

Purdy

Markup

Let's take a look at the markup for the page. First, the XAML used for both C# and C++ in the main horizontal grid:
<Grid
        Style="{StaticResource LayoutRootStyle}"
        DataContext="{Binding Group}"
        d:DataContext="{Binding AllGroups[0], Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}">

        <Grid.RowDefinitions>
            <RowDefinition Height="140"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!-- Horizontal scrolling grid used in most view states -->
        <GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemGridView"
            AutomationProperties.Name="Items In Group"
            TabIndex="1"
            Grid.RowSpan="2"
            Padding="120,126,120,50"
            ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
            ItemTemplate="{StaticResource Standard500x130ItemTemplate}"
            SelectionMode="None"
            IsSwipeEnabled="false"
            IsItemClickEnabled="True"
            ItemClick="ItemView_ItemClick">

            <GridView.Header>
                <StackPanel Width="480" Margin="0,4,14,0">
                    <TextBlock Text="{Binding Subtitle}" Margin="0,0,18,20" Style="{StaticResource SubheaderTextStyle}" MaxHeight="60"/>
                    <Image Source="{Binding Image}" Height="400" Margin="0,0,18,20" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
                    <TextBlock Text="{Binding Description}" Margin="0,0,18,0" Style="{StaticResource BodyTextStyle}"/>
                </StackPanel>
            </GridView.Header>
            <GridView.ItemContainerStyle>
                <Style TargetType="FrameworkElement">
                    <Setter Property="Margin" Value="52,0,0,10"/>
                </Style>
            </GridView.ItemContainerStyle>
        </GridView>

        <!-- Vertical scrolling list only used when snapped -->
        <ListView
            x:Name="itemListView"
            AutomationProperties.AutomationId="ItemListView"
            AutomationProperties.Name="Items In Group"
            TabIndex="1"
            Grid.Row="1"
            Visibility="Collapsed"
            Padding="10,0,0,60"
            ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
            ItemTemplate="{StaticResource Standard80ItemTemplate}"
            SelectionMode="None"
            IsSwipeEnabled="false"
            IsItemClickEnabled="True"
            ItemClick="ItemView_ItemClick">

            <ListView.Header>
                <StackPanel>
                    <TextBlock Text="{Binding Subtitle}" Margin="10,0,18,20" Style="{StaticResource TitleTextStyle}" MaxHeight="60"/>
                    <Image Source="{Binding Image}" Margin="10,0,18,0" MaxHeight="160" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
                    <TextBlock Margin="10,20,18,30" Text="{Binding Description}" Style="{StaticResource BodyTextStyle}"/>
                </StackPanel>
            </ListView.Header>
        </ListView>

        <!-- Back button and page title -->
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
            <TextBlock x:Name="pageTitle" Text="{Binding Title}" Style="{StaticResource PageHeaderTextStyle}" Grid.Column="1" IsHitTestVisible="false"/>
        </Grid>

        <VisualStateManager.VisualStateGroups>

            <!-- Visual states reflect the application's view state -->
            <VisualStateGroup x:Name="ApplicationViewStates">
                <VisualState x:Name="FullScreenLandscape"/>
                <VisualState x:Name="Filled"/>

                <!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
                <VisualState x:Name="FullScreenPortrait">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/>
                        </ObjectAnimationUsingKeyFrames>

                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Padding">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="100,126,90,0"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>

                <!--
                    The back button and title have different styles when snapped, and the list representation is substituted
                    for the grid displayed in all other view states
                -->
                <VisualState x:Name="Snapped">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/>
                        </ObjectAnimationUsingKeyFrames>

                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
    </Grid>

So far so good. This is a big snippet of code for not a whole lot for functionality, and pretty typical XAML that you should be familiar with if you've worked on WPF, Silverlight, or a Windows Phone app. It's 146 lines long, of which 118 make up the code for the page itself (you'll see why this is important in a moment).

Now let's take a look at the same page, but in HTML for our JavaScript project:

<body>
    <!-- These templates are used to display each item in the ListView declared below. -->
    <div class="headertemplate" data-win-control="WinJS.Binding.Template">
        <h2 class="group-subtitle" data-win-bind="textContent: subtitle"></h2>
        <img class="group-image" src="#" data-win-bind="src: backgroundImage; alt: title" />
        <h4 class="group-description" data-win-bind="innerHTML: description"></h4>
    </div>
    <div class="itemtemplate" data-win-control="WinJS.Binding.Template">
        <div class="item">
            <img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" />
            <div class="item-info">
                <h4 class="item-title" data-win-bind="textContent: title"></h4>
                <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6>
                <h4 class="item-description" data-win-bind="textContent: description"></h4>
            </div>
        </div>
    </div>

    <!-- The content that will be loaded and displayed. -->
    <div class="groupdetailpage fragment">
        <header aria-label="Header content" role="banner">
            <button class="win-backbutton" aria-label="Back" disabled type="button"></button>
            <h1 class="titlearea win-type-ellipsis">
                <span class="pagetitle"></span>
            </h1>
        </header>
        <section aria-label="Main content" role="main">
            <div class="itemslist win-selectionstylefilled" aria-label="List of this group's items" data-win-control="WinJS.UI.ListView" data-win-options="{ selectionMode: 'none' }"></div>
        </section>
    </div>
</body>

Holy schnikeys, that's almost nothing compared to the XAML version! The entire HTML file is only 48 lines of code, of which only 30 make up the body of the document - that makes the XAML version a full 4 times larger than the HTML version. Score one for HTML / JavaScript.

There is obviously something going on behind the scenes that makes this all hum. The first thing to notice is all of the "data-win-" attributes and the "WinJS." attribute values. This is the Microsoft magic sauce that turns your HTML/JavaScript app into an honest to goodness Windows application (see this demonstration). There are enough tutorials out there, so we won't launch into one here. Do note, however, that these are different libraries than you've ever used before for your HTML development, with a specific layout style. There is no portability in this HTML - if you have a web site that you want to make into a store app, you'll need to rewrite the markup.

Code

Now that we've seen the XAML and HTML markup, let's look at the actual code that drives this page. We'll look at the native C++ first (comments removed):
void GroupDetailPage::LoadState(Object^ navigationParameter, IMap^ pageState)
{
 auto group = Data::SampleDataSource::GetGroup(safe_cast(navigationParameter));
 DefaultViewModel->Insert("Group", group);
 DefaultViewModel->Insert("Items", group->Items);
}

void GroupDetailPage::ItemView_ItemClick(Object^ sender, ItemClickEventArgs^ e)
{
 (void) sender; // Unused parameter

 auto itemId = safe_cast(e->ClickedItem)->UniqueId;
 Frame->Navigate(TypeName(ItemDetailPage::typeid), itemId);
}

Ahh, nice and simple: little code, clear method invocations, head is not spinning. This gives me a warm fuzzy feeling, and I haven't even programmed in C++ for the better part of a decade. The C# version is a direct analog to C++:
        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            var group = SampleDataSource.GetGroup((String)navigationParameter);
            this.DefaultViewModel["Group"] = group;
            this.DefaultViewModel["Items"] = group.Items;
        }

        void ItemView_ItemClick(object sender, ItemClickEventArgs e)
        {
            var itemId = ((SampleDataItem)e.ClickedItem).UniqueId;
            this.Frame.Navigate(typeof(ItemDetailPage), itemId);
        }

Now let's take a look at JavaScript:
(function () {
    "use strict";

    var appViewState = Windows.UI.ViewManagement.ApplicationViewState;
    var ui = WinJS.UI;

    ui.Pages.define("/pages/groupDetail/groupDetail.html", {
        /// 
        _items: null,

        // This function is called whenever a user navigates to this page. It
        // populates the page elements with the app's data.
        ready: function (element, options) {
            var listView = element.querySelector(".itemslist").winControl;
            var group = (options && options.groupKey) ? Data.resolveGroupReference(options.groupKey) : Data.groups.getAt(0);
            this._items = Data.getItemsFromGroup(group);
            var pageList = this._items.createGrouped(
                function groupKeySelector(item) { return group.key; },
                function groupDataSelector(item) { return group; }
            );

            element.querySelector("header[role=banner] .pagetitle").textContent = group.title;

            listView.itemDataSource = pageList.dataSource;
            listView.itemTemplate = element.querySelector(".itemtemplate");
            listView.groupDataSource = pageList.groups.dataSource;
            listView.groupHeaderTemplate = element.querySelector(".headertemplate");
            listView.oniteminvoked = this._itemInvoked.bind(this);

            this._initializeLayout(listView, Windows.UI.ViewManagement.ApplicationView.value);
            listView.element.focus();
        },

        unload: function () {
            this._items.dispose();
        },

        // This function updates the page layout in response to viewState changes.
        updateLayout: function (element, viewState, lastViewState) {
            /// 

            var listView = element.querySelector(".itemslist").winControl;
            if (lastViewState !== viewState) {
                if (lastViewState === appViewState.snapped || viewState === appViewState.snapped) {
                    var handler = function (e) {
                        listView.removeEventListener("contentanimating", handler, false);
                        e.preventDefault();
                    }
                    listView.addEventListener("contentanimating", handler, false);
                    var firstVisible = listView.indexOfFirstVisible;
                    this._initializeLayout(listView, viewState);
                    if (firstVisible >= 0 && listView.itemDataSource.list.length > 0) {
                        listView.indexOfFirstVisible = firstVisible;
                    }
                }
            }
        },

        // This function updates the ListView with new layouts
        _initializeLayout: function (listView, viewState) {
            /// 

            if (viewState === appViewState.snapped) {
                listView.layout = new ui.ListLayout();
            } else {
                listView.layout = new ui.GridLayout({ groupHeaderPosition: "left" });
            }
        },

        _itemInvoked: function (args) {
            var item = this._items.getAt(args.detail.itemIndex);
            WinJS.Navigation.navigate("/pages/itemDetail/itemDetail.html", { item: Data.getItemReference(item) });
        }
    });
})();


Aye, there's the rub. This code has no alibi - it's ugly. While the JavaScript code file itself is not much larger than the C++/C# files (75 lines vs 63 lines), the amount of code to actually set up and create the page is much briefer in C++/C# (8 or 10 lines) than the JavaScript (about 60-65 lines, depending on how you count). The reason for this is that JavaScript is a terrible language for doing complex coding. (I'll have a post on this later that may generate some hate mail, but so be it). There are no classes, everything is a nested function, and it there are so many workarounds for uses that were never intended that your whole program inevitably becomes a kludge. The "use strict" string at the top of countless JavaScript files makes my skin crawl.

These deficiencies can be mitigated by TypeScript, but getting TypeScript to work in a Windows Store app app requires jumping through a lot of hoops.

So What Should We Use?

Given all the pros and cons, which of the three technologies should we use to develop our applications? For me an my company, CTS  the answer is clear: C#. The reasons for this, however, are largely based on the nature of our organization: 
  • We've invested in making a large body of developers proficient in .NET 
  • We have institutional support for the language at each of our offices 
  • C# is cleaner and more suited to large scale development than JavaScript
  • .NET apps appear to perform better than JavaScript apps
  • Windows store support for .NET in the community is stronger for than other languages

These reasons aren't universal, however. If you have strong knowledge in both C# and C++, you may want to consider using C++ since it will actually compile into a "native" app instead of having to be marshaled through a .NET container and the WinMD libraries. We didn't discuss this above, but if you app is graphics intensive, there is an extensive set of Direct2D and Direct3D libraries available for C++ programming that are not ready for other language. A final situation where C++ is clearly preferred is if you are developing custom component libraries that will be used in a variety of applications outside your organization. There is far less overhead and compatibility issues adding a C++ component to a C# or JS app than migrating C# or JS to an app of a different language. Of course, if you only develop components for internal use this is not a factor.

If you've been a web developer over the past few years, you may not know C# or C++. You may want to choose JavaScript which will get you up and running much quicker than going back and learning an entirely new language. In fact, I've even talked to an ASP.NET developer whose company writes a very modern single-page type web application, and he has told me that he's more comfortable in JavaScript than C#, and much much more comfortable writing HTML than learning XAML.  Additionally, there is evidence that JavaScript may be the preferred manner of development for store apps by Microsoft, though this is not official policy, and may change rapidly if the development community fails to embrace the JavaScript model.

I'm sorry I don't have one universal answer to the question. The key is determining which approach is right for your organization based on a wide variety of factors. Think of it this way, if the decision were easy, Project Managers could do it. This is where you get it shine.


1 comment:

  1. Bandicam Crack is a usefull software to record any thing happening on your screen just a single click in any your desired formate.
    Bandicam Registered Free

    ReplyDelete