Tuesday, September 13, 2016

Git: Rebase VS Merge

Distributed version control (git): Check.
Feature branches: Check.
Rebasing: Ugh, serioiusly.

On multiple projects I've attempted to introduce the concept of rebasing commits.  It rarely goes well (at first).  The initial reaction tends to be reluctance and confusion.  Reluctance, because it adds complexity and appears to give nothing back.  Confusion, because doing it wrong, and intertwangling feature branches in particular, turns out to be way too easy.
This is the first post in a series that covers how and why to make a clean commit history.  In this post I'll cover the history of merging, the difference between merging and rebasing, and the golden rule of rebasing.

In subsequent posts I'll cover the benefits of rebasing, cover common pitfalls, and provide several concrete workflow tips you can implement today to leave your project with a simple, clean, and linear source history with the ability to easily track down newly introduced issues.

The Good Old Days

Remember Source Safe and CVS?  Those were the good old days.  You'd simply check out files you were working on, and no one else could touch them.  No merge conflicts, ever.  It just worked, right?
That was great - right up until someone went on vaction and left a ton of files checked out, leaving the entire team unable to work.  Oh yea, not so great.
But remember subversion?  Those were the good old days.   Optimistic concurrency to the rescue.  Multiple people could work on the same file and 90% of the time it just worked.  And branching was super easy.
Subversion was great.  Right up until you had to merge branches.  Then it was time switch projects, and ASAP.  Merging was always a complete disaster.  Maybe subversion wasn't so great after all.
Git has revolutionized source control, first and foremost by making branching and merging easy.  Distributed version control systems (DVCS) like git allow us to work on features independently, and defer integrating with the rest of the team until the time is right.  Since we can commit locally, we can use small, frequent commits, thus allowing us to break complex features into smallier pieces and allowing our commit history to tell a story.
However, with git, while merging may be much easier than it once was - we still have to choose between two approaches.

To Merge or Not, That is the Question

The easiest option, and what most do by default is git merge.  Say you've started feature.awesomeness and committed "B" and "D" to it.  Except meanwhile back on develop someone committed "C".  
pre-merge.png
No big deal, you merge develop into feature.awesomeness with git merge develop and give it a nice descriptive commit message like "Merge branch 'develop' into feature.awesomeness".
merge-commit1.png
That last commit, a merge commit, is a necessary side-effect, and a teltale sign, of merging.  You'll end up with one of these sketchy looking commits each time you want to integrate with (pull from) another branch.
When the feature is done you can merge it back to develop with git checkout develop and git merge feature.awesomeness. And thanks to the magic of fast-forward you won't have a second commit in develop.
post-merge.png
While there the extra merge commit may be aesthetically unpleasing, and the lines branching and merging in the diagram a little noisy; this merge approach is easy, it's clear what happened, the commits maintain their chronology (A, B, C, D).

Marty McFly: "Yeah, well, history is gonna change"

The alternative is rebasing.  With this technique, you replay all of your local commits on top of another branch (usually develop or master).  This essentially deletes your original commits and does them again in the same order.  The other branch becomes the new "base".  So In the scenario above you'd do git rebase develop and end up with:
rebase1.png
Pretty.  Clean.  You can pull from develop as many times as you want, and you'll never get extra commits.
If you're done, you switch back to develop and with a quick git merge and a free fast-forward you get:
rebase2.png
Notice that the commits are no longer chronological (A, C, B, D rather than A, B, C, D) and that B and D both have the same commit time, 21:07.  Duplicate checkin times are the teltale sign of rebasing.    
Sounds just as easy as merging, looks clean, but rebasing can be dangerous.

Golden Rule of Rebasing

Since rebasing changes history, the most important rule is never to rebase after you're pushed to a remote branch.  Or, more subtly, never rebase if someone might be using using your remote branch (e.g. pure backups are ok).  The reasoning: if you've changed history, you can only push again with a git push -force, and forcing the push will overwrite remote history, making a mess for anyone needing to reconcile your old commits with your new ones.
An important corollary to the golden rule of rebasing is that if you push your local feature branch to origin but don't merge it to origin/develop, you are (usually) giving up the opportunity to rebase ever again on that branch.  In other words, if you want the benefits of rebasing (generally) refrain from pushing until you're ready to merge it back.
For example imagine you have a local unpushed branch like this:
goldenruleB1.png
Now you'd like to share your commit B with the world.  However, you aren't quite ready to merge it back to develop yet, and so you push without merging:
goldenruleB2.png
This may look fine, but you've just lost your ability to rebase.  This can be verified by examining the case where someone subsequently makes a change back on develop (C) while you have unpushed local changes (D):
goldenruleB3.png
Now if you rebase, you'll rewrite B, and that will result in a two commits called B, one locally and one on the server in origin/feature.awesomeness:
goldenruleB4.png
In this case git push -force can sometimes help, but it can also open a whole other can of worms.  The best option is to maintain the ability to rebase isby not pushing until it's absolutely necessary.

Conclusion

Hopefully you've learned a little about the history of merging, what merge commits are, how rebasing can elimiate merge commits, and a little of how to avoid rebasing trouble.  
But what if you're working on a large feature and you want to share it with another branch, but not merge back yet?  Are the benefits of rebasing really worth it?  This post has been more about tactics.  I'll cover strategy in subsequent posts.

Monday, June 6, 2016

4 Xamarin Misconceptions Debunked (aka What Even Is Xamarin)

This article explains what Xamarin is, the basics of how it works, and dispels four common misconceptions.
When Mary Jo Foley and Paul Thurott attempted and failed to describe Xamarin on Windows Weekly a couple of months ago, I grumbled about pundits not performing due research and moved on.  But when even Scott Hanselman (who I worshipgreatly admire) mischaracterized it on his most recent podcast, I realized there is sufficient confusion within our industry that additional clarification is needed.
Thus this post that attempts to dispel 4 common Xamarin Misconceptions and hopefully shed some light on what even is Xamarin.

Misconception #1: Xamarin UI's Require XAML


This was stated by a guest during Hanselman's recent podcast. The misconception is quite understandable given the popularity of Xamarin Forms and it's XAML-based UI abstraction layer.  However, a traditional (non-Forms) Xamarin solution involves no XAML whatsoever. With traditional Xamarin you write your UI multiple times -- once for every platform. On Android you write your UI in traditional .axml XML files. For iOS you write your UI using StoryBoards, .xib files, or manually in code by manipulating UIView's (ideally with EasyLayout) in a class that derives from UIViewController.
If traditional Xamarin sounds like a lot of work, keep in mind that writing fully native apps typically requires building two completely separate apps in two completely different languages with no code sharing ever. Which leads us to the next misconception:

Misconception #2: Sharing Code is Hard with Xamarin


My company was brought in recently to help a customer that had implemented a traditional Xamarin solution without any code sharing. They made the mistake of fully implementing an Android app first, and then once complete implementing a Xamarin iOS app by copy-pasting much of the same C# into the iOS app.
Sharing code isn't difficult with Xamarin, but the trap they fell into was not designing for it up-front. If they had spent a little more time architecting, or (better) written their Android and an iOS apps simultaneously, they would have likely ended up with Xamarin's recommended architecture:

All of their common logic would have been in a Shared Project implemented as either a Portable Class Library (PCL) that targeted iOS and Android (and Silverlight/Windows Phone), or as a Shared Project.
With either of these code sharing approaches there exists the problem of mixing shared code with platform specific code. The PCL approach solves the problem by having shared code call into interfaces or abstract classes defined in the PCL, and some form of dependency injection swaps in platform-specific concrete implementations at runtime.


On the other hand the Shared Project approach solves the problem with #ifdef compiler directives. It does this because shared projects don't produce a separate DLL. Instead, they essentially inject Symbolic Links from the Shared Project's C# files into each of the platform specific projects. That means any line of code written in a shared project is also written in the iOS and android projects.


There are plenty of people with strong opinions on which approach is better (e.g. Miguel De Icaza, co-founder of Xamarin, is pro Shared Project) but at the end of the day neither code sharing approach is hard, as long as you plan for it up-front.

Misconception #3: Xamarin Isn't Native

The topic of which cross platform mobile solutions are truly native seems to generate confusion. In his recent podcast Scott Hanselman implied that Xamarin produces the same non-native UI as Ionic. He is correct that Xamarin's HTML-based cross platform competitors such as Cordova PhoneGap, Ionic, and React Native are not and will never be fully native because they run in an embedded browser. Because of that their performance and user experience will never equal that of native apps written in Objective C, Swift, or Java.
However, Xamarin is different from the HTML based cross platform apps in that it is always 100% native. If you've read this far then you'll understand that a traditional Xamarin solution that uses StoryBoards and .axml will necessarily be fully native. However, Xamarin Forms is fully native too.
Xamarin Forms allows you to define user interface once, in XAML, and then Xamarin renders that XAML into fully native controls. For instance if you write an  then Xamarin Forms renders it as a UITextField in iOS and a EditText in Android.

The skeptical reader will undoubtedly think this sounds too good to be true, that one couldn't possibly make a decent native experience with this. While it's true that the Xamarin Forms abstraction falls short quickly for more sophisticated UI's, the framework accounts for this with Custom Renderers.
Custom Renderers allow the creation of new XAML elements or customization of existing Xamarin Forms elements in the platform specific projects. This solution ends up providing a fantastic level of flexibility. Unless you want a pixel perfect, or highly customized platform specific solution where you'd have more code in custom renderers than in XAML, Xamarin Forms is a great option -- but either way you'll end up with a fully native user experience.

Misconception #4: Xamarin Is Slow

People often seem surprised that a Xamarin based solution could perform as well as an app written in a native language. Perhaps this is because of a misconception that .Net apps on Windows typically run slower than C or C++ based ones that manage their own memory and don't require the Common Language Runtime (the Windows virtual machine that manages memory, does garbage collection, handles threads and performs just-in-time compilation).
While Xamarin apps still require a version of the CLR (aka the Mono Runtime), just like on Windows that doesn't mean slower.  The CLR may mean larger binaries (particularly for iOS apps that require Ahead-Of-Time rather than Just-In-Time compilation), but surprisingly Xamarin can actually run faster than native language based apps!
Last year Harry Cheung, one of the original Google engineers, measured the performance of a wide range of mobile platforms and came up with these amazing results:
If you get the chance you should read the updated article as well as his original one.

Summary

Hopefully this article has helped to clarify some of what Xamarin is and how Xamarin works.  Please post in the comments if there are any additional areas that could use clarification.

Thursday, April 21, 2016

How to Fade an LED with PWM in Windows IoT

Motors, dimmable LED's, speakers, multi-color LED's and a variety of other components have a requirement that's easy for an Arduino, but that turns out to be a little tricky in Windows IoT.  This is the second article in a series exploring Windows IoT on a Raspberry Pi.  In this post we'll describe PWM, discuss how to perform simple binary GPIO manipulation, and then dig into configuring a device to fade an LED using Pulse Width Modulation (PWM).

Pulse Width What?

Microcontrollers such as Arduino and System on Chip (SoC) devices such as Raspberry Pi can technically only output one of exactly two voltages on their General Purpose I/O (GPIO) pins: either 0 or 3.3 volts.  The problem is that many components such as speakers or multi-color LED's require not two, but a whole range of voltages.
Microcontrollers or SoC devices typically fulfill the requirement by switching a pin on and off so fast as to give the appearance to most components as being between the min and max.  For instance to get ~3.0 volts you keep the duty cycle, or the proportion of time the pin is at High at 90%.  This process is known as Pulse Width Modulation or PWM.  
The following diagram from Wikipedia is a beautiful illustration of how to accomplish a sine wave using PWM.  Hooking this output up to a speaker would produce a decent sounding continuous tone.
The problem is that PWM can be tricky for devices with non-realtime operating systems, because an OS can't just pause it's pin switching process to do a garbage collection or preemptively give some other process CPU time. Consequently, until recently Microsoft required you to get an external board if you wanted to output variable voltages in its fledgling Windows 10 IoT operating system.
However, as of version 10.0.10586.0 there is a way. That way is called Lightning Providers, but getting it working is a little tricky, and the documentation is scattered and doesn't work out of the box.

Binary GPIO

Before we get into how to do PWM, this series has yet to touch on regular binary GPIO manipulation.  Fortunately it's fairly simple and well documented.  Assuming you've got a hello world Windows IoT app, you can turn a pin high and then low like this:
gpioController = await GpioController.GetDefaultAsync();
if (gpioController == null)
{
    StatusMessage.Text = "There is no GPIO controller on this device.";
    return;
}
_pin = gpioController.OpenPin(22);
_pin.SetDriveMode(GpioPinDriveMode.Output);
_pin.Write(GpioPinValue.High);
await Task.Delay(500);
_pin.Write(GpioPinValue.Low);

Seems simple enough, it flashes an pin (and perhaps an attached LED) High for a half a second.  But there are a couple of things to note.  
First GpioController is in Windows.Devices.Gpio, and it's only available when you reference Windows IoT Extensions for the UWP.

Second, GpioController.GetDefaultAsync() may return null if we're running this Universal Windows Platform project on a regular PC, or a phone, or an XBox.  That's something to guard against.
Third, the pin 22 was (arbitrarily) picked from one of the Pi's available GPIO pins using the following diagram:

In other words, the above code will flash the 8th pin down on the left-hand side (aka the 15th pin).  
Quick word of warning: if you test this out with an LED, make sure you get the polarity right, since LED's are not omnidirectional.

PWM

There are five steps to get PWM working.

1. Latest Bits

First, ensure you have the latest version of Windows IoT.  Technically you only need the current public release of Windows IoT, aka Build 10586, December 2015.  However, I tested this on the Pi 3, and since it's supposed to be 60% faster, your Pi 2 results may vary.  For this reason I'm recommending you install the Insider Preview of Windows IoT, which I showed how to set up in the last post.

2. Lightning Driver

Second, you need to install the Lightning Direct Memory Mapped driver.  Lightning is a new driver that provides a variety of additional capabilities including device and remote board PWM support.  It's still in beta, and consequently there's a warning when you select it: "This option will reduce Windows security in exchange for performance using an in development driver". 
To do change drivers:
  1. Navigate to the configuration url for your device (e.g. http://LeesRasPi3:8080/).  
  2. Select Devices
  3. Under Default Controller Driver, select "Direct Memory Mapped Driver"


  4. Reboot your device when prompted

 Lightning SDK

Third, you'll need to reference the Lightning SDK.  According to the documentation, you just reference via NuGet.  Unfortunately, this doesn't work as of v1.0.3-alpha.  I had to download the Microsoft.IoT.Lightning.Providers C++ source, add the Microsoft.Iot.Lightning.Providers.vcxproj project to my solution, and then make a project reference.  
Incidentally, I contacted some folks at Microsoft, and they said a new nuget will be published shortly with binaries that will fix this issue.

4. Permissions

Next, Lightning providers require additional manifest permissions.  To grant them you'll need to edit the Package.appxmanifest file of your UWP app and add the following bits inside capabilities at the end of the document:
<iot:Capability Name="lowLevelDevices" />
<DeviceCapability Name="109b86ad-f53d-4b76-aa5f-821e2ddf2141"/>
And then add the iot namespace to the Package element at the top of the document and iot to IgnorableNamespaces: 
<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10"
  IgnorableNamespaces="uap mp iot">

5. PWM Code

Finally, we're ready for some code.  One nice thing is that we can keep all of our existing binary GPIO code, plus allow the device to use either driver by simply adding the following line:
if (LightningProvider.IsLightningEnabled)
{
    LowLevelDevicesController.DefaultProvider = LightningProvider.GetAggregateProvider();
}
But, to get full on-device PWM functionality we'll need something like this:
if (LightningProvider.IsLightningEnabled) {
  LowLevelDevicesController.DefaultProvider = LightningProvider.GetAggregateProvider();
  var pwmControllers = await PwmController.GetControllersAsync(LightningPwmProvider.GetPwmProvider());
  var pwmController = pwmControllers[1]; // use the on-device controller
  pwmController.SetDesiredFrequency(50); // try to match 50Hz
  _pin = pwmController.OpenPin(22);
  _pin.SetActiveDutyCyclePercentage(.25);
  _pin.Start();
}
The first couple of lines set up the lightning driver and PWM provider using the on-device controller (as opposed to a dedicated PWM board, which you could attach to get better performance).   It then requests a leisurely 50Hz frequency speed.
Finally it opens pin 22 and sets the duty cycle to 25%.  
And that's it!  With a scrollbar and a few extra lines of code you'll be able to get something like this: 


Source Code

The complete code for this project is available on the WindowsIotPwmExample github project.

Summary

In this article we've covered what Pulse Width Modulation is, how to use Windows IoT to write binary-states to GPIO pins, and finally how to generate variable voltages using PWM.  Keep an eye out for the next article in the series on how to turn a Raspberry Pi into an information radiator.

    Tuesday, April 12, 2016

    Getting Started With Windows IoT And Raspberry PI 3

    This is the first post in a series exploring Windows IoT on Raspberry Pi 3.  In this post I'll cover the what and the why of Windows IoT, then show how to install it on a Raspberry Pi 3 and finally how to deploy a first app to it.




    What Is This Thing?


    Windows IoT is a version of Windows 10 designed for small form factor, low cost, Internet connected devices.

    It has three versions.  IoT Core is free, and is the one most people will care about.  It currently works on four devices (three boards):

    • Raspberry Pi 2 (Broadcom BCM2835 )
    • Raspberry Pi 3 (Broadcom BCM2837)
    • Arrow DragonBoard 410c (Qualcomm Snapdragon)
    • MinnowBoard MAX (Intel Atom)

    Windows IoT Core has no shell (e.g. no start menu) and so when running a mouse and keyboard on an LCD feels like a single app version of Windows.  Otherwise this free operating system has no limitations.  You can take a product to market on hundreds of thousands of devices and pay absolutely nothing for the OS.

    IoT Enterprise and Mobile Enterprise, aren't free.  They're more for ATM or Point of Sale scenarios.  IoT Mobile Enterprise uses a "modern shell" like a windows phone.  IoT Enterprise additionally work on x64 and larger devices and uses a "desktop shell" like traditional Windows 10.  They also allow system administrators to defer system updates.

    Windows, Seriously?


    There are a lot of options if you're looking to build a device that interacts with the real world. Arduino, for instance, is a fantastic choice if there's a chance you'll ever mass produce your thing, since you can find ATMEL chips that cost less than $2 and the ecosystem and set of libraries is huge. Also your thing will run faster (realtime even) without the overhead of an operating system.

    However, if your thing will require:

    • Multitasking (e.g. serving up web pages),
    • Running USB peripherals,
    • Displaying on an LCD screen, or
    • Connecting to the Internet

    Then one of the boards listed above may be a better choice.  But why not just run Linux?

    Security is one benefit.  For one thing you get automatic updates to help patch future vulnerabilities.  There's also Native UEFI , which helps protect against malware at the firmware and driver level.  There's Trusted Platform Module (TPM) support, which helps move cryptography operations to the hardware level.  Identity protection and access control may be important if you're running a kiosk that multiple people could log on to.  And there's even support for BitLocker and Enterprise Data Protection if things like encryption at rest, auditing, or remote device wiping matter to you.

    For another thing Windows IoT makes it easy to connect with other devices and services.  You can, for example easily and securely connect to Azure IoT Hub which can theoretically aggregate data from millions of devices in realtime.  It also has built in support AllJoyn, which is a way of connecting to other IoT devices.

    But one of the biggest benefits is the Windows ecosystem.  You build apps for it with Visual Studio, which is top notch IDE.  You can port existing Win32 or .Net applications to Windows IoT far more easily than to Linux.  You get remote desktop.  You can write in C#, Python, JavaScript, or Arduino C, and even embed Arduino libraries.  If you have experience building .Net apps, then the learning curve is extremely low.  And finally if you want your app to additionally target large screens, tablets, phones, and even XBox, then Windows IoT is your only option, because Windows IoT is designed to run Universal Windows Platform apps.

    Device Setup


    If you don't already have a Raspberry Pi 3, pick up one of the many good kits that includes an adequate power supply (outputs at least 1 Amp, 2 is better), a fast Micro SD card, and perhaps a case.

    Once you have a device you'll need to set it up with the Windows IoT operating system.  As of this writing, the official release is Build 10586, December 2015.  Unfortunately, this version doesn't work with Raspberry Pi 3.  Consequently, you'll need the Insider Preview of Windows IoT.

    To set a new Raspberry Pi 3 device follow the Insider Preview Setup Instructions (or if they've RTM'd, download the Core IoT Dashboard).  You'll download an image (Build 14295 supports remote desktop) and use the IoT Dashboard app to flash the image to an SD card.




    Now you can put the SD Card into your Raspberry Pi, plug an HDMI cable into a monitor, and attach power via micro USB.  If all goes well you should see Windows loading up.



    Once it's loaded up it will start the default app, which provides a place for basic device configuration.



    Before you can go much further you need to set up Internet access.  You can do that most easily via  Ethernet cable or approved WiFi device (careful, the list isn't big), and power it on.

    But wait, doesn't Raspberry Pi 3 have build-in WiFi?  Unfortunately, that isn't supported in the current build.  Hopefully it will be in there soon.

    Once you have the device on the network you'll have a much more robust set of options for accessing it.  You can, for instance, get in through PowerShell.

    Or better, when you go to Devices in the IoT Dashboard app, your device should be listed.  If you click the web link you can access the snazzy web browser interface.  This might be a good time to change the device name and password.


    Build Environment Setup


    Great, now you've got an Internet connected mini PC with no software.  To write apps for it you'll need to set up a "real" PC with Visual Studio.

    To set up your PC to build apps for Windows IoT you need Visual Studio 2015 Update 1 or better (any edition).  Be careful, when doing so you need to select the "Universal Windows App Development Tools" feature or else you'll get the ever helpful

    Error: this template attempted to load component assembly 
    'Microsoft.VisualStudio.Universal.TemplateWizards, Version=14.0.0.0, 
    Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. For more information 
    on this problem and how to enable this template, please see documentation 
    on Customizing Project Templates.

    Next, install the Windows IoT Core Project Templates.  Restart Visual Studio.

    Finally, enable developer mode to enable installing store apps via Settings, Updates & Security -> For Developers -> Developer mode

    Hello World


    To create a hello world app:
    1. File -> New -> Project
    2. Blank App (Universal Windows)

      1-NewProject.png


    3. Add a reference to the Windows IoT extension SDK

    4. Update MainPage.xaml with some XAML like

      <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Hello World</TextBlock>

    5. Under solution Platform Select: Arm
    6. For Device Configuration Select Remote Machine



    7. In the resulting dialog type the name of your device



    8. Hit F5!
    Once you've done that try putting a button on the screen, setting breakpoints, inspecting variables.  You'll find it's the exact same experience you've come to love in other Visual Studio projects, just in a small, inexpensive form factor.

    Summary


    This post has covered the what and why of Windows IoT as well as how to configure a Raspberry Pi 3 for Windows IoT and deploy a very simple application to it.  The next post in the series will cover how to control pins, and how to run a simple motor.


    Lee_-71-square-150px.jpgLee Richardson is a senior software developer at Inferno Red with a passion for .Net development, open source software, continuous integration, building cross platform mobile apps, and hardware hacking. In his spare time he runs Siren of Shame.  He has been consulting in the Washington DC area for over 17 years.  Keep up with him @lprichar.

    Thursday, February 4, 2016

    Xamarin vs Ionic: A Mobile, Cross Platform, Shootout

    Ever faced with choosing among competing frameworks; needing to make a decision you/your customer won't regret?  If those frameworks are for building cross-platform mobile apps and are Xamarin and Ionic, hopefully this article will help.

    The background is I had the somewhat rare pleasure of working on these competing frameworks on back-to-back projects recently.  Project #1 used Xamarin (and Xamarin Forms more specifically), the C# based framework for building fully native, cross platform apps.

    Project #2 used Ionic, the Angular.js, Cordova/PhoneGap, HTML, and JavaScript based framework for building apps that look and act native, but are technically running in an embedded browser.

    And what if I had to recommend one?  I'd probably want to think about a customer's budget, desired end product, and timeline.  I'd consider development speed, ramp up time, and maintainability.  Basically I'd evaluate based on the following six criteria:

    1. Price: Ionic++


    The single most obvious framework differentiator is price. Ionic's free price tag may seem like a no brainer.  However, $1,000 per developer per year for Xamarin is quite doable for most companies, especially if there is a compelling enough reason. Two very compelling reasons are:

    • We only have .Net developers; and
    • Our architecture is already exclusively .Net

    If these bullets apply to you, then the price is likely justified, and the Xamarin choice obvious. However, if you have a mix of talent and technologies, then free is hard to beat.

    2. End Product: Xamarin++


    Your customers won't be able to pinpoint exactly why they prefer your competitor's fully native app, but you're more likely to lose in the end

    Surprise: an HTML-based app, however well styled, will never look, feel, and perform like a native app.

    How different is the Ionic look and feel? If you stick to the default controls and don't overly customize, I guarantee your users won't notice. However, faced with a choice your customers won't be able to pinpoint exactly why they prefer your competitor's fully native app, but you're more likely to lose in the end.

    We were lucky enough to have a full-time design professional provide assistance on the Ionic project, and several of his (fairly time consuming) suggestions would not have been an issue if we'd gone with Xamarin.  Furthermore, the UI always felt a little laggy, even with theoretically GPU accelerated CSS3 transitions.

    Simply put if you want the best, fastest, most authentic experience for your users, Xamarin is the clear winner.

    3. Development Speed: Ionic++


    If you need to get an app out the door yesterday, Ionic is your friend.

    Development speed differs between the frameworks in two main aspects.  First is the amount of time from writing a line of code to seeing results. For Xamarin, pushing out code to an iOS device required several seconds of compilation plus 10 to 15 seconds of deploy time.  Ouch.

    By comparison Ionic with a ripple emulator provided zero-compilation, sub-second feedback times. This feature alone significantly increased development speed.  Perhaps more importantly the fast feedback cycles actually made coding more fun.

    The second development speed difference was in UI debugging.  Ripple plus Chrome tools makes debugging the UI in Ionic amazingly easy.  With Xamarin you have a very limited ability to figure out why an element is rendered exactly where it is at runtime, let alone tweak its attributes. In short Ripple + Chrome Tools makes UI work significantly easier in Ionic.

    Overall, Ionic was a significantly better development experience.  If you need to get an app out the door yesterday, Ionic is your friend.

    4. Maintainability: Xamarin++


    This where I rag on JavaScript, right?  Well, before I start, I have to admit I made three architectural decisions off the bat that made working with a JavaScript app more palatable to someone with my background and um, well biases, frankly.

    TypeScript


    As much as I appreciate JavaScript, I value refactoring, a great IDE experience, and the free unit tests that a compiler provides. TypeScript gave us all that goodness back, and with it the possibility of working with a large codebase and/or a larger, more diverse team. Without TypeScript I personally could not recommend Ionic for anything beyond fairly simple or a single developer mobile app.

    Visual Studio + ReSharper


    You thought Visual Studio and Resharper were just for .Net apps? Wrong, they helped us immensely with things like Bower and NPM package management, code navigation, refactorings, and great static analysis, plus a full-on fantastic debugging experience like you'd expect from a .Net app. Microsoft thoroughly surprised (dare I say delighted) us by providing a fantastic IDE for a historically non-Microsoft tech stack.

    Wallaby.js


    Our app had a fairly complicated core engine and with it a lot of unit tests. Wallaby allowed us to run our unit tests continuously, as we typed, before we saved even. Everyone on the team knew instantly if they had broken a test, and it kept code coverage at the fore-front of everyone's mind. Karma would have been ok I guess, but Wallaby made working exclusively in JavaScript/TypeScript enjoyable.

    Overall Maintainability


    While these three decisions made our JavaScript application more maintainable, refactorable, and less prone to incurring technical debt; Xamarin continues to feel more maintainable.  There's no way around that Angular is extremely heavy on magic strings.  My co-workers and I simply felt less scared of creating obscure bugs while modifying each other's code or refactoring existing code when we had a real compiler double checking 95% of our work.

    5. Unit Testing Experience: Conflicted


    A good framework needs a great unit testing experience if you're going to bake quality into your app.  Unfortunately, as great as Wallaby is, even with Karma, I could not figure out how to breakpoint debug and inspect variables from within a unit test.  With Xamarin, on the other hand, unit testing is a first class citizen.  It's easy and powerful and with nCrunch, feedback is nearly as fast as with Wallaby.

    Why conflicted?  Because I love this:

    // describe + it blocks offers a hard to match level of expressiveness
    describe('when you calculate dimension effects for a question', () => {
      // notice this generic helper function relevant to most/all of the tests
      var makeDimensionEffects = () => { ... };

      // nested describe -> I LOVE THIS
      describe('with a transformation', () => {
        // this 2nd helper is relevant to only nested tests
        var makeQuestionWithTransformation =  = () => { ... };

        it('should error gracefully if blah blah blah', () => {
          expect('actual').toBe('expected');
        });
      });
    });

    Even with SpecFlow, of which I am a huge fan, .Net fails to offer the same power, flexibility, and expressiveness.

    6. Ramp Up Time: Xamarin++


    The amount of ramp-up time obviously depends on your background.  However, with Xamarin it was just a little easier to fall into the pit of success.  Architecturally speaking, we made a wide variety of mistakes in Ionic that made things very messy for us later (notice how I switch to the third person when it's something bad that happened, sneaky, huh?).  Those mistakes mostly manifested themselves as poor memory management, although we screwed up our ngCache data structures too resulting in poor performance under load.

    Now one might argue it's easy to mess up memory management with any new framework.  In Angular, however, upon which Ionic is based, it seems to be especially easy to create leaks.  By the time we finished our Minimum Viable Product and realized all of the anti-patterns we'd implemented we had a real mess to recover from.

    Conversely, we had only one major memory issue with our Xamarin MVP, and we cleaned it up without issue.  Obviously if you have anyone on your team with prior Angular experience that mitigates this concern, but if not and you're choosing Ionic, consider yourself forewarned.

    Summary


    So what if I had to recommend a framework today?  Obviously the safe (and correct) answer is: it depends.  It depends on the team, the existing architecture, who's maintaining the app, the budget and timeline, and a host of other concerns.

    However, just to be provocative I'll avoid the safe answer.

    For me: I value quality over speed.  Just because you can build something with free tooling (#1), do it faster and have more fun doing it (#3); that's no substitute for building an authentic, top notch, responsive mobile UI (#2) on a clean, refactorable code base (#4) that will be ready for market when it hits first release (#6).

    But perhaps time to market is more important for you.  Every circumstance is different.  Hopefully this has helped shed some light on what decision will be right in your case.