You are on page 1of 76

Angular, Lambdas, Python, C#, Azure Skyline

NOV
DEC
2016
codemag.com - THE LEADING INDEPENDENT DEVELOPER MAGAZINE - US $ 5.95 Can $ 8.95

Box Up Your Microservices


with F#!
shutterstock.com/Scanrail1

The Resurgence of XAML


Data Science using Python
Swiftly moving from Objective-C
TABLE OF CONTENTS

Features
8 The Journey to Angular: Part 4 46 Introduction to Data Science using Python
Paul continues his deep dive into AngularJS. This time, If youre curious about Data Science or Pythonand if youre interested
he adds validation to the page so you can spot input errors. in the Internet of Things, you should beyoull find this introduction
Paul D. Sheriff both important and exciting. Wei-Meng makes it all clear for us by
explaining the basics.
Wei-Meng Lee
14 Angular 2 Forms
Sahil continues his series on Angular 2 and this time, 58 Azure Skyline: Using WebJobs for Event-Driven,
looks at that essential element: the form.
Sahil Malik Asynchronous Services
If your call to services times out after four minutes, you can have a
24 Simplest Thing Possible: problem if the process needed to retrieve the data or a fire-and-forget
operation takes longer than that. What if the user makes a
Dynamic Lambda ExpressionsPart 3 request and then wanders away from the computer?
If you want to re-use some of the concepts John introduced in the last two issues, Mike solves it for you with WebJobs in Azure Skyline.
youll want to learn all about how Dynamic Lambda Expressions work in .NET. Mike Yeager
John Petersen

28 Moving Forward:
The Transition from Objective-C to Swift
If youve been paying attention to programming trends, youll see that Swift,
Columns
Apples new language, is gaining popularity at an impressive rate.
You dont have to toss out everything you already know, though,
74 Managed Coder: On Strong Teams
as Jason helps you see Swifts similarities to Objective-C. Ted Neward
Jason Bender

Departments
36 The Resurgence of XAML
Microsoft seemed to have put XAML out to pasture for a while, but Billy shows us
how its back, and why even Microsoft is touting its praises.
Billy Hollis
6 Editorial
42 Case Study: Writing Microservices with F#
If youre lucky enough to be involved in building a new enterprise system,
23 Advertisers Index
youll want to check this out. Rachel takes a look at how the company
where she works made some interestingand forward-lookingdecisions,
and she shows us the benefits of microservices while shes at it.
73 Code Compilers
Rachel Reese

US subscriptions are US $29.99 for one year. Subscriptions outside the US pay US $44.99. Payments should be made in US dollars drawn on a US bank. American Express,
MasterCard, Visa, and Discover credit cards are accepted. Bill me option is available only for US subscriptions. Back issues are available. For subscription information, send
e-mail to subscriptions@codemag.com or contact customer service at 832-717-4445 ext 028.
Subscribe online at codemag.com
CODE Component Developer Magazine (ISSN # 1547-5166) is published bimonthly by EPS Software Corporation, 6605 Cypresswood Drive, Suite 300, Spring, TX 77379 U.S.A.
POSTMASTER: Send address changes to CODE Component Developer Magazine, 6605 Cypresswood Drive, Suite 300, Spring, TX 77379 U.S.A.
Canadian Subscriptions: Canada Post Agreement Number 7178957. Send change address information and blocks of undeliverable copies to IBC, 7485 Bath Road, Mississauga,
ON L4T 4C1, Canada.

4 Table of Contents codemag.com


ONLINE QUICK ID 00
EDITORIAL

Shokunin
How much time are you willing to spend in order to master your craft? This is the $64,000 question.
There are many developers in the world and theres a single trait that separates a great developer from
an average one: dedication to craft. Greatness in any creative pursuit takes dedication. For instance,

if you want to be a writer, you have to do all the was the amount of time that people serve as ap- such a literal description does not fully
things that make writers great. You must write, prentices. express the deeper meaning. The Japanese
and I mean write a LOT. You only get better at apprentice is taught that shokunin means
writing by doing it. You must also read. How can An apprenticeship at Jiro lasts 10 years. When a not only having technical skills, but also
you expect to be a great writer if you dont take meal is started there, the customer is first given a implies an attitude and social conscious-
the time to read other peoples work? You must hot towel. This is the first lesson for apprentices, ness. The shokunin has a social obliga-
also search for and receive criticism. Its only by who learn to properly prepare towels for custom- tion to work his/her best for the general
dedicating yourself to being a student of all the ers. The apprentices then move on to tasks like welfare of the people. This obligation is
forms of a particular craft that you can achieve preparing rice, preparing fish, and ultimately, both spiritual and material, in that no mat-
greatness. This is true in any creative endeavor. after 10 years as an apprentice, how to prepare ter what it is, the shokunins responsibility
Want to be a singer? Sing. Want to be a painter? the traditional Tamago (egg omelet). Yes, the fi- is to fulll the requirement. Tasio Odate
Paint. Want to be a photographer? Take pictures. nal step is not fish but eggs. In this documentary,
Want to be a chef? Cook! one of the apprentices spends literally months I love this term. The concept of shokunin as
perfecting making Tamago. I believe it took over craftsman or artisan is pretty cool, but its the
Its this last craft that formed the inspiration for 200 tries for the apprentice to get it right. When The shokunin has social obligation to work his/
this editorial. My son and I are hooked on watch- the apprentice finally achieved perfection with her best for the general welfare of the people
ing cooking shows and documentaries. We watch his Tamago, he received one of the highest ac- that really stops me. Its a truly striking state-
Top Chef, Chopped, Chefs Table, and many colades an apprentice can achieve: Jiro called him ment. This means that when you achieve great-
others. One of my favorite documentaries is called shokunin. ness, you have an obligation to the community
Jiro Dreams of Sushi. Jiro Dreams is all about you serve.
sushi chef Jiro Ono, who owns Sukiyabashi Jiro, Shokunin is a wonderful Japanese word.
a Michelin three star-rated restaurant in Tokyo. I always look for the reasons I like being a soft-
This documentary is a study of sushi, tradition, The Japanese word shokunin is dened by ware developer and I believe it must have some-
and dedication to the craft of making perfect su- both Japanese and Japanese-English dic- thing to do with shokunin. Software development
shi. The most striking part of this documentary tionaries as craftsman or artisan, but is a service industry and its our responsibility to
deliver a product that ultimately makes peoples
lives better.

One of my favorite activities is watching people


use the software Ive created. Sometimes the
software is boring and mundane stuff, like an ac-
counting tool. Other times, its something that
makes a persons work or life truly better. Its in
those moments when a user says Thank you. That
really helped, that weve lived up to our obliga-
tions as a shokunin.

So now you need to ask yourself: Do you have the


dedication to achieve shokunin?

PS: This last summer, I had the honor of dining


at Sukiyabashi Jiro. Was it worth it? YES! And the
omelet? It was AMAZING. When they asked if I
would like anything more I said, Yes! More om-
elet please.

Rod Paddock

Figure 1: Jiro, my daughter, and I enjoyed ourselves in Tokyo.

6 Editorial codemag.com
ONLINE QUICK ID 1611021

The Journey to Angular: Part 4


In my last three articles for CODE Magazine, you learned to use AngularJS to search and select data. You also saw
how to add, edit, and delete data. In this article, youll see how to add validation to the page in order to catch any input
errors prior to sending the data to the server. Of course, youre not going to get rid of your server-side validation; you still

need to protect the data in case someone bypasses your tionDate and URL input fields. To the Price input field,
client-side validation. add required, min, and max to enforce a minimum and
maximum value that may be entered.
This article builds upon the sample from the last article.
If you dont have that code and wish to follow along, visit
www.pdsa.com/downloads, select PDSA Articles, then Display Error Messages
select Code Magazine - The Journey to Angular - Part 3 You can display error messages for each of the validation
from the drop-down list. attributes you added to the input fields in Listing 1. On
the HTML page, theres an unordered list used to display
Paul D. Sheriff any error messages. You can also use this list to display
www.pdsa.com
Add a Form Tag validation errors that Angular reports.
The first step is to add a <form> tag around all of your data
Paul D. Sheriff is the President entry fields. Be sure that the <form> tag is within the ng- Angular performs validation on all input fields as you
of PDSA, Inc. PDSA develops app=app and the ng-controller=productController modify them. The current state of the validation is re-
custom business applications statements, as shown in Figure 1. Give the <form> tag trieved via the FormController thats automatically set up
specializing in Web and mobile
a name and add the novalidate attribute. Although this by Angular on your <form> tag. Use either the $error or
technologies. PDSA, founded
may seem counter-intuitive to add novalidate, this is $valid properties on each input field to determine va-
in 1991, has successfully
what Angular needs because its going to take over all lidity of the data in the field. The $error allows you to
delivered advanced custom
application software to a wide data validation and doesnt want the browser to do any determine exactly what the error is. The $valid tells you
range of customers and diverse validation on its own. whether or not the input field contains valid data accord-
industries. With a team of ing to all of the validation on that field.
dedicated experts, PDSA deliv-
ers cost-effective solutions,
Add Validation Attributes The $error property has additional properties you can
on-time and on-budget, using For each field on your screen, you need to decide on which query to determine the exact cause of the validation fail-
innovative tools and processes fields to perform validation. Of those you need to validate, ure. The valid properties are required, max, maxlength,
to better manage todays com- determine which type of validation you can accomplish min, minlength, pattern, email, number, url, date, date-
plex and competitive environ- within the attributes available in HTML/HTML5 and Angu- timelocal, time, week, and month. You query these prop-
ment. Paul is also a Pluralsight lar. Later in this article, youll learn to create your own erties by specifying the name of the form, the name of the
author. Check out his videos at custom validation directives. In Table 1, youll find a list of input field, $error and the name of the property. Some
http://www.pluralsight.com/ the attributes you can use with Angular validation. examples are shown in the following code snippet.
author/paul-sheriff.
Each input field must have the name attribute in addition productForm.ProductName.$error.required
to the id attribute. The name attribute, combined with one productForm.ProductName.$error.maxlength
or more of the attributes listed in Table 1, is what Angular productForm.ProductName.$error.minlength
uses to determine the set of fields that need to be vali-
dated. Go ahead and add the name attribute to each of the productForm.Price.$error.max
input fields in the detail area of the page. Make the value productForm.Price.$error.min
of the name attribute the same as value of the id attribute.
Each of the properties above returns a true or false, in-
Add the appropriate validation attributes to the input dicating whether or not the input field meets the criteria
fields, as shown in Listing 1. To the ProductName field, expressed in the attribute. If theres no value contained in
add the attributes required, ng-minlength, and ng- the ProductName input field, the $error.required property
maxlength. Add the required attribute to the Introduc- returns a true value. You use these properties in combina-
tion with the ng-show or ng-hide directives to display an
error message to the user. Add list item elements with an
Attribute Type Description appropriate error message to the unordered list message
area on your page, as shown in Listing 2. As you can see
required HTML The field must contain a value. from the code in Listing 2, adding the ng-show directive
min HTML A minimum value for a numeric input field and querying one of the $error or $valid properties, you
max HTML A maximum value for a numeric input field determine whether or not that particular error message is
displayed in the list.
ng-minlength Angular The minimum number of characters for a field
ng-maxlength Angular The maximum number of characters for a field
ng-required Angular The field must contain a value. Same as required Initialize the Product Object
ng-pattern Angular A regular expression the input value must match When the user clicks on the Add button, its often a good
idea to initialize some of the fields of the vm.product ob-
Table 1: Validation attributes you may add to any input field ject to valid start values. Open the productController.js

8 The Journey to Angular: Part 4 codemag.com


Listing 1: Modify input fields to use Angular validation
<div class="form-group"> type="text" />
<label for="ProductName"> </div>
Product Name <div class="form-group">
</label> <label for="Url">Url</label>
<input class="form-control" <input class="form-control"
id="ProductName" id="Url"
name="ProductName" name="Url"
required required
ng-minlength="4" ng-model="product.Url"
ng-maxlength="150" type="text" />
ng-model="product.ProductName" </div>
type="text" /> <div class="form-group">
</div> <label for="Price">Price</label>
<div class="form-group"> <input class="form-control"
<label for="IntroductionDate"> id="Price"
Introduction Date name="Price"
</label> required
<input class="form-control" min="0.01"
id="IntroductionDate" max="9999.99"
name="IntroductionDate" ng-model="product.Price"
required type="text" />
ng-model="product.IntroductionDate" </div>

Listing 2: Add error messages to the message area


<ul> <li ng-show="!productForm.IntroductionDate.$valid">
<li ng-repeat="msg in uiState.messages"> Invalid Introduction Date
{{msg.message}} </li>
</li> <li ng-show="productForm.Url.$error.required">
<li ng-show="productForm.ProductName.$error.required"> Url is Required
Product Name is Required </li>
</li> <li ng-show="productForm.Price.$error.required">
<li ng-show="!productForm.ProductName.$valid"> Price is required
Product Name must have more </li>
than 4 characters and less than 150 <li ng-show="!productForm.Price.$valid">
</li> Price must be between $0.01 and $9,999
<li ng-show="productForm.IntroductionDate.$error.required"> </li>
Introduction Date is Required </ul>
</li>

file and add a new function named initEntity(), as shown


in the following code snippet.

function initEntity() {
return {
ProductId: 0,
ProductName: '',
IntroductionDate:
new Date().toLocaleDateString(),
Url: 'http://www.pdsa.com',
Price: 0
};
}

When you click on the Add button, the ng-click directive


calls the addClick() function. In this function, you call
the initEntity() function and assign the return value
to the vm.product variable. All of the properties of this
object are bound to the input fields on the HTML page
and thus the values created in this function are then
displayed in each of the fields. Run the form right now
and click the Add button to see these values displayed.
The validation doesnt work yet, but youll hook that up
next. Figure 1: Add a <form> tag within your Angular app and controller.

codemag.com The Journey to Angular: Part 4 9


function addClick() { tion failures, and then ng-showing that it has received a
vm.product = initEntity(); true value from querying the $error or $valid properties.
setUIState(pageMode.ADD); If you wipe out all of the input fields and click Save again,
} you should see many errors appear.

Whats interesting is that as you clear each field, the er-


Using the Product Form ror messages appear immediately. This is because Angular
When you add the <form> tag and assign a name to it, constantly monitors any bound fields. When they change,
Angular creates a FormController object. The name used the validity of each field is checked and the $error and
in this article, productForm, can be queried from the vm $valid properties are updated. This causes the appropri-
variable in the controller. In the saveClick() function, ate ng-show directives to be re-evaluated and the mes-
modify the code to use this form controller object to sages to be displayed in the unordered list.
check to see whether the form is valid or not. If it isnt,
display the messages area so all of the validation messag-
es are displayed in the unordered list. Modify the save- Custom Validation Directive
Click() function to look like the following code snippet. Using the built-in validations is fine, but sometimes you
might need something a little more specific to your own
function saveClick() { environment. You could write some JavaScript in the vali-
if (vm.productForm.$valid) { date() function in your controller, but a more Angular ap-
vm.productForm.$setPristine(); proach is to create a directive. In Listing 3 , you can see
Sample Code saveData(); how to create a directive to enforce that an input field cant
} have the word microsoft within the entry. At the top of
You can download the sample
else { the productController.js file, where you define the Product-
code for this article by visiting my
vm.uiState.isMessageAreaVisible = true; Controller, chain the directive() function to this definition
website at http://www.pdsa.com/
downloads. Select PDSA Articles, } and write some code to create your own custom directive.
and then select Code Magazine }
- The Journey to Angular - Part 4 You pass two arguments to the directive() function: the
from the drop-down list. You can see that if the form is valid, youre going to set name of the directive and a function thats executed each
the form back to a pristine state. Call the $setPristine() time the model value is updated by the user typing into
function to reset all internal properties of the form con- the input field. The name of the directive needs to be
troller object back to a valid state. The form also needs created in camel case. When used as an attribute, you
to be set to pristine, as you will read about a little later separate the lower case portion and the word with the
in this article. upper case letter by a dash (-). For example, in Listing
3 the name of the directive is urlMicrosoft; when added
The other change youre going to make is to modify the as an attribute to an HTML element, its expressed as url-
saveData() function. Modify this function so it looks like microsoft.
the following code snippet. Youre removing some code
from a function that was written in a previous article and The function you write creates an object with two proper-
is no longer needed. ties: require and link. As youre going to be using this
as a validation directive, you require the ngModel. The
function saveData() { link property is a function that accepts four parameters;
// Insert or Update the data scope, element, attributes and ngModel. Attach your own
if (vm.uiState.mode === pageMode.ADD) { property name to the ngModel.$validators collection. In
insertData(); this case, Im using the name Microsoft, but feel free
} to name it whatever you want. Assign a function to this
else if (vm.uiState.mode === pageMode.EDIT) { new property thats passed the model value that the user
updateData(); just typed in. This function returns a true or a false value
} based on whether or not the value typed is valid.
}
To use the validation directive, apply the attribute to the
If you run the sample HTML file, click on the Add but- appropriate input field. In this case, add it to the URL
ton, immediately click on the Save button, and then you field to make sure someone doesnt type in www.micro-
should see a couple of error messages show up in the soft.com. In the code snippet below, you can see the di-
unordered list. These messages are the result of Angular rective applied using the dash notation mentioned previ-
evaluating the validation attributes, detecting the valida- ously.

Listing 3: Add some custom validation to the validate function


angular.module('ptcApp') function (value) {
.controller('ProductController', ProductController) if (value) {
.directive('urlMicrosoft', function () { return value.indexOf("microsoft") == -1;
return { }
require: 'ngModel', }
link: function (scope, element, }
attributes, ngModel) { };
ngModel.$validators.microsoft = });

10 The Journey to Angular: Part 4 codemag.com


<input class="form-control"
id="Url"
name="Url"
ng-model="product.Url"
required
url-microsoft
type="text" />

Locate the unordered list in the messages area and add


one more list item to display an error message when the
$error.microsoft is set to a true value.

<li ng-show="productForm.Url.$error.microsoft">
Url cannot have the word 'microsoft' in it
</li>

The property microsoft is dynamically added to the


$error property because thats what you defined in the
directive. Run the sample again and click on the Add but-
ton, and then immediately click on the Save button. You
should see a couple of error messages. Click into the URL
input field and type the word microsoft anywhere in this
field. As soon as you do, you should see your new error
message in the messages area. Remove the word micro-
soft, fill in a valid product name, and the error messages
disappear. Note that the message area doesnt go away,
as shown in Figure 2.

To fix this problem, youre going to take advantage of the


form controller and its properties. Modify the <div> that
surrounds the message area. Currently, it looks like the
following:

<div ng-show="uiState.isMessageAreaVisible"
class="row"> Figure 2: The message area doesnt completely disappear.

Instead of using the ng-show, youre going to use the


ng-hide directive. The expression you use to determine objects, only some hard-coded mock data. If youre us-
whether or not to display the message area should look ing Entity Framework, youre probably using Data An-
like the following code snippet. notations so that required values, min and max lengths,
and data types are taken care of. Im going to use the
<div ng-hide="!uiState.isMessageAreaVisible || ModelStateDictionary that the Web API provides as part
(productForm.$valid && of the System.Web.Http.ModelBinding namespace. Note
!productForm.$pristine)" that this model state dictionary is different from the
class="row"> one that the Entity Framework uses. If youre using the
Entity Framework, you need to transfer any data an-
You want the message area to be hidden if the isMes- notations messages from one model state dictionary to
sageAreaVisible property is set to false, or if the product another.
form is valid and the product form is no longer pris-
tine. This means that youve modified the form data in For the purposes of this article, Im only going to show
some way. After making these changes, go ahead and you how to add validation messages to the System.Web.
run the form again, click Add and press the Save but- Http.ModelBInding.ModelStateDictionary, serialize that
ton to display an error message. Fix the product name object, and report the messages on the HTML page. The
field so that it has valid data in it, and you should see first step is to open the ProductController.cs file and add
the message area removed from the page. The use for a using statement at the top of the file.
the productForm.$pristine is why as soon as the data
is valid on the page, in the saveClick() function, you using System.Web.Http.ModelBinding;
want to call the $setPristine() function on the product
form. This allows the message area to once again be Next, add a property of the type ModelStateDictionary
hidden. and set the name to ValidationErrors. This property is
what youre going to fill in with any validation errors. The
values in this property are serialized and passed back as
Server-Side Validation part of a BadRequest() Web message.
Client-side validation can be bypassed fairly easily, so
you always need to validate your data once you post it public ModelStateDictionary
to the server. In this article, I havent used any database ValidationErrors { get; set; }

codemag.com The Journey to Angular: Part 4 11


Listing 4: Write additional validation code
protected bool Validate(Product product) { "Introduction Date Must Be Greater Than 1/1/2010");
bool ret = false; }

ValidationErrors = new ModelStateDictionary(); // Add more validation here to match


// client-side validation
// Add custom validation
if (product.IntroductionDate < ret = (ValidationErrors.Count == 0);
Convert.ToDateTime("1/1/2010")) {
ValidationErrors.AddModelError( return ret;
"Introduction Date", }

Listing 5: Call the Validate() function when updating data


public IHttpActionResult Put(int id, Product product) { }
IHttpActionResult ret = null; else {
ret = NotFound();
if (Validate(product)) { }
if (Exists(id)) { }
if (Update(product)) { else {
ret = Ok(product); ret = BadRequest(ValidationErrors);
} }
else {
return InternalServerError(); return ret;
} }

Listing 6: Call the Validate() function when inserting data


public IHttpActionResult Post(Product product) { }
IHttpActionResult ret = null; }
else {
if (Validate(product)) { ret = BadRequest(ValidationErrors);
if (Add(product)) { }
ret = Created<Product>(Request.RequestUri +
product.ProductId.ToString(), return ret;
product); }
}
else {
ret = InternalServerError();

Create a Validate Method ning the other code that exists in these methods. If the
Add a Validate() method to your product controller, as validation fails, set the IHttpActionResult return value to
shown in Listing 4. I added just one additional rule just BadRequest, passing in the ValidationErrors model state
to show you how to add a validation error. The additional dictionary that contains all of your validation errors to
rule I added was to ensure that the IntroductionDate prop- display on your HTML page.
erty contains a date that is greater than January 1, 2010.
If it doesnt, add a model error to the ValidationErrors
collection using the AddModelError() method.
Handle Server-Side Validation Errors
on the Client-Side
You should write any other if statements to verify that When you return the BadRequest Web message, this trig-
required fields are filled, and that minimum and maxi- gers the error function in your data service call. In each
mum lengths and values are enforced. You need to write of these error functions, you wrote code to call the han-
any validation logic that matches all of the attributes dleException() function in your productController.js file.
you added to your input. Or, if youre using Data An- Modify the handleException() function to handle any of
notations on your entity objects, you can retrieve the the status codes that can be returned from your Web API.
ModelStateDictionary object, get the errors from the an- In each case, you add the appropriate error message to
notations and add those to the ValidationErrors collec- the vm.uiState.messages array. To make it simpler to add
tion property. a message, create a addValidationMessage() function, as
shown in the following code snippet:
Modify Put and Post methods
After writing the Validate() method, modify both the function addValidationMessage(prop, msg) {
Put() and Post() methods (Listing 5 and Listing 6) in vm.uiState.messages.push({
your controller to call the Validate() method prior to run- property: prop,

12 The Journey to Angular: Part 4 codemag.com


Listing 7: Add a case statement to check for validation errors from the server
function handleException(error) { 'The product you were ' +
vm.uiState.messages = []; 'requesting could not be found');
break;
switch (error.status) {
case 400: // 'Bad Request' case 500: // 'Internal Error'
// Model state errors addValidationMessage('product',
var errors = error.data.ModelState; error.data.ExceptionMessage);
break;
// Loop through and get all
// validation errors default:
for (var key in errors) { addValidationMessage('product',
for (var i = 0; 'Status: ' +
i < errors[key].length; error.status +
i++) { ' - Error Message: ' +
addValidationMessage(key, error.statusText);
errors[key][i]); break;
} }
}
break; vm.uiState.isMessageAreaVisible =
(vm.uiState.messages.length > 0);
case 404: // 'Not Found' }
addValidationMessage('product',

message: msg learned how to check additional values on the server-side


}); and return a bad request (HTTP status of 400) to trig- SPONSORED SIDEBAR:
} ger an exception on the client-side. You then extracted
the messages returned from the Web API and added those Does Your Cloud App
Locate the handleException() function in your product- to your messages array so those messages could be dis-
Have You Feeling Under
the Weather?
Controller.js file and modify it to look like Listing 7. The played on your HTML page.
important part in this function is handling the case for The developers at CODE
the bad request that has a status code of 400. You know Paul D. Sheriff have worked on everything
that youre passing back a model state dictionary object from cloud applications to
for any bad request generated from your Web API, so you mobile projects. If youre
get that dictionary object in the ModelState property at- having problems with your
tached to the error.data property. Cloud Application and need
guidance, the developers at
Loop through all of the errors in this ModelState prop- CODE Consulting can help
erty and extract the key. From this key name, you can you with your project.
access the message property and pass in both the key For more information visit
name and the message to the addValidationMessage() www.codemag.com/
function to add the message to the vm.uiState.messages consulting or email us at
array. Once this message is in the array, the message is au- info@codemag.com to set
tomatically displayed in the unordered list in the messages up your time with a developer
today.
area on your HTML page. To ensure that the message area
is visible, set the vm.uiState.isMessageAreaVisible equal to
true at the end of the handleException() function.

Run the sample one last time. Click on the Add button
and set the product name field to a valid value, but set
the introduction date to 1/1/2000, or any date prior to
1/1/2010. Click the Save button to post to the server.
You should now see the appropriate error message, tell-
ing you that the introduction date must be greater than
1/1/2010.

Summary
In this article, you learned the basics of adding validation
to your Angular page. You took advantage of the built-
in validation attributes and learned how to display error
messages within an unordered list. You learned to create
a custom validation directive for functionality that was
beyond what the standard validation can do. Finally, you

codemag.com The Journey to Angular: Part 4 13


ONLINE QUICK ID 1611031

Angular 2 Forms
Forms are essential and deceptively simple, but they can also be incredibly involved. Theyre just a <form/> tag with a bunch
of input controls, right? Wrong. Things can become quite complex quickly once you consider issues such as data-binding,
validations, change tracking, etc. You need to consider that youre in a browser, disconnected from the server and you need

to worry about change tracking. Even validations can be every single aspect here, but Ill mention some high-level
simple validations, or they could be validations that you portions.
write code for, that need an asynchronous call, or that in-
volve multiple controls. See? Their simplicity is deceptive! The code for the Start application is quite simple. It
contains two components. The first is a TodoComponent,
Forms are a very important part of any framework, and which renders a single Todo that it receives as an input
therefore its reasonable to expect that Angular 2 has rich from the startup component, which is the TodosCompo-
support for forms. Angular2 lets you support forms in two nent.
different ways:
NameMalik
Sahil Autor The second is the TodosComponent, which relies on the
www.winsmarts.com
www.internet.com Template-driven forms, which you can think of as TodoService to get an observable of Todo[]. The To-
@sahilmalik very similar to how Angular 1 let you write forms doService populates this Observable whenever it queries
asdfasdfasdfasdfker, a .NET Model driven forms, which is the new functional re- the backend with an Ajax call. The reason I preferred to
Sahil
author,Malik is a Microsoft
consultant MVP,
and trainer. active way use Observables over promises here is because it greatly
INETA speaker, a .NET author,
simplifies the code. Perhaps the most interesting part
Sahilasfasdfasdfasdfasdfasdfd-
consultant, and trainer.
fainings are full of humor and In this article, Ill write a simple ToDo application and il- here is the service itself, which can be seen in Listing 2.
Sahil loves
practical interacting
nuggets. withfifel-
You can nd lustrate both ways of writing the form. First, let me start
low
moregeeks
aboutinhis
realtrainings
time. Hisattalks describing what the application is all about. You should, I used a special class called the Subject. The Subject
and trainings are full of humor
http://wwasdfasdfasfasdfasdf at this point, clone the git repo at: https://github.com/ is both an Observer and Observable. IUsing a Subject
and practical nuggets. You can maliksahil/AngularForms, which is the associated code is a very convenient way to convert the results of the
find more about his training at for this article. HTTP GET operation, massage the results as need be,
http://www.winsmarts.com/ and populate the massaged Todos, which are ready to
training.aspx. be consumed as an Observable using the asObservable
Strawman ToDo Application method, which I expose as a public property.
His areas of expertise are cross- ToDo applications are the new HelloWorld because ev-
-platform mobile app develop- eryone knows what they are. I dont have to explain the Go ahead and get the Start application working on your
ment, Microsoft anything, and business problem, so you can focus your energy on under- computer. This code is extremely simple, but do ensure
security and identity.
standing the technical problem. Also, ToDo applications that you understand it well before proceeding further.
provide enough flexibility to allow me to craft up nearly
any canonical example.
Enhancing the Service
In this strawman application, youll have a form that lets Now that the simple example is in place, I want to aim
you edit an array of Todo objects. The Todo objects are higher. I want to give the user the ability to edit, de-
loaded using an AJAX call from a JSON file. You can see lete. And add ToDos. To support these operations, the first
the structure of the data in Listing 1. thing Ill do is change the implementation of the TodoSer-
vice. Note that this section of this article applies to both
Start with a simple read-only application that you can template-driven forms and model-driven forms.
find in the associated code download under the Start fold-
er. Clone the github repository for the associated code In addition to supporting Observables for GET operations,
download. The code is way too wordy for me to explain it needs to support additions, modifications, and dele-
tions. Deletions? But if Observables are the end of a read-
only pipe, how are you going to handle deletions? Well,
Listing 1: Structure of the data its easy! First of all, most likely, youre not deleting in
[ the browser only; you probably want to mark the objects
{ as added, deleted, or modified, and to change their value.
"id": 0, You can add more intelligent change tracking if you wish,
"title": "Steal donut truck" but marking the row state is enough for the purposes of
}, this article.
{
"id": 1, To support row states, add a property called rowState in
"title": "Speed on the freeway" the Todo business object, as can be seen in Listing 3.
},
{ Next, turn your attention to the service, which needs to
"id": 2, support deletes, adds, and modify operations.
"title": "Get caught by cop"
} Because you need to handle deletes and modify opera-
] tions eventually, you need to remember the overall state

14 Angular 2 Forms codemag.com


of the application. Note that Im not using Redux. To re- Listing 2: The TodoService
member state, simply create a variable at the top of your
@Injectable()
service, as shown in the next snippet:
export class TodoService {
private _todos: Subject<Todo[]> = new Subject<Todo[]>();
let allTodos: Todo[] = [];
todos: Observable<Todo[]> = this._todos.asObservable();

constructor(private _http: Http) {


this._http.get('data/todos.json').subscribe(res => {
Theres an alternate this._todos.next(res.json());
pattern called Redux that });
gives you a very standardized }
way of handling state }
and actions on the state.
Ill leave that for a
future article.
Listing 3: Adding the rowState property
export class Todo {
public id: number;
Lets tackle getting objects from the server and adding public title: string;
them. Thiss easy with a kink, which will become clear public rowState:string;
quite soon. constructor(todo?: Todo) {
Object.assign(this, todo);
this.rowState = "ADDED";
In your TodoService, add a property called newTodo as
}
shown in the next snippet:
}

newTodo: Subject<Todo> = new Subject<Todo>();

This is an Observable (a subject is both an Observer To handle new Create operations, add the following Sub-
and an Observable), which always shows the last added ject:
Todo. Why are you adding this? Because when you add
objects into an array, you want to notify all the interested create: Subject<Todo> = new Subject<Todo>();
parties that a new object is available. Wait a minute! I
thought you wanted to notify the rest of the parts of the The eagle-eyed among you might have caught an oddity
application that the Todo array has changed. Yes indeed! above. The first snippet has a Subject of type ITodosOperation,
But what does the notification? For now, lets name that and the other has a Subject of type Todo. You need this
mythical character who does this notification Piggie. because Create always creates new Todos, but an Update
Piggie dearest needs to notify the TodosComponent that receives operations that need to be applied to all Todos.
the Todo array has changed. And the newTodo Observable Doing it this was means that youve chosen to generically
can notify Piggie that a new Todo is available, and then, represent that as an interface.
in turn, Piggie can notify the TodosComponent.
Next, add a new Todo to notify the creation subject. This
So, now theres a newTodo -> Piggie -> TodosComponent? is easy to do with the following line of code:

No, that isnt enough! You not only want to notify in the this.newTodo.subscribe(this.create);
case of additions, you also wish to notify in the case of
deletions and modifications. In fact, lets call these by In other words, whenever theres a new thing happening
the generic name Todos Operation, which you can conve- on newTodo, like when a new Todo is added, it calls this.
niently represent using an interface. Now you can add the create. The creation operation is shown as next.
following Todos operation in your TodoService file.
this.create.map(
interface ITodosOperation extends Function { function (todo: Todo): ITodosOperation {
(todo: Todo[]): Todo[]; return (todos: Todo[]) => {
} return todos.concat(todo);
};
If youre familiar with redux, you might be thinking that }).subscribe(this.updates);
this looks shockingly similar to a reducer function. Yeah,
it is! But Redux is this plus a few more things. Lets leave This puts the Create operations on the updates stream.
that for another day. Youre effectively subscribing your Updates stream to lis-
ten to the Create stream. In other words, if Create gets a
With this newTodo in place, you also need similar Subjects new Todo (by virtue of the newTodo subject), it emits an
to handle updates and creations. To handle updates, add ITodosOperation, which will be received to the updates
the following Subject to your service: stream.

updates: Subject<ITodosOperation> = Now, you need to handle the Updates stream. This can be
new Subject<ITodosOperation>(); seen in the next snippet:

codemag.com Angular 2 Forms 15


Listing 4: The Todoservice
export class TodoService { // watch the updates and accumulate operations on the todos
// All Todos this.todos = this.updates
todos: Observable<Todo[]>; .scan((todos: Todo[], operation: ITodosOperation) => {
// Latest Todo return operation(todos);
newTodo: Subject<Todo> = new Subject<Todo>(); }, allTodos)
// Receives changes that can be applied to all Todos .publishReplay(1).refCount();
updates: Subject<ITodosOperation> =
new Subject<ITodosOperation>(); this.create.map(function (todo: Todo): ITodosOperation {
// action stream return (todos: Todo[]) => {
create: Subject<Todo> = new Subject<Todo>(); return todos.concat(todo);
};
constructor(private _http: Http) { }).subscribe(this.updates);
// Hydrate todos
this._http.get('data/todos.json').subscribe(res => { this.newTodo.subscribe(this.create);
allTodos = res.json(); }
allTodos.forEach((todo) => {
let toAddTodo = new Todo(todo); addTodo(todo: Todo): void {
this.addTodo(toAddTodo); todo.rowState ="ADDED";
}); this.newTodo.next(todo);
}); }
}

Listing 5: Delete and Update operations.


updateTodo(todo: Todo): void { delete: Subject<Todo> = new Subject<Todo>();
this.todos.subscribe((_todos: Todo[]) => { removeTodo(todo: Todo) {
_todos.forEach((_todo) => { // console.log(todo);
if (_todo.id === todo.id) { this.todos.subscribe((_todos: Todo[]) => {
_todo.title = todo.title _todos.forEach((_todo) => {
_todo.rowState = "UPDATED" if (_todo.id === todo.id) {
}; _todo.rowState = "DELETED";
}); };
}); });
} });
}
// deletes

this.todos = this.updates Now with the service ironed out, youll reuse the same ser-
.scan((todos: Todo[], operation: ITodosOperation) => { vice for both Template-driven forms and Model-driven forms.
return operation(todos);
}, allTodos) Template-Driven Forms
.publishReplay(1).refCount(); Angular 1 provided many directives, one of which was
ng-model and which gave us two-way databinding. The
What youre doing here is watching all the Updates biggest advantage of ng-model-based forms or controls
and the accumulation the Operations on Todos. Youre was that they were simple. They were simple to write and
replaying the last change using the publishReplay(1) simple to understand.
method, which youre setting to this.todos, which
is the Observable that youre databinding to in the Angular2 has an identical mechanism using ngModel. To
TodosComponent. see it in action, lets extend the Start application to al-
low you to edit, add, and delete ToDos. Youll find the fin-
Putting all this together, my TodoService now looks like ished code for the template-driven form in the Template
Listing 4. folder of the associated code download for this article.

After all this effort, deletes and updates become really Template-driven forms are quite similar to how you wrote
simple. You can see the delete and update methods in forms in Angular 1. The first thing to do is to make the
Listing 5. TodoComponent support two-way data binding. Im doing
this because I wish to also edit the Todo and the edited value
As can also be seen in Listing 5, you are simply iterating needs to be reflected back to the parent TodosComponent.
over the ToDos, and if you find the matching ToDo, youre
updating or deleting it. Well, youre also marking the row The TodoComponent
state, but thats the equivalent of deleting in a discon- The first change you need to make is to the
nected system. todo.component.html file. This can be seen in Listing 6.

16 Angular 2 Forms codemag.com


codemag.com Title article 17
You may have guessed by looking at Listing 6 where Im
headed. Ive added a simple Edit/Save functionality that
sets a Boolean isEdit, which shows/hides the Textbox that
allows the user to edit the Todos title. In addition, Ive
used the banana in a box ngModel syntax to two-way
databind my textbox to todo.title. The code backing this
in todo.component.ts is shown in Listing 7.

As can be seen in Listing 7, Ive enabled this to be a two-


way databound component, which provides basic Edit/
Save functionality for the Todo.

The TodosComponent
Next, lets focus on the TodosComponent. Ive added
some code at the bottom of my TodosComponent that al-
lows me to see the databound business object, which can
be seen in Listing 8.

And thats where the easy part ends! Just kidding. Or at


least, thats where the elegant part ends, and that unfor-

Listing 6: The todo.component.html file for Template-driven forms


<span>
<span *ngIf="!isEdit">
{{todo.id}}. {{todo.title}}
</span>
<span *ngIf="isEdit">
{{todo.id}}. <input name="title" [(ngModel)]="todo.title"/>
</span>
<a href="#" (click)="toggleEdit($event)">Edit</a>
</span> Figure 1: The template-driven form

Listing 7: The todo.component.ts for template-driven forms tunately Im not kidding about. The rest of the TodosCom-
ponent can be seen in Listing 9.
@Component({
selector: "todo-control", The first thing that sticks out in Listing 9 is that it really
templateUrl: './app/Components/todo.component.html', pollutes your HTML, doesnt it? But lets leave the pros
directives: [FORM_DIRECTIVES] and cons for the end. Essentially what happens here is
})
that Ive declared a variable called #f (or just f in type-
script) to represent my form. And wherever I specify a
export class TodoComponent {
Name attribute, it becomes a Property on my form. As
@Input() todo: Todo;
long as I can databind using ngModel, the user interface
@Output() todoChange: EventEmitter<Todo> = new EventEmitter<Todo>();
shows the new values and the underlying business object
changes. When you hit submit, youre logging the value
private isEdit: boolean = false;
toggleEdit($event) {
of f.value, as shown in the next snippet:
this.isEdit = !this.isEdit;
$event.srcElement.innerText = this.isEdit ? "Save" : "Edit"; onSubmit(formData:any) {
this.todoChange.emit(this.todo); console.log(formData);
} }
}
At this point, go ahead and run the application. You prob-
ably want to use the code from the Template folder of the
associated code download.
Listing 8: Viewing the business object
<table> When you run the application, it should load a user inter-
<thead> face as shown in Figure 1.
<td><b>Business Object</b></td>
</thead> Now go ahead and add a new Todo and add some text in
<tr> the new Todo field. As you can see in Figure 2, the busi-
<td> ness object stays in sync. Thats great! You can also add
<pre>{{_todos | async | json}}</pre> validations just like you did in Angular 1, and you have
</td> various properties on the form object to help you out,
</tr> along with CSS classes in the UX. It didnt take a lot of
</table> code to make this happen.

18 Angular 2 Forms codemag.com


Listing 9: Todos Component with Template-driven forms
<form #f="ngForm" (ngSubmit)="onSubmit(f.value)"> <div>
<div *ngFor="let todo of _todos | async; let i = index"> <h2>Add a todo:</h2>
<todo-control [todo]="todo" <label for="todoTitle">Title</label>
(todoChange)="updateTodo($event)" <input type="text" id="todoTitle" name="title" ngModel>
name="todo{{i}}" ngDefaultControl ngModel> </div>
</todo-control> <button type="submit">Submit</button>
</div> </form>

Listing 10: The todos.component.html examining our objects


<table> <pre>{{ myForm.valueChanges | async | json}}</pre>
<thead> </td>
<td><b>Databound data</b></td> <td>
<td><b>Business Object</b></td> <pre>{{_todos | async | json}}</pre>
</thead> </td>
<tr> </tr>
<td> </table>

Youll note that, for brevity sake, Ive chosen not to show you need to know here is that the service is not going to
the delete and add functionality. Theyre going to be change. This is the reward you get for modeling your code
simple method calls to the service methods that youve nicely and separating the heavy lifting into the service.
already written, but that brings me to a big downside of The only changes are in the components. This time, Ill
this approach of creating forms. Go ahead and click the start with the parent TodosComponent.
Submit button. You should see an output like that shown
in Figure 3.

Hmm, thats not quite what you were expecting, right?


This looks nothing like the object you were working with.
In fairness, in the databound object, the Todos Observ-
able is where you can look for proper data structure, but
that gets quickly out of hand because you effectively have
to tie your UX to your business object structure. That
means that you have to model your components to reflect
the object structure. This brings me to the pros and cons
of template-driven forms.

Pros and Cons


The template-driven form is easy to understand but has
the following disadvantages:

In order to TDD, you need the DOM.


Your components structure invariably end up get-
ting affected by your business object structure.
Changing the business object structure can cause
huge changes in your application.
Validations etc. make the form less and less read-
able.
None of the validation logic is easy to unit test.

On the other hand, template-driven forms are simple!


That, in my eyes, is a big win.

Model-Driven Forms
Next, lets look at being able to create the very same form
using the model-driven forms approach. The first thing Figure 2: The edited template-driven form

Figure 3: The form.value in template-driven forms

codemag.com Angular 2 Forms 19


The TodosComponent your business object and this FormGroup in sync? Luckily,
The one big difference between template-driven forms thats not the case. Because you wrote the service to use
and model-driven forms is that model-driven forms work Observables, and because model-driven forms understand
on their own business object of data type FormGroup. Observables very nicely, bridging the two together is
This may sound like a negative, because after all, dont very easy. In other words, with very little plumbing code,
you then have to write lots of plumbing code to keep the business object stays in sync with the form and vice
versa.

Listing 11: Hydrating Todos and creating controls In the form, youll have variable called myForm of data
ngOnInit() { type FormGroup representing the forms data. List-
this.myForm = this._fb.group({ ing 10 shows some diagnostic databinding code that
'todos': this._fb.array([]) helps you view both the databound object and the
}); business object side-by-side. This code goes in the
todos.component.html file.
this._todoService.newTodo.subscribe((todo) => {
const control = <FormArray>this.myForm.controls['todos']; In order to construct the myForm variable, make use of an
control.push(this.initTodoControl(todo)); Angular service called FormBuilder.
});
Start by injecting an instance of FormBuilder into the
this._todos = this._todoService.todos; constructor of TodosComponent, as shown in the next
} snippet:

constructor(
private _todoService: TodoService,
Listing 12: The initTodoControl method
private _fb: FormBuilder) { }
initTodoControl(todo: Todo) {
var formGroup = this._fb.group({ Now, use the life cycle hooks of the component, and le-
id: [todo.id], verage the ngOnInit method to make a call to the service
title: [todo.title, Validators.required] to get the Todos. This can be seen in Listing 11.
});
formGroup.valueChanges.subscribe((todo) => { Listing 11 does some really interesting things. First, it
this._todoService.updateTodo(todo); creates a control array called todos. Youre writing some
}); code here to mimic the business object and keep things
return formGroup; understandable, but your business object structure could
} be different from the UX if you desire it to be. Next, sub-
scribe to the newTodo observable. Whenever a new Todo
appears, youre adding a new control under the todos
Listing 13: The addTodo and removeTodo methods. control array.
addTodo(todo: Todo) {
this._todoService.addTodo(todo); How does the code know that this new control is tied to
} the TodoComponent? That information is embedded in
the HTML template, which Ill discuss momentarily. First,
removeTodo(todoFormGroup: FormGroup, i: number) { I want to talk about the initTodoControl method. This can
let deletedTodo: Todo = todoFormGroup.value; be seen in Listing 12.
const control = <FormArray>this.myForm.controls['todos'];
control.removeAt(i); As you saw in Listing 12, the initTodoControl method
this._todoService.removeTodo(deletedTodo); adds a Validator indicating that the title is required for
} the newly added Todo. But most interestingly, on this
new FormControl, it subscribes the valueChanges. This

Listing 14: The todos.component.html file for Model driven forms.


<form [formGroup]="myForm" novalidate (ngSubmit)="onSubmit(myForm)"> </div>
<div formArrayName="todos"> </div>
<div <hr/>
*ngFor="let todo of myForm.controls.todos.controls; let i=index"> <button
<div [formGroupName]="i"> (click)=
<todo-control "addTodo({'id':myForm.controls.todos.controls.length,'title':''})">
[group]="myForm.controls.todos.controls[i]"> Add New
</todo-control> </button>
<button <hr/>
*ngIf="myForm.controls.todos.controls.length > 0" <button type="submit">Submit Form</button>
(click)="removeTodo(myForm.controls.todos.controls[i],i)"> </form>
Delete
</button>
</div>

20 Angular 2 Forms codemag.com


Figure 4: The model-driven form

Observable fires whenever the value of the underlying Listing 15: The TodoComponent for model-driven forms
object changes. How interesting! Now, if only there <span [formGroup]="todoForm">
were a way to sync this to the business object. Thats <span *ngIf="!isEdit">
the next line of code, which you can see in the next {{todoForm.value.id}}.
snippet. {{todoForm.value.title}}
</span>
this._todoService.updateTodo(todo); <span *ngIf="isEdit">
{{todoForm.value.id}}. <input formControlName="title"/>
Yeah, thats really it! Thats all it took to sync the form </span>
with the business object. You could always add more <button (click)="toggleEdit($event)">Edit</button>
logic here if your application gets more complex. But </span>t
this is a degree of magnitude simpler and more power- ..
ful than trying to do the same thing in template-driven ..
forms. Do note that this approach works well with Ob- export class TodoComponent {
servables only, which is another reason Im a fan of Ob- @Input('group')
servables. public todoForm: FormGroup;
private isEdit:boolean = false;
The logic for deletion and addition of new Todos is also
quite simple, and can be seen in Listing 13. toggleEdit($event) {
this.isEdit = !this.isEdit;
The add method calls the service and adds a Todo there. $event.srcElement.innerText = this.isEdit ? "Save" : "Edit";
The service churns through its logic and publishes the }
update to the Todo Observable on which the form is dat- }
abound, and that refreshes the UI.

The delete method is slightly more complex if you intend by disassociating the UX with the business object and yet
to delete the object only in the UX but not in the underly- keeping them linked via Observables.
ing business object. Why are you doing this? Well, you
dont have to! Most Web-based UIs are disconnected. You The update logic is encapsulated in the TodoComponent.
want the UX to differ from the business object for one Before we go there, lets quickly look at the HTML tem-
reason: You havent gone back to the server to save the plate for the TodosComponent first. This can be seen in
changes yet. This flexibility is yet another power you gain Listing 14.

codemag.com Angular 2 Forms 21


SPONSORED SIDEBAR:
CODE Framework:
Free, Open Source, and
Fully Supported
CODE Framework is
completely free and open
source with no strings
attached. But that doesnt
mean that the framework is
unsupported! Contact us with
any questions; well never
charge you for answering a
few questions by email.
For those looking for more
sophisticated and hands-on
support, we also offer
premium support options.
http://codeframework.
codeplex.com/

Figure 5: The edited model-driven form

As can be seen in Listing 14 at the very top, youre Now lets go ahead and run the application. When you
associating the form with the myForm variable using start the application, it shows a user interface, as shown
the [formGroup] tag. Then you use properties such as in Figure 3. Clearly, with much less code and much clean-
formArrayName to associate the object with a Form Con- er HTML, you were able to produce even more function-
trols array. Inside there, youre creating instances of the ality than the template-driven form equivalent. Imagine
Todo-control component. All the while, youre working what its like when your application grows more complex.
with the myForm object, not the Todos object. With the
help of Observables, the two always stay in sync anyway. Now, add a Todo, edit a Todo, and delete a Todo. The
results can be seen in Figure 4. Note that Todo #4 is
TodoComponent something I added, edited, and deleted. Its final state is
The TodoComponent follows the same theme. Both the DELETED.
HTML and TS (Typescript) for the TodoComponent can be
seen in Listing 15. The underlying business object is now a lot easier to pro-
cess for the service when you send these changes to the
As can be seen in Listing 15, the TodoComponent gets server. Also, just like template-driven forms, you have all
its own formGroup. This allows you to treat this under- the Validators, or even custom Validators, available to you.
lying component completely independent of the parent.
The underlying object has no knowledge about the busi- Pros and Cons
ness object and it doesnt care about the rest of the form. Model-driven forms requires some learning. Maybe creat-
Via the usual data-binding code, it works by editing this ing the form also requires some thought. But you gain
formGroup. several things:

22 Angular 2 Forms codemag.com


Because the business object and the form object perhaps an easy migration path. But model-driven forms
are separate, you gain a lot of flexibility here. are much more powerful and flexible, and end up requir-
Two-way data-binding isnt all that its cracked up ing less code for more complex applications, especially
to be if you dont have a processing pipe in the when paired with reactive Extensions and Observables.
middle. A good example is where deletion doesnt
mean deletion; thats when it only means marked There are additional patterns such as Redux that can also
for deletion. be used to manage and structure your applications. In
Both the form and object are streams of values. They future articles, I hope to talk more about reactive pro-
can both be independently tested or processed. For gramming and RxJS in general.
instance, you could only subscribe to values that
are invalid and act accordingly, which is really easy Until then, happy coding!
to do because you can use the .filter method on Ob-
servables to help you out. How would you do this in Sahil Malik
template-driven forms?
Your validation logic can also now be testable.

I feel that theres no absolute way forward that suits all


cases. If your form or application is very simple, perhaps
template-driven forms are the right approach. They are
simple and they require less code if your needs are also
very simple. But as the application gets more complex
and TDD becomes a requirement, model-driven forms are
a far better alternative.

Summary
Forms are complex and important. Thats why any good
framework, including Angular, provides you with rich
functionality to support forms. In this article, I showed
you how to write forms using two approaches in Angular
2. The template-driven forms approach is very similar to
what we had in Angular 1. Thats still supported and is

ADVERTISERS INDEX
Advertisers Index
1&1 Internet, Inc. LEAD Technologies Angular, Lambdas, Python, C#, Azure Skyline

www.1and1.com 7 www.leadtools.com 2
AppDevTrends Conference SSWUG Virtual Conference NOV
DEC
2016

www.appdevtrends.com 5 www.sswugvc.comw 69
codemag.com - THE LEADING INDEPENDENT DEVELOPER MAGAZINE - US $ 5.95 Can $ 8.95

Box Up Your Microservices


CODE Consulting SXSW Interactive with F#!
www.codemag.com/consulting 38, 39, 76 www.sxsw.com 27
CODE Divisions The MIT Press
www.codemag.com 75 www.mitpress.mit.edu 25
CODE Framework
shutterstock.com/Scanrail1

www.codemag.com/framework 61
The Resurgence of XAML

CODE Magazine Data Science using Python


Swiftly moving from Objective-C
www.codemag.com/advertise 17
dtSearch Advertising Sales:
www.dtSearch.com 55 Tammy Ferguson
832-717-4445 ext 026
tammy@codemag.com

This listing is provided as a courtesy to


our readers and advertisers.
The publisher assumes no responsibility
for errors or omissions.

codemag.com Angular 2 Forms 23


ONLINE QUICK ID 1611041

The Simplest Thing Possible:


Dynamic Lambda ExpressionsPart 3
In my previous two columns for CODE Magazine, I introduced you to how dynamic lambdas and expression trees work
in .NET. As promised, in this installment, Im going to share some classes that make it easier for you to re-use the concepts
Ive introduced in the last two issues. If you havent read the previous articles in this series or are unfamiliar with dynamic

lambda expressions, I strongly encourage you to read for dynamic lambda expressions and thats the use case
those articles before continuing with this one. Im going to tackle in this article.

The most common use case for lambda expressions is with


LINQ (Language Integrated Query). LINQ is a great abstrac- Expression Criteria Class
tion for executing queries against data collections. If your The Expression Criteria Class encapsulates all of the func-
LINQ statements rely on static lambda expressions, LINQ tionality required to build dynamic LINQ queries with-
itself should be usable as is. But what if your development out the need to understand how LINQ works. Lets step
staff isnt familiar with LINQ or if you need to generate through the code:
John V. Petersen LINQ statements at run time? In these cases, you and your
johnvpetersen@gmail.com team may benefit from a different, less leaky abstraction. public class ExpressionCriteria<T>
linkedin.com/in/johnvpetersen By less leaky, I mean an abstraction that doesnt expose
@johnvpetersen more complexity than whats absolutely necessary to ac- You wont know at design time what the specific data type
complish the task at hand. Lets get started. will be. Thats precisely why generics exist in .NET. After
John is a graduate of the Rut-
gers University School of Law you step through the code, the next section demonstrates
how to use this class.
in Camden, NJ and has been
admitted to the courts of the
What Do You Need?
Commonwealth of Pennsylvania To accomplish the task, you need the following: List<ExpressionCriterion> _expressionCriterion = new
and the state of New Jersey. List<ExpressionCriterion>();
For over 20 years, John has Defined criteria that specifies a property, some val-
developed, architected, and ue to compare to, and a comparison type such as The Expression Criteria Class consists of one or more cri-
designed software for a variety equals, greater than, or equals, etc. teria elements. Each criteria element manifests as an in-
of companies and industries. String multiple criteria that supports both And and stance of an Expression Criterion Class that are discussed
John is also a video course Or conjunctions later in this section.
author for Lynda.com. Some level of validation
His latest course, Foundations A lambda that can be used as the basis of a LINQ private string _andOr = "And";
of Programming, Open Source query
Licensing, teaches everything Each criterion can be grouped and joined with other cri-
you need to understand The following snippet illustrates these features: teria with an And or an Or conjunction.
about the legal aspects of
open-source licensing. _people.Where(x => public ExpressionCriteria<T> And()
(x.Age > 60 && x.Address.City == "Paoli") || {
(x.Address.Street == "Market Street")); _andOr = "And";
return this;
Read from left to right, the query fetches records where }
a persons age > 60 and the city is Paoli or if the street is public ExpressionCriteria<T> Or()
Market Street. If the query structure is constant and the {
only variable parts are the comparison values, theres no _andOr = "Or";
problem in referencing variables: return this;
}
var age = 60;
var city = "Paoli";
var street = "Market Street"; The Expression Criteria Class exposes a fluent interface.
By invoking the And() or Or() methods, the criterion
_people.Where(x => specified will be joined with the And or Or conjunction
(x.Age > age && x.Address.City == city) || respectively.
(x.Address.Street == street));
public ExpressionCriteria<T> Add(string propertyName,
In the real world, of course, more flexibility is needed. object value, ExpressionType operator)
You need some way to specify any field in the collection {
as part of a query. You also need to be able to specify var newCriterion = new
multiple criteria elements that can be joined with any ExpressionCriterion(propertyName, value, operator,_
combination of And/Or logic. This is the precise use case andOr);

24 The Simplest Thing Possible: Dynamic Lambda ExpressionsPart 3 codemag.com


_expressionCriterion.Add(newCriterion);
return this;
}

Keeping in line with the fluent interface, the Add Method


returns an instance of the Expression Criteria class. There
are three critical elements of a criterion element:

Property Name: The property of the Expression


Criterias type that will be used as the basis of a
criterion element.
Value: The value used, in conjunction with an ex-
pression type to compare to the property.
Op: The Expression Type used to compare the Prop-
erty Name with the Value.

The following is an example of the Property, Value, Opera-


tor relationship:

x.Age > 60

Property: Age
Value: 60
Operator: Greater Than

When the Add() Method is invoked, the current state of


the _andOr variable is applied as well. By default, the
value is set to And.

The following is the private class definition for each cri-


terion:

class ExpressionCriterion
{
public ExpressionCriterion(
string propertyName,
object value,
ExpressionType operator,
string andOr = "And")
{
AndOr = andOr;
PropertyName = propertyName;
Value = value;
Operator = op;
validateProperty(typeof(T), propertyName);
}

PropertyInfo validateProperty(
Type type, string propertyName)
{
string[] parts = propertyName.Split('.');

var info = (parts.Length > 1)


? validateProperty(
type.GetProperty(
parts[0]).PropertyType,
parts.Skip(1).Aggregate((a, i) =>
a + "." + i))
: type.GetProperty(propertyName);

if (info == null)
throw new ArgumentException(propertyName,
$"Property {propertyName}
is not a member of
{type.Name}");

codemag.com The Simplest Thing Possible: Dynamic Lambda ExpressionsPart 3 25


return info; expression,
} GetExpression(parameterExpression, item));
public string PropertyName { get; }
public object Value { get; } }
public ExpressionType Operator { get; } }
public string AndOr { get; }
} return expression != null ?
Expression.Lambda<Func<T,
Each criterion has four attributes: bool>>(expression, parameterExpression) :
null;
Property Name }
Value
Expression Type
AndOr Putting It All Together
The following code replicates the first LINQ query illus-
When an Expression Criterion Expression is created, the trated in this article:
property name is validated against the specified type.
var lambda = new ExpressionCriteria<Person>()
The first step in creating a lambda expression is to first .Add("Age", 60, ExpressionType.GreaterThan)
create an expression: And()
Lambdas and .Add("Address.City", "Paoli",
Expression Trees Expression ExpressionType.Equal)
GetExpression(ParameterExpression Or()
A good resource for further
parameter, ExpressionCriterion .Add("Address.Street", "Market Street",
details on lambdas and
ExpressionCriteria) ExpressionType.Equal)
expression trees can be
found on the MSDN site: { .GetLambda().Compile();
https://msdn.microsoft.com/ Expression expression = parameter;
en-us/library/bb397951.aspx. foreach (var member in
ExpressionCriteria.PropertyName.Split('.')) var result = _people.Where(lambda);
{
expression = With the abstraction illustrated above, two important
Expression.PropertyOrField(expression, member); things are accomplished. First, in the event that your
} developers arent comfortable with LINQ syntax, those
Return issues are addressed with a user-friendly fluent-type in-
Expression.MakeBinary( terface. Second, the class illustrated here can support
ExpressionCriteria.Operator, on-the-fly LINQ queries. In other words, at run time, this
expression, class can be leveraged to account for any field and any
Expression.Constant(ExpressionCriteria.Value)); combination of criteria that are joined with And or Or
} conjunctions.

Once the expression is created, a lambda expression can In the next column, Ill extend the Expression Criteria
be created: Class with the ability to leverage methods and arrays.

public Expression<Func<T, bool>> If you want a copy of the Expression Criteria Class, follow
GetLambda() me on Twitter: @johnvpetersen and Ill send you a link
{ to the code
Expression expression = null;
var parameterExpression = Enjoy!!
Expression.Parameter(typeof(T),
typeof(T).Name.ToLower()); John V. Petersen
foreach (var item in
_expressionCriterion)
{
if (expression == null)
{
expression =
GetExpression(parameterExpression, item);
}
else
{
expression =
item.AndOr == "And" ?
Expression.And(
expression,
GetExpression(parameterExpression, item)) :
Expression.Or(

26 The Simplest Thing Possible: Dynamic Lambda ExpressionsPart 3 codemag.com


ONLINE QUICK ID 1611051

Moving Forward:
The Transition from Objective-C to Swift
If you follow iOS development in any capacity, youve likely heard of Apples proprietary programming language called Swift.
Since its introduction in 2014, Swift has undergone several iterations and continues to grow in popularity among the iOS
developer community. RedMonk, a developer-focused analysis firm, assesses the popularity of programming languages by

analyzing the volume of conversation around a specific For instance, one specific area where Swift needs im-
language on Stack Overflow in combination with the provement is tooling. As any iOS developer knows, Xcode
number of repositories created using that language on is the official IDE (Integrated Development Environment)
GitHub. In recent years, Swift has been trending up in the used to develop and deploy iOS applications. It supports
popularity chart and, in 2016, Swift hits an all-time high, a full range of tools for Objective-C development, like syn-
coming in at number 17 on the list. tax highlighting, auto-complete, memory leak detectors,
refactoring tools, runtime performance monitoring, and
With this rise in popularity, developers who previously benchmarks, etc. These tools can often prove invaluable
worked with Objective-C (Apples original iOS program- to developers. Although you can get the same level of
Jason Bender ming language) must adapt to the shifting landscape in tooling support by using third-party products or by look-
Jason.bender@rocksaucestudios.com order to stay relevant. Objective-C still remains a viable ing into alternative IDEs, Swift lacks much of the same
www.controlappdelete.com language at the moment, coming in at number 10 on the tooling that Objective-C offers out of the box with Xcode.
www.twitter.com/TheCodeBender RedMonk list, but many industry jobs already require Swift Youll likely see additional tooling support in future itera-
proficiency and it could eventually replace Objective-C as tions of Swift, but for the time being, this is one of Swifts
Jason Bender is the Director
of Development for Rocksauce the primary means for developing iOS applications. weakest areas and its definitely something to keep in
Studios, an Austin, Texas-based mind as you transition to and/or experiment with Swift.
Mobile Design and Development The transition from Objective-C to Swift wont require re-
Company. He has 11 years cod- learning everything you know because many of the same Library support should also be considered when transi-
ing experience in multiple lan- concepts you acquired while working with Objective-C tioning to Swift. Objective-C has been the de facto de-
guages including Objective-C, will transfer. However, as someone like me whos been velopment language for nearly 10 years on iOS and more
Java, PHP, HTML, CSS, and Ja- working with Objective-C since the inception of the first than double that on MacOS. As a result, many of the most
vaScript. With a primary focus iPhone, it will take time to remaster and polish your Swift popular frameworks and third-party libraries are written
on iOS, Jason has developed skills to the same level of expertise and efficiency. in Objective-C. Technically, you can still use Objective-C
dozens of applications includ- libraries from within a Swift project, but it requires the
ing a #1 ranking reference app tedious and error-prone process of creating Objective-C
in the US. Jason was also called Compare and Contrast: wrapper classes, which act as bridges between the two
upon by Rainn Wilson to build Objective-C versus Swift platforms. This can often result in additional overhead
an iOS application for his wildly Swift is likely the more future-proof option at this point, and technical debt for the project.
popular book and Youtube but that doesnt mean that it trumps Objective-C in every
channel: SoulPancake. scenario. Each of these languages has their own pros and This same argument somewhat applies to learning ma-
cons respectively. Choosing which option will suit your terial as well. Blog posts, tutorials, books, and online
project best requires taking inventory of the projects courses for Objective-C will exist in higher quantity then
needs and then contrasting those needs with both of the their Swift counterparts for a while. Although almost ev-
languages strengths and weaknesses. ery online self-learning code institution offers some form
of Swift class (see the sidebar for class suggestions),
youll find fewer practical examples of Swift implementa-
tions on sites like Stack Overflow and less library content
Swift is likely the more future- on sites like GitHub.
proof option at this point,
but that doesnt mean it trumps You should also consider the target operating system
Objective-C in every scenario. when choosing between the two languages. As time
passes, this issue becomes less and less relevant but cur-
rently, in order to support Swift, you must target iOS 7.0+
and Mac OS 10.9+. Anything prior to that and youll have
Objective-C isnt IrrelevantYet to resort to Objective-C. Contrarily, all versions of tvOS
Before you look at the improvements that Swift brings with and watchOS support Swift.
it, lets take a look at Objective-Cs strengths and why it
still remains relevant. You can attribute that relevancy to Additionally, applications built using anything prior to
the simple fact that Objective-C has been around consider- Swift 3.0 will likely be 10-20MB greater in size then their
ably longer then Swift. As a result, there are tools, librar- respective Objective-C counterparts. This results from
ies, support, and a surrounding community thats devel- needing to include all of the Swift runtime libraries within
oped and matured over many years. Swift will get to that the application, even if the application only has a single
point eventually but it still has significant ground to cover. line of Swift code.

28 Moving Forward: The Transition from Objective-C to Swift codemag.com


Swift is still very much in its maturation process. Apple also means that Swift resembles other popular modern
continues to iterate on the platform and each new version languages like JavaScript, Java, Python, and C#, mak-
seems to retire the previous one rather then simply add- ing it easier for newcomers to adopt.
ing to it and maintaining backward compatibility. While Maintenance: Swift eliminates the two-file system
Swift remains in its growth period, Objective-C still has a that Objective-C uses (.h header file paired with .m
place in iOS development. implementation file), which means less code and less
to manage. Previously, a developer needed to manu-
So why would you bother learning or switching to Swift at ally synchronize method and variable names between
this point? Because if you plan on being an iOS developer the two files, but with Swift, you dont have that extra
for the long run, Swift will eventually become your primary overhead to worry about, giving you more time to fo-
language for development. Its not a question of whether this cus on application logic. Keith Smiley, an iOS developer
will happen, but rather its a question of how long it will take. for Lyft, gave a talk about the company rewriting their
Sooner or later, Swift will supplant Objective-C and become application in Swift. He boasted that the code base
the dominant, if not the only, development language used to shrunk by over 70%, going from an original 75,000
build applications for iOS, MacOS, Apple Watch, and Apple TV. lines of code in Objective-C to a mere 22,000 in Swift
As with learning anything, it takes time to perfect your craft while maintaining the same level of functionality and
and failing to get started now could be detrimental later. performance (check the side bar for a link to the talk).

If you plan to be an iOS developer Lyfts code base shrunk by Learning Swift
for the long run, Swift will over 70%, going from 75,000
lines of code in Objective-C to Although TeamTreehouse.com
eventually become your primary is one of my favorite online
language for development. a mere 22,000 in Swift while coding education providers,
Its not a question of whether maintaining the same level of it doesnt look like theyve
this will happen, but rather a functionality and performance. updated their Swift courses
for Swift 3 yet. However,
question of how long it will take. they do have 55 hours of
excellent Swift 2 course material at
Playgrounds: Swift comes with an interactive en- https://teamtreehouse.com/
vironment called Swift Playgrounds. Within a play- tracks/ios-development-with-
The Strengths of Swift ground, developers can write and test code in real swift-20
As mentioned earlier, Swift still has ground to cover, but time without compiling. It has a split view with the
it does offer several significant improvements over its implementation on one side and the execution on the If youre looking for a Swift 3
Objective-C counterpart. Lets take a look at some of the other. It can provide a quick way to debug applica- course, Udemy.com has a
key improvements and strengths of the platform. tion logic in small chunks, help programmers visual- 30 hour course
ize data, and provide a stage for interactive learning. https://www.udemy.com/
Speed: Swift is generally faster then Objective- Open Source: Because Apple made Swift open complete-ios-10-developer-
course
C for several reasons, including: Swift is a static source, there have already been initiatives to expand
typed language, it can use static dispatching, it has the platforms that Swift can run on. Its expanding to
improved dynamic dispatching, memory optimiza- build on Linux and you can currently find solutions
tions, inline functions, and also because the LLVM that let you write backend code in Swift. Additionally
linker can optimize across source file boundaries. an effort is underway to make Swift Android compat-
Safety: Objective-C uses pointers and if you call an ob- ible (see the sidebar for more details).
jects method using an object that has yet to be initial-
ized (nil pointer), nothing happens. The line of code
does nothing. Although at first glance it might seem
Moving from Objective-C
like a good idea that this doesnt cause the applica- to Swift in Code
tion to crash, it can be the source of all sorts of bugs Now that youve looked at the philosophical differences
and lead to many developer headaches as you try to between Objective-C and Swift, turn your attention to the
pinpoint whats gone wrong. Swift introduces optional practical differences in implementation. How exactly does
types for better handling of nil values. If a non-option- building a Swift project differ from building an Objective-
al variable is assigned a nil value, it generates a com- C one? What are the major syntax differences? Youll take
piler error. This consistent behavior results in errors as a look at this and more in the next sections.
you write the faulty code, shortcutting the feedback
loop and letting you correct your errors in real time. It Syntax Differences
ultimately leads to less time spent debugging. Although Swift contains most of the object types you
Readability: Swift is independent of the C foundation know in Objective-C, the syntax to use those objects has
that Objective-C is tied to. This allows Swift to unify changed. In fact, most of the operations youve grown
keywords, drop legacy conventions, and depart from accustomed to in Objective-C have seen some syntax
more obscure syntax. Additionally, you no longer need changes, some more drastic then others. Lets run
semicolons to end a line, parenthesis to surround through some of the familiar objects and operations to
conditionals, and the removal of nested method calls compare the Objective-C and Swift syntax.
means you no longer have brackets inside of brackets
inside of brackets. You end up with an expressive lan- Variables and Constants: In Swift, variables are
guage that more closely resembles natural English. It declared using the var keyword.

codemag.com Moving Forward: The Transition from Objective-C to Swift 29


// Declaring a variable in Swift return a + b
var numberVariable = 1 }
var textVariable = "Hello World
// Call function in Swift
In the previous snippet, two variables of different types get addTwoNumbers(a: 5, b: 7)
declared: numberVariable of type integer and stringVariable
of type string. Notice how you dont have to specify the type // Function declaration in Objective-C
when declaring the variable. Swift is a type-safe language, - (int)addTwoNumbers:(int)a b:(int)b {
so it can automatically deduce the variable type by assessing return a + b;
the assigned value. However, depending on the context, you }
may not assign a value at the same time you declare the vari-
able. In this case, from a code readability standpoint, the in- // Call function in Objective-C
tended type might not be inherently clear at first glance. In [self addTwoNumbers:5 b:7];
these instances, you can specify the type when you declare
the variable as shown in the following snippet. Additionally, functions in Swift are first-class types, mean-
ing that you can assign them to variables and use them
// Declaring a variable in Swift as either parameters or return values for other functions.
var numberVariable: Int Consider the following snippet. In this scenario, you see
numberVariable = 1 a function that takes another function as a parameter and
then executes whatever function you pass to it.
Lyft Swift Optimization Talk // Declaring a variable in Objective-C
int numberVariable; // Using a Swift function as a parameter
A Lyft developer talks
numberVariable = 1; func helloWorld() {
about re-writing the popular
print("Hello World)
ride sharing application
in Swift in this video Constants in Swift use the let keyword instead of the var key- }
https://www.skilled.io/ word. You can only assign a value to a constant one time. Try-
keithsmiley/tales-of-a- ing to change the value of a constant once its already been func executeFunction(function: () -> ()) {
rewrite-at-lyft assigned an initial value results in an error. Its important to function()
note that the value of a constant doesnt need to be known at }
compile time, rather it can get generated during run time as
long as its only assigned once. Additionally, you can declare executeFunction(function: helloWorld)
other object types like arrays as constants as well.
Enumerations: Swift enumerations (enums) have quite a
// Declaring a constant in Swift (compile time) bit more flexibility in Swift than they did in Objective-C.
let textConstant = "Hello World For instance, Swift enums can assign strings, characters,
integers, or floats whereas Objective-C was limited to
// Declaring a constant in Swift (runtime) integers. Additionally, theyre also considered first-class
var randomNumber = arc4random() types, adopting many of the same functionalities usually
let numberConstant = randomNumber reserved for classes, such as computed properties and in-
stance methods, which can provide additional context to
// Declaring a constant in Objective-C an enums current value.
NSString *const textConstant = @Hello Worldd;
// standard enum in Objective-C
String Interpolation: Swift makes string interpolation enum carMakes {
easier and more readable then its Objective-C counter- Honda,
parts. You can insert variables into the string directly, Toyota,
resulting in more readable code. Chevy,
Ford
// String Interpolation in Swift };
var firstName = "Jason
var author = "The authors name is \(firstName) // example of how to utilize enum
int carMake = Honda;
// String Interpolation in Objective-C
NSString* firstName = @Jason; This standard Objective-C enum, demonstrated in the
NSString* author = [NSString stringWithFormat: previous snippet, called carMakes contains a list of vari-
@The authors name is %@, firstName]; ous automobile manufacturers. By default, the system as-
signs an integer to each of the listed types starting with
Functions: The function syntax in Swift differs pretty sig- 0 for Honda, 1 for Toyota, etc. You can change the default
nificantly from Objective-C. The following snippet demon- system-assigned value of the enum types but beyond that,
strates a function in Swift and compares it to the tradition- there isnt much additional functionality to take advantage
al Objective-C syntax for the same function. Notice that the of. As mentioned previously, with Swift, you can use other
return type appears at the end of the function declaration data types and implement functions and computations
in Swift, as opposed to the beginning in Objective-C. within the enum, as you can see illustrated in Listing 1.
Notice that in Listing 1, you have an enum called Car.
// Function declaration in Swift It has two cases that describe how you can create a Car:
func addTwoNumbers(a: Int, b: Int) -> Int { using make and model with the Make case or using color

30 Moving Forward: The Transition from Objective-C to Swift codemag.com


Listing 1: Swift enumeration example
enum Car case let .Appearance(color, size):
{ return color + " " + size
case Make(make:String, model:String) }
case Appearance(color:String, size:String) }
}
func description() -> String
{ let car1 = Car.Make(make: "Toyota", model: "Camry")
switch self let car2 = Car.Appearance(color: "Blue", size: "Sedan")
{ print(car1.description()) // Toyota Camry
case let .Make(make, model): print(car2.description()) // Blue Sedan
return make + " " + model

Listing 2: Swift class example with setter method (required values)


class NewCar
{ func description() -> String
var condition: String = "New" {
var make:String return "The \(make) \(model) is
var model:String in \(condition) condition"
}
init(make:String, model:String) }
{
self.make = make var car = NewCar(make: "Toyota", model: "Corolla")
self.model = model car.description() // The Toyota Corolla is in New Condition
}

and size with the Appearance case. It also contains a func- tializer, you could instantiate an instance of the class
tion called description, which looks to see what case was without assigning a value to make or model. Listing 2
used to construct the respective Car enum and returns a also shows how you then create an instance of the class
string representation of the cars associated values. Below using that initializer method while assigning the class in-
the enum, you can see two examples of creating a Car stance to a variable at the same time. Once done, you can
using the different Make and Appearance cases. Regardless then access the description method on the class using
of which case you used to create car1 and car2, you can the assigned variable reference, as demonstrated.
call the description function on either and it uses the
information to construct a string description and return it. What if you didnt want to set the make or model at the
time the class gets initialized? Listing 3 demonstrates
Classes: An Objective-C class usually consists of two files: a how this is achieved using Optionals. Changing make and
.h header file and a .m implementation file. The structure, model to optional types allows you to remove the initial-
in most cases, resembles the following code snippet. izing method. Ill cover Optionals and Listing 3 in more
detail in the next section.
// class .h file
@interface ClassName : NSObject New Data Types: Optionals and Tuples
@end Swift expands on the data types you grew accustomed to
in Objective-C with the addition of Optionals and Tuples. As
// class .m file mentioned briefly in the previous section, Optionals provide
@implementation ClassName a way to tell the system that its okay if this variable has a
@end nil value at some point. Without the optional notation, a nil
value results in a compiler error. You can declare a variable
With Swift, the two-file system has disappeared and as an optional with the addition of a question mark after the
theres no longer a need for header files. As a result, class variable type, as demonstrated in the following examples.
definitions get simplified to now resemble the following:
// Swift Optionals
// Swift Class Definition var integerOptional: Int? // starts as nil
class ClassName { var stringOptional: String? // starts as nil
}
Notice how you didnt have to assign any value at the
Listing 2 demonstrates a more robust class definition point that you declared the variable. Although you tech-
and implementation. You can see that a class called New- nically dont have to assign a value to any var when you
Car gets created with three properties: condition, make, declare it, when you declare it as an Optional, it takes on
and model. Notice that under the property declarations, an initial value of nil. Lets look at the following snippet
theres an initializer. This is important because with- to see how that makes a difference.
out that initializer, the compiler throws an error. Swift
doesnt allow nil values unless you use an Optional data // Normal Swift Variable
type (covered in the next section) and without that ini- var someNumber: Int

codemag.com Moving Forward: The Transition from Objective-C to Swift 31


Listing 3: Swift class example using optional values
class NewCar in \(condition) condition"
{ }
var condition: String = "New" }
var make:String?
var model:String? var car = NewCar()
car.make = "Toyota"
func description() -> String car.model = "Corolla"
{ car.description() // The Toyota Corolla is in New Condition
return "The \(make!) \(model!) is

print(someNumber) // this will cause a crash The tuple in the previous example groups together two
strings and an integer to give the used car three contextual
// Swift Optional Variable values: make, model, and total mileage on the vehicle. No-
var someNumber: Int? tice that the tuples data types dont have to be consistent.
print(someNumber) // prints nil There you have (String, String, Int) but you could have (Int,
someNumber = 20 Bool) or any other permutation. Once you create a tuple
print(someNumber) //prints Optional(20) like usedCar, you can deconstruct it into individual vari-
ables at any point, as shown in the next example. Further-
In the first example, the variable was declared but accessed more, that code snippet also shows that if you want to de-
before it has been assigned a value, causing the applica- construct the tuple but only need access to part of the data
tion to crash. In the second example, because you declared set it contains, you can use an underscore to let the system
someNumber as an Optional, it starts as nil until its later know to ignore the remaining values. Lastly, the snippet
assigned the value of 20. Notice that when you go to print also demonstrates that you can reference the values of
someNumber after assigning it a value of 20, the result of usedCar using dot notation with the index of the value.
the operation is Optional(20). What does this mean? Be-
cause an Optional can technically be nil and accessing nil // 1. deconstruct entire tuple
values directly can cause runtime errors, theres a layer of let (make, model, mileage) = usedCar
safety in between the program and the value that the Op- print("the make is \(make))
tional contains. Think of the Optional as a wrapper around print("the model is \(model))
the value. In order to access the raw value, you need to print("the mileage is \(mileage))
unwrap it. Unwrapping an Optional is as easy as adding an
exclamation point after the variable name, but take special // 2. deconstruct single value
care, because unwrapping a nil Optional causes a runtime let (make, _, _) = usedCar
error as the exclamation point essentially translates to I print("the make is \(make))
know this variable definitely has a value; please use it.
Consider the following examples. // 3. access tuple values using dot notation
print("the make is \(usedCar.0))
// Incorrect optional unwrapping print("the model is \(usedCar.1))
var someNumber: Int? = Int("abc)
print(someNumber!) // value nil, fatal error Refer back to the initial creation of the usedCar tuple. You
assigned it a tuple containing (Toyota, Corolla, 45109).
// Correct optional unwrapping Most of us could deduce that Toyota and Corolla refer to a
var someNumber: Int? = Int("abc) brand of automobile. Using that context, its a logical assump-
if (someNumber != nil) { tion that the last set of numbers might be mileage. However,
print(someNumber!) not all data sets have the same level of transparency. If you
} wish to give your tuple additional context when you create it,
you can provide element names, as shown in the next snippet.
As you can likely deduce from the example, you should con-
firm that the Optional doesnt contain a nil value before var usedCar = (make: "Toyota", model: "Corolla",
you unwrap it. Additionally, if you know that the Optional mileage: 45109)
will contain a value at the time you plan to access it, you print("the make is \(usedCar.make))
can have it automatically unwrap itself by swapping the print("the model is \(usedCar.model))
question mark in the variable declaration for an exclama- print("the mileage is \(usedCar.mileage))
tion point.
Creating a New Project
The other new data type found in Swift is called tuples. Creating a new Swift project is essentially the same process
Tuples provide a way to group many values into a single as creating an Objective-C project. In Xcode, go to File ->
compound value. The values that a tuple contains can be of New -> Project to trigger the New Project dialog. Choose
any type and you can mix and match types within a single the project template and youll get presented with the form
tuple. Consider the following example containing a tuple pictured in Figure 1. Notice the language selection box il-
for a used car. lustrated. Here, you can select Swift as the language option
for the project. Name your project as usual, click Next to
var usedCar = ("Toyota, "Corolla, 45109) choose a location to save the project into, and then press
// usedCar is of type (String, String, Int) Create to launch into your new Swift project.

32 Moving Forward: The Transition from Objective-C to Swift codemag.com


The project structure of a standard single-view Swift ap-
plication resembles its Objective-C counterpart, as shown
in Figure 2. Figure 2 demonstrates a traditional Objective-
C project file structure on the left-hand side and a Swift
starting structure on the right. Each has an application
delegate, an initial view controller, and a main storyboard.
Even the files contents are nearly identical from a method
standpoint. Controllers each have their initial viewDidLoad
and didReceiveMemoryWarning canned functions and the
app delegate has all the standard method calls that youre
used to seeing. Once you understand the fundamental syn-
tax differences between the two languages, jumping into
Xcode shouldnt present a big challenge to anyone whos
used to using the IDE for writing Objective-C applications.

Practice Makes Perfect


Lets take what you just learned in the previous sections and
put it into practice to make a simple application. Often the
best way to learn a new language in programming is to get
your hands on it and work with it. Here, youll continue the Figure 1: Swift language selection during new Xcode project creation
car theme to create an application that lets users look up the
mileage of a used car by searching for a license plate num-
ber. Figure 3 demonstrates what the end result will look like.

The Set Up
The set up for this application is simple. First, create a
new Swift project as described in the last section, choos-
ing the Single View Application template when prompted.
Once created, youll first want to go to the main story-
board (Main.storyboard) and set up the UI elements. You
can find the art assets from the screenshots in the sample
code provided with this article. Add the background im-
age, the logo, and the text field to the view and position
them accordingly. You can set the background image to
AspectFill so it looks good on any resolution device. Once
done, youre ready to switch over to the ViewController.
swift file and implement the application logic, which will
get covered in the next section.
Figure 2: Objective-C versus Swift starting project file structure
Application Logic
The applications main function is to let the user input a
license plate number, at which point the app searches its car1.licensePlate = "12345
data store (local mock data in this case) for a used car car1.mileage = 17564
that matches the entered plate. If the application locates a
match, it displays a dialog pop up with the car information Moving past the UsedCar class declaration, youll notice sev-
and mileage, as shown in the far right screenshot in Figure eral variable declarations. These variable declarations appear
3. Listing 4 shows the entire ViewController.swift source outside of any one function so that the entire controller has
from this completed application. Lets walk through it so access to them. In this example, var is used instead of let
that you understand exactly whats happening. because it makes sense that the inventory of used cars could
change over time. In a practical, real world example, that
The first thing youll notice is a class declaration for inventory would probably load in from a database or other
UsedCar. This class has several properties, such as make, external source, but for the sake of simplicity, you create a
model, license plate, and mileage. Notice that the initial- mock representation of that data using four car variables and
izer function takes all four as input, meaning that its not an array. In addition to those variables, you create an IBOut-
possible to declare an instance of UsedCar with a nil value let that corresponds to the UITextField that you already
for any of the class properties. If you hadnt used an ini- added to your main storyboard. Once you add that variable,
tializer there, youd have needed to declare all the prop- jump over to the storyboard and link it to the field.
erties as Optionals using the ? notation. Furthermore,
instead of creating the class with a single line as shown Now, you arrive at the standard controller function view-
later in Listing 4, youd have needed to first initialize it DidLoad. Here, youll instantiate the four car objects and
and then later assign the values, as follows: add them to the carList array so you can iterate on them
later when searching for a matching license plate. No-
var car1 = UsedCar() tice how the initializer function that you created in the
car1.make = "Toyota class definition insures all properties of the UsedCar class
car1.model = "Corolla get assigned with the creation of each object. Once you

codemag.com Moving Forward: The Transition from Objective-C to Swift 33


complete that, you override the currently empty carList associate it with the Did End on Exit option, as shown
array with a new array containing the four car objects. You in Figure 4.
include the ! to unwrap the object so that the array holds
the actual car and not the wrapped package of the object. Now you can implement the logic for the searchForCar
In most cases, you need to confirm that the object you function. The function takes no direct input because
unwrap isnt nil, but since you just physically assigned its going to reference the text entered into the search
values to all four cars, you know its safe. field. You start by declaring a constant variable that rep-
resents the result of the search. Because the context of
The next function gets called when the user presses the the search result is local to the search function, its only
return key on the keyboard, indicating that theyve con- assigned a value once per search performed, so let works
cluded their input and wish to search for a used car based here. The lookup function compares the license plate that
on the value they entered. @IBAction precedes the func- the user entered with the carList you created earlier. If
tion declaration so that it can be linked to the text field it finds a match, the matching UsedCar object gets re-
in the storyboard. To link the action to the return key, go turned. If it fails to find a match, nil gets returned. This
to the storyboard and drag the action to the text field and causes searchResult to become an Optional even though

Listing 4: ViewController.swift from sample car application


import UIKit // call lookup with the text entered in field
let searchResult =
class ViewController: UIViewController { lookupUsedCar(licensePlate: (searchField?.text)!)

// a used car object to manage car data // show appropriate message depending on
class UsedCar { // result that was found
var make: String if(searchResult != nil) {
var model: String showAlertPrompt(message: "The car with
var licensePlate: String license plate \(searchResult!.licensePlate)
var mileage: Int is a \(searchResult!.make)
\(searchResult!.model) with
init (make: String, model: String, \(searchResult!.mileage) miles")
licensePlate: String, mileage: Int) { }
self.make = make else {
self.model = model showAlertPrompt(message: "car not found");
self.licensePlate = licensePlate }
self.mileage = mileage }
}
} // takes license plate and searches for a car that matches
func lookupUsedCar (licensePlate: String) -> UsedCar? {
// variables available to whole controller
var car1: UsedCar? for car in carList {
var car2: UsedCar? if(car.licensePlate == licensePlate) {
var car3: UsedCar? return car;
var car4: UsedCar? }
var carList = [UsedCar]() }

@IBOutlet weak var searchField: UITextField? return nil;


}

override func viewDidLoad() { // show an alert modal with a custom message


super.viewDidLoad() func showAlertPrompt (message: String) {
let alertController =
// simulate a data source with some mock cars UIAlertController( title: "Lookup Results",
car1 = UsedCar(make: "Toyota", model: "Corolla", message: message,
licensePlate: "12345", mileage: 17564) preferredStyle: .alert)
car2 = UsedCar(make: "Dodge", model: "Durango",
licensePlate: "abcdef", mileage: 22465) let cancelAction =
car3 = UsedCar(make: "Nissan", model: "Maxima", UIAlertAction(title:"Ok", style: .cancel, handler: nil)
licensePlate: "123abc", mileage: 503) alertController.addAction(cancelAction)
car4 = UsedCar(make: "Ford", model: "F150", self.present(alertController, animated: true,
licensePlate: "abc123", mileage: 49078) completion: nil)
}
// add the cars to the array
carList = [car1!, car2!, car3!, car4!] override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
} // Dispose of any resources that can be recreated
}
// function that is called when
// return is pressed on the keyboard }
@IBAction func searchForCar() {

34 Moving Forward: The Transition from Objective-C to Swift codemag.com


Figure 3: Screenshots from the sample application youll create

you didnt explicitly tell it to. Its important to note that


if the value you assign to a variable (in this case, the
function return value, which is an Optional: UsedCar?)
has the potential to be nil, the variable you assign it to
becomes an optional.

Because the searchResult has the potential to be nil, you


need to check whether it contains a value before you un-
wrap it. If it has a value, you call a function to display
an alert dialog with the car information, passing a mes-
sage that you compose by combining unwrapped values
of the corresponding UsedCar class object via string in-
terpolation. If it doesnt have a value, you call a dialog
to inform the user that no results were found. How do
you determine if a used car exists corresponding to the
users entry? The lookupUsedCar function in Listing 4 de-
termines this for you. It iterates over the car list using a Figure 4: Link the search function with the return key action of the UITextFields keyboard
for-in loop. Each loop iteration checks to see whether the
corresponding car matches the users entry by performing
a string comparison on the respective license plates. If a youve completed the logic for the application and can
match is found, it gets returned. If you reach the end of run it to test your work. Entering a license plate corre-
the loop with no match found, nil gets returned. sponding to 12345, abcdef, 123abc, or abc123
should find a match, whereas anything else should re-
turn no results.
Its important to note that
if the initial value you assign Wrapping Up
to a variable has the potential Hopefully, over the course of this article you gained an
to be nil, the variable you understanding of the basic differences between Objec-
assign becomes an Optional tive-C and Swift. Although the examples in this article
even if you didnt declare may seem elementary, they represent the fundamental
it using the ? notation. building blocks of knowledge that youll need to tackle
Swift effectively. As with anything, practice makes per-
fect. If youre interested in learning more about Swift,
check the sidebar for additional educational material.
The last piece of the puzzle is the showAlertPrompt Lastly, check the code download section for a link to the
function that takes in a string message and generates source code demonstrated in Listing 4.
a default system alert dialog to display the passed mes-
sage. The searchForCar function uses this to display Jason Bender
the results of the search effort. With that implemented

codemag.com Moving Forward: The Transition from Objective-C to Swift 35


ONLINE QUICK ID 1611061

The Resurgence of XAML


At the Build 2015 conference in April 2015, when Windows 10 was on the verge of release, Microsoft revealed a significant
shift in strategy. Microsoft made it clear that they were betting heavily on the Universal Windows Platform (UWP) and
that XAML was back as the centerpiece of native-Windows user interface development. In the keynote at that conference,

I saw the most innovation packed into a Microsoft key- But we also know the power of XAML, and have built many
note that Ive seen since PDC 2000. The vast majority of modern apps leveraging that power. For most of those
the keynote demonstrations used XAML as the UI stack. applications, it would have been too costly, or even im-
possible in some cases, to give them the sophisticated in-
At the Build 2016 conference a year later, Microsoft teractions and visualizations we needed using HTML5/JS.
continued this track, rolling out the UWP and XAML to
HoloLens, Xbox, and embedded devices. Microsoft didnt
build much hype around the UWP. They just used it a lot How About WPF?
and there were lots of sessions about it. It was casually Although XAML on the UWP is getting most of the love
Billy Hollis mentioned in a couple of sessions that the Windows 10 right now, out in the real world, most companies still
billyhollis@gmail.com shell is written in XAML. So are various parts of the Office have some users on Windows 7. Microsoft recognized this,
www.nextver.com 2016. Plus its the default choice for the built-in apps for and rebuilt the WPF team. XAML in WPF is getting some
@billyhollis Windows 10 and for the vast majority of third-party apps new features, and is a quite viable choice if you have no
in the Windows Store. idea when your users might all be on Windows 10.
Billy Hollis and his team of
world-class XAML developers
specialize in producing in- In essence, if you want to do new native development
novative applications on native that runs on Windows 7, WPF is the last man standing.
XAML is the default choice Windows Forms has been quiescent for over ten years. Sil-
Microsoft platforms. You can
for the built-in apps for verlight was mortally wounded during Microsofts political
see examples of their work at
www.nextver.com. Windows 10 and for the vast infighting and is rapidly fading away.
majority of third-party apps
Billy has also presented at over in the Windows Store. WPF applications also run on the Windows 10 desktop, of
100 major conferences, and is course. So you have a pretty good medium-term shelf-life
the author of dozens of books, for new WPF applications. Plus, although learning any fla-
articles, and video training vor of XAML is a steep climb, once you learn WPF, switch-
courses. He offers onsite train- With those two conferences, Microsoft put to rest the ing to UWP XAML for Windows 10 wont be hard. The un-
ing in XAML and user experi- idea that XAML has no long-term viability. Instead, derlying concepts in XAML, such as layout, data binding,
ence design, and has trained XAML was quietly promoted to be the UI stack of choice and templating, work the same on all XAML platforms.
over forty teams at companies
for leveraging the most innovative parts of the Windows
from medium sized businesses
10 world.
to Fortune 100 companies. Applications for Tablets
This was quite a reversal in Microsofts attitude from late Although WPF is fine for typical corporate desktop appli-
2010 to 2014. During those days, I was sagely assured by cations, I honestly cant recommend it for mobile apps on
various people within Microsoft that XAML was on the way tablet form factors such as the Surface. Getting a smooth
out. HTML was The One True Waythe only viable technol- touch experience on WPF is quite hard, while touch is el-
ogy for user interfaces. I was told that virtually all busi- egantly handled in UWP apps. Even for WPF shops, I gen-
ness software UIs will be done in HTML5/JS in eighteen erally recommend that mobile apps for tablets be done in
months (thats a direct quote from a Microsoft Product Windows 10 /UWP. Those devices come with Windows 10
Manager in 2012). Open systems and all that, and you installed, so compatibility with Windows 7 is generally a
just cant resist it, so give in. Come on Billy. Let the pod non-issue for mobile apps.
settle in on your brain and turn you into one of us.

I doubted all of that because I knew that XAML was a Getting Value Out of XAML
powerful and innovative technology. I found it hard to I must admit something about XAML, though. Most teams
believe that Microsoft would simply throw it away. XAMLs who adopt XAML dont really take advantage of its power.
decline was caused much more by political infighting in- They tend to write XAML apps that are colorized versions of
side Microsoft than by any technological considerations. desktop apps that they would have written ten or twenty
So I felt vindicated by Microsofts re-emphasis on XAML years ago.
as a key technology.
Leveraging XAML means thinking about how you interact
Please dont misunderstand. I dont hate HTML/JS; not with the user at a different, deeper level. Heres an example.
at all. I just dont think its a magic bullet or universal
answer. Most systems that we build have a Web-facing I recently began work on an application that manages
portion built in HTML/JS, along with a desktop or mo- fuel deliveries to tanks. Each tank has a fuel level, which
bile interface in native technologies. We understand what might be from a remote sensing gauge or from a projec-
HTML/JS can do, and if all or part of an application must tion based on usage. When the app shows a list of tank
have broad reach, thats the platform of choice. locations, the user needs to see that level.

36 The Resurgence of XAML codemag.com


During the design phase, the team sketched out a cross- height for one of the rectangles. The UWP code for that
section of a fuel tank with the level shown graphically. value converter is in Listing 2.
We then implemented that design in XAML. The result
looked like Figure 1. The WPF equivalent for Listing 2 has a slightly different
argument signature, but the logic is the same. The XAML
Developers rarely design using such visualizations. They in Listing 1 works on either platform. You can obtain the Figure 1: A fuel tank
expect the amount of work involved to be too much for the full UWP version of the example, plus the other demon- visualization with the fuel level
additional value of the visualization. In general, for other stration applications Ill be covering below, by download- determined by a bound data
ing the zip file at http://bit.ly/CodeMagXAML. property

Most teams tend to write XAML Notice that the fuel tank visualization depends on the
apps that are colorized versions layering capabilities of the XAML-rendering engine. If you
dont see what the XAML in Listing 2 is doing, heres an
of desktop apps theyd have
English version of whats happening:
written ten or twenty years ago.
Its time to change that. The bottom layer of the tanks rendering is a Grid
with a gray background.
The next layer is a rounded rectangle representing the
platforms, theyre correct. Its not that it cant be done on fuel. It has a Fill of #FFFAE937, which is a yellowish
those platformsit just takes too much cost and effort for color. Rounding the corners just right gives it the cap-
the value returned. sule shape thats appropriate for a propane tank. This

Using XAML, the team did the visualization in Figure 1 in


about ten minutes. The XAML for it contains a Grid element as
a container, four Rectangle shapes (some of them with round-
ed corners), and a TextBlock. The XAML for that visualization,
plus a Slider to control the fill percentage, is in Listing 1.

The XAML in Listing 1 uses a simple value converter


to change the percent full value into the appropriate Figure 2: More fully developed fuel tank visualizations

Listing 1: The XAML for creating the fuel tank visualization


<Grid Background="Gray"> RadiusX="20" RadiusY="20"
<Grid.Resources> Margin="5, 8, 5, 4" />
<local:FillPercentToRectangleHeightConverter <Rectangle Fill="#FF111111"
x:Key="PercentConverter" /> Height="12" Width="40"
</Grid.Resources> VerticalAlignment="Top"
<Grid Name="PropaneTankGrid" Margin="0,1,0,0" />
Height="45" Width="120" <TextBlock Foreground="White"
Background="Gray"> HorizontalAlignment="Center"
VerticalAlignment="Top"
<Rectangle Fill="#FFFAE937" Margin="0,14,0,0">
RadiusX="20" RadiusY="20" <Run Text="{Binding Path=Value, ElementName=PercentSlider}" />
Opacity=".8" Margin="6, 8, 6, 4" <Run Text="%" />
/> </TextBlock>
<Rectangle Fill="Gray" VerticalAlignment="Top"
Height="{Binding Path=Value, </Grid>
ElementName=PercentSlider, <Slider VerticalAlignment="Bottom" Margin="5"
Converter={StaticResource PercentConverter}}" /> Value="30" Maximum="100" Minimum="0"
<Rectangle Stroke="#FF111111" Name="PercentSlider" />
StrokeThickness="2" </Grid>

Listing 2: A simple value converter


Public Class FillPercentToRectangleHeightConverter h = 38.0 - (30 * CDbl(value)) / 100.0
Implements IValueConverter Return h
End Function
Public Function Convert(value As Object,
targetType As Type, Public Function ConvertBack(value As Object,
parameter As Object, targetType As Type,
language As String) As Object parameter As Object,
Implements IValueConverter.Convert language As String) As Object
If value Is Nothing OrElse CDbl(value) < 0 Then Implements IValueConverter.ConvertBack
Return 0 Return Nothing
End If End Function
Dim h As Double End Class

codemag.com The Resurgence of XAML 37


38 Title article codemag.com
codemag.com Title article 39
Figure 3: A simple example of a XAML ListBox or ListView that shows planes positioned at their respective gates

Figure 4: The template for a contact allows intuitive visualization of useful information, such as
customer satisfaction and the time since last contact.

40 The Resurgence of XAML codemag.com


rounded rectangle represents fuel at the 100% level. Box/ListView has a transparent background so that the
The next layer is a gray rectangle that obscures part of first Canvas containing the concourse shows through.
the rounded rectangle representing the fuel. It drops The ListBox or ListView containing the Canvas is
down from the top, with a value converter to determine bound to a list of data items representing planes.
its height. That height is calculated to leave enough of The data template for the ListBox or ListView con-
the fuel showing for the current percentage full. tains the shape of the plane as a Path plus informa-
The next layer is another rounded rectangle. It fur- tion about the flight bound to text elements. Value
nishes the outline of the tank. It has a nearly-black converters are used to calculate the position of the
Stroke for the tank outline, but it has no Fill, so the plane and its angle relative to the gate.
earlier layers show through.
Finally, the TextBlock showing the percent full is This example contains only about 150 lines of XAML and
layered on top of everything else. 120 lines of code. A production version with top-notch
aesthetics might need double that amount of XAML.
As the team continued to design, the need for different
colors to represent different fuel types became apparent. Figure 4 shows a final example of a list that presents infor-
Also, fuel tanks vary in shape, and the user may need to mation to the user in a highly visual way using the capa-
know the capacity of the tank. All of these were added, bilities of XAML. The list contains contacts for a healthcare
again with very modest amounts of XAML, giving results application. Some contacts are physicians and others are
like those shown in Figure 2. not. The data contains information on the last date I talked
to them and on their satisfaction level with the services.
The team ended up creating a XAML control for this func-
tionality because it was used over and over, but that This screen requires no training to see the most important
control wasnt conceptually much more complex than the information. The archetypal figure for physician is used,
examples in Figure 1 and Figure 2. along with a face to communicate the contacts satisfac-
tion with our services. The layering capabilities of XAML
XAML is also a great fit for information that has some sort are again used to compose those elements.
of spatial positioning in the real world. Ive done that for a
number of clients, from managing helicopters in the air to The human brain is optimized to gain information from faces,
arranging cattle feedlots on open ground. Figure 3 shows so the satisfaction level is much more quickly understood
a simplified example of using XAML to work with data that with a smile or frown than from an equivalent number in the
corresponds to positions in the real world. Its an airport database. The last contacted information is presented as a
terminal with planes shown at gates. I often use it as an ex- timespan rather than a date, because thats the way users
ample in conference sessions, because I can explain every want to see it. Inactive contacts are shown with a muted gray
part of it to an audience in about ten minutes. foreground, which most users intuitively think of as inactive.

Exposing the data as shown in Figure 4 was about an hour


The same XAML controls used of work. With that kind of productivity, the bottleneck in
getting to better UX with XAML isnt usually time or cost.
to get a boring vertical list of
The challenge is breaking free from past habits rooted in
data items can also be used experience with older technologies, and learning how to
to show items positioned in a design the right experience for your data and your users.
coordinate system with colors
and shapes for visualization.
Wrap up
Even in a Web-based world, a lot of the economy still runs
on complex, data-heavy desktop applications. Touch-
I have both WPF and UWP versions of the example in Fig- based mobile applications have been added for many
ure 3. The planes are shown in a ListBox in WPF and a business scenarios, and in the future, well use devices
ListView in UWP. In other words, the same XAML controls like the HoloLens to raise innovation to new levels.
that are used to get a boring vertical list of data items
can also be used to show items positioned in a coordinate XAML is often superior to other platforms for those sce-
system, with colors and shapes for visualization. narios. It allows you to quickly and cost-effectively create
intuitive, compelling, and innovative applications that of-
The layering capabilities of XAML are an essential part of the fer higher productivity, lower training, better decisions,
planes-at-gates example, along with some other capabilities and fewer errors.
rarely used by XAML developers. You can download the com-
plete code examples for both UWP and WPF versions of the Theres a lot more Id like to discussdeployment, state
example in Figure 3 from my website (www.nextver.com), management, security, layered service architecture, and
but here are some of the techniques used in the example: other factors that influence the platform choice for an
application. But Im out of space, and right now, my main
One Canvas panel is used to contain the rectangles message is that XAML is back, and you should know what
and text elements that make up the concourse. it can do so that you can make the best decisions for your
Another Canvas is used as the ItemsPanel of the List- own applications.
Box or ListView. That allows the items in the ListBox or
ListView to be precisely positioned. That second Can- Billy Hollis
vas is layered right on top of the first Canvas. The List-

codemag.com The Resurgence of XAML 41


ONLINE QUICK ID 1611071

Case Study:
Writing Microservices with F#
In my May/June 2016 article in CODE Magazine, I covered a few key features of F#, and discussed how and why it can be
beneficial to consider F# as your primary programming language. In this issue, Ill expand on that, and talk about how we
decided to use an F# and microservices architecture at Jet.com.

Who is Jet.com? pizza-team rule), the complexity of the code within the
I work at Jet.com, which is an e-commerce startup, com- microservice, as well as the intended usage for the ser-
peting in the US with Amazon.com, and with a main goal vice.
of surprising and delighting customers, particularly with
regard to our pricing. We use a complicated pricing algo- Jet.com takes a stance in all of this. We define the 700
rithm thats able to make smart sense of your shopping microservices that weve successfully put into production
cartit combines the items in your cart and ensures that as having a couple of important features:
youre purchasing from merchants who are closer, faster,
and cheaper, so that they can ship to you in one package. Its a short script file with well-defined inputs and
Rachel Reese This saves money because we dont break the cart up into outputs.
rachel@jet.com many packages that are more convenient to the distribu- It should be an application of the Single Responsi-
http://rachelree.se tor than to the customer. bility Principle, applied at the service level.
https://twitter.com/rachelreese
If you havent heard of The Single Responsibility Prin-
Rachel Reese is a long-time
software engineer and math ciple, it means that a microservice should have one, and
Microservices are intentionally only one, reason to exist. This doesnt necessarily mean
geek who can often be found
talking to random strangers small, but people argue that there should be only one function within the service,
about the joys of functional about how small is small only that the microservice should have only one job.
programming and F#. She enough.
currently handles training and
evangelism for Jet.com in the
Why Use F#?
NYC area, and has a habit of Early on in Jet.coms history, we hadnt fully decided yet
starting user groups, so far, From a technology standpoint, were heavy users of F#, on either microservices or F#. Our CTO, Mike Hanrahan,
in Hoboken, NJ (Pluralsight Go, Azure, Kafka, EventStore, and microservices. In fact, had attended one of the early F# conferences in NYC and
Study Group), Nashville, TN Jet.com only launched a year ago and we already have decided that F# would be a good fit for our pricing en-
(@NashFSharp) and Burling- over 700 cloud-based, event-driven, functional microser- gine, and some of the early hires were F# engineers. As
ton, VT (@VTFun). Shes also vices in production. Using this architecture, we were able the site started to develop and the early engineers had
an ASPInsider, an F# MVP, a to scale from 30,000 customers in July 2015 to 2.5 mil- some thoughtful conversations, it became clear that F#
Xamarin MVP, a community lion in October 2015, and barely stress our systems. fit into more places than the team had originally antici-
enthusiast, one of the founding pated. After exploring F# even more, they decided to split
@lambdaladies, and a Rachii. and start working on two completely separate solutions,
You can find her on twitter, @ What are Microservices? one entirely in C# and one entirely in F#, to compare
rachelreese, or on her blog:
First, let me define what Im going to be talking about. approaches. Eventually (and obviously), the F# solution
rachelree.se
Over the last year or so, as Ive started to read about won out. Several key reasons drove this choice.
microservices, Ive come to realize that theres no one
definition for what they are. Even how large a single mi- Fewer Lines of Code
croservice should be is a contentious topic, with several In general, F# has significantly fewer lines of code than
different camps arguing for vastly different sizes. One C#. In some cases, this is merely a reflection of the lack
thing we know: Microservices are intentionally small, but of curly brackets and explicitly written types, but in many
how small are they? Some recent guidelines put forth by cases this is more about the correct use of some standard
teams currently using a microservices approach include: F# patterns. For example, discriminated unions (covered
in my last article). I showed how just a few lines of code
Being able to rewrite each service in fewer than six can be used to represent a simple object hierarchy in C#.
weeks There are other patterns though, such as partial applica-
Using DDD, wherein there should be one service per tion. You can think of partial application as inheritance
bounded context for functions. Consider a very simple, if somewhat con-
That each microservice has fewer than 300 lines of trived case: a function that adds two numbers.
code
That each microservice is a single function let add num1 num2 = num1 + num2

There are additional metrics that should be considered; This Add function has a type signature showing that it
some folks have offered up the size of the team that takes in two integers (num1 and num2), and returns an
builds and maintains each service as relevant (the two- integer. Look at Figure 1 to see it in action.

42 Case Study: Writing Microservices with F# codemag.com


likely to be correct. Bonus: You dont need to understand
the mathematics involved!

Cross-Cutting Concerns
What are cross-cutting concerns? Consider issues such
as logging and validation, that necessarily touch several
Figure 1: The type signature for the Add function. parts of the system and often require code to be dupli-
cated across these pieces of the system. Theres often no
easy way to isolate this code nicely. Perhaps most impor-
tantly to Jet.com, we needed a way to handle our cross-
cutting concerns. In ASP.NET MVC, this is traditionally
done through the use of Action Filters. To apply a filter
to a single function (or a controller), you decorate it with
the relevant attribute. ASP.NET injects an extra call before
your function call to handle authorization. ASP.NET Web
Figure 2: Type signature for add2 function. API takes a similar approach, using attributes to inject an
extra function call before your function is called.

Once youve constructed this Add function, you can think In Jet.coms case, we needed this same ability to handle
of it as a base function. Then, making use of a partial cross-cutting concerns for services not based on HTTP.
application, its easy to create additional functions simi- Unfortunately, after several attempts, we discovered that
lar to these: this proved extremely difficult to do in a generic way.
Once we began to look to F#, we realized that we could
let add1 = add 1 handle cross-cutting concerns with no difficulty. Plus, we
let add2 = add 2 realized that we could do it in a way that neither pollut-
ed the codebase with fabricated interfaces nor required
Even though these two functions take no explicit param- adapting a specific architecture. We simply took a more
eters, their type signatures (see Figure 2) show that they functional and composable approach. Any filter in our
still expect the (now unnamed) num2 parameter. The module can be used with functions that have type Input
second parameter (num2) is inherited from the original -> Async<Output>, and all filters in our module are com-
Add function. Just as inheriting a class can save you from posable, using our andThen operation, like so:
repeating several lines of code, inheriting a function can
as well. let compositeFilter = filter1
|> Filter.andThen filter2
Although having fewer lines of code isnt necessarily an
end goal in and of itself, of course, it does mean that For example, if you have a service that simply echoes its
youll be able to more easily keep track of several key output:
pieces of code at once. This leads to an increased under-
standing of the code, which leads directly to fewer bugs. let echoService : Service<string, string> =
It just makes sense: If you can understand and process fun str -> async.Return str
more code at once, youll naturally make fewer mistakes.
And you have a filter that will print messages before and
after a service is run:

Theres a saying in let printBeforeAfter:Filter<string, string> =


the F# community: Filter.beforeAfterSync
Once your code compiles, (fun _ -> printfn "before")
it works. (fun _ -> printfn "after")

Then, you can simply compose the two, and the messages
print before and after the service is invoked:
Correct Code
F#s strict typing makes writing correct code easy. With let filteredEchoService:Service<string, string>=
each new line of code thats added, the compiler infers printBeforeAfter
the types for the new code, and then double-checks that |> Filter.apply echoService
these types perfectly fit into your program. If theres a
mismatch of types, youll know at design-time rather than This is clearly a much simpler, more intuitive, and effec-
run-time. F# and the other related languages in the ML tive way of handling filters than creating and implement-
family of programming languages were originally cre- ing a series of custom filters for either ASP.NET MVC or
ated to work closely with mathematical theorem-proving ASP.NET Web API.
software, which has led to a type inference system that
can be mathematically proven. Theres a saying in the F#
community: Once your code compiles, it works. Although
Why Did Jet.com Choose
that isnt always true because humans can get in the way, Microservices?
once your code compiles, its passed several rigorous There are two answers to the question of why Jet.com
mathematical tests of consistency, and its much more chose microservices. First, because theyre a perfect fit for

codemag.com Case Study: Writing Microservices with F# 43


a functional-based architecture. Second, well, the origi- Independent Releasability
nal team didnt actually choose microservices. They chose Although its possible to release a single service at once,
F#. They intentionally wrote idiomatic F#, in the form of we organize ourselves into teams, and our microservices
small, functional scripts with well-defined inputs and out- into groups within our teams. Because were using F#,
puts. Rather than naming the scripts with titles similar to each group of microservices is usually within the same
SkuScript or SkuService, they named them ImportSkus. Visual Studio solution. When we talk about independent
The team didnt aim for a microservices architecture, and releasability, we usually mean that well promote an en-
because Jet.com is a new product, they werent breaking tire solution of related servicesoften a group of five to
pieces off of a larger monolithic app to work their way tenat the same time.
into a microservices architecture. The team just woke up
one day and realized that they had been naturally build- More Even Distribution of Complexity
ing toward one all along. By a more even distribution of complexity, I mean that
using microservices generally makes it much more simple to
There has been much discussion around whether to cre- create, maintain, and update your services, but also that it
ate a microservices architecture from scratch or to create tends to be much more difficult to manage the infrastructure
a monolith as your first version and then refactor it into needed to handle all of your services. This is more of a trade-
relevant services a few at a time. Weve ended up in the off than a direct benefit, but I argue that it ultimately wins
first group, but only by accident. over some especially large projects Ive worked on. Think
of 46 projects loaded into a single solution that were cre-
Microservices First ated by a team of 27 developers over three years, all to be
The microservices-first folks warn that splitting up a released one dark and stormy evening, if the fates allowed.
monolithic application is a huge amount of effort, especial-
ly if youre splitting one that wasnt designed to be loosely As Ive mentioned, we happened into the microservices
coupled. If your application has messy service boundaries, first camp. Regardless of which side you choose, its
youll need to tighten these up first before you can even crucial that you at least have your management story
begin to work on a conversion path for microservices, and thought through, if not completely determined, right up
that work is best done at the very beginning of the project front before you start to create or break off those ser-
so that it can be architected in correctly. vices, because of the additional layers of complexity gen-
erated with needing to manage everything.

If your application has messy Show Me the Code!


service boundaries, Lets check out an example microservice. Ive created one
youll need to tighten these here that performs a price comparison check for a specific
up first before you can even product on a made-up Nile website.
begin to work on a conversion
path for microservices. Inputs and Outputs
I mentioned previously that an important part of the defi-
nition of a microservice at Jet.com is having well-defined
inputs and outputs. So lets define some F# types to use
Monolith First for the inputs and outputs for this microservice.
The monolith-first camp tends to caution developers
about two things. First, that because there are layers Youll need to input some product information, so that
of unnecessary complexity that microservices generate, you know which product youre comparing. Set up a Prod-
this slows down your project in the early stages, when uct type that has a SKU, an ID, a description of the prod-
rapid iteration is the most important. Second, that there uct, and a cost for a single unit of the item.
is tremendous difficulty in determining, at the beginning
of a project, where the natural microservice boundaries type Product = {
should lie. Because of these two concerns, breaking apart Sku : string
an established monolithic application at the now stabi- ProductId : int
lized, natural microservice boundaries becomes a much ProductDescription : string
easier approach. CostPer : decimal
}

Benefits of Using a Microservices Youll also need a failure type, ProductCheckFailed, that
Architecture will contain the product ID and a message indicating the
The benefits of using a microservices architecture tend to type of failure, and containing additional information
fall into three main groups: Easy scalability, Independent about the failure.
releasability, and a more even distribution of complexity.
type PriceCheckFailed = {
Easy Scalability ProductId : int
Easy scalability is a matter of scaling a single service as Message : string
needed. Did we receive a large shipment to the warehouse }
today, putting the related services and people under
heavy load? We can scale only those services without af- Using these two, you can construct our inputs. In this
fecting the rest of the system. case, a single Product:

44 Case Study: Writing Microservices with F# codemag.com


type Input = standard result of this would be to write to EventStore
| Product of Product or Kafka, in order to make an appropriate update in the
expected system.
Now, youll need to construct the outputs. In most cases,
youll want a discriminated union. The first potential return The second case, Some (Output.ProductPriceCheckFailed e),
type, ProductPriceNile, is the typical successful return. asks if you received a response that indicates a failure case.
Its a tuple type that returns the original Product infor- Because youll have access to the ProductPriceCheckFailed
mation back to you, with a decimal that contains the price information, you log the failure, then check to determine
on the Nile site. The second, ProductPriceCheckFailed, if theres a way to recover. Maybe there was a standard er-
is the failure case, and contains the PriceCheckFailed ror that you understand and you can attempt a recovery,
type that you created above. depending on the information in the contained Message.

type Output = Finally, None asks if you received no response at all. In


| ProductPriceNile of Product * decimal this case, you still might want to log the failure, but you
| ProductPriceCheckFailed of PriceCheckFailed wouldnt have the additional information contained in
the Message statement.
Transforming Inputs into Outputs
Once you know the inputs and outputs, you need to think let resolve id output =
about how to transform the inputs into the outputs. You match output with
next create the transform function. Remember that to | Some (Output.ProductPriceNile (e, price)) ->
use the filters module described above, you want the async {()} // write to event store
SPONSORED SIDEBAR:
functions to have type Input -> Async<Output>. In | Some (Output.ProductPriceCheckFailed e) ->
this case, youre constructing a successful case to return, async {()} // log, and attempt to recover Need Help?
but this is really the meat of the microservice. Here, you | None ->
might connect out to an API, then process some informa- async.Return () // log failure Looking to convert your
tion, or otherwise do the work of converting from your application to a new
inputs into your outputs. By using the Option type here, youre able to handle an language, or need help
additional failure case, the one where you receive no re- optimizing your application?
let transform input = sponse at all, very naturally. The experts at CODE
async { Consulting are here to
return Some(ProductPriceNile( Consuming the Service help with your projects needs!
{Sku="343434"; Finally, you need to gather the decoded input and the From desktop to mobile
ProductId = 17; two functions to send to a consume function that youve applications, CODE developers
have a plethora of
ProductDescription="My amazing product"; created internally. This function will then be called for
experience in developing
CostPer=1.96M}, each event in an event stream to which youre subscribed.
software and programs
3.96M))
for different platforms.
} consume (decode Input.Product) resolve interpret For more information visit
www.codemag.com/consulting
Note that youre also returning an Option type. This is
similar to C#s Nullable, but more powerful in the fol- Conclusion or email us at
info@codemag.com.
lowing ways: The tools and techniques outlined in this article have
introduced you to functional programming and microser-
Although C#s nullable can be used on an Integer, vices and helped clear up some misconceptions you may
a Boolean, or a few other fundamental types, Op- have had. Ideally, theyve also helped show you a suc-
tion is available to use on any type: a string, a cus- cessful, real-world case of functional programming that
tom type, or even a whole function. you can use as an example to help your company get
Its possible to nest Option, and create an started with microservices in F#. Good luck!
Option<Option<string>>.
You can use Map, Filter, and other functions to op- Rachel Reese
erate on your Option type.
Possibly most importantly, in order to use the value
thats returned, you must pattern match on the Op-
tion type. In doing so, you have a forced built-in
null check that can save you from NullReference-
Exceptions.

Interpreting the Output


Now that youve obtained output from the transform
function, you need to process, interpret, and resolve it.
Was it successful or was there a failure? Heres where the
Option type comes in handy. The resolve function isnt
much more than one large pattern match statement.

The first case that you want to check, Some


(Output.ProductPriceNile (e, price)), asks if you re-
ceived a response that indicates a successful case. A

codemag.com Case Study: Writing Microservices with F# 45


ONLINE QUICK ID 1611081

Introduction to Data Science


using Python
In my previous article (CODE Magazine, July/August 2016) on the Internet of Things (IoT), I mentioned the two components
of IoT: Data Collection and Data Analysis. In that article, you learned how the Python language was used to program
your Raspberry Pi for data collection, talking to all the different sensors and at the same time allowing you to use it to

write server-side apps for communicating with third-party mixture of integer, string, double, and Boolean values. To
servers (such as for push notifications). In this article, access the items in a list, you use an index (starting at 0):
Im going to turn my attention to the second component
of IoT: Data Analysis. print(lst[0]) # 4
print(lst[1]) # Hello
In recent years, youve often heard the term Data Science. print(lst[2]) # 3.14
According to Wikipedia, Data Science is an interdisciplin- print(lst[3]) # True
ary field about processes and systems to extract knowl-
edge or insights from data in various forms, either struc- Slicing Lists in Python
Wei-Meng Lee tured or unstructured, which is a continuation of some of When youre dealing with lists, you usually want to extract
weimenglee@learn2develop.net the data analysis fields, such as statistics, data mining, a group of items from them, not just a single one. For this
www.learn2develop.net and predictive analytics, similar to Knowledge Discovery purpose, Python has this concept known as slicing.
@weimenglee in Databases (KDD). In simple terms, Data Science in-
volves using tools to derive meaning from a huge pool of
Wei-Meng Lee is a technolo-
gist and founder of Developer data, allowing you to draw conclusions about the past or
Learning Solutions (http:// predict the future. Slicing extracts
www.learn2develop.net), a one or more elements
technology company special- from a list.
izing in hands-on training
In simple terms, Data Science
on the latest technologies.
Wei-Meng has many years of involves using tools to derive
training experience and his meanings from a huge pool Slicing in Python has the following syntax:
training courses place special of data, allowing you to make
emphasis on the learning-by- conclusions about the past or list[start:end:step]
doing approach. His hands-on
predict the future.
approach to learning program- As you can see in that snippet, start is the index of the
ming makes understanding starting item, end is the index of the last item (which is
the subject much easier than not included in the answer), and step is the number of
reading books, tutorials, and Data Science is a big subject and just one article doesnt items to advance. If any of those parameters is omitted,
documentation. His name do it justice. But you need to start somewhere. In this the following defaults are assumed:
regularly appears in online and article, Ill start by introducing you to some of the tools
print publications such as DevX.
commonly used in Data Science. Youll see that because If start is omitted, its assumed to be 0.
com, MobiForge.com, and CODE
Python is such a widely used language, and coupled with If end is omitted, its assumed to be the length of
Magazine.
an active community of Python libraries developers, its the list.
no coincidence that Python is a favorite language among If step is omitted, its assumed to be 1.
data scientists.
Lets take a look at some examples. The following state-
ment prints out the items from index 0 to 1 (remember
A Quick Introduction to Python that the item at index 2 isnt returned in the answer):
Before I get to the heart of Data Science using Python,
its important to ground yourself in the basics of one of print(lst[0:2]) # [4, 'Hello']
the key data types in Python: list. A lot of operations that
you can perform on a list apply to the other data types An easy way to understand the above syntax is to interpret it
that youll see later in this article, so nows a good time this way: get (2-0) items from the list starting from index 0.
to take a look.
The following snippet prints out the items from index 1 to
In Python, a list is a collection of values: 1 and only one item is returned:

lst = [4,"Hello", 3.14, True] print(lst[1:2]) # ['Hello']


print(lst) # [4, 'Hello', 3.14, True]
If you use this the way I showed you in the previous ex-
As you can see in the output above, the items in a list ample to interpret the syntax, thats: get (2-1) items from
need not be of the same type in that snippet, theres a the list starting from index 1.

46 Introduction to Data Science using Python codemag.com


Figure 1: Understanding list slicing in Python

The following statement prints out all the items starting The following statement prints all of the items starting
from index 1: from index 0 to 4, and a step of 2, which means that it
prints items at index 0 and 2:
print(lst[1:]) # ['Hello', 3.14, True]
print(lst[0:4:2]) # [4, 3.14]
Notice that in this case, the end isnt specified. Its value
defaults to the length of the list, which is four items. So If you have difficulty remembering how slicing works in
the above is essentially the same as: Python, you can use the method shown in Figure 1. Just
imagine the index to be sandwiched between the ele-
print(lst[1:4]) ments and it will be very easy for you to understand how
slicing works.
The following statement prints the first three elements:

print(lst[:3]) # [4, 'Hello', 3.14]


Extending Pythons List DataType
using NumPy
In this case, the start isnt specified so it defaults to 0, The key problem with the Pythons list data type is its ef-
which is essentially the same as: ficiency. A list allows you to have non-uniform type items;
each item in the list is stored in a memory location, with
print(lst[0:3]) the list containing an array of pointers to each of these
locations. A Python list requires:
The following statement prints all items in the list except
the last two: At least 4 bytes per pointer
At least 16 bytes for the smallest Python object: 4
print(lst[:-2]) # [4, 'Hello'] bytes for the pointer, 4 bytes for the reference count,
and 4 for the value. These round up to 16 bytes.
The following statement prints the last two items:
Because of the way the Python list is implemented, ac-
print(lst[-2:]) # [3.14, True] cessing items in a large list is computationally expensive.
To solve this problem, you can use NumPy. NumPy is an
The following statement reverses all the items in the extension to the Python programming language, adding
list: support for large, multi-dimensional arrays and matri-
ces, along with a large library of high-level mathematical
print(lst[::-1]) # [True, 3.14, 'Hello', 4] functions to operate on these arrays.

codemag.com Introduction to Data Science using Python 47


NumPy Array Basics zeroes, you can use the zeros() function with a number
In NumPy, an array is of type ndarray (n-dimensional array). A indicating the size of the array:
NumPy array is an array of homogeneous values (all of the same
type), and all items occupy a contiguous block of memory. a1 = np.zeros(2) # array of rank 1 with all 0s
print a1.shape # (2,)
To use NumPy, you first need to import the numpy package: print a1[0] # 0.0
print a1[1] # 0.0
import numpy as np
If you want to create a rank 2 array, simply pass in a tuple:
Array operations are very similar to that of the Python
list. For example, the following code snippet creates a a2 = np.zeros((2,3)) # array of rank 2 with all 0s;
Python list and then converts it to a NumPy array: # 2 rows and 3 columns
print a2.shape # (2,3)
l1 = [1,2,3,4,5] print a2
array1 = np.array(l1) # rank 1 array '''
[[ 0. 0. 0.]
In this case, array1 is known as a rank 1 (one dimen- [ 0. 0. 0.]]
sional) array. You can print out the array as usual using '''
the print() function:
To initialize the array to some other values other than
Trying Out the Examples print (array1) # [1 2 3 4 5] zeroes, use the full() function:
For this article, Im using Jupyter
You can print out the shape of the array using the shape a3 = np.full((2,3), 8) # array of rank 2
Notebook for all the examples.
property: # with all 8s
To install Jupyter Notebook,
print a3
download and install Anaconda
from https://www.continuum.io/ print (array1.shape) # (5,) '''
downloads. Anaconda comes [[ 8. 8. 8.]
with all the major packages that The shape property returns a tuple containing the dimen- [ 8. 8. 8.]]
you need for Data Science, such sion of the array. In the above example, array1 is a 1-di- '''
as NumPy and pandas. mensional array of five items.
In linear algebra, you often need to deal with an identity
Just like Python list, you can access items in the NumPy matrix, and you can create this in NumPy easily with the
array using indexing as well as slicing: eye() function:

print (array1.shape) # (5,) a4 = np.eye(4) # 4x4 identity matrix


print (array1[0]) # 1 print a4
print (array1[1]) # 2 '''
print (array1[1:3]) # [2 3] [[ 1. 0. 0. 0.]
print (array1[:-2]) # [1 2 3] [ 0. 1. 0. 0.]
print (array1[3:]) # [4 5] [ 0. 0. 1. 0.]
[ 0. 0. 0. 1.]]
You can also pass in a list containing the index of the '''
items you want to extract to the array:
And if you need to populate an array with some random
print (array1[[2,3]]) # [3,4] values, you can use the random.random() function to
generate random values between 0.0 and 1.0:
The following code snippet shows how you can create a
two-dimensional array: a5 = np.random.random((2,4)) # populate a rank 2
# array (2 rows
l2 = [6,7,8,9,0] # 4 columns) with
array2 = np.array([l1,l2]) # rank 2 array # random values
print (array2) print a5
''' '''
[[1 2 3 4 5] [[ 0.21135397 0.39570425 0.25548923 0.05606163]
[6 7 8 9 0]] [ 0.14495175 0.19093966 0.29366716 0.61189549]]
''' '''
print (array2.shape) # (2,5) - 2 rows and
# 5 columns Finally, you can create a range of values from 0 to n-1
print (array2[0,0]) # 1 using the arange() function:
print (array2[0,1]) # 2
print (array2[1,0]) # 6 a6 = np.arange(10) # creates a range from 0 to 9
print a6 # [0 1 2 3 4 5 6 7 8 9]
Creating and Initializing Arrays using NumPy
NumPy contains a number of helper functions that make Boolean Array Indexing
it easy to initialize arrays with some default values. For One of the many useful features of the NumPy array is its
example, if you want to create an array containing all support for array boolean indexing. Consider the following

48 Introduction to Data Science using Python codemag.com


example: You have a list of numbers and you need to re-
trieve all of the even numbers from the list. Using Pythons
list, you need to iterate through all items in the list and
perform a check individually. Using NumPy array, however,
things are much easier. Look at the following example:

nums = np.array([23,45,78,89,23,11,22])

You first specify the condition, testing for even numbers,


and then assign it to a variable: Figure 2: Generating the cumulative sums over the rows
for each column
even_nums = nums % 2 == 0

The even_nums variable is now a NumPy array, contain-


ing a collection of Boolean values. If you print it out,
youll see just that:

print (even_nums)
'''
[False False True False False False True]
''' Figure 3: Generating the cumulative sums over
the columns for each row
The True values indicate that the particular item is an
even number. Using this Boolean array, you can now use
it as an index to the numbers array: Likewise, you can subtract, multiply, and divide arrays
directly:
print (nums[even_nums])
''' print x1 - y1 # same as np.subtract(x1,y1)
[78 22] '''
''' [[-6 -6 -6]
[ 2 2 2]]
The above statements could be written succinctly like this: '''

print (nums[nums % 2 == 0]) print x1 * y1 # same as np.multiply(x1,y1)


'''
The array boolean indexing feature makes it extremely useful [[ 7 16 27]
to manipulate a large amount of data without worrying about [ 8 15 24]]
the underlying implementation. Heres another example: '''

prices = np.array([45,23,56,89,12,48]) print x1 / y1 # same as np.divide(x1,y1)


reasonable = (prices > 20) & (prices < 50) '''
print prices[reasonable] [[0 0 0]
''' [2 1 1]]
[45 23 48] '''
'''
Very often, you need to generate the cumulative sum of
Array Math a series of numbers. NumPys array makes it really easy.
Another area where the NumPy array excels is in array Suppose you have the following array:
math. Consider the following rank-2 arrays:
a = np.array([(1,2,3), (4,5,6), (7,8,9)])
x1 = np.array([[1,2,3],[4,5,6]]) print (a)
y1 = np.array([[7,8,9],[2,3,4]]) '''
[[1 2 3]
You can add each of the two arrays items by using the + [4 5 6]
operator on the two arrays: [7 8 9]]
'''
print x1 + y1
''' To generate the cumulative sum of all the numbers in the
[[ 8 10 12] array, use the cumsum() function:
[ 6 8 10]]
''' print (a.cumsum()) # prints the cumulative sum
# of all the elements in
Alternatively, you can also use the add() function to add # the array
the two arrays: '''
[ 1 3 6 10 15 21 28 36 45]
np.add(x1,y1) '''

codemag.com Introduction to Data Science using Python 49


Note that the result is returned as a rank-1 array.

To generate a cumulative sum over the rows for each of


the columns, specify the axis parameter with a value of 0:

print (a.cumsum(axis=0)) # sum over rows for


# each of the 3
# columns
'''
[[ 1 2 3]
[ 5 7 9]
[12 15 18]]
'''

Figure 2 shows how the cumulative sums are generated


when the axis parameter is set to 0.

To generate a cumulative sum over the columns for each


of the rows, specify the axis parameter with a value of 1:

print (a.cumsum(axis=1)) # sum over columns for


# each of the 3 rows
'''
Figure 4: A simple line chart using matplotlib [[ 1 3 6]
[ 4 9 15]
[ 7 15 24]]
'''

Figure 3 shows how the cumulative sums are generated


when the axis parameter is set to 1.

Visualizing Data using Matplotlib


As the saying goes, a pictures worth a thousand words. With
huge amount of data, theres no better way to understand the
data than to visualize it graphically. A popular charting ap-
plication for Python is the matplotlib library. The matplotlib
library is a Python 2D plotting library, which produces publi-
cation quality figures. Whats more, a lot of Python libraries,
like NumPy and Pandas (discussed in the next section), have
inherent support for it, making plotting very accessible.

Consider the following code snippet:

%matplotlib inline
import matplotlib.pyplot as plt

plt.plot(
[1,2,3,4,5,6,7,8,9,10],
[2,4.5,1,2,3.5,2,1,2,3,2]
Figure 5: Displaying the number of rainy days per month for the past three years )

Listing 1: Plotting the number of rainy days per month for the past three years
%matplotlib inline 'Jul','Aug','Sep','Oct','Nov','Dec']
import numpy as np
import matplotlib.pyplot as plt plt.xticks(range(len(year_2013)), labels, rotation='vertical')

year_2013 = [17,9,16,3,21,7,8,4,6,21,4,1] year = 2013


year_2014 = [7,3,6,8,12,5,19,22,16,13, 21,3] for month in rainy_days:
year_2015 = [9,2,12,3,4,15,5,13,1,4,5,9] plt.plot(month, label=year) # plot the rainy days for each year
year += 1
rainy_days = np.array([year_2013,year_2014,year_2015])
plt.legend() # show the legend
labels = ['Jan','Feb','Mar','Apr','May','Jun', plt.show()

50 Introduction to Data Science using Python codemag.com


Listing 2: Plotting a bar chart from data loaded from a CSV file
from matplotlib import pyplot as plt label="Jim",
from matplotlib import style color = "m",
import numpy as np align= "center"
)
style.use("ggplot")
plt.title("Results") # sets the title
semester,grade = np.loadtxt("results.csv", unpack=True, plt.xlabel("Semester") # sets the label for x-axis
delimiter=",") plt.ylabel("Grade") # sets the label for y-axis

plt.bar( plt.legend() # shows the legend


semester, plt.grid(True, color="y") # shows and sets the grid color to yellow
grade,

First, the %matplotlib inline statement tells Jupyter Listing 3: The readings of a persons blood glucose readings stored in a CSV file
Notebook to display the matplotlib chart inline, rather ,DateTime,mmol/L
than in a separate window. To plot charts, use the mat- 0,2016-06-01 08:00:00,6.1
plotlib librarys pyplot module and import it as plt (by 1,2016-06-01 12:00:00,6.5
convention). The plot() function displays a default line 2,2016-06-01 18:00:00,6.7
chart with the first argument (a Python list) on the x-axis 3,2016-06-02 08:00:00,5.0
and the second argument (also a Python list) as the y- 4,2016-06-02 12:00:00,4.9
axis. The result is as shown in Figure 4. 5,2016-06-02 18:00:00,5.5
6,2016-06-03 08:00:00,5.6
Although you can plot a matplotlib chart using Python 7,2016-06-03 12:00:00,7.1
lists, you can often plot it using NumPy arrays. Consider 8,2016-06-03 18:00:00,5.9
another example, where youve recorded the number of 9,2016-06-04 09:00:00,6.6
rainy days per month for the past three years. You want 10,2016-06-04 11:00:00,4.1
to plot this data on the same chart and do a visual com- 11,2016-06-04 17:00:00,5.9
parison. 12,2016-06-05 08:00:00,7.6
13,2016-06-05 12:00:00,5.1
14,2016-06-05 18:00:00,6.9
Listing 1 is the code to plot three line charts in a single
15,2016-06-06 08:00:00,5.0
figure, showing the number of rainy days per month for
16,2016-06-06 12:00:00,6.1
the past three years.
17,2016-06-06 18:00:00,4.9
18,2016-06-07 08:00:00,6.6
The xticks() function sets the locations and labels of the 19,2016-06-07 12:00:00,4.1
ticks on the x-axis. In this example, Ive set it to display 20,2016-06-07 18:00:00,6.9
the shorthand for each month and make them display ver- 21,2016-06-08 08:00:00,5.6
tically (see Figure 5). 22,2016-06-08 12:00:00,8.1
23,2016-06-08 18:00:00,10.9
Very often, your data is stored in files, such as Excel or 24,2016-06-09 08:00:00,5.2
CSV files. NumPy makes it easy to load and use data from 25,2016-06-09 12:00:00,7.1
files. Suppose theres a CSV file named results.csv con- 26,2016-06-09 18:00:00,4.9
taining the grade results of a student for 10 semesters:

1,2
2,4.5 returned array is unpacked as individual arrays for each
3,1 field, and the delimiter argument specifies the delimiter
4,2 used to separate the various fields in the text file. The
5,3.5 semester variable is now an array containing the values
6,2 from 1 to 10, and the grade variable is an array contain-
7,1 ing the grades (2,4.5, ,2).
8,2
9,3 Listing 2 shows the code to plot a bar chart using the
10,2 data loaded from the CSV file. The generated chart is as
shown in Figure 6.
You can load the file into a NumPy array as follows:

import numpy as np
Manipulating Data and Performing
Data using Pandas
semester,grade = np.loadtxt("results.csv", unpack=True, Although NumPy arrays are a much improved version over
delimiter=",") Pythons list, its insufficient to meet the needs of data
science. In the real world, data is often presented in table
The loadtxt() function loads the data from the specified formats. For example, consider the content of the CSV file
text file. The unpack argument indicates whether the shown in Listing 3.

codemag.com Introduction to Data Science using Python 51


Series
A Series is a one-dimensional NumPy-like array, with each
element having an index (0, 1, 2, by default); a Series
behaves like a dictionary, with an index. Figure 7 shows
the structure of a Series in pandas.

Although Python supports


lists and dictionaries
for manipulating structured
data, its not well-suited
for manipulating numerical
tables, such as the one stored
in the CSV file.

The following code snippet shows how a Series can be


created in pandas:

import pandas as pd

series = pd.Series([1,2,3,4,5])
print series
'''
0 1
Figure 6: Plotting the grades for a student for the various semesters 1 2
2 3
3 4
4 5
dtype: int64
'''

Like NumPy, you need to import the pandas package be-


fore using it. The Series() function creates a pandas se-
ries from a list of items.

One good use of


Series is for generating
date ranges.
Figure 7: The structure of a Series

One good use of Series is for generating date ranges. Con-


sider the following example:
Figure 8: The structure of a DataFrame
import pandas as pd

The CSV file contains rows of data divided into three col- dates1 = pd.date_range('20160525', periods=12)
umns: index, date and time of recording, and blood glu- print dates1
cose readings in mmol/L. '''
DatetimeIndex(['2016-05-25', '2016-05-26',
To be able to deal with data stored as tables, you need '2016-05-27', '2016-05-28',
a new data type thats more suited to deal with it: That '2016-05-29', '2016-05-30',
means that you want pandas. Pandas is a Python package '2016-05-31', '2016-06-01',
providing fast, flexible, and expressive data structures '2016-06-02', '2016-06-03',
designed to make working with relational or labeled '2016-06-04', '2016-06-05'],
data both easy and intuitive. dtype='datetime64[ns]', freq='D')
'''
Pandas supports two key data structures: Series and
DataFrame. Lets take a closer look at these two data The date_range() function creates a series representing
structures before I come back to look at how to use pan- a series of dates. The periods parameter allows you to
das to manipulate the blood glucose readings data. specify the date intervals. For example, in this case, 12

52 Introduction to Data Science using Python codemag.com


means 12 days starting with the specified date, which is
25 May 2016.

You can also specify the frequency using the freq param-
eter:

dates2 = pd.date_range('2016-05-01', periods=12,


freq='M')
print dates2
'''
DatetimeIndex(['2016-05-31', '2016-06-30',
'2016-07-31', '2016-08-31',
'2016-09-30', '2016-10-31',
'2016-11-30', '2016-12-31',
'2017-01-31', '2017-02-28',
'2017-03-31', '2017-04-30'],
dtype='datetime64[ns]', freq='M')
'''

The default frequency is in days, but if you specified M for


freq, the frequency is changed to monthly. You can even
change the frequency to hourly:

dates3 = pd.date_range('2016/05/17 09:00:00',


periods=8,
freq='H')
print dates3 Figure 9: Plotting a line chart from a Panda Series
'''
DatetimeIndex(['2016-05-17 09:00:00',
'2016-05-17 10:00:00', Here, youre creating a list from a string (ABCD). The Pandas
'2016-05-17 11:00:00', DataFrame created looks like this:
'2016-05-17 12:00:00', Pandas is a software library
'2016-05-17 13:00:00', ''' written for the Python
'2016-05-17 14:00:00', A B C D programming language for data
'2016-05-17 15:00:00', 0 1.269108 -0.496408 -0.162528 0.432953 manipulation and analysis. In
particular, it offers data structures
'2016-05-17 16:00:00'], 1 -0.895156 -0.014969 0.383383 1.902658
and operations for manipulating
dtype='datetime64[ns]', freq='H') 2 -1.292945 0.656012 0.376739 0.875683
numerical tables and time series.
''' 3 0.456998 0.863970 1.155423 0.587762
4 -0.630788 0.006764 0.734363 0.975344
Observe that in each of the above examples, the date_ 5 0.277726 0.947913 -0.838228 -0.318126
range() function is smart enough to detect the date for- 6 -2.095660 0.757282 -0.917780 -0.345179
mat passed in (the first one uses YYYYMMDD, and the 7 -1.399808 -2.210822 -2.009842 -1.449238
second one uses YYYY-MM-DD, and the third one uses 8 -1.801125 0.463970 -0.817592 1.147401
YYYY/MM/DD). 9 -0.938238 0.028543 -0.774980 -0.195423
'''
DataFrame
A DataFrame is a two-dimensional NumPy-like array. Notice that the index is automatically created for the
Think of it as a table. Figure 8 shows the structure of a DataFrame. If you wish, you can change the index to
DataFrame in pandas. something else, such as date and time. For example, the
following code snippet shows using a Series as the index
The following code snippet shows how a DataFrame can for the DataFrame:
be created in pandas:
days = pd.date_range('20150525', periods=10)
import pandas as pd data_frame = pd.DataFrame(np.random.randn(10,4),
import numpy as np index=days,
columns=list('ABCD'))
data_frame = pd.DataFrame(np.random.randn(10,4), print data_frame
columns=list('ABCD'))
print data_frame The index parameter is assigned a Series (days), which is
generated by the date_range() function. The DataFrame
First, you use the random.randn() function to generate now looks like this:
an array of the specified shape (10 rows and four col-
umns; in this example) filled with random floating-point '''
numbers sampled from a univariate normal (Gaussian) A B C D
distribution of mean 0 and variance 1. The columns pa- 2015-05-25 -0.181824 -0.522341 -0.629486 -0.098926
rameter specifies a list containing the column headers. 2015-05-26 -0.786451 0.270572 -0.007755 0.407279

codemag.com Introduction to Data Science using Python 53


2015-05-27 -1.801745 -0.627653 0.017884 -0.294941 Selecting Data From DataFrames
2015-05-28 -0.199777 -0.343533 -0.847143 0.230196 There are many ways to select data from a DataFrame.
2015-05-29 -0.470902 -1.882163 1.589637 0.041875 Let me highlight a few examples. First, to display a spe-
2015-05-30 0.223365 -0.367830 0.901914 -1.574907 cific column, pass in the column header as the index,
2015-05-31 -0.701686 2.185077 -0.787870 -1.014857 like this:
2015-06-01 2.078889 0.467649 0.462715 0.731940
2015-06-02 -0.739564 0.055060 -0.414679 1.229497 print data_frame['A'] # prints column A
2015-06-03 1.086807 0.134102 -1.114484 -0.277467
''' This prints out the index as well as all of column A:

'''
2015-05-25 0.400942
2015-05-26 0.553610
2015-05-27 -1.772219
2015-05-28 0.298267
2015-05-29 -0.079830
2015-05-30 0.619363
2015-05-31 -0.217129
2015-06-01 -0.111042
2015-06-02 1.080578
2015-06-03 1.937649
'''

Because the index of the data_frame is a date range, you


can perform slicing, like this:

# prints rows with index from 2015-05-25 to 2015-05-28


print data_frame['2015-05-25':'2015-05-28']

The result is as follows:

'''
A B C D
2015-05-25 0.400942 0.734476 -0.900102 -0.148904
2015-05-26 0.553610 1.729898 1.248708 0.353235
2015-05-27 -1.772219 -2.182172 -0.439986 -1.672310
2015-05-28 0.298267 1.049802 -2.093472 1.330577
'''
Figure 10: Plotting a line chart from a Pandas DataFrame
You can also perform slicing using row numbers:

print data_frame[2:5] # prints row 3 through


# row 5

The above statement prints all the rows from index 2 to


5 (not included in the result), which means from row 3
to row 5:

'''
A B C D
2015-05-27 -1.772219 -2.182172 -0.439986 -1.672310
2015-05-28 0.298267 1.049802 -2.093472 1.330577
2015-05-29 -0.079830 1.169019 0.047177 -0.599912
'''

Very often when plotting charts, you need to flip the col-
umns and rows of the DataFrame, and this can be accom-
plished using the T property:

print data_frame.T

The T property transposes (interchanges) the index and


columns of the DataFrame:

'''
Figure 11: Plotting blood glucose readings 2015-05-25 2015-05-26 2015-05-27 2015-05-28

54 Introduction to Data Science using Python codemag.com


2015-05-29 2015-05-30 \
A 0.575812 -0.401051 -1.767028 1.148867
-1.013309 -0.232075
B -0.994374 -0.225347 -0.683786 1.600078
0.655725 0.210781
C -0.641241 1.003547 0.308813 1.066649
-0.181266 0.140533
D -0.384547 0.256077 -0.980992 0.647792
0.151229 0.260636

2015-05-31 2015-06-01 2015-06-02 2015-06-03


A -0.892355 -0.178719 -0.174579 -0.364807
B -1.073592 0.985476 -1.347515 -0.735336
C -0.260684 -0.706353 -0.872690 1.385756
D 1.456331 -1.800571 0.416017 -0.392111
'''

The plot() function


on Series and DataFrame
is just a simple wrapper
around pyplot.plot().

Plotting in Pandas
Like NumPy arrays, you can directly plot using matplotlib
from a Series or DataFrame. The following code snippet plots
a line chart from a panda Series (see Figure 9 for the chart):

%matplotlib inline
import pandas as pd
import numpy as np

series = pd.Series(np.random.randn(30),
pd.date_range(end='2016-06-01',
periods=30))
series.plot()

Figure 12: Displaying a title for the chart

codemag.com Introduction to Data Science using Python 55


The following code snippet plots a line chart from a Panda
DataFrame (see Figure 10 for the chart): series = pd.Series(np.random.randn(30),
pd.date_range(end='2016-06-01',
%matplotlib inline periods=30))
import pandas as pd
import numpy as np data_frame = pd.DataFrame(np.random.randn(30,2),
index=series.index,
columns=
['Temperature 1',
'Temperature 2'])
data_frame.plot()

A Sample Case Study: Visualizing


Blood Glucose Readings Data
Healthcare is one area that receives a lot of consider-
ation from technology. One particular disease, diabetes,
garners a lot of attention. According to the World Health
Organization (WHO), the number of people with diabetes
has risen from 108 million in 1980 to 422 million in 2014.
The care and prevention of diabetes is obviously of para-
mount importance. Diabetics need to regularly measure
the amount of sugar in their blood.

For this case study, Im going to show you how to visual-


ize the data collected by a diabetic so that he can see at
a glance how well he is keeping diabetes under control.

Data Source
For this case study, Im assuming that you have a CSV file
named readings.csv, which was shown earlier in Listing
3. The CSV file contains rows of data that are divided into
three columns: index, date and time, and blood glucose
readings in mmol/L.

Reading the Data in Python


To read the data from the CSV file into your Python app,
use the following code snippet:

Figure 13: Displaying the chart as a bar chart import pandas as pd


data_frame = pd.read_csv('readings.csv',
index_col=0,
parse_dates=[1])
print data_frame

You first import the pandas module, then you use the
read_csv() function to read the data from the CSV file
to create a DataFrame. The index_col parameter specifies
which column in the CSV file will be used as the index
(column 0 in this case) and the parse_dates parameter
specifies the column that should be parsed as a datetime
object (column 1 in this case).

When you print out the dataframe, you should see the
following:

DateTime mmol/L
0 2016-06-01 08:00:00 6.1
1 2016-06-01 12:00:00 6.5
2 2016-06-01 18:00:00 6.7
3 2016-06-02 08:00:00 5.0
4 2016-06-02 12:00:00 4.9
5 2016-06-02 18:00:00 5.5
6 2016-06-03 08:00:00 5.6
7 2016-06-03 12:00:00 7.1
Figure 14: Displaying the chart as an area chart 8 2016-06-03 18:00:00 5.9

56 Introduction to Data Science using Python codemag.com


9 2016-06-04 09:00:00 6.6
10 2016-06-04 11:00:00 4.1
11 2016-06-04 17:00:00 5.9
12 2016-06-05 08:00:00 7.6
13 2016-06-05 12:00:00 5.1
14 2016-06-05 18:00:00 6.9
15 2016-06-06 08:00:00 5.0
16 2016-06-06 12:00:00 6.1
17 2016-06-06 18:00:00 4.9
18 2016-06-07 08:00:00 6.6
19 2016-06-07 12:00:00 4.1
20 2016-06-07 18:00:00 6.9
21 2016-06-08 08:00:00 5.6
22 2016-06-08 12:00:00 8.1
23 2016-06-08 18:00:00 10.9
24 2016-06-09 08:00:00 5.2
25 2016-06-09 12:00:00 7.1
26 2016-06-09 18:00:00 4.9

Visualizing the Data


Lets now try to visualize the data by displaying a chart. Add
the following statements in bold to the existing Python script:

%matplotlib inline
import pandas as pd
Figure 15: Changing the color of the area chart
data_frame = pd.read_csv('readings.csv',
index_col=0, The chart is now displayed as an area chart (see Figure
parse_dates=[1]) 14).
print data_frame
You can also set the color for the area chart by using the
data_frame.plot(x='DateTime', y='mmol/L') color parameter:

The x parameter specifies the column to use for the x-axis data_frame.plot(kind='area', x='DateTime', y='mmol/L',
and the y parameter specifies the column to use for the color='r')
y-axis. This displays the chart as shown in Figure 11.
The area is now in red (see Figure 15).
You can add a title to the chart by importing the matplot-
lib.pyplot module and using the title() function:
Summary
%matplotlib inline In this article, Ive touched on the foundation of Data Sci-
import pandas as pd ence, using Python and its companion libraries, NumPy,
import matplotlib.pyplot as plt pandas, and matplotlib, and youve learned to manipulate
data and present them in a visual manner. In a future
data_frame = pd.read_csv('readings.csv', article, Ill delve deeper into the world of Data Science.
index_col=0,
parse_dates=[1]) Wei-Meng Lee
print data_frame

data_frame.plot(x='DateTime', y='mmol/L')
plt.title('Blood Glucose Readings for John',
color='Red')

A title is now displayed for the chart (see Figure 12).

By default, matplotlib displays a line chart. You can


change the chart type by using the kind parameter:

data_frame.plot(kind='bar', x='DateTime', y='mmol/L')

The chart is now changed to a bar chart (see Figure 13).

Besides displaying as a bar chart, you can also display an


area chart:

data_frame.plot(kind='area', x='DateTime', y='mmol/L')

codemag.com Introduction to Data Science using Python 57


ONLINE QUICK ID 1611091

Azure Skyline: Using WebJobs for


Event-Driven, Asynchronous Services
Calls to services hosted in Azure time out after four minutes. It doesnt matter if theyre WCF-style App Services or WebAPI,
theres nothing you can do about it. There are no settings to adjust, no options to configure. Its a system constraint set by
Microsoft and a reasonable one at that. So how do you handle long-running processes or fire-and-forget operations?

The answer is that you can build your own mechanism installed as part of the Azure SDK 2.5 and later and in-
or you can use some of the many Platform as A Service cludes some QuickStart templates for WebJobs, so if you
(PAAS) options that really smart and capable people have have the latest Azure SDK installed, youre all set. You can
built for you and made available to you for prices ranging download the source code from the Sept-Oct 2016 article
from free to very, very reasonable. http://www.codemag.com/Article/1609081.

In this article, Im going to show you how to program Add a new project to the CloudReporting solution
for long-running processes, fire-and-forget operations, and choose Cloud -> QuickStarts -> Compute -> Azure
event-driven operations, operations that may have to WebJobs SDK: Queues and name the new project
Mike Yeager scale up (and down) dramatically, and other scenarios CloudReporting.WebJobs, as shown in Figure 1.
www.internet.com that might be unfamiliar to the typical line-of-business
app developer. These solutions can scale automatically The template automatically adds the appropriate NuGet
Mike is the CEO of EPSs Houston from micro to massive. Theyre modular and shareable. packages and project references and creates a console appli-
office and a skilled .NET devel- These techniques and technologies are not for every- cation, which is where the report will run. Make the WebJobs
oper. Mike excels at evaluating thing, but theyre fantastic when you need them. project the startup project for the solution and press F5 to
business requirements and
run it. Youll see a console window pop up with a message
turning them into results from
In my last article in CODE Magazine (Sept/Oct 2016), I telling you to add your Azure Storage account credentials to
development teams. Hes been
wrote about generating reports as PDFs, on the server-side the App.config. Whats the storage account for? One type of
the Project Lead on many
projects at EPS and promotes via a WebAPI call, and using the Visual Studio report con- storage in Azure is a queue and youre going to drop messag-
the use of modern best trols. But reports can sometimes take a while to generate es on that queue whenever a report needs to be generated
practices, such as the Agile and clients dont usually want to sit and wait. What if the and emailed. Do you think that its starting to sound expen-
development paradigm, use of user navigates away from the page so the callback for the sive? Well, it isnt. The WebJob is going to run in the exist-
design patterns, and test-drive completed report cant happen? And what if the report ing website and uses its resources. Even the Free pricing tier
and test-first development. takes more than four minutes and the call times out? Today, can run WebJobs. In the last article, I chose the Basic (B1)
Before coming to EPS, Mike was Im going to expand on that article and make the report pricing tier or higher to deploy the CloudReporting website
a business owner developing a generation asynchronous. Thats going to allow me to do because the nature of generating PDFs prevents you from
high-profile software business some wonderful things like give feedback to the user while using the Free or Shared pricing tiers for this purpose. But
in the leisure industry. He grew the report is being created, let the user do other things this has nothing to do with WebJobs. Queue prices start at
the business from two employees (like run other reports) while reports are created, and even seven cents per GB, per month, plus 0.3 cents per 100,000
to over 30 before selling let the user generate reports and send them, via email, text transactions per month. Because youll be pulling entries off
the company and looking for or some other method with a fire-and-forget call. As youll the queue almost as fast as you put them on, and because
new challenges. Implementation see, I can even trigger reports based on some event hap- you wont be running a whole lot of reports a month, I dont
experience includes .NET, SQL pening, without calling the report directly. And if I have a expect the queue to add more than a couple of cents to the
Server, Windows Azure, Microsoft report that takes four hours to put together and generate, monthly bill for the expected load.
Surface, and Visual FoxPro. it will still work while the user goes about his business.

WebJobs: Create a Sample WebJob Do you think that


WebJobs were introduced in Azure around 2014 and are its starting to
a powerful way to run background tasks in the cloud. sound expensive?
The background task can be anything from a simple Well, it isnt.
batch file, to a PowerShell script, to a .NET executable
that you create. You can even run Node.js, Python and
Bash scripts. They can be run on a schedule or triggered
by some event. You can think of them as the successors If you havent done so already, open up the Azure portal
to the old Worker Roles in Azure that pulled jobs off a at portal.azure.com, log into your account, and click New
queue and processed them. WebJobs are built, run, and in the left-hand menu. Under Data + Storage, select Stor-
deployed within an Azure website, but dont require a age Account and give it a name. The name must be unique
website. Because the cloud reporting project is an ASP. within .core.windows.net and can only contain lower-case
NET MVC website running in Azure, Im going to add a We- letters and numbers. I called mine codecloudreporting.
bJob to that website that allows users to request that a You can leave most of the defaults. Because this is a de-
report is generated and emailed to a user asynchronously velopment system, Im going to choose locally-redundant
in a fire-and-forget operation. The Azure WebJobs SDK is storage (LRS) for my replication because its the least ex-

58 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com


Figure 1: Add a WebJob project that uses queues.

Figure 2: Getting the Azure Storage connection string

codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 59


pensive option and because I dont care that much if I lose
some queue entries in the unlikely event that an entire
data center goes down. The resource group isnt important
for your purposes, but for best performance, do choose a
location close to where you are. In my case, I chose South
Central US, which is the same location my website runs in
and also close to where I work in Houston. Azure takes a
minute or two to provision the storage account. Once its
finished, open the storage account in the portal, find the
Access keys and click on the ellipses to view the connection
string, as shown in Figure 2. Copy and paste this string
into both entries in the app.config file. The connection
string includes both the endpoint to connect to and the
login credentials necessary to connect.

Save the app.config file and press F5 again. This time,


the app creates several queues and BLOB containers in
the storage account and does some processing. A very
good tool to look at Azure Storage accounts is the Cloud
Explorer in Visual Studio, as you can see in Figure 3. Be-
cause Cloud Explorer is now part of the Azure SDK, you
should already have it installed.

If you look at the contents of the queues, youll find that


theyre all empty, as all of the sample messages have been
processed by the sample code in the WebJob. If you like,
you can look at the CreateDemoData method of Program.
cs and follow the sample code in Functions.cs to see how
the sample messages were processed. The output on the
console window shows you the order in which the code
was executed. The sample code is a pretty good introduc-
tion to using queues in WebJobs.

Modify the Sample


Replace the call to CreateDemoData in the Main meth-
od of Program.cs and the method itself with configure-
Queues(), as shown in Listing 1. Because this code only
runs on startup of the WebJob, its a good place to make
sure that your queues are configured prior to listening
for events.

Youll notice that the most interesting code in Program.cs


are the last two lines of Main that create an instance of
JobHost and then call the RunAndBlock method. Thats es-
sentially all WebJobs are, a process that loads into memory
and then waits for something to trigger a method. All of
the interesting processing code can be found in Function.
Figure 3: BLOBs and Queues created by WebJobs in cs, but you arent going to need the sample code, so you
Cloud Explorer can delete or comment out all of that entire file as well.

Listing 1: CreateDemoData in the Main method of Program.cs


class Program }
{
static void Main()
{
if (!VerifyConfiguration()) private static void configureQueues()
{ {
Console.ReadLine(); var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.
return; ConnectionStrings["AzureWebJobsStorage"].ConnectionString);
} var queueClient = storageAccount.CreateCloudQueueClient();
var queue = queueClient.GetQueueReference("report-request");
configureQueues(); queue.CreateIfNotExists();
}
JobHost host = new JobHost(); }
host.RunAndBlock();

60 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com


codemag.com Title article 61
Figure 4: The report-request queue created when the WebJob starts up

Figure 5: Manually add a new message to the queue.

Listing 2: The public, static method, ReadReportRequestQueue filled in correctly. If you dont make the changes manu-
using Microsoft.Azure.WebJobs; ally, all of your new files will, by default, be in a different
using System.IO; namespace. I expect Microsoft to clean this up in some
future version of the project template.
namespace CloudReporting.WebJobs
{ Add a new Class to the WebJobs project and name it Run-
public class RunReport Report.cs. Add a using statement at the top for Microsoft.
{ Azure.WebJobs. This namespace contains the attributes
public static void ReadReportRequestQueue([QueueTrigger("report- youre going to add to some of the method parameters as
request")] string request, TextWriter log) well as some handy classes for building WebJobs. Make
{ the class public and add a new public, static method
log.WriteLine("Read from Report Request Queue: " + request); named ReadReportRequestQueue, as shown in Listing 2.
}
} Although most developers have seen attributes applied
} to classes, methods, and properties, it might be odd to
see them applied to method parameters. In this case, the
first parameter is a string named request, which has a
Right-click on the project and choose Properties. Change QueueTrigger attribute applied to it and that performs
the Assembly name and Default namespace to CloudRe- some magic for us. When this attribute is applied, the
porting.Webjobs. There appears to be a bug in the proj- WebJobs SDK uses the AzureWebJobsStorage connection
ect template that prevents these properties from being string in the app.config file that you configured earlier to

62 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com


log into your Storage account, looks for a queue named Listing 3: Adding public properties
Report-Request, and waits for queue entries to show up
namespace CloudReporting.Reports
in the queue. When they do, this method is triggered for
{
you and the payload of the queue entry gets stuffed into
public class ReportParameters
the request parameter. Thats a lot of plumbing work to {
get just by adding an attribute to your parameter! There public string Category { get; set; } = string.Empty;
are several attributes like this one that you can use to public string Format { get; set; } = string.Empty;
wire up plumbing. This one listens to an Azure Storage public string To { get; set; } = string.Empty;
queue, but there are many others. The second parameter public string From { get; set; } = string.Empty;
is a TextWriter named log that the WebJobs SDK provides public string Subject { get; set; } = string.Empty;
for you if you want to use it. There are a few such magic public Guid SessionId { get; set; } = Guid.Empty;
parameters you can add to your method calls, but this }
is the most common. I suggest downloading the Quick }
Reference PDF that outlines all of the attributes and spe-
cial parameter types available in the SDK from http://
go.microsoft.com/fwlink/?LinkID=524028&clcid=0x409. Listing 4: Add a few logging calls
public static void ReadReportRequestQueue([QueueTrigger("report-
How does this magic work? When the app is loaded and request")] ReportParameters request, TextWriter log)
JobHost.RunAndBlock() is called, the app is scanned (us- {
ing Reflection) for public classes with public, static meth- log.WriteLine("Read from Report Request Queue.");
ods and the method parameters are examined for type and log.WriteLine(" to: " + request.To);
attributes. The app then listens for the specified events log.WriteLine(" from: " + request.From);
and, when they occur, makes calls to your methods. This log.WriteLine(" subject: " + request.Subject);
is actually pretty similar to how ASP.NET MVC finds startup }

Figure 6: View the log for the WebJob.

codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 63


code, controllers, etc., and wires them up for you. So its Press F5 again and run the app. There will be a lot less
really JobHost that uses Azures WebHooks, a polling sys- chatter on the screen this time because were not running
tem and/or timers to listen and wait for events that trigger the sample code anymore. It only shows that it found your
calls to your methods. Its also JobHost that creates and ReadReportRequestQueue function and started running.
passes the TextWriter to you in a process similar to depen- If you take a look in Cloud Explorer, you should also see
dency injection. All of that plumbing work comes from the that it created the report-request queue that you speci-
WebJobs SDK so you can concentrate on writing logic. fied in Main.cs, as shown in Figure 4.

Double-click on the report-request queue in Cloud Ex-


Listing 5: The RunReport.cs plorer, click the Add Message toolbar button, enter some
text, and click OK, as shown in Figure 5. Youll see your
public static void ReadReportRequestQueue([QueueTrigger("report-
request")] ReportParameters request, TextWriter log)
message added to the queue, and then a few moments
{ later, youll see a message on the WebJob console win-
log.WriteLine("Read from Report Request Queue."); dow indicating that it saw your queue entry and executed
var pdf = getReport(request.Category, request.Format, log); your ReadReportRequestQueue method. If you refresh the
if (pdf == null) queue in Cloud Explorer, the message will be gone.
{
log.WriteLine("Failed to send report to: " + request.To); In Cloud Explorer, double-click on the azure-webjobs-
sendEmail(request.From, "helpdesk@mycompany.com", request. hosts Blob Container, open the output-logs folder, and
Subject, "Please check the WebJob logs.", null); double-click on the most recent entry, as shown in Figure
return; 6. This is where your WebJob log entries are written when
} you use the TextWriter parameter in a WebJob function.
log.WriteLine("Susscessfully sent report to: " + request.To); Each entry is the summation of everything written to the
sendEmail(request.From, request.To, request. TextWriter within the entire function call.
Subject, "You must have a PDF reader installed on your machine to open the report.", pdf);
} But Wait! Theres More!
If thats all that the WebJobs SDK did for you, It would be
a lot, but theres more. In this first example, you want to
Listing 6: Connect to the queue generate a report and email it to someone when its ready,
so it would make sense to pass in an object containing the
public EmailReportResponse Get(string category, string format, string email) To and From email addresses and the Subject of the email.
{
Youve probably noticed that the queues payload is a string,
try
{
but what if you want to pass something more sophisticated?
var response = new EmailReportResponse(); Because JSON can represent complex objects as a string, its
var parameters = new ReportParameters not a big leap to serialize the object into JSON before you
{ put it on the queue and then de-serialize it back into an
Category = category, object before you use it in the function. Because the SDK is
Format = format, already doing a lot of work for you, between spotting new
To = email, queue entries and calling your functions, its not surprising
From = "system@cloudreporting.com", that the authors of the SDK thought of this. Deserialization
Subject = "Here is your report" of parameters into objects is handled automatically.
};
Add a new class to the CloudReporting.Reports project
var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionString
(so that it can be shared with other projects later) and
s["AzureWebJobsStorage"].ConnectionString);
var queueClient = storageAccount.CreateCloudQueueClient();
name it ReportParameters. Add public properties for Cat-
var queue = queueClient.GetQueueReference("report-request"); egory, Format, To, From, Subject and SessionId (which
queue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(parameters))); youll use later), as shown in Listing 3.

response.Success = true; Next, add a reference to both the CloudReporting.Reports


return response; and CloudReporting.DataRepository projects. Change the
} request parameter type from string to ReportParameters in
catch (Exception ex) RunReport.cs. Add a few logging calls to echo out the values
{ of the properties, as shown in Listing 4. If you get an error
//Log the error here. on build, check the references for the WebJobs project. If
return new EmailReportResponse theres a problem with the references to the other projects,
{
it may be because those projects were created with .NET
Success = false,
FailureInformation = "Could not queue report."
Framework 4.6.1. You may need to update the framework
}; version in the WebJobs project via the project properties.
}
} Press F5 to run the WebJob again. Open up the queue in
Cloud Explorer and add a new queue entry. This time, for
public class EmailReportResponse the message, type in the following JSON:
{
public bool Success { get; set; } = false; {
public string FailureInformation { get; set; } = string.Empty; To: "myemail@mycompany.com",
} From: "system@cloudreporting.com",

64 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com


Subject: "Here is your report" an error processing the request, check the logs. It may be
} because you cut and pasted the JSON and the parser didnt
like the fancy quotes. You may want to try typing in the
Once the WebJob is processed, open the log in the azure- JSON. If you dont receive the email, you may not have
webjobs-hosts Blob Container and verify that the data is replaced the sample email address with your own.
correct. Note that you may have to refresh the data in
Cloud Explorer. Be aware that the maximum message size
for a Storage Queue message is 64k, so your serialized Listing 7: Add a fourth sessionID parameter
JSON payload cannot exceed 64k.
public static void Register(HttpConfiguration config)
{
Because youre going to be generating reports in the WebJob,
config.SuppressDefaultHostAuthentication();
youll need to add the same Microsoft.ReportViewer.2015 config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
NuGet package to the WebJobs project that you added to the
MVC project in the last article. Also, add a reference to Sys- config.MapHttpAttributeRoutes();
tem.Web, which is required by the ReportViewer control to
work properly. The actual code for generating the report and config.Routes.MapHttpRoute(
sending emails can be found in the accompanying source name: "DefaultApi",
code download for this article. The mechanics of generating routeTemplate: "api/{controller}/{category}/{format}/{email}/{sessionId}/",
the report was well covered in the last article, so I wont list defaults: new { category = RouteParameter.Optional,
that code here. The logic for using the report in the WebJob format = RouteParameter.Optional,
can be found in RunReport.cs, as shown in Listing 5. email = RouteParameter.Optional,
sessionId = RouteParameter.Optional }
);
You can test the report and email by manually adding an
}
entry to the queue with the following JSON. If you run into

Figure 7: Test queueing a report to be emailed

Figure 8: Create an Azure Service Bus Namespace.

codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 65


{ Triggering WebJobs from a Service Call
Category: "Bikes", Up until now, youve been manually starting jobs by adding
Format: "PDF", entries to an Azure Storage queue. You could ask your client
To: "myemail@mycompany.com", app developers to use the Azure Storage queue REST API to
From: "system@cloudreporting.com", add new requests to the queue, but itll be easier for them if
Subject: "Here is your report" you just add service calls to the existing WebAPI services and
} have the services communicate with the queues.

Figure 9: Add the connection string for the new Service Bus Namespace.

Listing 8: Create the request and response Service Bus queues


private static void configureQueues() var queueDescription = new QueueDescription("report-request");
{ queueDescription.RequiresSession = false;
//Azure Storage queue queueDescription.MaxDeliveryCount = 1;
var storageConn = ConfigurationManager.ConnectionStrings["AzureWebJobsSto queueDescription.DefaultMessageTimeToLive = new TimeSpan(1, 0, 0);
rage"].ConnectionString; namespaceManager.CreateQueue(queueDescription);
var storageAccount = CloudStorageAccount.Parse(storageConn); }
var queueClient = storageAccount.CreateCloudQueueClient();
var queue = queueClient.GetQueueReference("report-request"); //Azure Service Bus Response Queue
queue.CreateIfNotExists(); if (!namespaceManager.QueueExists("report-response"))
{
//Azure Service Bus Request Queue var queueDescription = new QueueDescription("report-response");
var servBusConn = ConfigurationManager.ConnectionStrings["AzureWebJobsSer queueDescription.RequiresSession = true;
viceBus"].ConnectionString; queueDescription.MaxDeliveryCount = 1;
var namespaceManager = NamespaceManager.CreateFromConnectionString(serv queueDescription.DefaultMessageTimeToLive = new TimeSpan(1, 0, 0);
BusConn); namespaceManager.CreateQueue(queueDescription);
if (!namespaceManager.QueueExists("report-request")) }
{ }

66 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com


Because youll be working with Azure Storage Queues in and the WebJob to get status updates and/or be notified
the service calls, add the WindowsAzure.Storage NuGet when a process is complete? Could you have the WebJob put
package to the MVC project. Its already being used in status messages on a response queue to be picked up by the
the WebJobs project, thanks to the WebJobs project tem- caller? Storage queues dont allow you to direct a message to
plate that you used. Open ReportController.cs in the MVC a particular consumer. Consumers of a Storage queue cant
project and add a new Get method with three string pa- ask for only messages pertaining to them and they cant
rameters: category, format and email. The code you use to
connect to the queue is almost identical to the code you
used to initialize the queue in Program.cs in the WebJobs
project, so the code in Listing 6 should look familiar.

The code you use to connect


to the queue is almost
identical to the code
you used to initialize
the queue in Program.cs
in the WebJobs project.

Copy the two connection strings related to Storage Queues


from the app.config in the WebJobs project into the
web.config in the MVC project. Not only will the service
call in the MVC project need this information to find the
queue, when you later deploy the WebJobs as part of the
MVC application, the WebJobs reads their settings from the
web.config and not from their own app.config files.

Because youre adding a new GET WebAPI call with a third


parameter, make sure to allow for up to three optional pa-
rameters in the routeTemplate in WebAPIConfig.cs. In fact,
youre going to add a fourth sessionId parameter as well
because youll be using that later, as shown in Listing 7.

Right-click on the solution and choose Set Startup Proj- Figure 10: Use Server Explorer to test and modify Service Bus queues.
ects Choose Set Multiple Startup Projects, and set both
the MVC and WebJobs project to start. When you run the
code, you can test the WebAPI call by adding /api/report/ Listing 9:Tell the JobHost to use the Service Bus queues
clothing/pdf/myemail@mycompany.com/ to the site static void Main()
URL. Most modern browsers URL-encode the @ symbol {
in the email address for you, but if your browser doesnt, if (!VerifyConfiguration())
you can replace @ with %40. Make sure to end the URL {
with a forward slash so that both the @ and period in the Console.ReadLine();
email address are handled properly, as shown in Figure return;
7. Dont forget to use your email address in the URL. The }
service call returns almost instantly with success, as long
as the request can be put on the queue. Success, in this configureQueues();
case, doesnt indicate that the report has run or will run
var config = new JobHostConfiguration();
successfully, only that the request is successfully queued
config.UseServiceBus();
and that is a very fast operation. config.Queues.BatchSize = 1;
JobHost host = new JobHost(config);
Using Service Bus Queues for Better Communication host.RunAndBlock();
Up until now, youve used WebJobs to run potentially long }
running tasks outside of the clients process and used Azure
Storage queues to trigger those tasks. This is a powerful pat-
tern, but it also has some limitations. The nature of Storage
queues is that a client drops a message on a queue in a fire- Listing 10: Add a new class to the Reports project
and-forget fashion, and then the message is picked up by public class ReportStatusResponse
a single instance of a WebJob or by any one of an army of {
dozens, hundreds, or even thousands of WebJob instances. public bool IsProcessComplete { get; set; } = false;
This gives you a fast user experience, allows you to achieve public string Message { get; set; } = string.Empty;
immense scale, and to size and scale the WebJobs separately public int Count { get; set; } = 0;
from the rest of the system. But what if you want to go be- public int TotalCount { get; set; } = 0;
yond fire-and-forget and communicate between the client }

codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 67


inspect the entire queue and grab certain messages from it. Service Bus queues are considerably more capable than
This type of queue is designed only to hand out messages Storage queues and the most interesting feature of Ser-
from the top of the queue to whatever process asks for those vice Bus queues, for my purposes, is the Session. To use
messages. Its not designed for point-to-point communica- sessions, the client passes a SessionId (a string) to the
tion, but theres another type of queue that can do this. WebJob as a regular parameter. The WebJob stamps all
of the messages it puts on the response queue with the
SessionId it was passed. The client can then pick up all
Listing 11: The SDK connect to the queue and passes a parameter response messages stamped with that SessionId.
public static void ReadReportRequestQueue([ServiceBusTrigger("report-
request")] ReportParameters request, Start by creating a new Service Bus Namespace in the Azure
[ServiceBus("report- portal. I named mine codecloudreporting. Choose the
response")] ICollector<BrokeredMessage> responseQueue, TextWriter log) Standard pricing plan that costs about ten dollars per 12.5
{ million messages per month. The Basic tier doesnt support
var sessionId = request.SessionId.ToString(); Sessions. Choose the location nearest to you for best per-
var msg = "Read from Report Request Queue."; formance, as shown in Figure 8. As Im writing this article,
log.WriteLine(msg); access to Service Bus within the new portal has just gone
var queueMsg = new ReportStatusResponse { Message = msg }; into Preview. Ive experienced some issues and limitations
responseQueue.Add(new BrokeredMessage(queueMsg) { SessionId = sessionId }); that I hope will be worked out by the time you read this. If
not, you may have to use the old portal for some things, as
var pdf = getReport(request.Category, request.Format, responseQueue, sessionId, log);
if (pdf == null)
I did. As always, when viewing pricing tiers in the portal,
{ you may have to switch from Recommended to View all in
msg = "Failed to send report to: " + request.To; order to see all of the pricing tier options available to you.
log.WriteLine(msg);
queueMsg = new ReportStatusResponse { Message = msg, IsProcessComplete = true };
responseQueue.Add(new BrokeredMessage(queueMsg) { SessionId = sessionId });
Service Bus queues
sendEmail(request.From, "helpdesk@mycompany. are considerably
com", "Emailing failed", "Please check the WebJob logs.", null);
more capable than
return;
} Storage queues

sendEmail(request.From, request.To, request.


Subject, "You must have a PDF reader installed on your machine to open the report.", pdf);
You may have to refresh the screen to see the new Ser-
msg = "Successfully sent report to: " + request.To; vice Bus Namespace. Once it appears, open the Set-
log.WriteLine(msg); tings, click on Shared access policies, and then open the
queueMsg = new ReportStatusResponse { Message = msg, IsProcessComplete = true }; RootManageSharedAccessKey and copy the Connection
responseQueue.Add(new BrokeredMessage(queueMsg) { SessionId = sessionId }); String Primary Key to your clipboard. Open the app.config
} file for the WebJobs project and add a new connec-
tion string with name=AzureWebJobsServiceBus and
connectionstring=<paste your connection string here>,
Listing 12: Add static fields and properties for the service bus connection string as shown in Figure 9. Dont remove the existing connec-
tion strings, as the SDK uses these for logging, even if
public class ReportController : ApiController your code is using Service Bus. Ive noticed that some
{ of the newer NuGet packages add an example key to the
private static string _servicesBusConnectionString = ConfigurationManager.ConnectionStri
appSetting section instead of the connectionStrings sec-
ngs["AzureWebJobsServiceBus"].ConnectionString;
tion. Either method should work by modifying where you
private static NamespaceManager _namespaceMgr = null; look in the .config file, but the sample code expects it in
protected static NamespaceManager NamespaceMgr the connectionStrings section. Copy the same connection
{ string into the web.config file of the MVC project so that
get its available to the WebJob when you deploy to Azure.
{
if (_namespaceMgr == null) _namespaceMgr = NamespaceManager. Right-click on the solution and add the NuGet package
CreateFromConnectionString(_servicesBusConnectionString); Microsoft.Azure.Webjobs.ServiceBus to both the WebJobs
return _namespaceMgr; and MVC projects. This package extends the plumbing that
} you used earlier to automatically attach to an Azure Storage
} queue by applying the QueueTrigger attribute to a param-
eter in the WebJob. It adds some additional attributes that
private static MessagingFactory _msgFactory = null;
work with Azure Service Bus in a similar way. It also adds the
public static MessagingFactory MsgFactory
{ classes that you need to manage Service Bus queues.
get
{ Edit the configureQueues method in Program.cs in the Web-
if (_msgFactory == null) _msgFactory = MessagingFactory.Create(NamespaceMgr. Jobs project to create the request and response Service Bus
Address, NamespaceMgr.Settings.TokenProvider); queues if they dont already exist, as shown in Listing 8.
return _msgFactory;
} Notice that the RequiresSession property is set to false for
} the request queue and set to true for the response queue.

68 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com


codemag.com Title article 69
This allows any number of instances of the WebJob to pro- sive tool for modifying queues that Ive found. Oddly,
cess the initial request from the request queue but it only Cloud Explorer has only limited support for Service Bus.
allows the client to ask for messages from the response
queue that are stamped with the clients SessionId. Open RunReport.cs and change the QueueTrigger attri-
Messages in both queues will be killed off if theyre not bute to a ServiceBusTrigger attribute. The name of the
processed within one hour. This keeps orphaned mes- queue is the same. At this point, youve replicated the
sages from accumulating in the queue forever if theres a functionality that you had with Storage queues, allowing
problem with the system. Also MaxDeliveryCount is set to the WebJob to pick up requests from the request queue
one so that any failed deliveries wont be retried. and process them. Next, youll edit the code in the Run-
Report class to write responses on the response queue
Edit the Main method by calling JobHost with an instance that can be retrieved by the original caller.
of JobHostConfiguration, directing it to use Service Bus
queues, as shown in Listing 9. Add a new class to the Reports project, as shown in List-
ing 10. This class contains the structure of the response
Press F5 to run and create the queues. Open Server Ex- queue messages the WebJob sends back to the client.
plorer (not Cloud Explorer) in Visual Studio and connect
to your Azure account, if you havent already. Open the Again, you let the WebJobs SDK take care of the plumbing
Service Bus node and find your queues. Server Explorer for you to get access to the response queue. You simply
is a handy tool to use when developing and testing with add a parameter to the ReadReportRequestQueue method
Azure Service Bus, allowing you to test sending and re- that is of type ICollector<BrokeredMessage> and has the
ceiving messages. It also allows you to Update a queue, attribute [ServiceBus(report-response)]. The SDK con-
as shown in Figure 10, giving you the most comprehen- nects to the queue and passes a parameter that you can
use to write entries into the queue, as shown in Listing 11.

Listing 13: Add a fourth Get method to ReportController.cs Notice that you can add messages to the response queue
public EmailReportResponse Get(string category, string format, string email, Guid sessionId) by simply adding a new instance of BrokeredMessage to re-
{ sponseQueue. BrokeredMessage serializes whatever class is
try passed into its constructor. When putting BrokeredMessages
{ on the response queue, you specify the SessionId passed in
var response = new EmailReportResponse(); by the original caller so that caller can request only status
var parameters = new ReportParameters messages on the response queue intended for them. For
{ demonstration purposes, Ive also added some code to the
Category = category, getData method to simulate a long process, which sends ten
Format = format,
status update messages and includes a Thread.Sleep call that
To = email,
From = "system@cloudreporting.com",
pauses for two seconds between each message.
Subject = "Here is your report",
SessionId = sessionId, Now that the WebJob can respond to the request queue
}; and post status updates on the response queue, you need
to update the services to point to the Service Bus queues
var queueClient = MsgFactory.CreateQueueClient("report-request"); instead of the Storage queue. Open ReportController.cs
queueClient.Send(new BrokeredMessage(parameters)); in the MVC project and add static fields and properties
for the service bus connection string, NamespaceManager
response.Success = true; and MessageFactory so that you dont have to repeat that
return response; code in every method call, as shown in Listing 12.
}
catch (Exception ex)
Add a fourth Get method to ReportController.cs, which
{
//Log the error here.
takes a fourth parameter and returns an EmailReportRe-
return new EmailReportResponse sponse, as shown in Listing 13.
{
Success = false, Notice that this method passes the sessionId as a param-
FailureInformation = "Could not queue report.", eter to the WebJob.
};
} Add a new WebAPI service call to the MVC project to re-
} trieve status updates by adding a new method to Report-

Figure 11: Status messages from the WebJob

70 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com


Controller.cs, then add the GetQueuesReportStatusRe- Listing 14: Add the GetQueuesReportStatusResponse class
sponse class below, as shown in Listing 14.
public GetQueuedReportStatusResponse GetQueuedReportStatus(Guid sessionId)
{
This code connects to the response queue, asks for any
try
messages on the queue that have the specified SessionId,
{
and returns all of the messages to the caller.
var response = new GetQueuedReportStatusResponse();
Because this call expects a GUID as a parameter, you have
var queueClient = MsgFactory.CreateQueueClient("report-response", ReceiveMode.
to update WebApiConfig.cs with a new route, as shown in ReceiveAndDelete);
Listing 15. If you fail to do this, the parameter is inter- var messageSession = queueClient.AcceptMessageSession(sessionId.
preted as a string and is sent to the original GET method ToString(), new TimeSpan(100));
of the Report controller, which returns the raw data for var brokeredMessage = messageSession.Receive(new TimeSpan(1));
the report. Make sure to put this route above the default while (brokeredMessage != null)
route so that it gets evaluated first. {
response.Messages.Add(brokeredMessage.GetBody<ReportStatusResponse>());
Incorporate WebJobs into brokeredMessage = messageSession.Receive(new TimeSpan(1));
the Sample Web Application }
Up to this point, you havent updated the ASP.NET client messageSession.Close();
application to work with the new WebJobs capability of
sending the report by email and receiving progress noti- response.Success = true;
fications. Open Index.cshtml in the Views -> Home folder return response;
of the MVC project. Add an input box for an email address, }
a button to email the report and an unordered list to dis- catch (Exception ex)
play status messages, as shown in Listing 16. {
//Log the error here.
Inside the script tag, below the DownloadReport func- return new GetQueuedReportStatusResponse
tion, add the two functions shown in Listing 17. {
Success = false,
The EmailReport function queues up a request for the Web- FailureInformation = "Could not get queued report status."
Job, passing along the email address entered by the user and };
a GUID used as a unique session ID. JavaScript and JQuery }
dont have native functions to create GUIDs, so I download- }
ed the generateGUID function from the Internet. If the call is
successful, it passes the same GUID as the SessionId to the public class GetQueuedReportStatusResponse
GetStatusMessages function, which polls the WebAPI service {
for status updates and displays the status messages in the public bool Success { get; set; } = false;
unordered list. Once the function receives a message indi- public string FailureInformation { get; set; } = string.Empty;
public List<ReportStatusResponse> Messages { get; set; } = new List<ReportStatusResponse>();
cating that the process is complete, it exits the polling loop.
}
This code doesnt contain a lot of error handling, so that it
could be kept as simple as possible for this example.

Press F5 to run the solution. Enter an email address in the Listing 15: Update WebApiConfig.cs with a new route
textbox and press the button to test the app. The results
should look something like Figure 11. config.Routes.MapHttpRoute(
name: "statusUpdatesApi",
Deploy to Azure routeTemplate: "api/{controller}/{sessionId}/",
defaults: new { },
The final step is to deploy the updated website and the
constraints: new
new WebJobs project to Azure. One option often used in
{
production is to use the Publish wizard on the WebJobs
sessionId = @"^[{(]?[0-9A-F]{8}[-]?([0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$"
project to deploy the WebJobs independently from the
} //must be a Guid
website. In production, thiss often the best choice, as it
);
not only allows you to deploy WebJobs independently, but
also allows you to scale them independently. For the pur-
poses of this sample, youre going to bundle the website
and the WebJobs so that theyre deployed together and Listing 16: Add an input box
run within the same App Service. Right-click on the MVC
<div class="jumbotron">
project, choose Add -> Existing Project as Azure WebJob.
<h1>Testing Report Services</h1>
Youll have to either remove the period from the WebJob
<p class="lead">Press the button to call our ASP.NET Web API service and get a PDF.</p>
name or replace it with a dash to make the name valid.
<p><button onclick="DownloadReport()">Download Report</button></p>
Set the run mode to Run Continuously. This mode runs the
<p>Email: <input id="emailAddress" /> <button onclick="EmailReport()">Email Report</
WebJob immediately upon deployment so that the Web-
button></p>
Job can begin monitoring the queues. If you look under </div>
the Properties node in the MVC project, youll see that all <div class="row">
it does is add a webjobs-list.json file to the project. You <ul id="statusMessages"></ul>
can edit this file if you want to change any of your selec- </div>
tions. If you didnt copy the connection strings from the

codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 71


Listing 17: Add two functions inside the script tag
function EmailReport() { url: "/api/report/" + sessionId + "/",
var email = $("#emailAddress").val(); success: function (statusResult) {
var sessionId = generateGUID(); if (statusResult.Success) {
$.ajax({ for (var i in statusResult.Messages) {
url: "/api/report/bikes/pdf/" + email + "/" + sessionId + "/", var currentMessage = statusResult.Messages[i];
success: function (result) { var display = currentMessage.Message;
if (result.Success) { if (currentMessage.
$("#statusMessages").empty(); Count > 0) { display = display + " " + currentMessage.
$("#statusMessages"). Count + " of " + currentMessage.TotalCount; }
append("<li>Request was successfully queued.</li>"); $("#statusMessages").
GetStatusMessages(sessionId); append("<li>" + display + "</li>");
} if (currentMessage.IsProcessComplete) {
else { clearInterval(timerHandle);
alert(result.FailureInformation); }
} }
}, waitingOnLastResponse = false;
error: function (xhr, status, error) { }
alert(error); else {
} alert(statusResult.FailureInformation);
}); }
} },
error: function (xhr, status, error) {
function GetStatusMessages(sessionId) { alert(error);
var waitingOnLastResponse = false; }
var timerHandle = setInterval(function () { })
if (waitingOnLastResponse == false) { }
waitingOnLastResponse = true; }, 2000);
$.ajax({ }

app.config file in the WebJobs project to the web.config in the title bar. As I write this, Im getting an errone-
SPONSORED SIDEBAR: file in the MVC project, nows your chance. When you de- ous error message that the AzureWebJobsDashboard con-
ploy WebJobs as part of a Web application, they become nection string is missing or invalid, however when I click
New State of .NET Events part of the Web app and only the web.config is deployed. on the Toggle Output button, I can see the trace logger
Announced messages indicating that, in my case, the issue is being
San FranciscoNov 9, 2016; If you deployed the project from the previous article to caused by Azure not being able to connect to my local
Los AngelesNov 10, 2016; Azure, your Publish profile is already set up. Otherwise, email server. After changing my email server to point to
HoustonDec 12, 2016; step through the Publish wizard for the MVC app to cre- the free SendGrid account I set up in Azure, the app works
DallasDec 13, 2016 ate a new App Service in Azure and deploy to it. Make as expected.
sure that the App Service you deploy to is not set to the
Claim your chance to get a Free or Shared pricing tier. Use at least the Basic tier. Conclusion
free, unbiased look at .NET and This comes from a limitation in rendering reports using In this article, you started with a problem: How to handle
relevant technologies. the Visual Studio reporting control and not from WebJobs long-running service calls that timed out on users and
or Service Bus queues. After a successful deployment, a how to handle such calls on a massive scale without hav-
Attendees of this event will
browser comes up showing the website running in Azure. ing to scale up the entire app. You imagined a long-run-
come away with a clear
Type in an email address and send the email. There is a ning report that could not only cause timeouts for end us-
understanding of which
strong chance that the process will fail. ers, but could also bog down the Web servers if too many
technologies to use for various
technical challenges and what clients wanted to run these reports. I introduced WebJobs
you can do today to make as a way to offload the long-running process, allowing
sure that your code is ready users to trigger report generation, then go about their
If you didnt copy the business without having to wait for the report to finish.
for the future.
connection strings from Splitting out the long-running process in a WebJob also
Register to attend at the app.config file in the allowed you to run these tasks on the same or different
www.StateofDotNet.com; WebJobs project to the hardware if you chose, and allowed you to scale both up
space is limited! web.config file in the MVC and out, independent of the website and WebAPI service
calls. To trigger the long-running reports, you used Azure
project, nows your chance.
Storage queues to communicate with the WebJobs. To
make things easy for the end user application developers,
you wrapped all of this up behind a WebAPI call so that
Because you didnt include any robust error handling in they wouldnt have to know anything about queues or
the WebJobs project, you should check the WebJobs log WebJobs. They could continue developing against familiar
for clues. Open the Azure Portal, navigate to the App Ser- WebAPI calls as they always had. Not content with fire-
vice and click on WebJobs under the settings section to and-forget calls, you changed from using Azure Storage
see the deployed WebJob and its current status, which queues to more powerful Azure Service Bus queues, which
should be Running. Select the WebJob and click on Logs allowed your WebJobs to send status messages about the

72 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com


CODE COMPILERS

progress of the long running jobs so that the end mon problems facing modern application devel-
user applications could be updated as work pro- opers. In future articles, I hope to cover some of
gressed, if they chose. the advanced topics, like Functions (the next level
of WebJobs) and Service Bus Topics (a different Nov/Dec 2016
Finally, you updated the sample end-user client take on queues). Until then, have fun adding new Volume 17 Issue 6
application, an ASP.NET MVC website to make use tools to your Azure toolbox.
of the new features, and then published every- Group Publisher
thing to Azure for testing, QA, and eventually for Mike Yeager Markus Egger
final deployment. Along the way, you discovered Associate Publisher
Rick Strahl
some useful tools like Visual Studios Cloud Ex-
plorer and Server Explorer that make working with Editor-in-Chief
Rod Paddock
Azure a whole lot easier. I only touched the sur-
Managing Editor
face of the capabilities of WebJobs and the Azure Ellen Whitney
Service Bus, and the app isnt quite ready for
Content Editor
production use, but you covered a lot of ground Melanie Spiller
and ended up with a concrete example that can
Writers In This Issue
be modified and extended to address a lot of com- Jason Bender Billy Hollis
Wei-Meng Lee Sahil Malik
Ted Neward John Petersen
Rachel Reese Paul Sheriff
Mike Yeager
Technical Reviewers
(Continued from 74) However, in general, it begins somewhere, and Markus Egger
often it begins with the groups nominal leader Rod Paddock
cessful groups individual attributes, the success- thats you, the team lead or the managerof- Art & Layout
ful groups did two things well: fering up some degree of vulnerability to them. King Laurin GmbH
info@raffeiner.bz.it
Ensure that the others talk; give them room and
They more-or-less-evenly split up the time to make their opinions known, and respect Production
Franz Wimmer
talk time. Quite literally, the researchers those opinions even if you disagree. (And in no King Laurin GmbH
referred to it as equality in distribution way can you shoot them down publicly when 39057 St. Michael/Eppan, Italy
of conversational turn-taking. So long as seeking to building this safe zone.) But it can Printing
each member got a chance to talk, the group require more than that; sometimes, you have to Fry Communications, Inc.
as a whole did well. If only one person, or a open up and talk about things yourself, which, if 800 West Church Rd.
Mechanicsburg, PA 17055
small subset of the group did all the talking, the group desires, could be hurtful if they react
Advertising Sales
the group performed far less well. badly to it. Talk about your concerns, your goals, Tammy Ferguson
They had high average social sensitiv- your secret fears. Talk about things that make you 832-717-4445 ext 026
ity. Or, put another way, the good groups human and not just a body in a suit. tammy@codemag.com
were skilled in intuiting how others felt Circulation & Distribution
based on all the non-verbal cues like tone Make no mistake: This can be a terrifying mo- General Circulation: EPS Software Corp.
International Bonded Couriers (IBC)
of voice and facial expressions. If a group ment, particularly as you are now wagering with Newsstand: Ingram Periodicals, Inc.
could tune in when one of their members that most valuable commodity of all, the human Media Solutions
was feeling upset or left out, they had a ego. But if the goal is to create a safe place, the Subscriptions
much better chance of keeping all the mem- only way to demonstrate that it is safe is to show Subscription Manager
bers collectively feeling connected. some faith and trust in the people around you Colleen Cade
832-717-4445 ext 028
by offering that very same valuable commodity ccade@codemag.com
These qualities both contribute to what psycholo- up to the group for embarrassment, rejection, or
gists call psychological safetya sense of confi- punishment, and allowing them to see that such US subscriptions are US $29.99 for one year. Subscriptions
outside the US are US $44.99. Payments should be made
dence that the team will not embarrass, reject, or reactions are not forthcoming. In other words, as in US dollars drawn on a US bank. American Express,
punish someone for speaking up. Bren Brown has pointed out in her TED talk en- MasterCard, Visa, and Discover credit cards accepted.
titled The power of vulnerability, sometimes the Bill me option is available only for US subscriptions. Back
issues are available. For subscription information, email
Interestingly enough, some of the practices of an best things can only happen when you deliber- subscriptions@codemag.com
agile teamthe daily standup, for exampleac- ately open yourself up to other people. or contact customer service at
cidentally contribute to this kind of environment. 832-717-4445 ext 028.
But at the same time, its not simply sufficient Give it a shot.
to just enforce a strict talk timer. Psychological Subscribe online at
www.codemag.com
safety suggests that the other members of the (This was inspired by a column from the New
team trust each other, professionally and (to a York Times: What Google Learned From Its Quest CODE Developer Magazine
degree) emotionally, and theres nothing in the to Build the Perfect Team, available at http:// 6605 Cypresswood Drive, Ste 300, Spring, Texas 77379
Phone: 832-717-4445
Agile Manifesto that describes how to build that. www.nytimes.com/2016/02/28/magazine/what- Fax: 832-717-4460
google-learned-from-its-quest-to-build-the-per-
fect-team.html. Those interested in more about
Summary the power of vulnerability should see Browns TED
How best, then, to create this kind of environment? talk of that name, or check out her book Daring
Greatly.)
Alas, not all answers are easily forthcoming. What
might work for one team may horribly backfire for Ted Neward
another.

codemag.com Managed Coder 73


MANAGED CODER

On Strong Teams
For an industry that prides itself on its analytical ability and abstract mental processing, we often dont
do a great job applying that mental skill to the most important element of the programmers tool
chestthat is, ourselves.

Have you ever been part of one of those teams Should there be any real doubt as to the veracity According to Abeer Dubey, one of the Googlers in-
where everything just seems to be awesome? of these claims, one need only tune in to any sea- volved with the study, We had lots of data, but
son of televisions The Apprentice, where two there was nothing showing that a mix of specific
Seriously. Somehow, the team gels. Everybody teams are formed out of the participants randomly personality types or skills or backgrounds made
doesnt actually like each other, or at least thats and compete against each other under particular any difference. The who part of the equation
what they say, but somehow, everybody feels con- business conditions only to see that coming to a didnt seem to matter.
nected. Theres little to no tension, and any ten- highly effective team state isnt easy.
sion that does emerge seems like it gets handled So if its not who, then what?
without management getting involved (and cer- Whats worse, this is not just some academic
tainly without getting HR into the picture). The exercise; The days of the developer in the dark
team is productive, innovative, responsive to room have long since ended, and a recent study Group Norms
changing criteria, you name it. by the Harvard Business Review (https://hbr. It turns out that in any group, theres an unwrit-
org/2016/01/collaborative-overload) has discov- ten set of rules that the group comes to embrace
Having been a part of that team before, youre ered that the time spent by managers and em- collectively, often without discussing it outright.
reluctant to leave work for the day, loathe to ac- ployees in collaborative activities has ballooned Psychologists and sociologists call these group
tually leave the company, and you spend the rest by 50 percent or more over the last two decades. norms: behavioral standards, traditions if you
of your career trying to recreate that experience. In fact, some firms find that more than three- will, that the group follows when interacting with
quarters of an employees day is spent communi- one another. They vary from group to group. One
Youre not the only one. cating with colleagues. group may seek to avoid dissent while another
heartily encourages it. One group may deliber-
To paraphrase the American patriot, If we cannot ately seek to allow each person to say their piece
Effective Teams figure out how to work together, we shall surely during a meeting, while another simply allows
Various management consultants and Zen mas- hang together. meetings to devolve into chaos. One group may
ters have long sought the key to these kinds of enforce a high degree of politeness and deference
teams and for obvious reasons: if managers can during their discussions, where another one em-
discover how to move through the storm and Research braces argument and even name-calling. Conflicts
into the norm and perform parts of the agile- Google, as it turns out, has been spending a tre- may be sought or downplayed. These norms are
inspired forming/storming/norming/perform- mendous amount of time and energy trying to dis- often completely different from one group to an-
ing cycle, then high team productivity (and man- cover what causes some teams to be successful in other, but theyre always there.
agement promotions) can be had that much more bonding while others dont. Originally, Googles
quickly. In fact, universities and graduate schools, beliefechoed by many experts who were asked And whether explicit or implicit, these group
from the smallest no-name community college to this questionheld that the best teams were norms often trump our individual styles of work.
prestigious schools like Harvard Business School, made up of the best people. And that it was better An employee deeply distrustful of authority may
have their students form into groups for particular to put like-styled people together (like introverts find herself quite enthusiastically going along
projects (or sometimes, for the entirety of their with introverts) or create groups that were made with the ideas of the teams leader. Another one
schooling), so that students can get used to the up of people who were friends both inside and who is habitually early to meetings will embrace
idea of working in teams, rather than as individu- outside of work. But, as is common with many of the groups more casual grip on time. And so on.
als, as is the case for most of our school careers. these common knowledge kinds of beliefs, nobody
had ever actually studied the effects of doing so So how do these group norms come to be?
But its not just a measure of experience with be- under any kind of scientific conditions.
ing part of a groupits quite common for people
whove been part of one of these exemplary groups In 2012, Google began Project Aristotle to do ex- Talk Time and Social Sensitivity
to turn around and find themselves in groups that actly that and the results are fascinating. In 2008, psychologists from Carnegie Mellon and
are entirely less so, even under similar or near- MIT started a two-year examination of 699 people
identical conditions. In fact, sometimes the group In the earliest stages of the project, they sought split out into various groups over and over again.
can consist of some of the same people as the (as Google does) patterns in the data. They ex- They gave each group relatively trivial tasksgro-
previously exemplary group, but now the magic amined interests, backgrounds, friendships, and cery shopping, for exampleand examined how
is gone for some reason. And it certainly doesnt other interpersonal dynamics, personality styles well each group was able to accomplish its task,
rest with qualities like intelligence or motivation; (introvert, extrovert, etc.), motivational goals and how the group collectively interacted. What
groups can be made up of the smartest and most and/or styles, and pretty much any personal at- they discovered was that regardless of the suc-
highly-motivated participants and still fail to tribute that came to mind. But the harder they
come to any kind of cohesiveness. looked, the more any sort of pattern eluded them. (Continued on page 73)

74 Managed Coder codemag.com

You might also like