Jekyll2023-10-03T16:59:59+00:00https://dachou.github.io/feed.xmlDavid ChouA software engineer's personal blogImplementing a Serverless Architecture2018-11-07T19:00:00+00:002018-11-07T19:00:00+00:00https://dachou.github.io/2018/11/07/implementing-serverless-architecture<p><a href="/2018/10/15/event-driven-serverless.html">Event-driven serverless architectures</a> promise improved resiliency and scalability, as serverless platforms consist of managed services that abstract away the infrastructure used to operate them. Serverless also promises increased agility because we can focus on building and delivering new capabilities quickly, without needing to work with the infrastructure.</p>
<p>In the <a href="/2018/10/15/event-driven-serverless.html">previous article</a> we discussed how to design an application architecture to effectively leverage serverless, and showed a simple example (based on the “<a href="https://docs.microsoft.com/en-us/azure/functions/tutorial-static-website-serverless-api-with-database">Build a serverless web app in Azure</a>” tutorial). In this article we discuss how that architecture can be made highly available and fault-tolerant across multiple data center regions in Azure, as well as enabling continuous deployment, operations automation, and monitoring, etc.; just as real applications do.</p>
<p><img src="/assets/20181107-architecture-application.png" alt="application architecture" />
<!--more--></p>
<h2 id="application-architecture">Application Architecture</h2>
<p>This app allows users to upload images, then resizes it into a thumbnail image, calls the Computer Vision API in Cognitive Services to recognize its contents, and saves the metadata. The architecture is simple functionality-wise, though it has many typical and necessary elements of a real web application, and all implemented entirely in a serverless model.</p>
<ul>
<li><strong>Web Server</strong> – Blob Storage (GPv2) with the <a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website">static website hosting</a> feature is used to serve the HTML, CSS, and JavaScript files that make up the client application (single page app (SPA)). This is neat because we’re not using a persistent server process running 24/7 in a VM instance listening on a port waiting for client requests from a browser. All static files are served from Blob Storage directly</li>
<li><strong>Application Service API’s</strong> – the web app interacts with service API’s to access cloud-based functionalities, implemented as Function apps (in this case written using Node.js):
<ul>
<li><em>GetImages</em> – this is the frontend API for the client app to get a list of available images and their metadata from Cosmos DB</li>
<li><em>GetUploadUrl</em> – when a user wants to upload an image file, the client app calls this Function app via an HTTP trigger, which requests a <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1">shared access signature</a> (SAS) token from Blob Storage and sends it back to the client app, to upload the image file directly into Blob Storage</li>
<li><em>ResizeImage</em> – this is the backend worker process that gets triggered by Blob Storage when a new image file is uploaded into Blob Storage; it resizes the image into a thumbnail, saves it into Blob Storage, calls Cognitive Services to recognize the image, then saves the metadata into Cosmos DB</li>
</ul>
</li>
<li><strong>Database</strong> – Cosmos DB</li>
<li><strong>File Storage</strong> – Blob Storage</li>
</ul>
<p>The end-to-end architecture is serverless – that is, when idle (no users), no compute processes are allocated and running to wait for user input. The only resources that would incur charges when idle are the data and files in database and storage; compute resources would only incur charges when there are requests sent from client apps. The only one exception being the Request Unit throughput level allocation in Cosmos DB which has a time-based factor in its billing meter.</p>
<p>The architecture at this point is also highly resilient and highly scalable (from 0 to many users) without needing any configuration for auto-scaling or instances across fault domains; it’s all built-in to the services used. The only exception is the Request Unit throughput level allocation in Cosmos DB, which requires adjustment if more throughput is needed to accommodate significant changes in transaction volume (this can be automated too; we’d need to build some functionality to monitor the metrics and interact with Cosmos DB’s service API’s based on how the application should behave).</p>
<h2 id="resource-provisioning">Resource Provisioning</h2>
<p>The provisioning and configuration of various resources in a region can be scripted to help minimize errors, and provision additional sets of resources consistently. In this implementation, a Bash script invoking the <a href="https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest">Azure CLI 2.0</a> (command-line interface) is used, instead of the JSON-based ARM (Azure Resource Manager) templates. Shell scripting environments provide a lot of useful utilities, and CLI 2.0 has many rich features such as <a href="http://jmespath.org/">JMESPath</a> queries, so the resulting scripts are pretty much infrastructure-as-code, which is pretty neat. Plus, with a personal bias towards Unix shell scripting, and now being able to run Bash scripts with the Windows Subsystem for Linux in Windows 10, or with the Cloud Shell in Azure Portal, provides a lot of flexibility to automate resource provisioning and management.</p>
<p>Below is the Azure CLI Bash script used for provisioning resources used for this application architecture.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
# Set variables
resourceGroupName='<Azure Resource Group name>'
location='<Azure region name>'
accountName='<Location-specific Blob Storage account name>'
compVisionName='<Location-specific Cognitive Services account name>'
functionName='<Location-specific Function account name>'
functionStorageName='<Location-specific Storage account name used for Function apps>'
cosmosName='<Cosmos DB account name>'
databaseName='<Cosmos DB database name>'
githubUrl='<Github repo URL>'
# Resource group
az group create -n $resourceGroupName -l $location
# Blob Storage
az storage account create -n $functionStorageName -g $resourceGroupName \
--kind StorageV2 -l $location \
--https-only true \
--sku Standard_GRS
az storage account create -n $accountName -g $resourceGroupName \
--kind StorageV2 -l $location \
--https-only true \
--sku Standard_RAGRS
az storage container create -n images \
--account-name $accountName \
--public-access blob
az storage container create -n thumbnails \
--account-name $accountName \
--public-access blob
blobConnection=$(az storage account show-connection-string \
-n $accountName -g $resourceGroupName \
--query "connectionString" \
--output tsv)
az storage cors add \
--methods OPTIONS PUT \
--origins '*' \
--exposed-headers '*' \
--allowed-headers '*' \
--services b \
--account-name $accountName
blobBaseUrl=$(az storage account show \
-n $accountName -g $resourceGroupName \
--query primaryEndpoints.blob -o tsv | sed 's/\/$//')
webBaseUrl=$(az storage account show \
-n $accountName -g $resourceGroupName \
--query primaryEndpoints.web -o tsv | sed 's/\/$//')
# Cosmos DB
az cosmosdb create -g $resourceGroupName -n $cosmosName \
--enable-multiple-write-locations true
az cosmosdb database create -g $resourceGroupName -n $cosmosName \
--db-name $databaseName
az cosmosdb collection create -g $resourceGroupName -n $cosmosName \
--db-name $databaseName \
--collection-name images \
--throughput 400
# Cognitive Services
az cognitiveservices account create -g $resourceGroupName -n $compVisionName \
--kind ComputerVision \
--sku S1 \
-l $location
compVisionKey=$(az cognitiveservices account keys list \
-g $resourceGroupName -n $compVisionName \
--query key1 --output tsv)
compVisionUrl=$(az cognitiveservices account show \
-g $resourceGroupName -n $compVisionName \
--query endpoint --output tsv)
# Function
az functionapp create -n $functionName -g $resourceGroupName \
-s $functionStorageName -c $location
az functionapp cors add -g $resourceGroupName -n $functionName \
--allowed-origins $webBaseUrl
az functionapp config appsettings set -n $functionName -g $resourceGroupName \
--settings AZURE_STORAGE_CONNECTION_STRING=$blobConnection -o table
az functionapp config appsettings set -n $functionName -g $resourceGroupName \
--settings COMP_VISION_KEY=$compVisionKey COMP_VISION_URL=$compVisionUrl \
-o table
az functionapp config appsettings set --n $functionName -g $resourceGroupName \
--settings FUNCTIONS_EXTENSION_VERSION=~1
az functionapp deployment source config -n $functionName -g $resourceGroupName \
--repo-url $githubUrl \
--branch master \
--repository-type github
az functionapp deployment source sync -n $functionName -g $resourceGroupName
functionUrl="https://"$(az functionapp show \
-n $functionName -g $resourceGroupName \
--query "defaultHostName" \
--output tsv)
# Update Settings in client app
echo "window.apiBaseUrl = '$functionUrl'" > settings.js
echo "window.blobBaseUrl = '$blobBaseUrl'" >> settings.js
az storage blob upload -c \$web \
--account-name $accountName \
-f settings.js \
-n settings.js
</code></pre></div></div>
<p>As shown, most of the required resources can be provisioned and configured using Azure CLI 2.0, including retrieving connection strings, account keys etc. and setting them as configuration values for other resources, setting CORS (cross-origin resource sharing) rules, etc. However, even though CLI 2.0 (v2.0.49) at the time of this writing supports most of the resources we’d want to use, there are still a few resources that are missing, such as setting up diagnostic logging which is supported via CLI 1.0 (e.g., with the <code class="language-plaintext highlighter-rouge">azure insights diagnostic</code> command). So there are still a few steps that need to done separately.</p>
<p>As a result, the resource group that hosts this application looks like this:</p>
<p><img src="/assets/20181107-resource-group-1.png" alt="resource group" /></p>
<h2 id="configuration-management">Configuration Management</h2>
<p>Another neat thing in this architecture is that environment configurations are abstracted from the code, leveraging the <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings">triggers and bindings</a> feature in Azure Functions. This means that the application code and configurations don’t have to be modified between environments, such as when setting up production, QA, staging, development, etc. environments. The connection strings, account keys, etc. for the resources a Function needs to work with, can be set up during resource provisioning time. In this case, this is done via the few lines of <code class="language-plaintext highlighter-rouge">az functionapp config appsettings set</code> commands in the resource provisioning Bash script above, which sets the information from the provisioned Blob Storage and Cognitive Services resources into application settings for the Function apps as environment variables, which then gets used by the Functions host.</p>
<p>For example, taking a look at the most simple Function app in this implementation, the GetImages HTTP service API. Here is the application code (JavaScript on Node.js) used in the Function app in index.js, which doesn’t do anything other than receiving the request, then setting the output documents to the response:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">context</span><span class="p">,</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">documents</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">res</span> <span class="o">=</span> <span class="nx">documents</span><span class="p">;</span>
<span class="nx">context</span><span class="p">.</span><span class="nx">done</span><span class="p">();</span>
<span class="p">};</span>
</code></pre></div></div>
<p>And the trigger and binding configuration in function.json:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"bindings"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"authLevel"</span><span class="p">:</span><span class="w"> </span><span class="s2">"anonymous"</span><span class="p">,</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"httpTrigger"</span><span class="p">,</span><span class="w">
</span><span class="nl">"direction"</span><span class="p">:</span><span class="w"> </span><span class="s2">"in"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"req"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http"</span><span class="p">,</span><span class="w">
</span><span class="nl">"direction"</span><span class="p">:</span><span class="w"> </span><span class="s2">"out"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"res"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"documentDB"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"documents"</span><span class="p">,</span><span class="w">
</span><span class="nl">"databaseName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"imagesdb"</span><span class="p">,</span><span class="w">
</span><span class="nl">"collectionName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"images"</span><span class="p">,</span><span class="w">
</span><span class="nl">"sqlQuery"</span><span class="p">:</span><span class="w"> </span><span class="s2">"select * from c order by c._ts desc"</span><span class="p">,</span><span class="w">
</span><span class="nl">"connection"</span><span class="p">:</span><span class="w"> </span><span class="s2">"imgrec_DOCUMENTDB"</span><span class="p">,</span><span class="w">
</span><span class="nl">"direction"</span><span class="p">:</span><span class="w"> </span><span class="s2">"in"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"disabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>As shown, GetImages uses the HTTP trigger so it can be called from the client app, and provides a response via HTTP. The work it does to query Cosmos DB to get a list of images is all in configuration in function.json – the database and collection names, the SQL query to execute, and the connection which is provided by Azure (as long as we name the Cosmos DB account “imgrec” in this case).</p>
<p>And below is a screenshot of the application settings tab for the Function app.</p>
<p><img src="/assets/20181107-application-settings.png" alt="app settings" /></p>
<p>As well as the function.json configuration for the ResizeImages function, where we can see how the connection string for Blob Storage is accessed by ResizeImages.</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"bindings"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"myBlob"</span><span class="p">,</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"blobTrigger"</span><span class="p">,</span><span class="w">
</span><span class="nl">"direction"</span><span class="p">:</span><span class="w"> </span><span class="s2">"in"</span><span class="p">,</span><span class="w">
</span><span class="nl">"path"</span><span class="p">:</span><span class="w"> </span><span class="s2">"images/{name}"</span><span class="p">,</span><span class="w">
</span><span class="nl">"connection"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AZURE_STORAGE_CONNECTION_STRING"</span><span class="p">,</span><span class="w">
</span><span class="nl">"dataType"</span><span class="p">:</span><span class="w"> </span><span class="s2">"binary"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"blob"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"thumbnail"</span><span class="p">,</span><span class="w">
</span><span class="nl">"path"</span><span class="p">:</span><span class="w"> </span><span class="s2">"thumbnails/{name}"</span><span class="p">,</span><span class="w">
</span><span class="nl">"connection"</span><span class="p">:</span><span class="w"> </span><span class="s2">"AZURE_STORAGE_CONNECTION_STRING"</span><span class="p">,</span><span class="w">
</span><span class="nl">"direction"</span><span class="p">:</span><span class="w"> </span><span class="s2">"out"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"documentDB"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"$return"</span><span class="p">,</span><span class="w">
</span><span class="nl">"databaseName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"imagesdb"</span><span class="p">,</span><span class="w">
</span><span class="nl">"collectionName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"images"</span><span class="p">,</span><span class="w">
</span><span class="nl">"createIfNotExists"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"connection"</span><span class="p">:</span><span class="w"> </span><span class="s2">"imgrec_DOCUMENTDB"</span><span class="p">,</span><span class="w">
</span><span class="nl">"direction"</span><span class="p">:</span><span class="w"> </span><span class="s2">"out"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nl">"disabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>And the code snippet in ResizeImage’s index.js to call the Computer Vision API in Cognitive Services, where it accesses the environment variable directly via <code class="language-plaintext highlighter-rouge">process.env.COMP_VISION_URL</code> and <code class="language-plaintext highlighter-rouge">process.env.COMP_VISION_KEY</code>:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">axios</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">COMP_VISION_URL</span> <span class="o">+</span> <span class="dl">'</span><span class="s1">/vision/v1.0/analyze?visualFeatures=Description&language=en</span><span class="dl">'</span><span class="p">,</span> <span class="nx">myBlob</span><span class="p">,</span> <span class="p">{</span>
<span class="na">headers</span><span class="p">:</span> <span class="p">{</span>
<span class="dl">'</span><span class="s1">Ocp-Apim-Subscription-Key</span><span class="dl">'</span><span class="p">:</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">COMP_VISION_KEY</span><span class="p">,</span>
<span class="dl">'</span><span class="s1">Content-Type</span><span class="dl">'</span><span class="p">:</span> <span class="dl">'</span><span class="s1">application/octet-stream</span><span class="dl">'</span>
<span class="p">}</span>
</code></pre></div></div>
<p>One thing to point out, at the time of this writing, Azure CLI returns the Computer Vision API URL as “<region>.api.cognitive.microsoft.com", so we had to manually append "/vision/v1.0" to fix the implementation. This can be done either in the COMP_VISION_URL variable in the App Settings page for the Function App (as shown in the screenshot above), or in the JavaScript code for this function (as shown in the code snippet above).</region></p>
<p>The ability to abstract environment configuration details from code is key to enabling a consistent resource provisioning and configuration process when managing the architecture that has multiple environments, and/or spans multiple physical regions.</p>
<h2 id="continuous-deployment">Continuous Deployment</h2>
<p>The Azure CLI Bash script helps to provision resources consistently across environments and to correctly set configuration, but the application code and assets for the Function apps should also use automation to ensure a consistent deployment, especially from an ongoing maintenance perspective, and as the number of environments grow.</p>
<p>We simply use the built-in <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-continuous-deployment">continuous deployment</a> support in Azure Functions. In this case Github is used (among a number of integrations Azure Functions provide out-of-the-box), and is implemented as part of the Azure CLI Bash script when provisioning resources, using the <code class="language-plaintext highlighter-rouge">az functionapp deployment source config</code> command to set up, then <code class="language-plaintext highlighter-rouge">az functionapp deployment source sync</code> to synchronize from the repository.</p>
<p>For example, this is the project structure for this application that is uploaded to Github (though there are +100 folders and thousands of files in node_modules):</p>
<p><img src="/assets/20181107-project-structure.png" alt="project structure" /></p>
<p>Below is a screenshot of the Deployment Center in a Function app instance, with some additional details that show the status and log of a repository synchronization process.</p>
<p><img src="/assets/20181107-deployment.png" alt="deployment center" /></p>
<p>In the Azure CLI Bash script the sync command is called just to ensure a repository synchronization is done. However, that isn’t necessary from an ongoing basis because automated synchronization is also enabled so that changes are synchronized whenever they are committed to the designated branch in Github. As a result, we can manage the updates to the appliation code in multiple environments via Github. And from that perspective, we can also add in Azure DevOps for more development process management capabilities.</p>
<h2 id="multi-region-deployment">Multi-Region Deployment</h2>
<p>Having the application highly available in one region is a good start, but it’d be even better if the application works across multiple regions (in this case, “West US 2” (Washington) and “East US 2” (Virginia) regions in Azure), expanding the footprint of the architecture to accommodate more users closer to their physical locations. And, be able to operate seamlessly in the unlikely event of region failures, without impacting users.</p>
<p><img src="/assets/20181107-architecture.png" alt="multi-region architecture" /></p>
<p>To implement this, a few additional changes are needed.</p>
<p><strong>Traffic Manager</strong> – created a Traffic Manager profile to serve as the top-level DNS name for the service API’s hosted Azure Functions in each Azure Region. The client app only needs to interact with this DNS name, such as “imgrec.trafficmanager.net”, instead of the actual end points hosted in each Azure region (e.g., imgrec-functions-usw.azurewebsites.net for the one in West US 2, and imgrec-functions-use.azurewebsites.net for the one in East US 2).</p>
<p>As a result, we can access the service API’s via the Traffic Manager end point, as shown in the screenshot below from Postman:</p>
<p><img src="/assets/20181107-postman.png" alt="postman" /></p>
<p>And to accommodate CORS requirements from the client app in the browser issuing HTTP requests to service API’s, we need to provide a CNAME for the Traffic Manager and Function end point DNS names. However, for Blob Storage, Traffic Manager at this point supports App Service, Cloud Service, or Public IP address end points, but not Storage end points, so the static website CNAME can only be mapped to one of the regions. If there’s a preference to work-around this, we can deploy an instance of App Service and use it to serve the static files for the website in each region, and these end points can be mapped to the Traffic Manager profile.</p>
<p><strong>Cosmos DB</strong> – added “East US 2” as an additional write-enabled region for the Cosmos DB account used in this architecture. This means the Function apps deployed in each region can access its local instance of Cosmos DB, and Cosmos DB will take care of any data replication needed to maintain data integrity as a result of writes in any region.</p>
<p><img src="/assets/20181107-cosmosdb-geo-replication.png" alt="cosmosdb" /></p>
<p>And that’s all we have to do for Cosmos DB; we don’t need to add logic to the application code to handle a fail-over scenario because Cosmos DB provides a top-level end point for applications to use (e.g., application clients use the “https://imgrec.documents.azure.com:443/” end point in this case, and Cosmos DB internally directs connections to the appropriate instances at “https://imgrec-westus2.documents.azure.com:443/” or “https://imgrec-eastus2.documents.azure.com:443/”).</p>
<p>It isn’t necessary to create more Cosmos DB instances, because Function app instances in separate regions can use a shared Cosmos DB instance. But, working with a Cosmos DB instance locally in the same region as the Function app instances yields better performance and provides fault-tolerance if/when region failures occur. Plus, Cosmos DB takes care of data replication across instances, which is the most complex part of this architecture.</p>
<p><strong>Blob Storage</strong> – since we’re using RA-GRS (read-access geo-redundant storage), all files stored in Blob Storage will be available in the event of regional failures (even though read-only). Though the application needs some changes in order to use multiple Blob Storage regions, such as making sure the entire URL to each file stored is recorded along the metadata for each file in Cosmos DB (the original implementation assumes a single-region deployment but now image files can reside in either west or east region), so that the client application knows where to retrieve the file</p>
<p><strong>Monitoring</strong> - now with a distributed architecture, Application Insights and Log Analytics also become shared (as opposed to regional) resources, like Traffic Manager. So the new resources should be configured to send diagnostics and application telemetry data to these resources, for centralized monitoring.</p>
<p>As a result, the resource group that hosts this application looks like this, now with the newly added resources in “East US 2” region:</p>
<p><img src="/assets/20181107-resource-group-2.png" alt="resource group" /></p>
<p>Finally, the configuration management, continuous deployment, logging and monitoring aspects mentioned earlier all help to quickly on-ramp additional regions in a consistent manner. If needed, this application can be provisioned in more regions across the world, to provide resources to customers closer to their locations, extending the production environment without disrupting live users. Each region scales independently, but works together seamlessly, leveraging Cosmos DB and its multi-master write capability to maintain data integrity across all regions.</p>
<h2 id="a-few-more-thoughts">A Few More Thoughts</h2>
<p>Even if we provision this application across more regions across the world, such as two in Europe and two in Asia (6 regions total), this serverless architecture at idle state (no user transactions) has no running processes. It would only incur charges for the amount of storage consumed in Blob Storage (<1MB for the static web app files, plus images uploaded by users), and the Cosmos DB Request Unit (RU) throughput level allocation (and data storage consumed in Cosmos DB but that’s usually a smaller portion of the cost). We didn’t have to allocate and provision any persistent ‘servers’ to implement this architecture.</p>
<p>At the 400 RU/s level, each Cosmos DB instance costs approximately $50 per month (at list pricing published on the Azure website; rounded up for sake of looking at simpler numbers), and we’d incur that for each region provisioned for this architecture. Thus for this particular architecture with 2 regions provisioned, the minimal cost at idle would be (roughly) $100 per month. That is similar in cost to running two B1S Virtual Machine instances (B1S ‘burstable’ instance provides 1 Core, 1GiB RAM at $0.011/hour pay-as-you-go price level).</p>
<p>However, with this serverless implementation we are getting a highly available and resilient, fault-tolerant (active-active), highly scalable architecture with a globally distributed, multi-model database and storage solution. Cosmos DB with its multi-master write capability solves the most complex issue of maintaining a consistent database across multiple instances in different physical regions; the rest of the architecture is relatively simple and can all be maintained locally in each region. The cost plus effort would be significantly higher if a similar set of capabilities is implemented with Virtual Machine instances, even when using open-source software and application frameworks.</p>
<p>There is still a lot we can do to improve this implementation, such as adding security features, and a more robust and seamless user experience in case of region failures. The data in Cosmos DB is replicated to every region in a multi-master relationship, but we may need to think about partitioning in case the dataset may grow to a massive size. With RA-GRS storage the architecture ensures no data loss in case of region failures, and that Azure would seamlessly geo-failover to a secondary region while maintaining the same DNS entries for the Blob Storage service end points. However, in a geo-failover scenario, the data in the secondary region is read-only, so the application should <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-designing-ha-apps-with-ragrs">handle this appropriately</a>. In the case of this two-region implementation, roughly half of the image files would be read-only. So the application should present a different experience instead of throwing exceptions, when write operations are attempted in the secondary region in a geo-failover scenario.</p>
<p>Saving some of this work for another time. 😊</p>Event-driven serverless architectures promise improved resiliency and scalability, as serverless platforms consist of managed services that abstract away the infrastructure used to operate them. Serverless also promises increased agility because we can focus on building and delivering new capabilities quickly, without needing to work with the infrastructure. In the previous article we discussed how to design an application architecture to effectively leverage serverless, and showed a simple example (based on the “Build a serverless web app in Azure” tutorial). In this article we discuss how that architecture can be made highly available and fault-tolerant across multiple data center regions in Azure, as well as enabling continuous deployment, operations automation, and monitoring, etc.; just as real applications do.Event-Driven Serverless Architectures2018-10-15T19:00:00+00:002018-10-15T19:00:00+00:00https://dachou.github.io/2018/10/15/event-driven-serverless<p>Serverless - the latest and most ‘cloud-native’ approach to developing applications, offers increased agility, improved resilience and scalability, and a pure on-demand consumption-based cost model. However, to truly realize those benefits and deliver more advanced outcomes, we should look beyond the relatively narrow focus on Functions-as-a-Service (FaaS; or related variants such as BaaS (Backend), fPaaS (Function Platform), serverless PaaS, etc.). Basically, it is worthwhile to approach serverless from an architectural perspective; and more specifically, with event-driven serverless architectures.</p>
<p><img src="/assets/20181015-event-driven.png" alt="event-driven architecture" />
<!--more--></p>
<p>The focus on FaaS (or function platforms) and the related considerations are still useful, as functions can be applied to a variety of use cases, especially when implemented as point solutions for a gradual decomposition of monolithic architectures into microservices, or as net-new microservices on existing systems to add new functionality (such as in a manner similar to the <a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/sidecar">Sidecar distributed computing pattern</a>). However, other than being able to run singularly focused units of work on an abstraction of immutable infrastructure, what truly differentiates serverless computing, is that it inherently advocates an event-driven architecture design. Thus for this article we want to take a step further, and evaluate the design considerations when using serverless technologies for an entire application architecture. That is, to build a complete cloud-native application using an event-driven serverless architecture.</p>
<h2 id="architecture-design-principles">Architecture Design Principles</h2>
<p>Now this isn’t a brand new concept, as serverless computing builds upon microservices and domain-driven design, which builds upon service-oriented architecture (SOA) and <a href="/2008/11/10/using-events-in-highly-distributed-architectures.html">event-driven architecture</a> (EDA), which build upon distributed computing best practices, etc. So a lot of the design fundamentals and best practices from the past still apply. Here we discuss a couple that have some unique elements and/or are especially interesting to serverless computing.</p>
<ul>
<li>Events over Functions</li>
<li>Microservices over Monoliths</li>
<li>Meta over Data</li>
<li>Distributed over Stateless</li>
<li>Consumer over Service</li>
<li>Choreography over Orchestration</li>
<li>Composition over Integration</li>
</ul>
<p>More elaboration on these below.</p>
<h3 id="events-over-functions">Events over Functions</h3>
<p>As we’re alluding to, event-driven serverless architectures are, well, event-oriented. 😉 Even though function platforms support both event-driven and request/response service invocation patterns, we should aim to use an event-driven design as the default service interaction model.</p>
<p>Event-driven design inherently enables loose coupling, which enables service abstraction and isolation, deployment flexibility, independent scale, etc. This is especially relevant to function platforms because functions are inherently fine-grained, and a loosely coupled architecture enables the functions/services to operate independently similar to individual musicians in a jazz ensemble.</p>
<p>That is, loose coupling is key to enabling more smaller components to work effectively together, while leveraging their operational independence, auto-scaling, and on-demand cost models. On the other hand, when services are tightly coupled in a synchronous request/response model, the system behaves more like a monolith (bigger components), and in that case fewer differentiated benefits can be gained from serverless computing.</p>
<p><img src="/assets/20100930-lego.png" alt="lego" /></p>
<p>Or, one more analogy with LEGO bricks - we can easily see how the regular LEGO bricks (~4,000 parts) are more flexible and scalable (in terms of the things we can build), than the fewer and larger Duplo bricks. Similarly with serverless computing - we get more agility from a loosely coupled system made up of many fine-grained services.</p>
<p>Thus from a design perspective, taking an events-led approach helps to drive towards an event-driven architecture, which leads into many of the principles below. This means thinking more about events, and organizing application logic as reactive elements to events, where events can represent a change in state (e.g., something happened), or a task submission (e.g., do something). This then leads into functional design, which is the opposite direction than when taking a functions-led approach. The end result is a more loosely coupled architecture that looks like a set of discrete microservices operating independently, working directly with a number of resources (e.g., database, storage, service API’s, etc.), and tied together by events that don’t necessarily map to sequential workflows.</p>
<p>This type of architecture design is especially effective at supporting modern applications with unpredictable scale and user demand. Event-driven design helps with concurrency as it breaks down large sequential transactions into several smaller parallel tasks. Serverless functions help with the operational aspects of auto-scaling and resiliency of individual processes to fulfill these tasks, without the development teams to be concerned with provisioning the necessary infrastructure to manage spikes in demand, and to handle concurrency, while maintaining cost levels accordingly.</p>
<h3 id="microservices-over-monoliths">Microservices over Monoliths</h3>
<p>This isn’t a general statement against monolithic applications, as monoliths are an effective approach for some application scenarios, just as serverless computing isn’t suitable for all application scenarios. However, function platform implementations inherently follow the microservices model, thus a microservices design is favored over a monolithic design.</p>
<p>Of course, we can still deploy monoliths into functions; just let the platform invoke an entry point into the monolithic application. However, a key thought is that smaller programs are less complex than bigger programs (though distributed programming is a different matter). Plus, most function platforms have constraints such as execution duration, memory allocation size, etc. which are likely insufficient for large monoliths. So for serverless computing, systems composed of small, independent, and interconnected units of functionality, are favored over larger bundles of functionality.</p>
<p>Thus, many of the existing best practices in designing microservices apply in serverless computing as well. However, there are some differentiating aspects, such as the concept of decentralized data management, which microservices architectures advocate each ‘service’ to own and encapsulate its database and dependent services, and that other services in a system should not create ‘back doors’ to access those ‘internal’ resources directly.</p>
<p>In event-driven serverless architectures, this could be slightly different as we can further decompose a ‘service’ down to multiple ‘functions’, where a set of functions may need to manage the same set of data (which would be considered an ‘aggregate’). And to maintain a consistent level of serverless-ness, the resources that functions use should align with serverless computing fundamentals as well (e.g., provisionless vs. provisioned resources).</p>
<p>By ‘aggregate’, we mean a set of functions and a set of data that represent a specific domain, and make up a bounded context; consistent with the similar concepts for microservices (or an ‘aggregate’ is kind of like a microservice).</p>
<p>With aggregates, in larger systems we can implement them to help modularize the architecture, so that changes (in function code or data structure) and faults can be isolated and localized in an aggregate without impacting the entire system. And of course, this means that functions external to an aggregate should not have direct access (e.g., ‘back doors’) to the resources mapped to that aggregate; access to an aggregate should go through function interfaces. This architecture would be organized into several aggregates each managing its own resources (like microservices), instead of many functions all working on the same set of data.</p>
<p>For smaller systems and simpler applications, it’s conceivable that a principled approach might add more overhead than benefits. In those cases it might be more effective to prioritize for agility and simplicity instead. Besides, this particular system can be managed as an aggregate later if/when participating in a larger architecture.</p>
<p>Similarly, from a data management perspective, we may need to consider a modular and/or sharded data design approach (e.g., decomposing the database down to smaller collections and keeping certain data collections mapped to a set of functions as an aggregate) instead of enforcing separate physical databases for individual microservices. Serverless databases like Azure Cosmos DB help with this as Cosmos DB provides structures around databases/containers, collections, and partitions, and provides controls on throughput scaling factor, multiple data consistency levels (from eventual to strong), seamless geo-replication with multi-master support, etc. This helps with maintaining separate sets of data without increasing complexities in data management infrastructure.</p>
<p>Thus, even though serverless computing favors a microservices design, we still need to carefully consider the granularity of individual functions (similar to service granularity considerations in SOA, and class/object granularity in OOP, etc.) and how data is managed. One difference for function platforms is that each invocation on a function incurs cost, so trade-offs in cost, performance, service autonomy, change and service versioning management, scale and concurrency, value of agility, etc. need to be considered when deciding whether a unit of work should be decomposed into separate functions, or bundled in one function.</p>
<h3 id="meta-over-data">Meta over Data</h3>
<p>Event-driven serverless architectures advocate passing metadata instead of actual data, between units of tasks (functions). This is especially relevant as direct cross-function communication is discouraged, and in those scenarios a message queue should instead be used to maintain loose coupling at a system level. However, most message queue solutions also have a limit in message sizes.</p>
<p>From the perspective of events, metadata consists of information that describes ‘something happened’ in the system, specific information relevant to the event, and common logistical elements such as event source, timestamp, and unique identifier.</p>
<p>For example, the storage system publishes an event that a file has been uploaded by a user. The event message itself would only contain the event type (e.g., “file uploaded”), and path/url information to the file. The consumer function of this event can decide what to do with the information, such as to download the file from the storage system and do its work (such as resizing the image into a fixed size and sending it to a computer vision service to recognize its contents) and then write data resulting from the work into the database, related to the user’s account. The user’s account lookup required this function to extract the internalized identifier from the path/url (container assigned to the user) and query the database to access the account information.</p>
<p>Hence the related thought earlier regarding distributed data management in microservices design. Since direct, synchronous request/response between functions is not encouraged, sometimes we can get away with not creating atomic data ‘read’ functions to be invoked by functions that need to lookup data; but writes should be submitted to a function to ‘do the work’. This means building on an eventual consistency model provided by a serverless database solution (such as Azure Cosmos DB), and use the platform bindings to execute read queries directly from the database. Though of course, thoughts around aggregates and implementing decentralized data management solutions still apply, as in larger systems it does make sense to enforce data access through a function when trade-offs weigh in this direction.</p>
<p>Metadata from this perspective should be immutable and not dependent on application state. Instead, user and application state should be maintained in a database solution that ensures data integrity and consistency, so no state is maintained in the form of events that live outside of the serverless database.</p>
<h3 id="distributed-over-stateless">Distributed over Stateless</h3>
<p>While functions should be written to be stateless (shared nothing) and idempotent (consistently same output from same input), the composite system (end-to-end architecture) in most cases does maintain application state in some form. The distinction is that, processes (functions) should be stateless, similar to events (that carry only metadata), so that any state is only maintained by stateful resources.</p>
<p>These resources can be serverless databases, distributed storage, message queue solutions, and other service API’s (that are implemented by their own architectures with data and dependencies encapsulated). From this perspective, application state is distributed among a set of resources in a system, and not stored and managed in a centralized resource. These platform resources themselves should operate in a model that aligns with event-driven serverless architectures (or microservices), with a consistent level of independent resiliency and scalability.</p>
<p>For example, Azure Cosmos DB may be the primary serverless database resource in Azure, but instead of thinking of it as one centralized database, application state should be decomposed into separate databases or collections mapped to relevant sets of functions, or use partitions and sharding for larger data sets. Basically, follow the microservices best practices in domain-driven design, where a function/data aggregate works with its own domain model within a bounded context (and use of canonical models is discouraged to minimize contention). Then there could also be files in Blob Storage, vertically aligned data in Table Storage, transient data in Redis Cache, etc. And when possible, push user session state to the client, such as in the cases of mobile apps, rich HTML/JS client apps (e.g., Single Page Apps).</p>
<p>As a result, application state is distributed across the platform resources used in an architecture. From a design perspective, following a distributed state approach (system-oriented as opposed to focus on ‘stateless’) and leverage the resources to do their work, enables functions to be stateless (as a result), and reach a consistent level of serverless-ness in the composite system architecture.</p>
<h3 id="consumer-over-service">Consumer over Service</h3>
<p>An event-driven model enables us to take a more consumer-centric approach to designing API’s for services (as opposed to service-centric). And specifically for event-driven serverless architectures, it is more effective to approach the designs of events and interactions between functions and resources from a consumer (or user, client, publisher) perspective.</p>
<p>Traditionally, the design of a system tends to be driven from the back-end; by first defining the data models, then application processes to manage the data, then service interface definitions to expose functionality to consumers. The consumer of these services then is responsible for understanding the service domain, the semantics of the service API’s, and often needs to grapple with a client SDK (which is needed to simplify interactions with service API’s), etc. As a result, the application design is service-centric, in that the onus is on the consumer to conform to the requirements of the services.</p>
<p>Taking a functions-led approach also tends to drive the design from the backend (service-centric). However, because of the loose coupling enabled in an event-driven model, we can drive the design from the frontend; using a consumer-centric (or user, client, publisher) perspective. This is because in an event-driven model, the event publisher (traditionally client/consumer role) drives the definition of the event, then it simply submits the event into an eventing system (or queue infrastructure), without any knowledge of the implementation details of the subscriber (traditionally service role). The onus is then on the subscriber (service) to adapt to the event and do its work.</p>
<p>Of course, technically we can still have the service implementation to define how an event message needs to look like (e.g., an exact JSON document format) that event publishers need to adhere to. But if we take a consumer-oriented approach, and leverage the function platform’s built-in capabilities such as agile code deployments, versioning, proxies, API mediation, etc. (to help with propagating design changes from front to back), we would end up having a more flexible system that is more agile and adaptable to business and technical changes.</p>
<h3 id="choreography-over-orchestration">Choreography over Orchestration</h3>
<p>The design of workflows or logical processes in an event-driven architecture should land in a choreography model, as opposed to an orchestration model.</p>
<p>An orchestration model points to a centralized process-driven view of sequential workflow, mostly aligned with synchronous request/response process that tightly manages the end-to-end execution of logic and interaction directly with resources and services to complete a transaction. A choreography model points to independent services that observe the system and react to events autonomously, to accomplish a logical task collectively. The subtle difference is that orchestration is a centralized process-centric view, vs. choreography is a distributed resources and functions-oriented view.</p>
<p>Basically, this highlights the thought to resist the urge to design workflows as traditional sequential (or in a way, monolithic) processes in a service implementation. Rather, approach the design from the use of resources needed for a task, then logic in functions to interact with the resources, and invoked via events. Consequently, a logical transaction in an event-driven architecture may result in the execution of multiple parallel tasks activated by events that represent changes in resources. These tasks have no knowledge of each other’s execution and implementation details, but the collective result of their work accomplishes the intended output of a logical user/system transaction.</p>
<h3 id="composition-over-integration">Composition over Integration</h3>
<p>The design of interactions between resources and functions should use more of a service composition approach, than service integration.</p>
<p>Service integration approaches tend to land in synchronous interactions that are tightly coupled, and sometimes need to embed client SDK’s to abstract the service API implementation, which also ends up tightly coupling the service implementation. This cannot be avoided when interacting with resources directly, but we can leverage the function platforms built-in capabilities to abstract service implementations as input and output bindings. Bindings provide a declarative way to connect to resources in a system, so that function implementations can avoid including details of the resources and their service API’s.</p>
<p>Integration solutions still play a significant role in the system. What this principle advocates is to be mindful of when/where which of these patterns/models are applied in the architecture design.</p>
<p>Abstracting resource communication details into declarative bindings is a mechanism to accomplish a form of loose coupling. It enables agile changes in how resources are used and accessed, and moves development focus towards designing workflows that compose of various resources and services. A compositive system provides higher agility to respond to business and technical changes, and enables an end-to-end system to be managed as a tangible product (not just the user-facing assets), responding to customer demand quickly and effectively. This is the key benefit for adopting cloud-native serverless platforms, especially when balanced against relevant design trade-offs.</p>
<h2 id="a-simple-example">A Simple Example</h2>
<p>Here we walk through an over-simplified view of how an event-driven serverless architecture differs from a monolithic architecture.</p>
<p><img src="/assets/20181015-monolithic-arch.png" alt="monolithic" /></p>
<p>We start with a typical web app view of a monolithic application, with these characteristics:</p>
<ul>
<li><strong>Monolithic application</strong>: all functions of this application are bundled together and hosted in an App Server process, with hard dependencies on other resources such as a Web Server frontend, file storage (local or mounted distributed disks), and a centralized database in another server tier. Modular design or forms of loose coupling can be achieved, but mostly encapsulated within the confines of the monolithic application process, and changes are typically released as updates to the entire implementation</li>
<li><strong>Orchestration model</strong>: the server process is invoked in a synchronous request/response model, and directly controls/manages the flow of application logic and use of resources and external services (Cognitive Services in this view) to accomplish the unit of work</li>
<li><strong>Centralized state</strong>: data and state are managed by centralized resources and shared between application processes. Reuse is a key benefit</li>
<li><strong>Integration model</strong>: code, components, processes, and resources are tightly coupled end-to-end in a synchronous and sequential processing model</li>
</ul>
<p>This application, when implemented using an event-driven serverless architecture, could look like this (saving the technical details of this implementation for another time).</p>
<p><img src="/assets/20181015-event-driven-arch.png" alt="serverless" /></p>
<p>Similarly, this serverless implementation has these characteristics:</p>
<ul>
<li><strong>Microservices application</strong>: the application process is decomposed into independent functions reacting to events autonomously, that operate on immutable infrastructure which plays the role of traditional server environments (but abstracted into a cloud environment; not individual servers). Each function can be updated and scaled independently, and failures are isolated. As in typical serverless environments, this architecture does not use any provisioned compute resources. That is, no idle servers listening on ports waiting for user requests. The entire architecture scales seamlessly from 0 to any load, and can expand deployment to more cloud regions when needed.</li>
<li><strong>Choreography model</strong>: work in this system is accomplished in a non-linear model; services get activated as conditions/changes (or events) arise. There is no longer a traditional sequential workflow view, but the collective results of the autonomous services and resources accomplish the unit of work</li>
<li><strong>Distributed state</strong>: data and state are managed by distributed resources (e.g., client state in the single page app (SPA), files in Blob Storage, modularized and domain-specific data in Cosmos DB, etc.). No compute resources are allocated for state and data maintenance resources (e.g., no need for an FTP process/server, file server, provisioned database server, etc.; these are now all resources aligned to the serverless model with similar on-demand consumption-based cost models)</li>
<li><strong>Composition model</strong>: functions and resources interact with each other with communication and connection details abstracted, enabling quick composition of new services and resources to bring value to market faster, and experimentation scenarios</li>
</ul>
<h2 id="a-few-more-thoughts">A Few More Thoughts</h2>
<p>An event-driven serverless architecture is not without its trade-offs. It isn’t suitable for all application scenarios such as ones with long-running jobs, processes with high memory requirements, workloads that require predictable performance, etc. It also requires re-architecting applications into minimal-latency microservices, and decompose data sets into smaller domains and maintained in bounded contexts mapped to function/data aggregates. And, a highly distributed architecture inherently distributes points of control and escalates system complexity, which correspondingly increases challenges in the operations and management of an end-to-end architecture.</p>
<p>There are some similarities to the discussion and comparison between monolithic kernels and microkernels in the operating systems design domain. Monolithic kernels, even though larger and more prone to errors (something crashes and can impact the entire process), have better performance (because everything is kept in the same address space) and are simpler to maintain (require less code). Microkernels run user and kernel services in different processes (different address space; distributed processes), so they are less prone to errors (better isolation and more secure) and updates are componentized (localized), but execute slower and more complex to maintain (require more code). Design trade-offs, essentially; and similar comparisons can be drawn between monolithic application and microservices application architectures.</p>
<p>Specifically with event-driven serverless architectures, there are additional areas that are worth exploring, such as those below; but we will save them for another time:</p>
<ul>
<li>Security</li>
<li>Performance</li>
<li>Operations (the Ops in DevOps; as function platforms make the Dev part simpler, but not the Ops part)</li>
<li>Change management and versioning, and experimentation
<ul>
<li>error handling</li>
<li>transaction monitoring and tracing</li>
<li>A/B, blue-green, canary testing</li>
</ul>
</li>
<li>Organizational culture and team dynamics</li>
<li>Economics and business case</li>
</ul>
<p>Thus, serverless computing isn’t a replacement to other models in modern computing; it is another option in the toolbelt, that when implemented effectively against suitable scenarios, can help improve resiliency and scalability, and agility and faster time to market. These key benefits of serverless computing are especially relevant to the modern class of application scenarios.</p>Serverless - the latest and most ‘cloud-native’ approach to developing applications, offers increased agility, improved resilience and scalability, and a pure on-demand consumption-based cost model. However, to truly realize those benefits and deliver more advanced outcomes, we should look beyond the relatively narrow focus on Functions-as-a-Service (FaaS; or related variants such as BaaS (Backend), fPaaS (Function Platform), serverless PaaS, etc.). Basically, it is worthwhile to approach serverless from an architectural perspective; and more specifically, with event-driven serverless architectures.Cloud Service Models (IaaS, PaaS, SaaS) Diagram2018-09-28T19:00:00+00:002018-09-28T19:00:00+00:00https://dachou.github.io/2018/09/28/cloud-service-models<p>Guessing most of us have seen a version of the diagram that compares the cloud computing service models (IaaS, PaaS, SaaS) and on-premises environments, sometime within the past few years? You know, the one that uses a visualization of four software (layer cake) stacks to describe the differences between infrastructure, platform, and software “-as-a-service” models as described in <a href="https://csrc.nist.gov/publications/detail/sp/800-145/final">The NIST Definition of Cloud Computing</a>?</p>
<p><img src="/assets/20110326-cloudmodels.png" alt="cloud service models" /></p>
<p>This is the (boring) story/recap of how this diagram came to be. 😉
<!--more--></p>
<h2 id="2008-hello-azure">2008: Hello, Azure</h2>
<p>At the time of this writing, it is almost 10 years since the initial announcement of Microsoft Azure (at that time named “Windows Azure”), <a href="https://channel9.msdn.com/Blogs/pdc2008/KYN01">by Ray Ozzie at the Microsoft Professional Developers Conference 2008</a> (PDC08) on October 27, 2008. If you recall, at that time this is something almost inconceivable for Microsoft to do. Afterall, only the cool kids on the block, Amazon and Google, seemed to be interested in cloud computing. Plus, take into account of the observation that a subscription-based revenue model potentially cannibalizes many of Microsoft’s existing license-based products.</p>
<p>After the announcement, there was a tremendous amount of interest in the community to learn about Azure. According to my notes, I alone had more than 300 meetings with organizations of all sizes in a 6-month period following the announcement.</p>
<p>Needless to say, presentation slides were a big part of my work at the time, as visual aids helped to explain many concepts and details, and facilitate the conversations. In one of the slide decks I used, there was this diagram (can be found on <a href="https://www.slideshare.net/davidcchou/microsoft-and-cloud-computing-presentation/5-On_premises_vs_in_the">Slideshare dated Nov. 19 2008</a>):</p>
<p><img src="/assets/20180928-cloud-service-models-20081119.png" alt="20081119" /></p>
<p>This was used to explain the platform-as-a-service (PaaS) approach Azure implemented. If you recall, Azure at that time only had Web Roles and Worker Roles (classic cloud services as categorized today) as primary compute options. These being services that operate in the PaaS model, we needed to rationalize/justify the fundamental differences in the PaaS model, relative to how people understood on-premises IT at the time. This diagram helped to articulate the major trade-offs between the well-known models at the time: on-premises, outsourced hosting, and the (new) public cloud environments.</p>
<h2 id="2009-concept-formation">2009: Concept Formation</h2>
<p>The first diagram succinctly highlighted the major differences and helped people recognize that PaaS is different from outsourced hosting and on-premises IT. But it only addressed the topic at a surface layer; we often ended up spending more time discussing how and why PaaS is different - not just with on-premises, but IaaS as well. So we needed a different visualization to help support that part of the conversation.</p>
<p>We needed a diagram/graphic/model, or visual representation, that:</p>
<ul>
<li>is simple and easy to understand (basically at first glance)</li>
<li>highlights the differences in a context that is familiar (relative to the similarities)</li>
<li>conveys the value of ‘managed’ services (we worry about some things so you don’t have to)</li>
<li>articulates the degree of differences (that one is more different than same)</li>
</ul>
<p>The approach we took landed in a visual representation of existing on-premises IT environments, and the cloud service models mapped in the same context, so that the differences can be highlighted in the context of the commonalities (as opposed to explicitly stating them in words in the earlier diagram). Thus the 9-layers stack view was developed, using common, high-level IT infrastructure domains that can be carried consistently across all of the models. The specific layers were chosen as they exemplify some levels of separation of concerns, and to imply a traditional IT stove pipe stack representation, with some direct dependencies between stack layers, or design/operational abstractions.</p>
<p>After a few iterations, this view was developed, first published on my MSDN <a href="/2009/01/13/cloud-computing-and-microsoft-platform.html">blog (dated Jan. 13 2009)</a>:</p>
<p><img src="/assets/20180928-cloud-service-models-20090526.png" alt="20090526" /></p>
<p>The visual design implied that:</p>
<ul>
<li>On-premises is as we understand it: we have full control over the entire stack as we own and manage them</li>
<li>IaaS is different from on-premises (even though it technically runs on the same stack), but it is also different from outsourced managed hosting</li>
<li>PaaS is really different!</li>
</ul>
<p>(as a side note) The inter-layer dependency and separation of concern aspect is often lost when trying to use other models to visualize this stack relationship, such as <a href="https://www.linkedin.com/pulse/20140730172610-9679881-pizza-as-a-service/">pizza-as-a-service</a> and <a href="https://community.dynamics.com/365/financeandoperations/b/axtipsandtricks/archive/2016/07/14/what-is-cloud-and-what-are-iaas-paas-and-saas">car-as-a-service</a>. To me these analogies make the diagram more interesting, but they ended up missing an important part of the context.</p>
<p>And the use of hot coloring (red slices) vs. cool coloring, and number of layers highlighted per model, were all intended to visually call out, and illustrate the scale in differences (e.g., on-premises has 9 red layers, IaaS has 4, and PaaS has just 1 - suggesting that they are more different than they are similar; oh, and PaaS is more ‘cool’).</p>
<p>As this view gained traction, a version of it was published on <a href="https://www.slideshare.net/davidcchou/patterns-of-cloud-applications-using-microsoft-azure-services-platform">Slideshare (dated Jun 9 2009)</a>. Along with this car analogy which mapped to the same 3-column structure to help people relate to the impact of the differences in these models.</p>
<p><img src="/assets/20180928-cloud-service-models-20090526-analogy.png" alt="analogy" /></p>
<p>The high-level talking points for this analogy were:</p>
<ul>
<li>On-premises: is like owning your cars - you can go anywhere you want at anytime (full <strong>control</strong>), in a car make/model/color/trim of your choice, but you own the car and you’re responsible for its maintenance</li>
<li>IaaS: is like a car rental service - you still can go anywhere you want at anytime, with some limits in car choices, but you don’t have to maintain the vehicles; just take the keys and go</li>
<li>PaaS: is like public transportation - you can go to places as defined/limited by available routes and schedules, but it’s easy to use and pay-per-use (full <strong>economies of scale</strong>)</li>
</ul>
<p>Fundamentally, this still mapped to the initial high-level trade-offs messaging between ‘control’ and ‘economy of scale’, but it is now visually easier to understand and helps facilitate a more engaging discussion during a presentation.</p>
<p>For the following months, from a visual design perspective, there was a shift starting to move away from rich, 3D looking graphics (e.g., boxes with gradients, lighting, bevels, borders, corners, shadows, effects, etc.) towards a flatter, simpler design. This diagram was also updated to reflect those trends (<a href="https://www.slideshare.net/davidcchou/windows-azure-platform">Slideshare (dated Oct 17, 2009)</a>); now with less complex objects (less visual noise), and fewer colors (a simpler palette).</p>
<p><img src="/assets/20180928-cloud-service-models-20091027.png" alt="20180928" /></p>
<h2 id="2010-full-realization">2010: Full Realization</h2>
<p>By this time many people have seen this diagram, as its usage proliferated publicly, and within Microsoft, when we went “all-in” with the cloud, and the armies of Microsoft employees and partners started blogging and presenting about Azure. Among the many feedback received, was one from <a href="https://www.linkedin.com/in/scottker/">Scott Kerfoot</a>, who suggested to add a fourth column to represent Software-as-a-service (SaaS).</p>
<p>Adding SaaS required us to modify the model a bit, especially as we needed to differentiate PaaS and SaaS, because it didn’t work to have just one layer of difference between the two, and we still needed to keep the scales of differences between the models relatively consistent. Thus “Security & Integration” was removed as security concerns exist at all layers, and added “Data” underneath “Applications”. Then “Databases”, “Servers”, and “Server HW” were changed to “Middleware”, “O/S”, and “Server”; respectively.</p>
<p>And then this view was created (dated Jan. 15 2010), with a consistent 2-layer difference between SaaS, PaaS, and IaaS; and a 5-layer difference between IaaS and on-premises to express that cloud environments are more different from on-premises environments.</p>
<p><img src="/assets/20180928-cloud-service-models-20100115.png" alt="20100115" /></p>
<p>And then further flattening and simplifying the graphic design of the diagram, plus a few minor edits, such as changing “O/S” to “Operating System”, and “On-Premises” to “Traditional IT” (as on-premises also included private cloud context so we needed to differentiate from that), and slightly adjusting the ‘managed by’ lines to express a shared responsibility view for O/S in IaaS (cloud vendors provide the base VM image, but customers still need to maintain its patching and updates, etc.), we reached the final version shown below (same as the one at the top of this post).</p>
<p><img src="/assets/20180928-cloud-service-models-20110226.png" alt="20110226" /></p>
<p>These versions were published and propagated via many sources, and as my presentation decks were mostly incremental technical detail updates, they were not published to avoid too much duplication (since I already have too many Azure overview decks on Slideshare). It was later in 2011 when I wrote about <a href="/2011/03/16/cloud-ecosystems.html">cloud ecosystems</a> this final version was referenced.</p>
<h2 id="today">Today</h2>
<p>Progress moves fast in this industry. Conversations soon shifted from explaining and justifying PaaS, towards primarily deeper discussions and engagements about real development projects. Lines between IaaS and PaaS started to blur even before Azure made Virtual Machines available in 2012 (Azure had VM Roles since 2010 but it’s not exactly IaaS). It was increasingly more about composing capabilities into cloud projects, regardless which ‘cloud model’ was used by a particular implementation (e.g., API, component, feature, service, etc.). Application projects were composing services and features built on both IaaS and PaaS options. It was no longer IaaS or PaaS; it was IaaS AND PaaS AND SaaS. Furthermore, there was increasing maturity around hybrid cloud approaches so even the lines with on-premises environments were blurring.</p>
<p>Hence this diagram was no longer part of my standard cloud computing presentations. However, it continues to be referenced and used widely in cloud computing literature in many forms. Some of the core content has been updated frequently over the years, but it’s interesting to see how this diagram is still being used by people today.</p>
<p>A simple image search on “iaas paas” would yield hundreds of hits from all kinds of sources around the world, and many kinds of variations and flavors, and in different languages. Some people claimed to have created this view, some credited “the Internet”; though most of the time it is just a visual with no source mentioned. It’s kind of fascinating to see how this unit of work took on a life of its own.</p>
<p><img src="/assets/20180928-search-results.png" alt="image search" /></p>Guessing most of us have seen a version of the diagram that compares the cloud computing service models (IaaS, PaaS, SaaS) and on-premises environments, sometime within the past few years? You know, the one that uses a visualization of four software (layer cake) stacks to describe the differences between infrastructure, platform, and software “-as-a-service” models as described in The NIST Definition of Cloud Computing? This is the (boring) story/recap of how this diagram came to be. 😉Multiple Inheritance2018-09-13T19:00:00+00:002018-09-13T19:00:00+00:00https://dachou.github.io/2018/09/13/multiple-inheritance<p>It was back in 2008 when I first wrote about <a href="/2008/04/17/net-and-multiple-inheritance.html">.NET and Multiple Inheritance</a>. Since then I have received many feedback (some were particularly pointed), though kind of amazed that this is still a subject of debate even today.</p>
<p><img src="/assets/20180913-class-multiple-inheritance.png" alt="multiple inheritance" />
<!--more--></p>
<p><em>(from <a href="https://www.uml-diagrams.org/generalization.html">https://www.uml-diagrams.org/generalization.html</a>)</em></p>
<p>To clarify - I don’t think multiple inheritance is inherently ‘bad’; I think it is an elegant solution for when we do want to inherit implementation and/or state from parent/super classes (such as classes that have orthogonal behaviors). But I am fascinated by the diverse perspectives on this language construct, and how different approaches were taken in designing Java and C#, which don’t support multiple inheritance of implementation and state (some think that inheritance of type, or interfaces, is a form of inheritance too but I tend to think of that as design by contract using abstract types as opposed to inheritance).</p>
<h2 id="design-principles">Design Principles</h2>
<p>From a design perspective, I am also intrigued by decisions to not add/include features, just as I do with features that are included. With multiple inheritance, I think it boils down to a ‘simple’ thought - the designers for Java and C# made the decision to not include it, for sake of simplicity.</p>
<p><strong>It was a design decision.</strong></p>
<p>And like typical design decisions, it was a judgment call based on the assessment made by the design team, by weighing trade-offs between the merits and costs of a particular product feature. Especially important is how a particular feature is considered within the context of the overall system it participates in.</p>
<p>From a systems perspective, Java and C# were intended to support newer classes of applications and environments, thus different approaches were taken, and many represented departures from C++ (or - why invent a new language that essentially does the same as what C++ already does well at?), and many decisions were made based on lessons learned from complex C++ projects. As a result of the collective design decisions, Java and C# are more different from C++, than similar, from a systems perspective.</p>
<p>For example, for Java in 1995, James Gosling wrote these as design principles (today the document is at <a href="http://www.oracle.com/technetwork/java/intro-141325.html">http://www.oracle.com/technetwork/java/intro-141325.html</a>):</p>
<ul>
<li>simple, object-oriented, and familiar</li>
<li>robust and secure</li>
<li>architecture-neutral and portable</li>
<li>high performance</li>
<li>interpreted, threaded, and dynamic</li>
</ul>
<p>Simplicity is a major thought, and is the weighing factor in trade-off decisions such as multiple inheritance. In particular, <a href="assets/OriginalJavaWhitepaper.pdf">James Gosling also wrote in 1995</a> (<a href="https://cs.dartmouth.edu/~mckeeman/cs118/references/OriginalJavaWhitepaper.pdf">https://cs.dartmouth.edu/~mckeeman/cs118/references/OriginalJavaWhitepaper.pdf</a>) when elaborating the “simple” design principle:</p>
<blockquote>
<p>JAVA omits many rarely used, poorly understood, confusing features of C++ that in our experience bring more grief than benefit. This primarily consists of operator overloading (although it does have method overloading), multiple inheritance, and extensive automatic coercions.</p>
</blockquote>
<p>And obviously there are many technical reasons, such as what <a href="http://dotnetjunkies.com/WebLog/unknownreference/archive/2003/09/04/1401.aspx">Chris Brumme said in 2003 about .NET (C#)</a>:</p>
<blockquote>
<p>Multiple implementation inheritance injects a lot of complexity into the implementation. This complexity impacts casting, layout, dispatch, field access, serialization, identity comparisons, verifiability, reflection, generics, and probably lots of other places.</p>
</blockquote>
<p>To me, this points out use cases for C# and Java that are more prevalent in the ‘newer’ class of applications, than when C and C++ were first developed. For example, today C++ is still well-suited for systems programming (e.g., writing Linux kernels, or systems software), whereas Java and C# tend to be used more for applications development. Seeing that these languages still dominate most language popularity indexes today, I think the design principles and decisions were directionally correct.</p>
<h2 id="complex-simplicity">Complex Simplicity</h2>
<p>Why does multiple inheritance get a bad rep? Why is it deemed to be adding more complexity than benefits? Typically, the ‘diamond problem’ is referenced (it even has more dramatic names such as “the dreaded diamond of death”).</p>
<p><img src="/assets/20180913-180px-Diamond_inheritance.svg.png" alt="diamond problem" /></p>
<p><em>(from <a href="https://en.wikipedia.org/wiki/Multiple_inheritance">https://en.wikipedia.org/wiki/Multiple_inheritance</a>)</em></p>
<p>For example, we have classes B and C defined as subclasses of class A, and then class D (multiple) inherits from both B and C. Now in C++ this can be avoided, but in Java and C# every class is a subclass of Object, so by default this situation would surface with multiple inheritance. This adds complexity, because the compiler needs to handle these object relationships correctly, when allocating copies of each class A, B, C in the new D instance.</p>
<p>In C++:</p>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="k">class</span> <span class="nc">A</span> <span class="p">{</span> <span class="p">...</span> <span class="p">};</span>
<span class="k">class</span> <span class="nc">B</span> <span class="o">:</span> <span class="k">public</span> <span class="n">A</span> <span class="p">{</span> <span class="p">...</span> <span class="p">};</span>
<span class="k">class</span> <span class="nc">C</span> <span class="o">:</span> <span class="k">public</span> <span class="n">A</span> <span class="p">{</span> <span class="p">...</span> <span class="p">};</span>
<span class="k">class</span> <span class="nc">D</span> <span class="o">:</span> <span class="k">public</span> <span class="n">B</span><span class="p">,</span> <span class="k">public</span> <span class="n">C</span> <span class="p">{</span> <span class="p">...</span> <span class="p">};</span></code></pre></figure>
<p>In this case, the compiler allocates a D object containing B and C, with B and C each containing its own instance of A, and so we’d end up with two independent A objects. Complications arise when we need to update a parent field, let’s say A::field, which either means needing to update it twice (through B::field and C::field), or allowing the chance for errors (e.g., new a pointer in B::field, and delete C::field). This is related to multiple inheritance of state, and how compilers need to allocate instance data from superclasses on the heap of the concrete subclass.</p>
<p>So C++ introduced virtual inheritance to address this issue (whereas the above would be considered multiple non-virtual inheritance):</p>
<figure class="highlight"><pre><code class="language-c--" data-lang="c++"><span class="k">class</span> <span class="nc">A</span> <span class="p">{</span> <span class="p">...</span> <span class="p">};</span>
<span class="k">class</span> <span class="nc">B</span> <span class="o">:</span> <span class="k">public</span> <span class="k">virtual</span> <span class="n">A</span> <span class="p">{</span> <span class="p">...</span> <span class="p">};</span>
<span class="k">class</span> <span class="nc">C</span> <span class="o">:</span> <span class="k">public</span> <span class="k">virtual</span> <span class="n">A</span> <span class="p">{</span> <span class="p">...</span> <span class="p">};</span>
<span class="k">class</span> <span class="nc">D</span> <span class="o">:</span> <span class="k">public</span> <span class="n">B</span><span class="p">,</span> <span class="k">public</span> <span class="n">C</span> <span class="p">{</span> <span class="p">...</span> <span class="p">};</span></code></pre></figure>
<p>In this case, only one instance of A would be included in the derived class, and referenced using pointers instead; essentially creating the ‘diamond’ relationship for the D instance. But now we have complications in how object initializations are executed. The compiler initializes A in the D constructor, and pointers to it in B and C, then the rest members of the classes B, C, and D are initialized. However there’s an implicit rule that once the D constructor has initialized A, the B and C constructors are not allowed to re-initialize A again (because the compiler doesn’t know which constructor between B and C the programmer intended to use). This often causes runtime issues. Then there are additional complexities with assignment operators, type conversion, etc. that are more frequently used throughout a program, but would require extra attention to avoid pitfalls.</p>
<p>And then there’s multiple inheritance of implementation, where complexities arise when the compiler needs to figure out which method implementation should be called, when derived classes have overridden methods in base/super classes. Or, a programmer can unwittingly introduce a name conflict by adding a new method to a superclass (such as when we have D::method and B::method, then someone adds A::method - which implementation should be used when D::method is invoked?).</p>
<p>Of course, we can avoid these complexities by ‘not writing bad code’ and adding some work-arounds, such as not defining instance variables in super classes and to not use virtual inheritance, be more careful when defining methods (or extend instead of override in subclasses - but that’s kind of like taking a step towards object composition too), and maintain the code having a keen awareness of the intricacies and added complexities. It can work, and it has worked well in many cases.</p>
<p>However, this boils down to the observation that multiple inheritance isn’t a highly used construct/feature, and that more often than not, it is mis-used in practice, which results in creating the problems and complexities, and needing additional work-arounds just to use the feature. Multiple inheritance requires expert knowledge to do it well, otherwise it is relatively easy to run into pitfalls and create issues. In the end, because of the high potential for mis-use, it is deemed that the costs outweigh the benefits.</p>
<h2 id="fundamental-differences">Fundamental Differences</h2>
<p>And as we discussed, in most cases where multiple inheritance is considered, we can instead use techniques such as object composition, delegation, AOP with mixins, etc.; as opposed to thinking multiple inheritance as the only solution to accomplish implementation and/or state reuse. However, this is indeed considered a work-around to a useful feature. I have to write and maintain more code to make composition/delegation work, and more code when referenced classes/instances are updated (such as new methods I’d need to also add to the wrapper code), compared to effectively using multiple inheritance.</p>
<p>From this perspective, what <a href="https://www.artima.com/intv/modern.html">Bjarne Stroustrup said in 2003</a> was particularly enlightening:</p>
<blockquote>
<p>People quite correctly say that you don’t need multiple inheritance, because anything you can do with multiple inheritance you can also do with single inheritance. You just use the delegation trick I mentioned. Furthermore, you don’t need any inheritance at all, because anything you do with single inheritance you can also do without inheritance by forwarding through a class. Actually, you don’t need any classes either, because you can do it all with pointers and data structures. But why would you want to do that? When is it convenient to use the language facilities? When would you prefer a workaround? I’ve seen cases where multiple inheritance is useful, and I’ve even seen cases where quite complicated multiple inheritance is useful. Generally, I prefer to use the facilities offered by the language to doing workarounds.</p>
</blockquote>
<p>To me this also pointed out some fundamental differences between C++ and Java/C#. C++ can be thought of as a large bag of tools (many language facilities/features), where in the hands of expert programmers it can be extremely versatile, and create well-engineered software. There are a lot of useful tools, but we have to know how to use them properly. Java and C# on the other hand, require a lower learning curve and can support a wide range of modern applications, precisely because their (comparatively more restrictive) language designs and implementations hide a lot of the complexities (hence not as easy to make mistakes).</p>
<p>The introduction of Java and C# also marked the transition between the age of expert systems programmers to the age of democratized applications programming for the masses. Where C/C++ places more weight towards flexibility, Java/C# derives power from restrictions/limits. So in a way, C/C++ and Java/C# are fundamentally different languages well-suited for somewhat different software development scenarios. Thus we don’t necessarily need to think, that because these are all ‘programming languages’ (that look especially similar), if one language has some useful features, then another language should have those same features too.</p>
<p>Personally, I kind of like it that differences in these languages exist, which help me focus on different things when developing different kinds of software. On the other hand, do I sometimes wish for some C++ features when working in Java/C#, or wish for the rich high-level frameworks in Java/C# from a C++ perspective? Sure I do; but not for long. It’s more fun to make things work so I just move on. 😉</p>It was back in 2008 when I first wrote about .NET and Multiple Inheritance. Since then I have received many feedback (some were particularly pointed), though kind of amazed that this is still a subject of debate even today.Artificial Intelligence Platform Overview (deck)2018-03-15T19:00:00+00:002018-03-15T19:00:00+00:00https://dachou.github.io/2018/03/15/artificial-intelligence-platform<p>Sharing the AI platform overview slide deck we delivered at the ISV Azure Innovation Series events across a couple of cities in the US.</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/2hPFZsUrbLgTVs" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen=""> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/davidcchou/microsoft-aiplatform" title="Microsoft AI Platform Overview" target="_blank">Microsoft AI Platform Overview</a> </strong> from <strong><a href="https://www.slideshare.net/davidcchou" target="_blank">David Chou</a></strong> </div>
<!--more-->Sharing the AI platform overview slide deck we delivered at the ISV Azure Innovation Series events across a couple of cities in the US. Microsoft AI Platform Overview from David ChouEnvisioning and Designing Artificial Intelligence (deck)2017-12-04T19:00:00+00:002017-12-04T19:00:00+00:00https://dachou.github.io/2017/12/04/artificial-intelligence-webcasts<p>Sharing the slide deck that has content from the webcasts we delivered on artificial intelligence.</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/vW6VQGIzfutue1" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen=""> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/davidcchou/designing-artificial-intelligence" title="Designing Artificial Intelligence" target="_blank">Designing Artificial Intelligence</a> </strong> from <strong><a href="https://www.slideshare.net/davidcchou" target="_blank">David Chou</a></strong> </div>
<!--more-->
<ul>
<li>8/17 - Envisioning Artificial Intelligence (<a href="https://info.microsoft.com/en-us-landing-ondemand-artificialintelligence.html">registration</a> / <a href="https://event.on24.com/wcc/r/1476052/FBCCC9DF6D0FA8A67D8ED15AFB7CCFE0">direct</a>)</li>
<li>8/24 - Designing Artificial Intelligence (<a href="https://info.microsoft.com/en-us-landing-ondemand-artificialintelligence2.html">registration</a> / <a href="https://wcc.on24.com/webcast/previewlobby?e=1476054&k=F1D2269C037ABCA57F3C57DCECFB24D4">direct</a>)</li>
<li>12/4 - Designing Artificial Intelligence (the deck above; <a href="https://event.on24.com/wcc/r/1535889/82944AFC53356E0C802B1DA765633C63">direct</a>)</li>
</ul>Sharing the slide deck that has content from the webcasts we delivered on artificial intelligence. Designing Artificial Intelligence from David ChouImmersive Computing (deck)2017-09-13T19:00:00+00:002017-09-13T19:00:00+00:00https://dachou.github.io/2017/09/13/immersive-computing<p>Sharing the Immersive Computing slide deck we delivered at the ISV Azure Innovation Series events across a couple of cities in the US.</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/4UhNBmx2cqTPfW" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen=""> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/davidcchou/immersive-computing" title="Immersive Computing" target="_blank">Immersive Computing</a> </strong> from <strong><a href="https://www.slideshare.net/davidcchou" target="_blank">David Chou</a></strong> </div>
<!--more-->Sharing the Immersive Computing slide deck we delivered at the ISV Azure Innovation Series events across a couple of cities in the US. Immersive Computing from David ChouDesigning Microservices (deck)2017-03-27T19:00:00+00:002017-03-27T19:00:00+00:00https://dachou.github.io/2017/03/27/microservices<p>Sharing the Designing Microservices slide deck we delivered at the ISV Azure Innovation Series events across a couple of cities in the US.</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/ffgroYJMle4eGg" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen=""> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/davidcchou/designing-microservices-114871184" title="Designing Microservices" target="_blank">Designing Microservices</a> </strong> from <strong><a href="https://www.slideshare.net/davidcchou" target="_blank">David Chou</a></strong> </div>Sharing the Designing Microservices slide deck we delivered at the ISV Azure Innovation Series events across a couple of cities in the US.Security in the Cloud (deck)2017-02-19T19:00:00+00:002017-02-19T19:00:00+00:00https://dachou.github.io/2017/02/19/security-in-the-cloud<p>Sharing the presentation slide deck we delivered during the <a href="https://event.on24.com/interface/registration/autoreg/index.html?eventid=1359115&sessionid=1&key=434A5012DDDEC748744778C58B6AC773&firstname=David&lastname=Chou&company=Microsoft&email=david.chou@microsoft.com&job_title=&country=&zip=&work_phone=">Security in the Cloud webcast</a>.</p>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/7CoBLTCkQMqZbn" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen=""> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/davidcchou/security-in-the-cloud-114871218" title="Security in the Cloud" target="_blank">Security in the Cloud</a> </strong> from <strong><a href="https://www.slideshare.net/davidcchou" target="_blank">David Chou</a></strong> </div>Sharing the presentation slide deck we delivered during the Security in the Cloud webcast.Roblox Universal Windows Platform App2016-05-17T19:00:00+00:002016-05-17T19:00:00+00:00https://dachou.github.io/2016/05/17/roblox-windows-10<p><img src="/assets/20060517-roblox-windows.png" alt="Roblox Windows" /></p>
<p>Roblox is a massively multiplayer online game created and marketed toward children and teenagers. In its immersive, 3D environment, players can create their own virtual world, in which they or other members may enter and socialize within the blocks of varying shapes, sizes, and colors. This user-generated online gaming platform has over 15 million games created by users, and millions of users playing the games.</p>
<iframe width="723" height="407" src="https://www.youtube.com/embed/lsV8cSwWXKw" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>
<p>Back in January we first released the Roblox build for Xbox One.</p>
<ul>
<li><a href="https://blog.roblox.com/2016/01/roblox-now-available-on-xbox-one/">https://blog.roblox.com/2016/01/roblox-now-available-on-xbox-one/</a></li>
<li><a href="https://www.prnewswire.com/news-releases/worlds-largest-user-generated-gaming-destination-now-available-on-xbox-300210481.html">https://www.prnewswire.com/news-releases/worlds-largest-user-generated-gaming-destination-now-available-on-xbox-300210481.html</a></li>
</ul>
<p>The Xbox One version also includes support for Cortana capability. It supports one function to search for games in the app. It’d listen for “find”, “look up”, or “search [for]” {query text}, and activate the in-app search experience. For example, if I speak “Hey Cortana, find pizza place”, then the game would execute that search and show the results:</p>
<p><img src="/assets/20160517-roblox-cortana.jpg" alt="Roblox Cortana" /></p>
<p>And now, the Windows 10 version of Roblox is released too.</p>
<p>Even though the project is built using Windows 10’s Universal Windows Platform (UWP), which enables UWP apps to run on all Windows 10 devices (phone, PC, console, tablets, etc.), there are still some differences between device platforms that need to be addressed. For instance, Xbox supports controller and has some UI/UX design differences, while Windows 10 supports touch and some Windows-specific UI modes.</p>