Improving conversion rates in KickSmoking

In part 1 of this series we looked at the current state of the application KickSmoking. In this series we'll take a look at some of the ways we're going improve conversion rates.

Always take care of your loyal users

People won't give you money if you treat them poorly.

There are two main groups of users on KickSmoking, those on the free app and those on the paid app. With features such as trial accounts and in-app purchases available to Windows Phone developers there's really no need to have multiple apps, however I don't want to leave one group of users out in the cold so we're forced to maintain two apps in the app store.

Because we don't want to force people to download a new app just to unlock all the features we're also going to support in-app purchases in the free version of the application which will bring it to feature parity of the pro version.

This has a few benefits

  • If someone bought the old KickSmoking pro version they will be seamlessly upgraded.
  • If someone downloaded the free version they will now have the convenience of upgrading in-app.

If it was free before, it's free now. All features that people used to enjoy for free will always be free. People just feel sad when you take things away - especially if you haven't warned them! But we want people to upgrade so there needs to be a reason to upgrade. We will be adding new features only available to our paying customers.

If you've already paid - then you won't be forgotten. Only a small percentage of users are on the paid app - we could just discontinue it as maintaining one application is so much easier. But that erodes the trust of your very first customers, the ones that believed in you at the very beginning. If you've purchased the app then it will be maintained and will receive all the same updates that are pushed to the free version of the app.

Continue Reading »

Monetising KickSmoking

KickSmoking is a windows phone app that I built 2-3 years ago which has been in maintenance mode for a while.

Despite being on the back-burner it's still the number one quit smoking app on the Windows Phone app store. It's had over 60k downloads and still achieves upwards of 50 new installs a day, and with 224 reviews at an average of 4.5 stars I'm not the only one who thinks it's awesome.

However, despite the stats I've only managed to earn about $300 to $400 over the lifetime of the application. I don't know many people who've managed to push over 60k downloads yet failed to make a grand.

This isn't due to the platform (the number of downloads are there) - I believe it's due to the poor monetisation strategy in use.

During this blog series we'll cover the existing app and monetisation model, the plan going forward, and finally the results of the experience.

Continue Reading »

Cocoapods: package management in xcode for iOS apps

I've just started building my first iPhone app and one of the biggest things I missed from .NET land was package management. Visual studio has amazing support for NuGet - even Microsoft distribute some of their core libraries on the platform.

Wouldn't it be amazing if we could have dependency management in xcode also?

Turns out there's a third party solution which is pretty fantastic despite the lack for first class support in xcode.

Continue Reading »

Migrating an Azure VM to a different region

Microsoft just launched Azure cloud services in Australia, given the proximity to New Zealand where the majority of our customers are based it made sense to migrate Solve's various azure hosted services there.

The majority of the services run on hosted platforms such as Azure Websites which were super simple to migrate, however there were a few legacy systems running on VMs which needed to be migrated.

Even though you can't do it from the online interface it, it's actually pretty simple.

Continue Reading »

Setting up a Jekyll workflow on windows

Static site generators are in at the moment, and for good reason. They remove a whole bunch of complexity from deploying and maintaining a site by creating a static representation of it, which you just upload to a web server.

For sites that are read heavy but get updated quite infrequently (like a blog, or marketing site) a static site is ideal.

Personally I love GitHub pages, it provides first class support for Jekyll which builds and your markdown content, templates, and other site assets into a static website.

The only problem is, Jekyll isn't officially supported on Windows; I was using it for a a start up running the .NET stack called Slipspace. The good news is that it's super simple to get up an running.

In this post we'll look at how we integrated Jekyll into our work flow using Grunt to glue all the moving pieces together.

Continue Reading »

Announcing Slipspace: Error management for software services companies

For the past couple of months I've been working on something awesome, that something is Slipspace.

I'm not going to lie, it has been the hardest couple of months my professional career. What everyone tells you is true, the actual engineering is the easy part.

Today is a big milestone, we've shipped something!

Although Slipspace may be far from finished we're at a point where we believe it can add value - a lot of value. Slipspace is now in closed beta and actively looking for strategic partners in the software services industry to help it to its next stage of development.

If you're interested, sign up here: We'll be getting in touch on a first come first serve basis. The product is completely free to use in beta, all we want is feedback.

Continue Reading »

How to add JSON Patch support to ASP.NET Web API

In this post we'll look at how to introduce support for the JSON Patch content type (RFC 6902) to ASP.NET Web API.

There's an unlimited number of ways to introduce HTTP Patch support into your API as there's no single specification on how to represent the set of changes to make to a resource.

The PATCH method requests that a set of changes described in the request entity be applied to the resource identified by the Request- URI. The set of changes is represented in a format called a "patch document" identified by a media type.

The only way I could find to introduce HTTP Patch support was through adding a dependency on the Microsoft ODATA library. Unfortunately OData library does updates using a partial entity, rather than a change document.

A PATCH or MERGE indicates a differential update. The service MUST replace exactly those property values that are specified in the request body. Missing properties, including dynamic properties, MUST NOT be altered.

I'm not that much of a fan of representing a set of changes as a partial entity, I don't want to introduce a dependency on the entire OData library just for their Patch support, and I want to use the JSON Patch standard.

So we're going to build it ourselves™

TL;DR: Not interested in the details, grab the source on Github, otherwise stick around for the implementation details.

Continue Reading »

Should I use www or not?

It's common convention to prefix the letter double-u three times on the front of every domain to represent the web host. It's pretty funny that we managed to pick the most awkward, visually dominating letter for this job.

Is it still required? Or can we just use the naked domain?

Continue Reading »

Setting up an elasticsearch cluster in azure

One of the best things about Azure is that you can set up most of your favourite software on it regardless of its roots. In this blog post we'll investigate how to set up an elasticsearch cluster on Windows Azure.

Elasticsearch is a powerful open source search engine that makes data easy to explore. To be honest, it's unfortunate it has search in its name because it's capable of so much more.

The set up

We'll set up our cluster so that it can be used in a stock-standard multi-tier web application.

In our configuration we will have a public facing web application that is using the elasticsearch cluster.

We will use Azure's new internal load balancing feature to enable us to run a highly available service which isn't publicly exposed. This means the web application can reference the ILB instead of an individual machine in the cluster.

Our elasticsearch server diagram

Continue Reading »

The great confusion about HTTP Patch

PATCH is a relatively new addition to the set of HTTP verbs. Proposed about 4 years ago in RFC 5789 it's designed to allow an API to support partial updates.

A new method is necessary to improve interoperability and prevent errors. The PUT method is already defined to overwrite a resource with a complete new body, and cannot be reused to do partial changes. Otherwise, proxies and caches, and even clients and servers, may get confused as to the result of the operation.

Great, myself along with a bunch of other API designers started to treat it as PUT but for partial updates. Sure it only worked for simple entities and started to break down with objects containing complex properties but this was Web 2.0 and we started to do something along the lines of this.

 PATCH /cars/1
 Content-Type: application/json

 { "colour": "new-paint-colour" }

Now we can just check the verb to see if we want to null out missing entities, if it was a PUT we'd replace the entire object, and if it's a PATCH we'd just update the properties specified right? ...right? Wrong!

Turns out I was using PATCH like an idiot.

Continue Reading »

Dependency injection for ASP.NET Web API action filters in 3 easy steps

This post looks at performing dependency injection on a WebAPI ActionFilter using Unity. Since we're looking at WebAPI we'll be looking at classes which implement the ActionFilterAttribute base class under the System.Web.Http.Filters namespace.

We will be using the Unity Application Block (Unity) to do most of the heavy lifting. It's a lightweight dependency injection container created by the Microsoft Patterns and Practices team.

1) The ActionFilter

First you need to implement your shiny new ActionFilter that requires a dependency to be injected.

public class MyCustomActionFilterAttribute : ActionFilterAttribute

    public ISomeRepository SomeRepository { get; set; }

    public override void OnActionExecuting(HttpActionContext actionContext)

        //do something amazing using that repository...



But now there's a problem, Web API no longer knows how to instantiate the ActionFilter as Web API knows nothing about ISomeRepository. We will fix this by modifying the default ActionDescriptorFilterProvider.

Continue Reading »

Automatically marking required labels in ASP.NET MVC

A common requirement with any sort of form is marking the required fields. A common convention is to append an asterisk (*) to the label of all required fields.

Normally I'd manually add the asterisk directly in the HTML, or add the [display] attribute to the model so that the @Html.LabelFor picks it up automatically.

public class SomeModel
    [Required, Display(Name = "Email*")]
    public string Email { get; set; }

    public string Subject { get; set; }

I prefer to get the HTML Helpers to add it as I'm less likely to forget to mark any of the fields.

However it does have one annoying consequence, the messages generated by the model validators are also impacted.

Continue Reading »

Implementing XML-RPC services in ASP.NET MVC

Earlier this month I moved my blog to a brand new design to improve the readability of the posts.

The admin section was also in desperate need of an upgrade but it would have taken a lot of development effort to create something decent. I ended up just nuking it in favour of using a desktop blogging client. To support various 3rd party blogging clients we just need to implement the MetaWeblog API.

In this post we'll look at how we implemented XML-RPC services in ASP.NET MVC by creating a custom model binder.

Continue Reading »

Malaysia: The road to Borneo

The road to Borneo

Borneo is the third largest island in the world, home to one of the oldest rainforests on the planet, and contains an assortment of endemic species. We only had 2 weeks here so we spent most of our time at two national parks, Bako and Mulu.

Continue Reading »

Nepal: The trek to Everest Base Camp

Sign to EBC

I've hiked to Everest Base Camp and I'm not going to lie; it's easier than everyone makes it out to be. Don't get me wrong, it's not a walk in the park either but you're rewarded with some of the most spectacular scenery on the planet.

Most tours complete the trek in about 12 days and even though this is manageable there is no room for unforeseen circumstances such as sickness or weather. Try squeeze in at least a few extra days as contingency, even if you don't need them you'll be thankful for the extra time to soak up the amazing atmosphere and scenery on the way down.

Without sounding overly dramatic – this is a life changing event, and comes highly recommended from me.

Continue Reading »

Fast times in Myanmar

Sunrise over Bagan

Myanmar is an emerging tourist destination nestled between India, China and Thailand. Being a union of many different ethnic regions the country comes with a diverse range of traditions and customs. It is a country defined by its difficult past and promising future; you can’t help but notice the burgeoning optimism of the Myanmar people. Come with an open mind and sense of adventure and you won’t leave disappointed.

Continue Reading »

You probably don't want your development team to share a single database

The shared database model has the developers building and running the web application on their own machine locally, but connecting remotely to the shared database. It's a super simple way to get started, and on the surface it has a few benefits:

  • Changes are reflected instantly so all developers are working on the latest version of the database.

  • Large data sets do not need to be replicated to each developer's machine.

But in reality there are quite a few problems with this model.

Continue Reading »

Packing for SE Asia Part 1: What I'm planning to take

There are literally a million packing lists on the internet for SE Asia, but only a few of them follow up with the realities of living out of a 38L carry-on sized bag.

All these lists have one thing in common - pack as little as possible. I set myself the one carry-on bag challenge and... I failed. Mainly because I had a couple of items that I could not take carry-on so I had to use a very small checked bag. But everything could fit into my carry-on bag ;)

Continue Reading »

Is it mine or yours?

When designing the interface for your application the exact wording often comes later in the process, once you have some wire frames complete and a basic app up and running.

But once you're up and running, what is the wording you should use when referring to items that belong to your user.

For example: how do I refer to the user's tasks in the interface for CronHQ? Are they My Tasks, or Your Tasks?

I like clean, consistent, natural interfaces. But I can't tell which of the two options above seem more natural, both the use My and Your seem to flow for me as I've seen both used through out the internet. I didn't know which one seemed more natural. And that bothered me.

Continue Reading »

The back button and browser caching

I recently found out that browsers absolutely love serving up cached pages when the user uses the back button.

How was this a problem?

We had an issue where'd we'd update a page in place and save the changes using JavaScript. If the user navigated away then used the back button they'd be shown the original page with the original data. They'd then think the fancy JavaScript was completely broken.

That makes a developer sad face. Especially when they put a whole bunch of effort in to creating such a seamless editing experience.

Continue Reading »

Configuring a Live Connect application to use the new Microsoft Account permission page

When I first configured the new version of ConceptHQ Accounts to federate with Microsoft account using OAuth I used these two endpoints.

It resulted in a slightly jarring user experience as we switch from the new look sign in page to the old style permissions page.

Continue Reading »

OpenID and OAuth: What's the difference?

I'm currently in the middle of upgrading ConceptHQ Accounts to accept a small subset of third party identity providers. Microsoft Account (previously Windows Live ID), Google, Facebook, and Twitter.

New ConceptHQ Accounts layout

However they all have a slightly different ways of allowing you to authenticate users with them.

  1. Facebook: OAuth 2.0
  2. Twitter: OAuth 1.0A
  3. Microsoft Account: OAuth 2.0
  4. Google: OpenID

Continue Reading »

ASP.NET MVC and TempData

TempData initially seemed kind of magical and uber useful!

Represents a set of data that persists only from one request to the next.

Today I almost used it in a multi-instance Azure set up which didn't use session state and so didn't have a central session store. Whoops.

Continue Reading »

Error handling in ASP.NET MVC Part 2: Our implementation

In part 1 of this series we looked at the options available to us to handle errors in ASP.NET MVC. In this part of the series we will look at our implementation.

Our implementation consists of two components. A custom exception filter that’s registered globally to handle any exceptions while processing filters, actions, and views. The Application_Error method in Global.aspx to catch any other errors generated while ASP.NET processes the request.

Continue Reading »

Error handling in ASP.NET MVC Part 1: Our options

This blog and most of the web applications we build over at ConceptHQ are based on Microsoft's ASP.NET MVC framework. We wanted a standardised way to approach error handling across our web applications.

We had a couple of requirements

  1. Super easy to implement
  2. Covers the entire ASP.NET request pipeline
  3. See friendly error messages in production and see stack traces in development
  4. Respects HTTP status codes - we do not want the site returning a 302 redirect on error to redirect to an error page
  5. Able to log exceptions

This is the first post in a two part series, in this part we will look at the options available to us in ASP.NET MVC.

Continue Reading »

The problem with absolute token expiration in Windows Identity Foundation (WIF)

When a secure token service generates a token it has an absolute lifetime (usually around 60 minutes). When the token expires the relying party must redirect the user back to the STS to get a new token.

That's not normally too much of a problem unless the session times out when the user is in the middle of editing a form and loses data. This happens a lot more often with absolute expiration as the user can easily request a form a minute or so before their session is going to expire.

Continue Reading »

Simple pluralisation in ASP.NET MVC

Your software application is like an iceberg. Your users only see a small fraction of the application, the parts that they interact with. Your application can be a mess under the covers but as long as you have a beautiful, quick interface that's super usable, your uses will think your app is designed really well.

If you don't bother with correct pluralisation your users will be less likely to appreciate the care you put into the rest of your application.

Continue Reading »

Keep calm and ship

Developers take pride in their work. We want to ship beautiful software using the latest frameworks, with a full suite of unit tests, that performs well and is über scalable.

But if we do that we're probably not going to get anything out of the door, as it'll never be perfect. The secret is not to worry about making something flawless.

Continue Reading »

Single sign out with Azure ACS

While developing CronHQ we initially had problems with our Facebook integration. Rule #6 of the Facebook guidelines require us to provide an explicit logout link.

6. Your website must offer an explicit "Log Out" option that also logs the user out of Facebook

However Azure ACS 2.0 doesn’t really support single sign out making the requirement a little harder to meet.

Continue Reading »