Serverless Microservice: The Backend

Part 1 – Planning and Getting Started
Part 2 –  Upload File

One of the key pieces when utilizing cloud architecture, be it for a Microservice or a more traditional monolithic approach, is selecting ready made components that can alleviate the need for custom code. For serverless this need is vitally important as going the serverless approach inherently implies a heavier reliance on theses components.

For our application, we are able to upload images and place them in our blob store. For the next step we would like the following to happen:

  • Upon being added to blob storage, an event is fired which triggers an Azure Function
  • The Azure Function will execute and take the new image and run it through Project Oxford (Microsoft Cognitive Services) and use Computer Vision to gather information about the image
  • Update the existing record in Mongo to have this data

BlobTrigger

As with our HTTP handling Azure Functions, we rely on Triggers to automatically create the link between our backend Cloud components and our Azure Functions. This is one of the huge advantages of serverless, it is to be able to easily listen for events that happen within the cloud infrastructure.

In our case, we want to invoke our Azure Function when a new image is added to our blob storage, so for this we will use the BlobTrigger. Here is an example of it in action:

[FunctionName("ImageAddedTrigger")]
public static async Task Run([BlobTrigger("images/{name}", Connection =
   "StorageConnectionString")]Stream imageStream, string name, TraceWriter log)
{
}

As with the HTTP Azure Function, we use the FunctionName attribute to specify the display name our function will use in the Azure portal.

To get this class you will need to add the WindowsAzure.Storage Nuget package, which will give you this trigger.

As with the HTTP Trigger, the “thing” that is invoking the function is passed as the first parameter, which in this case will be the stream of the newly added blob. As a note, there is a restriction on the type the first parameter can be when using the BlobTrigger. Here is a list: https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/azure-functions/functions-bindings-storage-blob.md#trigger—usage

Within the BlobTrigger the first parameter is a “route” to the new blob. So, if we dissect this, images is our container within the blob storage and the {name} is the name of the new image within the blob storage. The cool thing is, we can bind this as a parameter in the function, hence the second method parameter called name.

Finally, you will notice the named parameter here Connection. This can either be the full connection string to your blob storage which has your container (images in this case) or it can be a name in your Application Settings which represents the connection string. The later here is preferred as it allows things to be more secure and easier to deploy to different environments.

Specifying the Connection

Locally, we can use the local.settings.json file as such:

microservice5

On Azure, as we said, this is something you would want to specify in your Application Settings so it can be environment specific. The Values properties are surfaced in the application.

Executing Against Cognitive Services

So, with BlobTrigger we get a reference to our new blob as it is added, now we want to do something with it. This next section is pretty standard, it involves including Cognitive Services within our application and call the AnalyzeImageAsync which will run our image data through the Computer Vision API. For reference, here is the code that I used:

log.Info(string.Format("Target Id: {0}", name));
IVisionServiceClient client = new VisionServiceClient(VisionApiKey, VisionApiUrl);
var features = new VisualFeature[] {
    VisualFeature.Adult,
    VisualFeature.Categories,
    VisualFeature.Color,
    VisualFeature.ImageType,
    VisualFeature.Tags
};

var result = await client.AnalyzeImageAsync(imageStream, features);
log.Info("Analysis Complete");

var image = await DataHelper.GetImage(name);
log.Info(string.Format("Image is null: {0}", image == null));
log.Info(string.Format("Image Id: {0}", image.Id));

if (image != null)
{
    // add return data to our image object<span id="mce_SELREST_start" style="overflow: hidden; line-height: 0;"></span>

    if (!(await DataHelper.UpdateImage(image.Id, image)))
    {
        log.Error(string.Format("Failed to Analyze Image: {0}", name));
    }
    else
    {
        log.Info("Update Complete");
    }
}

I am not going to go into how to get the API key, just use this link: https://azure.microsoft.com/en-us/try/cognitive-services/

To get access to these classes for Computer Vision you will need to add the Nuget package Microsoft.ProjectOxford.Vision.

Limitations of the BlobTrigger

So, BlobTrigger is not a real time operation. As stated by Microsoft on their GitHub:

NOTE: The WebJobs SDK scans log files to watch for new or changed blobs. This process is not real-time; a function might not get triggered until several minutes or longer after the blob is created. In addition, storage logs are created on a “best efforts” basis; there is no guarantee that all events will be captured. Under some conditions, logs might be missed. If the speed and reliability limitations of blob triggers are not acceptable for your application, the recommended method is to create a queue message when you create the blob, and use the QueueTrigger attribute instead of the BlobTrigger attribute on the function that processes the blob.

https://github.com/Azure/azure-webjobs-sdk/wiki/Blobs#-how-to-trigger-a-function-when-a-blob-is-created-or-updated

What this means is, you have to be careful with using BlobTrigger because if you have a lot activity you might not get a quick enough response, so the recommendation here is to use QueueTrigger. Queue storage is a fine solution but, I am a huge fan of ServiceBus which also supports queues. So, instead of diving into QueueTrigger I want to talk about ServiceBusTrigger which I think is a better solution.

Create the ServiceBus Queue

First we need to create the queue we will be listening to, to do that we need to go back to the portal and click Add, search for Service Bus.

microservice4

You can take all of the defaults with the create options.

ServiceBus is essentially Microsoft’s version of SNS and SQS (if you are familiar with AWS), but it essentially supports all forms of Pub/Sub, absolutely vital in Microservice so the various services can communicate as state changes occur.

At the top of the screen we can select to Add a Queue. Give the queue a name (any name is fine), just something you will be referencing a bit later.

Once the queue finishes deploying you can access it and select the Shared access policies. Here you can create the policy that permits access to the queue. I generally have a sender and a listener policy. No matter how you do it, you need to make sure you have something that has the rights to read from the queue and write to it.

Once you have created the policy you can select it to get the Connection String; you will need this later so dont navigate away. Ok, lets code.

ServiceBusTrigger

The ServiceBusTrigger is not in the standard SDK Nuget package as the BlobTrigger and HttpTrigger are, for this you will need the Microsoft.Azure.WebJobs.ServiceBus. Now, as we did with the BlobTrigger we need to ensure we can specify the connection string we want the trigger to monitor.

https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus#trigger—attributes

We can do this, similar to above, by specifying the Connection string in our local.settings.json file, just remember to specify the same value in your Azure Function Application Settings. Here is an example of our backend trigger updated to use ServiceBusTrigger.

microservice6

As you can see, its roughly the same (apologies for using the image, WordPress failed to parse the code properly). The first parameter is the name of the queue we are listening to and is accessible by the given Connection string.

There is one thing I want to point before we move on, it has to do with Cognitive Services. I dont know whether its a bug or not but, when you are dealing ServiceBus your queue entries are simple messages or primitives. In this case, I am writing the name of the new image to the queue and this trigger will read that name and then download the appropriate blob from Storage.

For whatever reason, this doesnt work as you expect. Let me show you what I ended up with:

var url = string.Format("https://<blobname>.blob.core.windows.net/images/{0}", name);
var result = await client.AnalyzeImageAsync(url, features);

I actually wanted to read the byte data out of the blob storage based on the name, then I figured I would be able to pass that data into a MemoryStream and pass the stream to the AnalyzeImage and that would be the end of it. Not so, it crashes with no error message when passed. So, I noticed I can also pass a Url to AnalyzeImage so I just create the direct Url to my blob. Granted if you are wanting to keep the images private this doesnt work as well. Just something to note if you decide to copy this example.

The rest of the code here is the same as above where we read back the result and then update the entry inside Mongo.

Writing to the Queue

The final change that has to be made is when the user uploads an image we want to write our message into the queue, in addition to saving the image to Blob storage. This code is very easy and requires the WindowsAzure.ServiceBus Nuget package.

public static async Task<bool> AddToQueue(string imageName)
{
    var client = QueueClient.CreateFromConnectionString(SenderConnectionString);
    await client.SendAsync(new BrokeredMessage(imageName));

    return true;
}

Pretty straightforward. I am simply sending over the name of the image that was added, remember the name is the ObjectId that was returned from the Mongo create operation.

QueueTrigger

I didnt cover it here but there is such a thing as QueueStorage which is effectively a queue using our Storage account. This works similar to the ServiceBus but, as I said above, I really view this as a legacy piece and I think ServiceBus is the future. Nevertheless, it remains an option when dealing with a scenario where BlobTrigger does not work fast enough

Conclusion

Ok, so if everything is working you have a system that can take an uploaded image and send it off for processing to Cognitive Services. This is what we call “deferred processing” and is very common in high volume systems; systems where there is just not the ability to process things in real time. This “deferred processing” model is in widespread use at places like Facebook, Twitter, and others though much more complicated than our example. This even underpins popular design patterns like CQRS (Command Query Responsibility Segregation).

In short, the reason I like this model and, ultimately, Azure Functions (or the serverless model more specifically) is it allow us to take advantage of what is already there and not have to write things ourselves. We could write the pieces of this architecture that monitor and process but why? Microsoft and Amazon have already done so and support level of scalability that we likely cannot anticipate.

In our next section, we will create the GetAll endpoint and start talking about the API layer using Azure API Management.

Serverless Microservice: Upload File

See Part 1: Getting Started

For the first part of this application we are going to create an Azure Function which allows upload of a file. As this file is uploaded its binary data will be stored in Azure Blob Storage while other information will be stored in a MongoDB document. The later will also receive the Cognitive Service Analysis Result data.

I like to look at each project as a “microservice”, that is related functions which together fulfill a logic unit of functionality. Later, we will discuss how to connect these together using Azure API Management.

Before we perform any code, let us think back to our document and the overall flow we are going for. We know that the user will, via HTTP, upload a file which we want to save in Azure Storage and create a record for in Mongo.

Preparing Our Components

Logging into the Azure Portal, we will want to, optionally, create a Resource Group to hold everything in; this is my convention as I find it makes finding things easier as well as cleaning up when you need to tear things down.

I wont walk you through how to do these things but here is a high level summary of what you will need:

  • A Storage Account with a single container – I called my “images”
  • A CosmosDB using the Mongo API. Really you could use whatever API you want but, the rest of the examples will be using MongoDB.Driver for the Nuget package

For the CosmosDB you dont actually have to do anything more than create it as the MongoDB.Driver code will actually handle creating the database and collection for you.

What you will want to do is copy and hold onto the connection strings for both of these resources:

  • For Storage: Access the newly created Storage Account. In the left navigation bar select AccessKeys, the Connection String for the Storage Account is located here
  • For Cosmos: Access the newly created Cosmos Database. In the left hand navigation, select Connection String. You will want the Primary Connection String

Let’s write the code

So far I have tried creating Azure Functions with both Visual Studio and Visual Studio Code and for this case I have found Visual Studio to be the better tool, especially with the Azure Functions and Web Jobs Tools extension (download). This will give you access to the Azure Functions project type.

If we use Create New Project in Visual Studio, so long as you have the above update you should be able to make this selection:

microservice2

To help out, the extension provides an interface to select from the most common Azure Function types; by no means is this exhaustive but its a great starting point. Here is what each type is:

  • Empty – An empty project allowing you to create things from scratch
  • Http Trigger – An Azure Function that responds to a given path (we will be using this)
  • Queue Trigger – An Azure Function that monitors a Service Bus Queue
  • Timer Trigger – An Azure Function that fires every so often

For this we are going to use an HTTP Trigger since the function we are creating will service HTTP requests. For Access Rights just choose Anonymous, I will not be covering how authentication works with Azure Functions in this series.

Here is what the starting template for HTTP will look like:

public static class Function1
{
    [FunctionName("Function1")]
    public static async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
    {
        log.Info("C# HTTP trigger function processed a request.");

        // parse query parameter
        string name = req.GetQueryNameValuePairs()
            .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
            .Value;

        // Get request body
        dynamic data = await req.Content.ReadAsAsync();

        // Set name to query string or body data
        name = name ?? data?.name;

        return name == null
            ? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
            : req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
    }
}

The notable aspects of this code are:

  • FunctionName – This should parallel the name of the file (doesnt have to), but this is the name you will see when the function is listed in Azure
  • HttpTrigger – This is an attribute that informs the underlying Azure workings to map the first parameter to the incoming HttpRequestMessageYou can provide additional helpers to extract data out of the Url as well as provide for Route matching, the same as in WebAPI.

Let’s talk a bit more about HttpTrigger. You will see this sort of pattern through Azure Functions. These “bindings” allow us take the incoming “thing” and cast it to what we need. Depending on the type of binding (HttpTrigger in this case) you can bind it to various things.

Additionally, the HttpTrigger supports verb filtering so the above would only allow POST and GET calls. The named parameter Route allows you to specify the route that the Azure Function will look for to handle; these are the same concepts from WebAPI. This will also be used with BlobTrigger later on.

Finally, there are no limitations around return result. Azure will only look for a method called Run, you can return whatever you want. The default is an HttpResponseMessage but I have used IList and other complex and primitive types.

Here is the code for upload, you will note that I am also using HttpResponseMessage.

[FunctionName("UploadImage")]
public static async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "upload")]HttpRequestMessage req, TraceWriter log)
{
    var provider = new MultipartMemoryStreamProvider();
    await req.Content.ReadAsMultipartAsync(provider);
    var file = provider.Contents.First();
    var fileInfo = file.Headers.ContentDisposition;
    var fileData = await file.ReadAsByteArrayAsync();

    var newImage = new Image()
    {
        FileName = fileInfo.FileName,
        Size = fileData.LongLength,
        Status = ImageStatus.Processing
    };

    var imageName = await DataHelper.CreateImageRecord(newImage);
    if (!(await StorageHelper.SaveToBlobStorage(imageName, fileData)))
        return new HttpResponseMessage(HttpStatusCode.InternalServerError);

    return new HttpResponseMessage(HttpStatusCode.Created)
    {
       Content = new StringContent(imageName) };
    };

This code is pretty straightforward though, I admit, learning how to read the image data without using the Drawing API was challenging.

Basically, we are reading the contents of the response message as multipart/form-data. We can some basic information about the image from the processed form-data. We then use our helper method to create a record in Mongo thereby generating the unique ID identifying the document. We then use this unique ID as the name for the image in blob storage.

Here is the code for creating the Mongo Document:

public static async Task CreateImageRecord(Image image)
{
    var settings = MongoClientSettings.FromUrl(new MongoUrl(MongoConnectionString));
    var mongoClient = new MongoClient(settings);
    var database = mongoClient.GetDatabase("imageProcessor");
    var collection = database.GetCollection("images");
    await collection.InsertOneAsync(image);

    return image.Id;
}

And the code for adding the image to Azure Storage:

public static async Task SaveToBlobStorage(string blobName, byte[] data)
{
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(StorageConnectionString);
    CloudBlobClient client = storageAccount.CreateCloudBlobClient();
    CloudBlobContainer container = client.GetContainerReference("images");

    var blob = container.GetBlockBlobReference(blobName);
    await blob.UploadFromByteArrayAsync(data, 0, data.Length);

    return true;
}

To complete this code the following Nuget packages will need to be installed

  • MongoDB.Driver (latest)
  • Newtonsoft.Json (v9.0.1)
  • WindowsAzure.Storage (latest)

I had to use a different version of Newtonsoft because of differences when adding it to a .NET Standard Class Library.

Finishing Up

So, in this walkthrough we created our first service with our first endpoint. Now, we have a way to upload files to our storage. Our next step will be to write the code which, upon adding the file to blob storage, kicks off another Azure Function which runs the image data through Microsoft Cognitive Services Computer Vision API. We want to collect that data and update our existing Image record with the findings and then show that to the user. We still have a ways to go, but we made good strides.

Reference: https://drive.google.com/open?id=1lVo_woIZAAiiGyDECKvuKL97SfibwIja – this is the Image.cs class file I created with supports both serialization to and from Mongo via Bson and via the web using Json.

 

Serverless Micro Services: Getting Started

Serverless systems are all the rage these days, and why not? They are, in my view, the next evolution on the microservice architecture that has been quite common over the last few years. But they offer several benefits such as they require no infrastructure deployment and, within most cloud environments, can easily integrate with and respond to the events happening within the cloud system.

The two leaders in this category, as I see it, are Amazon (Lambda) and Microsoft (Azure Functions). I thought it would be useful to walk through creating a simple Image Processing Microservice and discuss the various pieces of the implementation, from planning to completion.

Planning

One of the most critical pieces in software development is planning, and with Cloud this is even more vital as the sheer number of ways to accomplish something can quickly create a sense of paralysis. It is important that, for your chosen Cloud provider, you understand its offerings and have some idea how things can integrate and how difficult that integration may be versus other routes.

This planning is not only for the archiecture and flow of the coming application but also a means to facilitate discussion with your team. For example, understanding that serverless may not be the best choice for everything. Serverless functions can take a while to spin up if they are not used often. Further, most serverless providers cap the execution time of a given function. Understanding these and other shortcoming may lead you down the road of a more traditional microservice using Docker and infrastructure, going purely serverless, or a hybrid of the two.

For our Image Processing application, I have concocted a very simple diagram with the pieces I intend to use.

microservice1

In our example, the user will access our API through the API Manager feature in Azure. Using this allows us to consolidate our various Azure Function blocks behind a consistent API name and Url. Further this allows easy definition of rate limiting rules, as well as other elements that while important, will not be in our example.

In our application, the user will upload an image which we will store in blob storage and create a record in our MongoDB instance. The addition of the image to blob storage will trigger another Azure function that is watching for new adds. This function will take the new add and run the image through Azure Cognitive Services which will tell us more about the image. The additional bits of data are then added to the NoSQL document. records from Mongo are transmitted to our user as calls to the GetAll function are made.

Closing Thoughts

For this example, I have chosen to use an Azure Function which means that my method MUST complete in 5 minutes or less or Azure will kill it. Now, the only time that matters is if you are upload a large file or doing a very intensive operation. Though, for the later you would not want to tie that to a web operation anyway, you would favor a form of deferred processing; we actually do that here with our call to Cognitive Services.

In a typical application we often want to consider the type of access a service will require, as it plays into a lot of selection for other components. I chose to use a NoSQL database here because, under normal circumstances for this sort of application, I would expect a lot of usage here but, I dont necessarily care about consistency as much as availability; this is an essential conversation that needs to be had as you plan to build the service.

Finally, I love Azure functions here because they tie so neatly into the existing Azure services. While it would be trivial to write a polling process or, even leverage a Service Bus queue, using Azure functions which can be configured to respond to blob storage adds, means I have less to think about.

Ok, so we have planned our application. Let’s get started by building our Image Upload process in the next section.

Go to Part 2: Create Upload File

 

React, Redux, and Redux Observables

Today I will conclude this series as we dive into the final bit of our example and feature the setup of one of my favorite ways to structure my data access layer.

Part 3: Redux Observables

One of the great things about Redux is how well it organizes your state and how easy it can be to follow state changes. The uni-directional flow works well for this, but where it falls flat is when it comes to asynchronous operations, namely calls to get and manipulate data from a backend server.

This is not a new problem. Sagas, Thunks, and other approaches have been made to solve this problem. I cannot say that Redux Observables are the best, but certainly I have finding more and more uses for Reactive approaches in the code I am writing so, I welcome the ability to use RxJS in Redux.

The first step in this process is to update Redux to support this approach. See, Redux expects an actual object to be returned from a reducer which is fine for state changes, but not realistic for async operations. We need to change the middleware to support other types being returned; for this we need custom middleware, which we get from the redux-observable NPM package.

Most of the setup work for the custom middleware happens in the configureStore method which we created during the Redux portion of this series. Here is a shot of the updated configureStore method

observable1

It is not at all unusual for this method, as your application grows in size and complexity to gain complexity as well. In this case, we have brought in the applyMiddleware method from redux.

We use this new method to apply the result of createEpicMiddleware which comes from the redux-observable package. The parameter to this call is a listing of our “epics”.

An epic is a new concept that redux-observable introduces. For reference, here is a look at the Redux flow with these Epics included.

observable2

I like to think of epics as “Observable aware Reducers” mainly because they sit at the same level and have a similar flow. That being said, I do not look at epics as devices for updating state in most cases, instead I look at them as more specialized aspects of the system. Here is an example of the epic I use to get a list of Todo items from my sample application:

observable3

What is happening here is actually straightforward, however the methods of RxJS can make things a bbit hard to understand at first. Essentially, our call above which passed in rootEpic allowed Redux to pass emitted actions into our Epics. You recall that, in Redux, every action is passed to every reducer; which is why every reducer must have an exist case. Using combineReducers we can mash all of these reducers into one giant one. Similarly the call above with rootEpic is doing the same thing.

Unlike Reducers however, Epics do not need to have an exit case defined. They can safely ignore an action if it does not pertain to it. In this case, we use switchMap to ensure the any pre-existing occurrences of the operation are cancelled to make way for the new. Full docs: https://www.learnrxjs.io/operators/transformation/switchmap.html

The rule here is that we always return the core object of RxJS: Observable. Observabbles are, in many ways, similar to Promises. However, one major difference is that Observables can be thought of as being alive and always listening where Promises exist for their operation alone. This difference enables Observables to very easily carry out advanced scenarios without adding a lot of of extra work.

For the above, if fetchItems was called more than once, only one call would ever be in play. This is important because, the Observable returned once the call does complete sends off an action to a Reducer to add the fetched items into state. As a general rule, on our teams we do not use Epics to carry out changes to state, though it is possible we find that having this separation makes things a bit easier.

To call into an epic, you simply raise the action as you would normally via the dispatcher.

observable4

Here we call loadItems in componentWillMount (essentially when the App loads). This will raise the FETCH action that caused things to happen.

A more advanced scenario

Ok, so now you have the general idea, let’s look at something a bit more complex: forkJoin (https://www.learnrxjs.io/operators/combination/forkjoin.html).

In our example, we allow the user to create new Todo items and update existing ones. When the user is ready they can hit our sync button which saves all of the changed data to the server. This is an obvious scenario where “we want to do a bunch of discrete things and then, when they are all done, we want to do a finishing action”. This sort of thing before Promises was absolutely brutal.

Since we are using Obbservables we can do this without Promises but we will use a similar structure. For us, forkJoin is analogous to Promise.all.

observable5

In this code we do some very basic filtering to find new and existing items which have changed. We want to call two separate endpoints for these two things. Another strategy would have been to send everything up and let the server figure it out; but that is less fun. And this is even easier to do in C#.

The important thing to understand is that our methods createItem and updateItem both return observables (they update the local state to reset dirty tracking flags and, for new items, hydrate the Id field to override the temp Id given).

Here we use mergeMap (https://www.learnrxjs.io/operators/transformation/mergemap.html) to allow the inner Observables to complete and update their state as that action is not important to the action of indicating the sync is complete. For reference, here is the code for createItem.

observable6

You can see that we use map (https://www.learnrxjs.io/operators/transformation/map.html) here which is crucial so the observable that is returned can work with forkJoin, we dont want to wait for any internal completion at this level.

So what will happen is when post is called, it will return an Observable and that is immediately returned (along with all others). Internally, when the call does complete it will return our action result; map will then wrap this in an observable.

Ok, so this inner observable will be striped out of the outer by mergeMap (along with all others) and will be added to an array of Observables within another one using concat, in addition to two others (syncComplete and snackbarItemUpdate).

So that is crazy complicated. Try to remember that the parameter passed into mergeMap is the array of completed observables (completed in the sense that the web call finished) which contain state changes that need to be applied in addition to actions which hide a busy indicator and show a snackbar.

This is all compressed into a single observable (via concat) and returned to the middleware. The middleware will then dispatch each internal (which it expects to resolve to an object) action. This will then be checked by other epics and your set of reducers. In our case, the actions will perform state changes before finally signalling to dismiss the busy indicator and show our snackbar.

I realize that my explanation there was probably very hard to follow, also I am no RxJS expert. However, it does enable some very cool scenarios out of the box, and I like it because I believe there many advantages offered over Promises.

Let’s bring it home

So that concludes the series. I am actually giving a presentation based on this material, most recently at Codemash in Sandusky. I really do believe that Observables offers some solid advantages over what I have seen of Thunks and Sagas bbut, as always, evaluate your needs first and foremost.

Here is the code for the full app used throughout this demo: https://gitlab.com/xximjasonxx/todo-app

Examine the various remote branches to see starting points that you can use to see how well you understand the setup for the various parts.

Cheers.

Codemash

With great humility I accepted the invitation to speak at Codemash for a second year in a row. Last year I spoke on Xamarin.Forms, this year I debuted my new talk based on the experience of a project I have been leading for 7 months at West Monroe; a talk on ReactJS, Redux, and Redux-Observables. The talk is a culmination of the lessons learned while using this stack to develop the product for our client.

This Codemash, however, was very different from all other experiences due mainly to my extended stay at the hotel (I am usually only there for the GA conference) and my fight with severe food poisoning on Wednesday. The later caused my session to be delayed until 830am on the final day of the conference. Thankfully things went well, but throwing up seven times on Wednesday was not at all fun.

But in the end things worked out, I even managed to catch an earlier flight back to Chicago to beat a snowstorm that was coming in. Throughout this trip I was reminded just how awesome it is to fly with Southwest as I had to make many changes to my trip and each time, super easy and no fees. I also discovered the Kalahari, and probably other similar hotels, are not well setup for person’s with upset stomachs – was very difficult to find bland foods on their menu. But their staff was amazing and even had the onsite EMT check me out to make sure I didnt need any additional treatment; I didnt.

As for the talk I got quite a few people which, given the reschedule, actually surprised me. It was a good audience, great questions. But I still feel the talk attempts to cover too much despite my best efforts to scale it down; it might well become a two part talk.

For now, I am resting and enjoying my 35th birthday and heading back to work with no travel on the calendar until March (MVP Summit). Time to find a new apartment in Chicago and start preparing for Ethan’s arrival in July.

StarCraft Unit API

It has been a long time since I last created a post here. It is not a question of desire, more of time. In the past two months, I served as Best Man at my youngest brother’s wedding on September 30 and then, two weeks later, I married my girlfriend Woo of four years. We only just got back from the honeymoon. I must say, I was thankful my many years in consulting taught me how to organize and plan; I ended up doing the lionshare of the wedding planning and, I will say, using Agile and Scrum to plan it made it a snap.

These events did force me to forgo speaking for the last 6 months of the year, mercifully in a way as West Monroe has kept me impressively busy. But now, with all of this behind me I can finally turn my attention back to speaking and community involvement. To that end, I will be returning to Codemash in January to speak on React, Redux, and Redux Observables (our team has been using this extensively in our current project).

To that end, I have been wanting to create a new source of data for my future talks and so I decided on cataloging the various StarCraft units. My hope is, in addition to serving as a data source, I might be able to use it also practice Machine Learning to calculate new build orders.

Anyway, to build this API I decided to take a new tactic and leverage Azure Functions with HTTP Triggers and the “new” Azure CosmosDB (the successor to DocumentDb). I thought I would walk through things here:

Creating the CosmosDb

Setting up the backend database was very easy. I simply searched in the Azure portal for Cosmos and followed the steps for setup. I wont get into throughput settings or anything like that as I dont see this being used that heavily.

Create the Azure Function to Create

This ended up being the hardest part, mainly because my Azure CLI tools were out of date and it caused a weird bug when running locally – the request would always come through as a GET – which sucks if you are expecting POST and looking for BODY content. Once I upgraded the problem went away. Just an FYI.

So, Visual Studio tooling has come a LONG way in this aspect, its super easy now to create these Azure functions locally, test them, and seamlessly deploy them. I recommend creating the solution after the project as a whole and using the the “projects” to partition off the various pieces of your API.

In my case, I went with StarcraftApi for my solution name and created AdminApi which will hold admin functions ( in this example we will create a unit ). You can also create class library projects to share logic between the various APIs – hint you will want to make sure these class libraries using the same .NET Standard setting as the Azure function project (AdminApi).

SolutionExplorer

I try to isolate a single Azure function for each file here so, CreateUnit for this example. The goal here is to take take the contents of the incoming BODY and insert the Json into my CosmosDb. You will remember that Cosmos is a NoSQL database so there is not defined schema you need to follow.

Ok, so if you actually look at one of these functions there is a lot to take in, especially in the method signature portion.

signature

  • FunctionName – this is for Azure and discovery – it gives the “name” for this function, since Run isnt very descriptive
  • HttpTrigger – indicates how the requested is given to the function. In this case, via a Http POST request matching the route api/Unit (case insensitive)
    • Admin here indicates that the _master key must be passed to this function to authenticate usage

Once you have these in place you can upload the code to Azure and it can be executed. You can also run it locally though, be aware, the local server does NOT seem to check for Admin creds; I think that is intentional.

Inserting Data

When you create your CosmosDb you will be given a connection string. Cosmos fronts a variety of different NoSQL Database technologies, for my example I am using Mongo, so I will have a Mongo connection string and use the Mongo .NET libraries to connect (MongoDB.Driver v2.3.0 – v2.4.x seems to have a known bug where it wont connect properly).

So, the weird thing here is, even though we have a CosmosDB we do not actually have a database. I mean, easy to create you can click +Add Collection and it will prompt you for the database at which point you can do “Create New”.

cosmos

Collections are where the data will actually live and collections live in databases. Like I said, not hard just very weird when you think about it. But it is a similar paradigm from SQL Azure, where you had to create the server first and then database; just the naming is weird here.

Full sample that I used is here: https://stackoverflow.com/questions/29327856/how-to-insert-data-into-a-mongodb-collection-using-the-c-sharp-2-0-driver

Happy Coding. Hit me in the comments if you have any questions.

Cloud Bootcamp at West Monroe

One of the great things I love about working at West Monroe is the spirit of mentorship and camaraderie that are central to our culture. While there are numerous examples, perhaps my up and coming favorite is our New Hire onboarding process. While we have, for many years, made it a priority to put new hires through our Consulting 101 class so they gain an understanding of the world of consulting, we took it to a whole new level last year when, as opposed to hiring an outside firm, we asked internal leaders to develop curriculum to onboard new hires in the various technologies and methodologies that are in use at West Monroe.

 

Last year, the inaugural year,  I helped lead the mobile portion of this training. Our main focus was iOS with Xamarin as this is where we see most of our client work. The result was impressive, two of those in the class were able to quickly roll on to a crucial Xamarin project and ultimately contributed to a rousing success (one is now leading his own project while the Senior is traveling in China, while the other has become our leading expert on Android).

As I have moved away from mobile to focus on my roots of web and backend development I was asked to put together a new curriculum this year, one focused on cloud computing. This is due to the immense success of the previous year which has seen the time for this training increase to 10 full working days – Cloud will have its own 4hr block.

This desire to mentor and cultivate our young developers into the future leaders is part of what makes working at West Monroe so rewarding. Now starting my 4th year at the firm I have taken great pride in seeing so many of the young consultants I have worked with and mentor now taking leading roles on their projects and continuing to improve.

Getting Started with Flow and VSCode

Normally when I do JavaScript development I leverage TypeScript, its been my goto for a few years now. But for a new project at work we are deciding to forgo Typescript and leverage pure JavaScript. As we are going to focus on using ES6 this is not a problem as much of the Typescript syntax is now available in ES6 (thanks to Babel we can transpile to ES5). But one thing that is not available is typing which sucks cause, having a type checker can really help developers avoid errors.

After much discussion we decided this is a great opportunity to play with Flow, which is a static type checker for JavaScript. The rest of this article will focus on getting flow running and VSCode validating your JS with type safety.

Let’s add Babel & Flow

Babel makes everything so nice, allows me to use the ES6 syntax in Node (v7.x has most of it but there are a few things). For Flow, it is recommended you install the following packages as dev dependencies:

babel-cli babel-preset-flow flow-remove-types

The last one can be confusing since their install docs do not call it out explicitly. In addition, you will want to add:

babel-preset-env flow-bin

Probably the trickiest thing for me was wrapping my head around flow-bin since it was not immediately clear. It basically allows you to have Flow locally in the project, which is the recommended approach over a global install.

Now, we need to update the package.json so that we can build using babel which will remove our type annotations. The command is simply:

babel src/ -d dist/

I am assuming here that all source files are in a directory called src and the transpiled final version will go into dist.

The final thing is to create the .babelrc file with the follow contents:

{
    "presets": ["flow", "env"]
}

These presets will strip out type annotations (since they are not valid JavaScript) and transpile our ES6 code into ES5 which is recognized by Node.

Integrating Flow

The absolute first thing you need to do is run the initialization script to create the default config file (.flowconfig) recognized by Flow.

yarn run flow init

You can leave this file be for the most part, wont be modifying it here.

Here is the code I wrote with flow:

/* @flow */

export default class Calc {
    static add(num1: number, num2: number): number {
        return num1 + num2;
    };

    static sub(num1: number, num2: number): number {
        return num1 - num2;
    };

    static mult(num1: number, num2: number): number {
        return num1 * num2;
    };

    static div(num1: number, num2: number): number {
        return num1 / num2;
    };
}

Its very simple and effectively creates a library of mathematical functions. Next, use this script as your index.js, I have included a couple type errors for flow to catch.

/* @flow */

import calc from './lib/calc';

console.log(calc.add("5", 6));
console.log(calc.sub(5, 6));
console.log(calc.mult(30, "20"));
console.log(calc.div(40, 20));

To run the follow command use yarn (or npm):

yarn run flow

You will need to invoke yarn (or npm) since, I assume, you used flow-bin package which means your Flow is packaged inside your project.

Against the code above, flow should pick out the two cases where a string was passed and the error is similar to what you would receive in a language like C# if you made the same error.

Add Some Scripts

The thing, as I said, about Flow code is its not JavaScript and so if you run it straight it will fail every time. The Flow preset from Babel stripes out the type annotations when building to leave valid JavaScript. Since this is the case, we should define an NPM script that we can run each time. Open package.json and add the following line to your scripts section.

“build”: “flow && babel src/ -d dist”

This command does two things:

1) it tells Flow to check the files with the @flow annotation for errors – if it finds any the process will fail.

2) it runs the code through Babel to both strip out type annotations (for all files under src/) and transpiles to ES5.

To execute this simply do

yarn build

or

npm run build

If you then examine the files under dist/ you will see a stark difference from the code you wrote; this is the power of Babel.

Let’s Configure VSCode

Ok, so at this point we can run everything from the command line, we get type checking and its all good, right? Well no. VSCode is probably going nuts because its still trying to parse the code in your .js files like its pure Javascript. We need to make it aware of Flow. Turns out, that is pretty easy.

Click the “Extensions” icon on the left hand navigation column and search for ‘Flow’. One of the items that will come up is Flow Language Support (below).

screen1

After installing you will notice the errors are still present. But why? Well, its because VSCode (correctly) assumes you are still working with pure JavaScript, we need to disable this. But because Flow is not a global part of our environment (and shouldnt be) we dont want to change settings for the editor, we want to do it for our workspace.

To do this, you need a settings.json file. Best way to create that is to indicate you want to override the default language settings.  First, click your current language from the lower right portion of the application status bar (below).

screen1.5

This will bring up a menu where you need to select to configure the language based settings for JavaScript (might also want to do this for JSX if you are using React and any other derivative JavaScript extensions).

screen2

This bring you into the settings.json file editor (it is a special file after all). From the right hand side of the top bar select ‘Workspace Settings‘.

screen3

You are now in your local settings.json file. Here is the absolute minimum that I recommend to support Flow.

screen4

flow.useNPMPackagedFlow just tells the extension to look in node_modules for the flow binary.

Basically, we are disable the internal JavaScript validator in favor of the Flow one. I do have a sidebar on this below since I believe you need to be aware of what this means. But regardless, after doing this, Visual Studio should cease seeing Flow type annotations as JavaScript errors. Congrats. That is it.

My Sidebar

I generally recommend that developers exclude .vscode from source control. However, there is an obvious problem in this case – without the settings.json file code will appear broken in VSCode for developers that dont have the right settings.

This goes one step further when everyone is using different editors (in our case we expect VSCode, Sublime, and WebStorm to be in play). Its not a huge deal really, you just need to make sure you communicate the usage of this library; I would really hate writing the type annotations just to get red squiggles all over my code, even though its valid.

So the point here is communicate and make sure that everyone can use Flow effectively. Its a great tool, but not something a single developer can use without the rest of the team, I feel, at least not easily or naturally.

Hybrid Xamarin.Forms Applications

When Xamarin.Forms was announced and released by Xamarin it represented an interesting take on their platform. The problem it attempted to solve was one that was becoming increasingly common in the mobile space and it represented a fair attempt to solve it. However, as a developer I do not consider Xamarin.Forms a replacement for the user of traditional Xamarin, just as I do not consider Xamarin a replacement for native development; all things have their places.

All that being said, Xamarin.Forms can give you some pretty cool advantages, one of which is the ability to design one code base and get decent rendering on multiple platforms. This makes it ideal for simple applications lacking significant customizations of the platform.

Most often, developers apply this advantage at a macro level, which is the designed purpose. However, if you consider that within complex applications you may have simple screens that do not gain any advantage from being developed in native code and that the potential of MIXING screens could yield a productivity benefit. This is what I have been looking at with Forms. I wanted to share with you what I found.

Understand the basic flow

Any mobile application represents an exercise in information architecture with the goal being to create the most efficient user flow possible. If you decide to mix screens, you have to really consider the order of your screens.

My advice for now is, assume that Xamarin.Forms will still control the navigation of your application at a high level. In some cases you may go from native page to native page, but even then, you want to do so while managing the Forms navigation flow. The rest of this article will assume this.

Custom Renderers

Each element that you see on your screen in Forms is drawn by a Renderer and one of the pillars of Forms customization is the notion of Custom Renderers whereby you can plug your own logic and perform custom rendering; this is the approach we will be using. When dealing with Custom Renderers you always want to define a custom control first. This will serve as a marker that will help to invoke your renderer.

public class NativePage : Page
{
     public string KeyName { get; set; }
     public string IosStoryboardName { get; set; }

     public NativePage()
     {
          IosStoryboardName = "Main";
     }
}

The properties on this class are used by the renderer to make sense for the various platforms:

  • KeyName – a unique name for the view or viewcontroller we will load for this page
  • StoryboardName – is specific to iOS and allow us to extract the related view controller out of a storyboard. The default of Main is used as the convention that most iOS developers use for their default storyboard.

For Xaml, we use this control as such:

<controls:NativePage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:controls="clr-namespace:NativeTransition" x:Class="NativeTransition.LoginPage" KeyName="Login">
</controls:NativePage>

By itself, this will do nothing. In fact, you could add normal content here and it would render as Forms normally does. This is because, by default, Xamarin.Forms registers a Renderer called PageRenderer for the Page class which is what does all of the magic. So, if Forms comes across a custom control it does the following:

  • Attempts to find a Renderer registered for its specific type name
  • Attempts to find a Renderer registered for its base class
  • Attempts to find a Renderer registered for its base class’ base class
  • And so on

So, our next step will be to define a Custom Renderer, and we should do this for each supported platform. If we dont, the above sequence will be applied.

About Custom Renderers (a few words)

Principally Custom Renderers are organized around two methods

  • OnElementChanged – called each time the primary element changes (that is it is initially created or a property is changed from its default value)
  • OnElementPropertyChanged – called each time the value of a property changes on an established control. This is used frequently to support custom data binding scenarios.

Generally, these methods are available in some form or another for each renderer you will create. The biggest point to understand about these methods, in particular with OnElementChanged, is that they are called multiple times. So, generally you want to setup some logic to ensure initial creation logic only runs one time.  Here is an example:

if (e.NewElement != null && e.OldElement == null)
{
     base.OnElementChanged(e);
     // Your Creation logic here
}

Having your creation logic inside this logic will ensure it is called one time and keep your rendering processing efficient.

The iOS Custom Renderer

With iOS, our goal is going to be to look at our KeyName and extract that ViewController from our storyboard. Once we have this ViewController we call some method to indicate to iOS that it is hosting our View Controller. As developers, we will be able to work with this View Controller as we would normally.

var keyName = (e.NewElement as NativePage)?.KeyName;
var storyboardName = (e.NewElement as NativePage)?.IosStoryboardName;
var viewController = BuildViewController(keyName, storyboardName);

// do the iOS thing to make it like the View Controller
ViewController.AddChildViewController(viewController);
ViewController.View.Add(viewController.View);				viewController.DidMoveToParentViewController(ViewController);

For simplicity, I have dropped my various null and parameter checks, but you will obviously want to code defensively here. The properties being used are defined on our custom Xamarin control in the XAML.

As for BuildViewController, its very simple and familiar to anyone who has done iOS for any amount of time.

UIViewController BuildViewController(string keyName, string storyboardName)
{
     var sourceStoryboard = UIStoryboard.FromName(storyboardName, null);
     var viewController = sourceStoryboard.InstantiateViewController(keyName);

     return viewController;
}

Once extracted, the view controller can be utilized as any normal View Controller in iOS would be, nothing special is required for Forms.

The Android Custom Renderer

Android is a bit more complicated, mainly because of how the windowing system works in general. Truthfully, Android is more well geared towards doing this sort of thing than iOS is, because we could have separate activities that represent different Forms applications. But like many things with Forms, it is made harder because you are abstract two different platforms. (If Xamarin would introduce a FormsViewController for iOS, I think the two could be made similar, but that is another conversation).

As we know, Android presents its view mainly though Xml layouts and Forms leverages a sort of dynamic view generation technique to accomplish this, I believe. In our case, we will want to use KeyName to dynamically load a view from our Resources folder. Here is the core logic:

var keyName = (e.NewElement as NativePage)?.KeyName;
var activity = Context as FormsAppCompatActivity;

_layoutView = BuildLayoutForKeyName(keyName);
var pageView = (LoginPageView)Activator.CreateInstance(typeof(LoginPageView));
AddView(_layoutView);

// support view interaction
pageView.PrepareView(
   activity, (e.NewElement as NativePage).Navigation, _layoutView);

So, this is where things get tricky because of the way Android is handled by Forms. In iOS, we get to work with full ViewController but in Android, everything is loaded into a single Activity, effectively replacing the ContentView each time, so we can expect to get an Android activity each time. This is the reason for the PageView concept which we will cover later.

Using the KeyName value, we attempt to find a layout whose name matches this value, inside BuildLayoutForKeyName.

Android.Views.View BuildLayoutForKeyName(string keyName)
{
     var id = Context.Resources.GetIdentifier(
          keyName.ToLower(), "layout", Context.PackageName);
     return (Context as Activity).LayoutInflater.Inflate(id, this, false);
}

Notice I have some leftover code as you would want to check for both forms of casing, not just assume lowercase, though you could as that is the standard in native Android.

The final bit is to adjust the size of the view as Android perform its layout operation, we do this using OnLayout lifecycle hook. As a note, I got this code off a Stackoverflow answer, but its pretty clear what it is doing.

protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
     base.OnLayout(changed, l, t, r, b);
     var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
     var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);

     _layoutView.Measure(msw, msh);
     _layoutView.Layout(0, 0, r - l, b - t);
}

Ok, using this approach will get our view to show up but, we have no way to interact with the View from the renderer, unless we create a dedicated renderer for each NativePage type which does not make a lot of sense. That is why I introduced the PageView concept.

The PageView

The idea behind PageView is not revolutionary, basically at a certain point we will pass off the generated View to a class whose sole purpose is to configure and setup the view. To be fair, there is a lot more we need to be able to do with Android views, so my approach here is still lacking, but its a fair start.

public class LoginPageView
{
     private FormsAppCompatActivity Activity { get; set; }
     private INavigation Navigation { get; set; }

     public void PrepareView(
          FormsAppCompatActivity activity, INavigation navigation,
          Android.Views.View view)
     {
          Activity = activity;
	  Navigation = navigation;

	  view.FindViewById<Android.Widget.Button>
               (Resource.Id.loginButton).Click += login_click;
     }

     void login_click(object sender, EventArgs e)
     {
     }
}

So, a few things that certainly need to change with this approach:

  • Its totally hard coded to LoginPageView. Since we cant use generics with renderers due to the export syntax not being amenable to it, we would need to specify it somewhere. My leading through is a convention based notation where I look for PageView and activate that.
  • It doesnt allow you to take advantage of the Android lifecycle methods. This is a big no no. My current leading thought is moving View inflation to this class as a base responsibility. But bringing the lifecycle methods over will remain tricky.

Definitely Android is a work in progress but, using this, you can create native Android interactions in your own custom View class without needing to reference Forms, though there is certainly more coupling with Forms here than there is in iOS.

Navigation back to Forms

So the cool thing here is, despite the fact that you are in native code, you are technically still in Forms, because all that is happening is Forms is rendering your Page as a native page. So, we can still use the standard Forms navigation techniques. For example, in Android you might do something like this:

async void login_click(object sender, EventArgs e)
{
     await Navigation.PushAsync(new PeopleListPage());
}

In iOS, you can do the above OR you can use traditional iOS navigation if you want (via PresentViewController). The reason this works is, under the hood all Forms does with each navigation is replace the RootViewController. Example:

partial void loginClick(NSObject sender)
{
     PresentViewController(
          new PeopleListPage().CreateViewController(), true, null);
}

To be fair, these are very simple scenarios that I have been testing, under normal application development, this may or may not work. But, remember, this sort of approach is designed to enable SOME screens to be Forms based and shared, not a large variety of them. Always consider your goal and what makes the most sense. Overusing this approach will lead you to problems.

Closing Notes

I want to once again reiterate that this approach should be used to augment your Traditional or Forms based applications. I do NOT advocate this being a 50/50 split, more like a 70/30 or 80/20. The navigation concerns alone suggest a high degree of caution when build apps with this feature.

The final note I would like to make is that this approach has gained a lot of popularity and Xamarin has taken notice. They have it tentatively planned to be in the 2.4 release of Forms. I say tentative because even they admit this is a hard problem to solve, but we all know it has some very strong advantages. It will be interesting to see how they support his use case, if they ever officially do.

Mobile Center vs Bitrise

At West Monroe one of the biggest pain points we had with developing mobile applications was we lacked an effective DevOps process. That all changed in April last year when we adopted Bitrise; nothing but smiles for the most part on this end.

One of our early attempts was to use the build engine in Visual Studio Online to carry out builds, but this came with the requirement to host a Mac Build Agent on-prem. To be frank, this was a clusterfuck. During the pilot project I spent as many hours over the first three weeks trying to keep it running as I did actual development work. Eventually, we terminated the pilot and went naked without a build process; our quality suffered. It was towards the end of this project that we brought Bitrise into the fold.

I will save you reading the whole article: Bitrise beats Mobile Center right now. Bearing in mind that Mobile Center is still in Preview this isnt surprising as it lacks any maturity (they just added VSTS support a few days ago). But the direction does look good and it does have managed Mac build agents so that is a huge plus over Visual Studio Online.

From my early experiences using it, this is still very much a work in progress and I am communicating a ton of feedback to the team; I even got early access to the VSTS connector by complaining on Twitter. But the end result is the same: Btirise is leaps and bounds ahead of Mobile Center at the current time. Will Mobile Center get there? Possibly. One of the great strengths of Bitrise is the Step library which has both curated and independently submitted Steps; we use a lot of these on more complex projects.

By contrast, Mobile Center has no flexibility and only a single build path that can be leveraged, little customization. Also, while Bitrise’s dashboard lets you see In Process and past builds, Mobile Center focuses on showing ALL remote branches and bubbling those performing build actions to the top; I find this busy.

However, I see a lot of runway for Mobile Center because of what it offers beyond a simple build engine: integrated analytics, crash reporting, and distribution. No having to use HockeyApp as a separate app. Having everything centralized makes a lot of sense, but if the build processes are not feature rich it wont be worth it; personally given the number of tasks available in VSO its hard to believe this wont change soon.

So, for right now, I would not even consider using Mobile Center for anything but the simplest of projects where the support was limited and the scope diminished. Its not ready to join the big boys….yet.