You are on page 1of 38

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
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


TABLE OF CONTENTS CODE COMPILERS

progress of the long running jobs so that the end mon problems facing modern application devel-

Features user applications could be updated as work pro-


gressed, if they chose.
opers. In future articles, I hope to cover some of
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
8 The Journey to Angular: Part 4 46 Introduction to Data Science using Python application, an ASP.NET MVC website to make use tools to your Azure toolbox.
Paul continues his deep dive into AngularJS. This time, If youre curious about Data Science or Pythonand if youre interested of the new features, and then published every- Group Publisher
he adds validation to the page so you can spot input errors. in the Internet of Things, you should beyoull find this introduction thing to Azure for testing, QA, and eventually for Mike Yeager Markus Egger
Paul D. Sheriff both important and exciting. Wei-Meng makes it all clear for us by final deployment. Along the way, you discovered Associate Publisher
explaining the basics. Rick Strahl
some useful tools like Visual Studios Cloud Ex-
Wei-Meng Lee plorer and Server Explorer that make working with Editor-in-Chief
14 Angular 2 Forms Rod Paddock
Azure a whole lot easier. I only touched the sur-
Managing Editor
Sahil continues his series on Angular 2 and this time, 58 Azure Skyline: Using WebJobs for Event-Driven, face of the capabilities of WebJobs and the Azure Ellen Whitney
looks at that essential element: the form. Service Bus, and the app isnt quite ready for
Sahil Malik Asynchronous Services production use, but you covered a lot of ground
Content Editor
Melanie Spiller
If your call to services times out after four minutes, you can have a and ended up with a concrete example that can
Writers In This Issue
24 Simplest Thing Possible: problem if the process needed to retrieve the data or a fire-and-forget be modified and extended to address a lot of com- Jason Bender Billy Hollis
operation takes longer than that. What if the user makes a
Dynamic Lambda ExpressionsPart 3 request and then wanders away from the computer?
Wei-Meng Lee
Ted Neward
Sahil Malik
John Petersen
Mike solves it for you with WebJobs in Azure Skyline. Rachel Reese Paul Sheriff
If you want to re-use some of the concepts John introduced in the last two issues, Mike Yeager
youll want to learn all about how Dynamic Lambda Expressions work in .NET. Mike Yeager
Technical Reviewers
John Petersen (Continued from 74) However, in general, it begins somewhere, and Markus Egger
often it begins with the groups nominal leader Rod Paddock
28 Moving Forward:
Columns
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
The Transition from Objective-C to Swift Ensure that the others talk; give them room and info@raffeiner.bz.it

If youve been paying attention to programming trends, youll see that Swift, They more-or-less-evenly split up the time to make their opinions known, and respect Production
Franz Wimmer
Apples new language, is gaining popularity at an impressive rate.
74 Managed Coder: On Strong Teams talk time. Quite literally, the researchers those opinions even if you disagree. (And in no King Laurin GmbH
You dont have to toss out everything you already know, though, referred to it as equality in distribution way can you shoot them down publicly when 39057 St. Michael/Eppan, Italy
as Jason helps you see Swifts similarities to Objective-C. Ted Neward
of conversational turn-taking. So long as seeking to building this safe zone.) But it can Printing
Jason Bender 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

Departments
36 The Resurgence of XAML 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
Microsoft seemed to have put XAML out to pasture for a while, but Billy shows us
They had high average social sensitiv- your secret fears. Talk about things that make you 832-717-4445 ext 026
how its back, and why even Microsoft is touting its praises.
ity. Or, put another way, the good groups human and not just a body in a suit. tammy@codemag.com
Billy Hollis
6 Editorial 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.
42 Case Study: Writing Microservices with F# of voice and facial expressions. If a group ment, particularly as you are now wagering with
International Bonded Couriers (IBC)
Newsstand: Ingram Periodicals, Inc.
If youre lucky enough to be involved in building a new enterprise system,
23 Advertisers Index could tune in when one of their members that most valuable commodity of all, the human Media Solutions
youll want to check this out. Rachel takes a look at how the company was feeling upset or left out, they had a ego. But if the goal is to create a safe place, the Subscriptions
where she works made some interestingand forward-lookingdecisions, much better chance of keeping all the mem- only way to demonstrate that it is safe is to show Subscription Manager
and she shows us the benefits of microservices while shes at it.
73 Code Compilers bers collectively feeling connected. some faith and trust in the people around you Colleen Cade
832-717-4445 ext 028
Rachel Reese 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
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, google-learned-from-its-quest-to-build-the-per-
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 fect-team.html. Those interested in more about
e-mail to subscriptions@codemag.com or contact customer service at 832-717-4445 ext 028. Summary the power of vulnerability should see Browns TED
Subscribe online at codemag.com How best, then, to create this kind of environment? talk of that name, or check out her book Daring
Greatly.)
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.
Alas, not all answers are easily forthcoming. What
might work for one team may horribly backfire for Ted Neward
Canadian Subscriptions: Canada Post Agreement Number 7178957. Send change address information and blocks of undeliverable copies to IBC, 7485 Bath Road, Mississauga, another.
ON L4T 4C1, Canada.

4 Table of Contents codemag.com codemag.com Managed Coder 73


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


ONLINE QUICK ID 00
EDITORIAL

Shokunin
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
How much time are you willing to spend in order to master your craft? This is the $64,000 question. messages on the queue that have the specified SessionId,
{
There are many developers in the world and theres a single trait that separates a great developer from and returns all of the messages to the caller.
var response = new GetQueuedReportStatusResponse();
an average one: dedication to craft. Greatness in any creative pursuit takes dedication. For instance, 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. {
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 response.Messages.Add(brokeredMessage.GetBody<ReportStatusResponse>());
things that make writers great. You must write, prentices. express the deeper meaning. The Japanese Incorporate WebJobs into brokeredMessage = messageSession.Receive(new TimeSpan(1));
and I mean write a LOT. You only get better at apprentice is taught that shokunin means the Sample Web Application }
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 Up to this point, you havent updated the ASP.NET client messageSession.Close();
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- application to work with the new WebJobs capability of
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- sending the report by email and receiving progress noti- response.Success = true;
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 fications. Open Index.cshtml in the Views -> Home folder return response;
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 of the MVC project. Add an input box for an email address, }
forms of a particular craft that you can achieve preparing rice, preparing fish, and ultimately, both spiritual and material, in that no mat- a button to email the report and an unordered list to dis- catch (Exception ex)
greatness. This is true in any creative endeavor. after 10 years as an apprentice, how to prepare ter what it is, the shokunins responsibility play status messages, as shown in Listing 16. {
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 //Log the error here.
Paint. Want to be a photographer? Take pictures. nal step is not fish but eggs. In this documentary, Inside the script tag, below the DownloadReport func- return new GetQueuedReportStatusResponse
Want to be a chef? Cook! one of the apprentices spends literally months I love this term. The concept of shokunin as tion, add the two functions shown in Listing 17. {
perfecting making Tamago. I believe it took over craftsman or artisan is pretty cool, but its the Success = false,
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/ The EmailReport function queues up a request for the Web- FailureInformation = "Could not get queued report status."
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 Job, passing along the email address entered by the user and };
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- a GUID used as a unique session ID. JavaScript and JQuery }
Top Chef, Chopped, Chefs Table, and many colades an apprentice can achieve: Jiro called him ment. This means that when you achieve great- dont have native functions to create GUIDs, so I download- }
others. One of my favorite documentaries is called shokunin. ness, you have an obligation to the community ed the generateGUID function from the Internet. If the call is
Jiro Dreams of Sushi. Jiro Dreams is all about you serve. successful, it passes the same GUID as the SessionId to the public class GetQueuedReportStatusResponse
sushi chef Jiro Ono, who owns Sukiyabashi Jiro, Shokunin is a wonderful Japanese word. GetStatusMessages function, which polls the WebAPI service {
a Michelin three star-rated restaurant in Tokyo. I always look for the reasons I like being a soft- for status updates and displays the status messages in the public bool Success { get; set; } = false;
This documentary is a study of sushi, tradition, The Japanese word shokunin is dened by ware developer and I believe it must have some- 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>();
and dedication to the craft of making perfect su- both Japanese and Japanese-English dic- thing to do with shokunin. Software development cating that the process is complete, it exits the polling loop.
}
shi. The most striking part of this documentary tionaries as craftsman or artisan, but is a service industry and its our responsibility to This code doesnt contain a lot of error handling, so that it
deliver a product that ultimately makes peoples could be kept as simple as possible for this example.
lives better.
Press F5 to run the solution. Enter an email address in the Listing 15: Update WebApiConfig.cs with a new route
One of my favorite activities is watching people textbox and press the button to test the app. The results
use the software Ive created. Sometimes the should look something like Figure 11. config.Routes.MapHttpRoute(
software is boring and mundane stuff, like an ac- name: "statusUpdatesApi",
counting tool. Other times, its something that Deploy to Azure routeTemplate: "api/{controller}/{sessionId}/",
defaults: new { },
makes a persons work or life truly better. Its in The final step is to deploy the updated website and the
constraints: new
those moments when a user says Thank you. That new WebJobs project to Azure. One option often used in
{
really helped, that weve lived up to our obliga- production is to use the Publish wizard on the WebJobs
sessionId = @"^[{(]?[0-9A-F]{8}[-]?([0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$"
tions as a shokunin. project to deploy the WebJobs independently from the
} //must be a Guid
website. In production, thiss often the best choice, as it
);
So now you need to ask yourself: Do you have the not only allows you to deploy WebJobs independently, but
dedication to achieve shokunin? also allows you to scale them independently. For the pur-
poses of this sample, youre going to bundle the website
PS: This last summer, I had the honor of dining and the WebJobs so that theyre deployed together and Listing 16: Add an input box
at Sukiyabashi Jiro. Was it worth it? YES! And the run within the same App Service. Right-click on the MVC
<div class="jumbotron">
omelet? It was AMAZING. When they asked if I project, choose Add -> Existing Project as Azure WebJob.
<h1>Testing Report Services</h1>
would like anything more I said, Yes! More om- 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>
elet please. 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>
Rod Paddock 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>
Figure 1: Jiro, my daughter, and I enjoyed ourselves in Tokyo. tions. If you didnt copy the connection strings from the

6 Editorial codemag.com codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 71
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


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 codemag.com Title article 69


inspect the entire queue and grab certain messages from it. Service Bus queues are considerably more capable than Listing 1: Modify input fields to use Angular validation
This type of queue is designed only to hand out messages Storage queues and the most interesting feature of Ser-
<div class="form-group"> type="text" />
from the top of the queue to whatever process asks for those vice Bus queues, for my purposes, is the Session. To use
<label for="ProductName"> </div>
messages. Its not designed for point-to-point communica- sessions, the client passes a SessionId (a string) to the
Product Name <div class="form-group">
tion, but theres another type of queue that can do this. WebJob as a regular parameter. The WebJob stamps all
</label> <label for="Url">Url</label>
of the messages it puts on the response queue with the
<input class="form-control" <input class="form-control"
SessionId it was passed. The client can then pick up all id="ProductName" id="Url"
Listing 11: The SDK connect to the queue and passes a parameter response messages stamped with that SessionId. name="ProductName" name="Url"
public static void ReadReportRequestQueue([ServiceBusTrigger("report- required required
request")] ReportParameters request, Start by creating a new Service Bus Namespace in the Azure ng-minlength="4" ng-model="product.Url"
[ServiceBus("report- portal. I named mine codecloudreporting. Choose the ng-maxlength="150" type="text" />
response")] ICollector<BrokeredMessage> responseQueue, TextWriter log) Standard pricing plan that costs about ten dollars per 12.5 ng-model="product.ProductName" </div>
{ million messages per month. The Basic tier doesnt support type="text" /> <div class="form-group">
var sessionId = request.SessionId.ToString(); Sessions. Choose the location nearest to you for best per- </div> <label for="Price">Price</label>
var msg = "Read from Report Request Queue."; formance, as shown in Figure 8. As Im writing this article, <div class="form-group"> <input class="form-control"
log.WriteLine(msg); access to Service Bus within the new portal has just gone <label for="IntroductionDate"> id="Price"
var queueMsg = new ReportStatusResponse { Message = msg }; into Preview. Ive experienced some issues and limitations Introduction Date name="Price"
responseQueue.Add(new BrokeredMessage(queueMsg) { SessionId = sessionId }); that I hope will be worked out by the time you read this. If </label> required
not, you may have to use the old portal for some things, as <input class="form-control" min="0.01"
var pdf = getReport(request.Category, request.Format, responseQueue, sessionId, log); id="IntroductionDate" max="9999.99"
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 name="IntroductionDate" ng-model="product.Price"
{ required type="text" />
msg = "Failed to send report to: " + request.To; order to see all of the pricing tier options available to you.
ng-model="product.IntroductionDate" </div>
log.WriteLine(msg);
queueMsg = new ReportStatusResponse { Message = msg, IsProcessComplete = true };
responseQueue.Add(new BrokeredMessage(queueMsg) { SessionId = sessionId });
Service Bus queues Listing 2: Add error messages to the message area
sendEmail(request.From, "helpdesk@mycompany. are considerably <ul> <li ng-show="!productForm.IntroductionDate.$valid">
com", "Emailing failed", "Please check the WebJob logs.", null);
more capable than <li ng-repeat="msg in uiState.messages"> Invalid Introduction Date
return;
Storage queues {{msg.message}} </li>
}
</li> <li ng-show="productForm.Url.$error.required">
<li ng-show="productForm.ProductName.$error.required"> Url is Required
sendEmail(request.From, request.To, request.
Subject, "You must have a PDF reader installed on your machine to open the report.", pdf); Product Name is Required </li>
You may have to refresh the screen to see the new Ser- </li> <li ng-show="productForm.Price.$error.required">
msg = "Successfully sent report to: " + request.To; vice Bus Namespace. Once it appears, open the Set- <li ng-show="!productForm.ProductName.$valid"> Price is required
log.WriteLine(msg); tings, click on Shared access policies, and then open the Product Name must have more </li>
queueMsg = new ReportStatusResponse { Message = msg, IsProcessComplete = true }; RootManageSharedAccessKey and copy the Connection than 4 characters and less than 150 <li ng-show="!productForm.Price.$valid">
responseQueue.Add(new BrokeredMessage(queueMsg) { SessionId = sessionId }); String Primary Key to your clipboard. Open the app.config </li> Price must be between $0.01 and $9,999
} file for the WebJobs project and add a new connec- <li ng-show="productForm.IntroductionDate.$error.required"> </li>
tion string with name=AzureWebJobsServiceBus and Introduction Date is Required </ul>
connectionstring=<paste your connection string here>, </li>

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 file and add a new function named initEntity(), as shown
{ of the newer NuGet packages add an example key to the in the following code snippet.
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 function initEntity() {
private static NamespaceManager _namespaceMgr = null; look in the .config file, but the sample code expects it in return {
protected static NamespaceManager NamespaceMgr the connectionStrings section. Copy the same connection ProductId: 0,
{ string into the web.config file of the MVC project so that ProductName: '',
get its available to the WebJob when you deploy to Azure. IntroductionDate:
{ new Date().toLocaleDateString(),
if (_namespaceMgr == null) _namespaceMgr = NamespaceManager. Right-click on the solution and add the NuGet package Url: 'http://www.pdsa.com',
CreateFromConnectionString(_servicesBusConnectionString); Microsoft.Azure.Webjobs.ServiceBus to both the WebJobs Price: 0
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 When you click on the Add button, the ng-click directive
private static MessagingFactory _msgFactory = null;
work with Azure Service Bus in a similar way. It also adds the calls the addClick() function. In this function, you call
public static MessagingFactory MsgFactory
{ classes that you need to manage Service Bus queues. the initEntity() function and assign the return value
get to the vm.product variable. All of the properties of this
{ Edit the configureQueues method in Program.cs in the Web- object are bound to the input fields on the HTML page
if (_msgFactory == null) _msgFactory = MessagingFactory.Create(NamespaceMgr. Jobs project to create the request and response Service Bus and thus the values created in this function are then
Address, NamespaceMgr.Settings.TokenProvider); queues if they dont already exist, as shown in Listing 8. displayed in each of the fields. Run the form right now
return _msgFactory; and click the Add button to see these values displayed.
} Notice that the RequiresSession property is set to false for The validation doesnt work yet, but youll hook that up
} the request queue and set to true for the response queue. next. Figure 1: Add a <form> tag within your Angular app and controller.

68 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com codemag.com The Journey to Angular: Part 4 9
function addClick() { tion failures, and then ng-showing that it has received a Because youll be working with Azure Storage Queues in and the WebJob to get status updates and/or be notified
vm.product = initEntity(); true value from querying the $error or $valid properties. the service calls, add the WindowsAzure.Storage NuGet when a process is complete? Could you have the WebJob put
setUIState(pageMode.ADD); If you wipe out all of the input fields and click Save again, package to the MVC project. Its already being used in status messages on a response queue to be picked up by the
} you should see many errors appear. 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
Whats interesting is that as you clear each field, the er- project and add a new Get method with three string pa- ask for only messages pertaining to them and they cant
Using the Product Form ror messages appear immediately. This is because Angular rameters: category, format and email. The code you use to
When you add the <form> tag and assign a name to it, constantly monitors any bound fields. When they change, connect to the queue is almost identical to the code you
Angular creates a FormController object. The name used the validity of each field is checked and the $error and used to initialize the queue in Program.cs in the WebJobs
in this article, productForm, can be queried from the vm $valid properties are updated. This causes the appropri- project, so the code in Listing 6 should look familiar.
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- The code you use to connect
es are displayed in the unordered list. Modify the save- Custom Validation Directive to the queue is almost
Click() function to look like the following code snippet. Using the built-in validations is fine, but sometimes you identical to the code
might need something a little more specific to your own you used to initialize
function saveClick() { environment. You could write some JavaScript in the vali- the queue in Program.cs
if (vm.productForm.$valid) { date() function in your controller, but a more Angular ap-
in the WebJobs project.
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- Copy the two connection strings related to Storage Queues
code for this article by visiting my
vm.uiState.isMessageAreaVisible = true; Controller, chain the directive() function to this definition from the app.config in the WebJobs project into the
website at http://www.pdsa.com/
downloads. Select PDSA Articles, } and write some code to create your own custom directive. web.config in the MVC project. Not only will the service
and then select Code Magazine } call in the MVC project need this information to find the
- The Journey to Angular - Part 4 You pass two arguments to the directive() function: the queue, when you later deploy the WebJobs as part of 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 MVC application, the WebJobs reads their settings from the
the form back to a pristine state. Call the $setPristine() time the model value is updated by the user typing into web.config and not from their own app.config files.
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 Because youre adding a new GET WebAPI call with a third
to be set to pristine, as you will read about a little later separate the lower case portion and the word with the parameter, make sure to allow for up to three optional pa-
in this article. upper case letter by a dash (-). For example, in Listing rameters in the routeTemplate in WebAPIConfig.cs. In fact,
3 the name of the directive is urlMicrosoft; when added youre going to add a fourth sessionId parameter as well
The other change youre going to make is to modify the as an attribute to an HTML element, its expressed as url- because youll be using that later, as shown in Listing 7.
saveData() function. Modify this function so it looks like microsoft.
the following code snippet. Youre removing some code Right-click on the solution and choose Set Startup Proj- Figure 10: Use Server Explorer to test and modify Service Bus queues.
from a function that was written in a previous article and The function you write creates an object with two proper- ects Choose Set Multiple Startup Projects, and set both
is no longer needed. ties: require and link. As youre going to be using this the MVC and WebJobs project to start. When you run the
as a validation directive, you require the ngModel. The code, you can test the WebAPI call by adding /api/report/ Listing 9:Tell the JobHost to use the Service Bus queues
function saveData() { link property is a function that accepts four parameters; clothing/pdf/myemail@mycompany.com/ to the site static void Main()
// Insert or Update the data scope, element, attributes and ngModel. Attach your own URL. Most modern browsers URL-encode the @ symbol {
if (vm.uiState.mode === pageMode.ADD) { property name to the ngModel.$validators collection. In in the email address for you, but if your browser doesnt, if (!VerifyConfiguration())
insertData(); this case, Im using the name Microsoft, but feel free you can replace @ with %40. Make sure to end the URL {
} to name it whatever you want. Assign a function to this with a forward slash so that both the @ and period in the Console.ReadLine();
else if (vm.uiState.mode === pageMode.EDIT) { new property thats passed the model value that the user email address are handled properly, as shown in Figure return;
updateData(); just typed in. This function returns a true or a false value 7. Dont forget to use your email address in the URL. The }
} based on whether or not the value typed is valid. service call returns almost instantly with success, as long
} as the request can be put on the queue. Success, in this configureQueues();
To use the validation directive, apply the attribute to the case, doesnt indicate that the report has run or will run
var config = new JobHostConfiguration();
If you run the sample HTML file, click on the Add but- appropriate input field. In this case, add it to the URL successfully, only that the request is successfully queued
config.UseServiceBus();
ton, immediately click on the Save button, and then you field to make sure someone doesnt type in www.micro- and that is a very fast operation. config.Queues.BatchSize = 1;
should see a couple of error messages show up in the soft.com. In the code snippet below, you can see the di- JobHost host = new JobHost(config);
unordered list. These messages are the result of Angular rective applied using the dash notation mentioned previ- Using Service Bus Queues for Better Communication host.RunAndBlock();
evaluating the validation attributes, detecting the valida- ously. 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-
Listing 3: Add some custom validation to the validate function tern, but it also has some limitations. The nature of Storage
angular.module('ptcApp') function (value) { queues is that a client drops a message on a queue in a fire- Listing 10: Add a new class to the Reports project
.controller('ProductController', ProductController) if (value) { and-forget fashion, and then the message is picked up by public class ReportStatusResponse
.directive('urlMicrosoft', function () { return value.indexOf("microsoft") == -1; a single instance of a WebJob or by any one of an army of {
return { } dozens, hundreds, or even thousands of WebJob instances. public bool IsProcessComplete { get; set; } = false;
require: 'ngModel', } This gives you a fast user experience, allows you to achieve public string Message { get; set; } = string.Empty;
link: function (scope, element, } immense scale, and to size and scale the WebJobs separately public int Count { get; set; } = 0;
attributes, ngModel) { }; from the rest of the system. But what if you want to go be- public int TotalCount { get; set; } = 0;
ngModel.$validators.microsoft = }); yond fire-and-forget and communicate between the client }

10 The Journey to Angular: Part 4 codemag.com codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 67
{ Triggering WebJobs from a Service Call <input class="form-control"
Category: "Bikes", Up until now, youve been manually starting jobs by adding id="Url"
Format: "PDF", entries to an Azure Storage queue. You could ask your client name="Url"
To: "myemail@mycompany.com", app developers to use the Azure Storage queue REST API to ng-model="product.Url"
From: "system@cloudreporting.com", add new requests to the queue, but itll be easier for them if required
Subject: "Here is your report" you just add service calls to the existing WebAPI services and url-microsoft
} have the services communicate with the queues. 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
Figure 9: Add the connection string for the new Service Bus Namespace. 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.
Listing 8: Create the request and response Service Bus queues form is valid and the product form is no longer pris-
private static void configureQueues() var queueDescription = new QueueDescription("report-request"); tine. This means that youve modified the form data in For the purposes of this article, Im only going to show
{ queueDescription.RequiresSession = false; some way. After making these changes, go ahead and you how to add validation messages to the System.Web.
//Azure Storage queue queueDescription.MaxDeliveryCount = 1; run the form again, click Add and press the Save but- Http.ModelBInding.ModelStateDictionary, serialize that
var storageConn = ConfigurationManager.ConnectionStrings["AzureWebJobsSto queueDescription.DefaultMessageTimeToLive = new TimeSpan(1, 0, 0); ton to display an error message. Fix the product name object, and report the messages on the HTML page. The
rage"].ConnectionString; namespaceManager.CreateQueue(queueDescription); field so that it has valid data in it, and you should see first step is to open the ProductController.cs file and add
var storageAccount = CloudStorageAccount.Parse(storageConn); } the message area removed from the page. The use for a using statement at the top of the file.
var queueClient = storageAccount.CreateCloudQueueClient(); the productForm.$pristine is why as soon as the data
var queue = queueClient.GetQueueReference("report-request"); //Azure Service Bus Response Queue is valid on the page, in the saveClick() function, you using System.Web.Http.ModelBinding;
queue.CreateIfNotExists(); if (!namespaceManager.QueueExists("report-response")) 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
//Azure Service Bus Request Queue var queueDescription = new QueueDescription("report-response"); hidden. and set the name to ValidationErrors. This property is
var servBusConn = ConfigurationManager.ConnectionStrings["AzureWebJobsSer queueDescription.RequiresSession = true; what youre going to fill in with any validation errors. The
viceBus"].ConnectionString; queueDescription.MaxDeliveryCount = 1; values in this property are serialized and passed back as
var namespaceManager = NamespaceManager.CreateFromConnectionString(serv queueDescription.DefaultMessageTimeToLive = new TimeSpan(1, 0, 0); Server-Side Validation part of a BadRequest() Web message.
BusConn); namespaceManager.CreateQueue(queueDescription);
Client-side validation can be bypassed fairly easily, so
if (!namespaceManager.QueueExists("report-request")) }
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; }

66 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com codemag.com The Journey to Angular: Part 4 11
Listing 4: Write additional validation code 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
protected bool Validate(Product product) { "Introduction Date Must Be Greater Than 1/1/2010");
like the fancy quotes. You may want to try typing in the
bool ret = false; }
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.
ValidationErrors = new ModelStateDictionary(); // Add more validation here to match
correct. Note that you may have to refresh the data in
// client-side validation
// Add custom validation
Cloud Explorer. Be aware that the maximum message size
if (product.IntroductionDate < ret = (ValidationErrors.Count == 0); for a Storage Queue message is 64k, so your serialized Listing 7: Add a fourth sessionID parameter
Convert.ToDateTime("1/1/2010")) { JSON payload cannot exceed 64k.
public static void Register(HttpConfiguration config)
ValidationErrors.AddModelError( return ret; {
"Introduction Date", } 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();
Listing 5: Call the Validate() function when updating data tem.Web, which is required by the ReportViewer control to
public IHttpActionResult Put(int id, Product product) { } work properly. The actual code for generating the report and config.Routes.MapHttpRoute(
IHttpActionResult ret = null; else { sending emails can be found in the accompanying source name: "DefaultApi",
ret = NotFound(); code download for this article. The mechanics of generating routeTemplate: "api/{controller}/{category}/{format}/{email}/{sessionId}/",
if (Validate(product)) { } the report was well covered in the last article, so I wont list defaults: new { category = RouteParameter.Optional,
if (Exists(id)) { } that code here. The logic for using the report in the WebJob format = RouteParameter.Optional,
if (Update(product)) { else { can be found in RunReport.cs, as shown in Listing 5. email = RouteParameter.Optional,
sessionId = RouteParameter.Optional }
ret = Ok(product); ret = BadRequest(ValidationErrors);
);
} } You can test the report and email by manually adding an
}
else { entry to the queue with the following JSON. If you run into
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); }
} Figure 7: Test queueing a report to be emailed
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, Figure 8: Create an Azure Service Bus Namespace.

12 The Journey to Angular: Part 4 codemag.com codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 65
code, controllers, etc., and wires them up for you. So its Press F5 again and run the app. There will be a lot less Listing 7: Add a case statement to check for validation errors from the server
really JobHost that uses Azures WebHooks, a polling sys- chatter on the screen this time because were not running
function handleException(error) { 'The product you were ' +
tem and/or timers to listen and wait for events that trigger the sample code anymore. It only shows that it found your
vm.uiState.messages = []; 'requesting could not be found');
calls to your methods. Its also JobHost that creates and ReadReportRequestQueue function and started running.
break;
passes the TextWriter to you in a process similar to depen- If you take a look in Cloud Explorer, you should also see
switch (error.status) {
dency injection. All of that plumbing work comes from the that it created the report-request queue that you speci-
case 400: // 'Bad Request' case 500: // 'Internal Error'
WebJobs SDK so you can concentrate on writing logic. fied in Main.cs, as shown in Figure 4.
// Model state errors addValidationMessage('product',
var errors = error.data.ModelState; error.data.ExceptionMessage);
Double-click on the report-request queue in Cloud Ex- break;
Listing 5: The RunReport.cs plorer, click the Add Message toolbar button, enter some // Loop through and get all
text, and click OK, as shown in Figure 5. Youll see your // validation errors default:
public static void ReadReportRequestQueue([QueueTrigger("report-
request")] ReportParameters request, TextWriter log)
message added to the queue, and then a few moments for (var key in errors) { addValidationMessage('product',
{ later, youll see a message on the WebJob console win- for (var i = 0; 'Status: ' +
log.WriteLine("Read from Report Request Queue."); dow indicating that it saw your queue entry and executed i < errors[key].length; error.status +
var pdf = getReport(request.Category, request.Format, log); your ReadReportRequestQueue method. If you refresh the i++) { ' - Error Message: ' +
if (pdf == null) queue in Cloud Explorer, the message will be gone. addValidationMessage(key, error.statusText);
{ errors[key][i]); break;
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 break; vm.uiState.isMessageAreaVisible =
return; 6. This is where your WebJob log entries are written when (vm.uiState.messages.length > 0);
} you use the TextWriter parameter in a WebJob function. case 404: // 'Not Found' }
log.WriteLine("Susscessfully sent report to: " + request.To); Each entry is the summation of everything written to the addValidationMessage('product',
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 message: msg learned how to check additional values on the server-side
a lot, but theres more. In this first example, you want to }); and return a bad request (HTTP status of 400) to trig- SPONSORED SIDEBAR:
Listing 6: Connect to the queue generate a report and email it to someone when its ready, } ger an exception on the client-side. You then extracted
so it would make sense to pass in an object containing the the messages returned from the Web API and added those Does Your Cloud App
public EmailReportResponse Get(string category, string format, string email) To and From email addresses and the Subject of the email. Locate the handleException() function in your product- to your messages array so those messages could be dis-
Have You Feeling Under
{ the Weather?
Youve probably noticed that the queues payload is a string, Controller.js file and modify it to look like Listing 7. The played on your HTML page.
try
{
but what if you want to pass something more sophisticated? important part in this function is handling the case for The developers at CODE
var response = new EmailReportResponse(); Because JSON can represent complex objects as a string, its the bad request that has a status code of 400. You know Paul D. Sheriff have worked on everything
var parameters = new ReportParameters not a big leap to serialize the object into JSON before you that youre passing back a model state dictionary object from cloud applications to
{ put it on the queue and then de-serialize it back into an for any bad request generated from your Web API, so you mobile projects. If youre
Category = category, object before you use it in the function. Because the SDK is get that dictionary object in the ModelState property at- having problems with your
Format = format, already doing a lot of work for you, between spotting new tached to the error.data property. Cloud Application and need
To = email, queue entries and calling your functions, its not surprising guidance, the developers at
From = "system@cloudreporting.com", that the authors of the SDK thought of this. Deserialization Loop through all of the errors in this ModelState prop- CODE Consulting can help
Subject = "Here is your report" of parameters into objects is handled automatically. 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
Add a new class to the CloudReporting.Reports project name and the message to the addValidationMessage() www.codemag.com/
var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionString consulting or email us at
(so that it can be shared with other projects later) and function to add the message to the vm.uiState.messages
s["AzureWebJobsStorage"].ConnectionString); info@codemag.com to set
var queueClient = storageAccount.CreateCloudQueueClient();
name it ReportParameters. Add public properties for Cat- array. Once this message is in the array, the message is au-
egory, Format, To, From, Subject and SessionId (which tomatically displayed in the unordered list in the messages up your time with a developer
var queue = queueClient.GetQueueReference("report-request"); today.
queue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(parameters))); youll use later), as shown in Listing 3. area on your HTML page. To ensure that the message area
is visible, set the vm.uiState.isMessageAreaVisible equal to
response.Success = true; Next, add a reference to both the CloudReporting.Reports true at the end of the handleException() function.
return response; and CloudReporting.DataRepository projects. Change the
} request parameter type from string to ReportParameters in Run the sample one last time. Click on the Add button
catch (Exception ex) RunReport.cs. Add a few logging calls to echo out the values and set the product name field to a valid value, but set
{ of the properties, as shown in Listing 4. If you get an error the introduction date to 1/1/2000, or any date prior to
//Log the error here. on build, check the references for the WebJobs project. If 1/1/2010. Click the Save button to post to the server.
return new EmailReportResponse theres a problem with the references to the other projects, You should now see the appropriate error message, tell-
{
it may be because those projects were created with .NET ing you that the introduction date must be greater than
Success = false,
FailureInformation = "Could not queue report."
Framework 4.6.1. You may need to update the framework 1/1/2010.
}; version in the WebJobs project via the project properties.

}
}
Press F5 to run the WebJob again. Open up the queue in Summary
Cloud Explorer and add a new queue entry. This time, for In this article, you learned the basics of adding validation
public class EmailReportResponse the message, type in the following JSON: to your Angular page. You took advantage of the built-
{ in validation attributes and learned how to display error
public bool Success { get; set; } = false; { messages within an unordered list. You learned to create
public string FailureInformation { get; set; } = string.Empty; To: "myemail@mycompany.com", a custom validation directive for functionality that was
} From: "system@cloudreporting.com", beyond what the standard validation can do. Finally, you

64 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com codemag.com The Journey to Angular: Part 4 13
ONLINE QUICK ID 1611031

Angular 2 Forms
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
Forms are essential and deceptively simple, but they can also be incredibly involved. Theyre just a <form/> tag with a bunch the request parameter. Thats a lot of plumbing work to {
of input controls, right? Wrong. Things can become quite complex quickly once you consider issues such as data-binding, 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;
validations, change tracking, etc. You need to consider that youre in a browser, disconnected from the server and you need 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;
to worry about change tracking. Even validations can be every single aspect here, but Ill mention some high-level is a TextWriter named log that the WebJobs SDK provides public string Subject { get; set; } = string.Empty;
simple validations, or they could be validations that you portions. for you if you want to use it. There are a few such magic public Guid SessionId { get; set; } = Guid.Empty;
write code for, that need an asynchronous call, or that in- parameters you can add to your method calls, but this }
volve multiple controls. See? Their simplicity is deceptive! The code for the Start application is quite simple. It is the most common. I suggest downloading the Quick }
contains two components. The first is a TodoComponent, Reference PDF that outlines all of the attributes and spe-
Forms are a very important part of any framework, and which renders a single Todo that it receives as an input cial parameter types available in the SDK from http://
therefore its reasonable to expect that Angular 2 has rich from the startup component, which is the TodosCompo- go.microsoft.com/fwlink/?LinkID=524028&clcid=0x409. Listing 4: Add a few logging calls
support for forms. Angular2 lets you support forms in two nent. public static void ReadReportRequestQueue([QueueTrigger("report-
different ways: How does this magic work? When the app is loaded and request")] ReportParameters request, TextWriter log)
NameMalik
Sahil Autor The second is the TodosComponent, which relies on the JobHost.RunAndBlock() is called, the app is scanned (us- {
www.winsmarts.com
www.internet.com Template-driven forms, which you can think of as TodoService to get an observable of Todo[]. The To- ing Reflection) for public classes with public, static meth- log.WriteLine("Read from Report Request Queue.");
@sahilmalik very similar to how Angular 1 let you write forms doService populates this Observable whenever it queries ods and the method parameters are examined for type and log.WriteLine(" to: " + request.To);
asdfasdfasdfasdfker, a .NET Model driven forms, which is the new functional re- the backend with an Ajax call. The reason I preferred to attributes. The app then listens for the specified events log.WriteLine(" from: " + request.From);
Sahil
author,Malik is a Microsoft
consultant MVP,
and trainer. log.WriteLine(" subject: " + request.Subject);
active way use Observables over promises here is because it greatly and, when they occur, makes calls to your methods. This
INETA speaker, a .NET author, }
simplifies the code. Perhaps the most interesting part is actually pretty similar to how ASP.NET MVC finds startup
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 Figure 6: View the log for the WebJob.

14 Angular 2 Forms codemag.com codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 63
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());
Figure 4: The report-request queue created when the WebJob starts up 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
Figure 5: Manually add a new message to the queue. 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);
Listing 2: The public, static method, ReadReportRequestQueue filled in correctly. If you dont make the changes manu- case of additions, you also wish to notify in the case of
using Microsoft.Azure.WebJobs; ally, all of your new files will, by default, be in a different deletions and modifications. In fact, lets call these by In other words, whenever theres a new thing happening
using System.IO; namespace. I expect Microsoft to clean this up in some the generic name Todos Operation, which you can conve- on newTodo, like when a new Todo is added, it calls this.
future version of the project template. niently represent using an interface. Now you can add the create. The creation operation is shown as next.
namespace CloudReporting.WebJobs following Todos operation in your TodoService file.
{ Add a new Class to the WebJobs project and name it Run- this.create.map(
public class RunReport Report.cs. Add a using statement at the top for Microsoft. interface ITodosOperation extends Function { function (todo: Todo): ITodosOperation {
{ Azure.WebJobs. This namespace contains the attributes (todo: Todo[]): Todo[]; return (todos: Todo[]) => {
public static void ReadReportRequestQueue([QueueTrigger("report- youre going to add to some of the method parameters as } return todos.concat(todo);
request")] string request, TextWriter log) well as some handy classes for building WebJobs. Make };
{ the class public and add a new public, static method If youre familiar with redux, you might be thinking that }).subscribe(this.updates);
log.WriteLine("Read from Report Request Queue: " + request); named ReadReportRequestQueue, as shown in Listing 2. 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.
} Although most developers have seen attributes applied that for another day. Youre effectively subscribing your Updates stream to lis-
} to classes, methods, and properties, it might be odd to ten to the Create stream. In other words, if Create gets a
see them applied to method parameters. In this case, the With this newTodo in place, you also need similar Subjects new Todo (by virtue of the newTodo subject), it emits an
first parameter is a string named request, which has a to handle updates and creations. To handle updates, add ITodosOperation, which will be received to the updates
Right-click on the project and choose Properties. Change QueueTrigger attribute applied to it and that performs the following Subject to your service: stream.
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 updates: Subject<ITodosOperation> = Now, you need to handle the Updates stream. This can be
ect template that prevents these properties from being string in the app.config file that you configured earlier to new Subject<ITodosOperation>(); seen in the next snippet:

62 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com 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 61


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 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 Figure 1: Add a WebJob project that uses queues.
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. Figure 2: Getting the Azure Storage connection string

18 Angular 2 Forms codemag.com codemag.com Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services 59
ONLINE QUICK ID 1611091

Azure Skyline: Using WebJobs for Listing 9: Todos Component with Template-driven forms
<form #f="ngForm" (ngSubmit)="onSubmit(f.value)">
<div *ngFor="let todo of _todos | async; let i = index">
<div>
<h2>Add a todo:</h2>

Event-Driven, Asynchronous Services


<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>
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?
Listing 10: The todos.component.html examining our objects
The answer is that you can build your own mechanism installed as part of the Azure SDK 2.5 and later and in- <table> <pre>{{ myForm.valueChanges | async | json}}</pre>
or you can use some of the many Platform as A Service cludes some QuickStart templates for WebJobs, so if you <thead> </td>
(PAAS) options that really smart and capable people have have the latest Azure SDK installed, youre all set. You can <td><b>Databound data</b></td> <td>
built for you and made available to you for prices ranging download the source code from the Sept-Oct 2016 article <td><b>Business Object</b></td> <pre>{{_todos | async | json}}</pre>
from free to very, very reasonable. http://www.codemag.com/Article/1609081. </thead> </td>
<tr> </tr>
In this article, Im going to show you how to program Add a new project to the CloudReporting solution <td> </table>
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. Youll note that, for brevity sake, Ive chosen not to show you need to know here is that the service is not going to
www.internet.com that might be unfamiliar to the typical line-of-business the delete and add functionality. Theyre going to be change. This is the reward you get for modeling your code
app developer. These solutions can scale automatically The template automatically adds the appropriate NuGet simple method calls to the service methods that youve nicely and separating the heavy lifting into the service.
Mike is the CEO of EPSs Houston from micro to massive. Theyre modular and shareable. packages and project references and creates a console appli- already written, but that brings me to a big downside of The only changes are in the components. This time, Ill
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 this approach of creating forms. Go ahead and click the start with the parent TodosComponent.
oper. Mike excels at evaluating thing, but theyre fantastic when you need them. project the startup project for the solution and press F5 to Submit button. You should see an output like that shown
business requirements and
run it. Youll see a console window pop up with a message in Figure 3.
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 Hmm, thats not quite what you were expecting, right?
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- This looks nothing like the object you were working with.
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 In fairness, in the databound object, the Todos Observ-
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- able is where you can look for proper data structure, but
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- that gets quickly out of hand because you effectively have
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 to tie your UX to your business object structure. That
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) means that you have to model your components to reflect
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 the object structure. This brings me to the pros and cons
a business owner developing a generation asynchronous. Thats going to allow me to do because the nature of generating PDFs prevents you from of template-driven forms.
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 Pros and Cons
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 The template-driven form is easy to understand but has
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 following disadvantages:
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 In order to TDD, you need the DOM.
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 Your components structure invariably end up get-
Server, Windows Azure, Microsoft report that takes four hours to put together and generate, monthly bill for the expected load. ting affected by your business object structure.
Surface, and Visual FoxPro. it will still work while the user goes about his business. Changing the business object structure can cause
huge changes in your application.
Validations etc. make the form less and less read-
WebJobs: Create a Sample WebJob Do you think that able.
WebJobs were introduced in Azure around 2014 and are its starting to None of the validation logic is easy to unit test.
a powerful way to run background tasks in the cloud. sound expensive?
The background task can be anything from a simple Well, it isnt. On the other hand, template-driven forms are simple!
batch file, to a PowerShell script, to a .NET executable That, in my eyes, is a big win.
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 Model-Driven Forms
to the old Worker Roles in Azure that pulled jobs off a at portal.azure.com, log into your account, and click New Next, lets look at being able to create the very same form
queue and processed them. WebJobs are built, run, and in the left-hand menu. Under Data + Storage, select Stor- using the model-driven forms approach. The first thing Figure 2: The edited template-driven form
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- Figure 3: The form.value in template-driven forms

58 Azure Skyline: Using WebJobs for Event-Driven, Asynchronous Services codemag.com codemag.com Angular 2 Forms 19
The TodosComponent your business object and this FormGroup in sync? Luckily, 9 2016-06-04 09:00:00 6.6
The one big difference between template-driven forms thats not the case. Because you wrote the service to use 10 2016-06-04 11:00:00 4.1
and model-driven forms is that model-driven forms work Observables, and because model-driven forms understand 11 2016-06-04 17:00:00 5.9
on their own business object of data type FormGroup. Observables very nicely, bridging the two together is 12 2016-06-05 08:00:00 7.6
This may sound like a negative, because after all, dont very easy. In other words, with very little plumbing code, 13 2016-06-05 12:00:00 5.1
you then have to write lots of plumbing code to keep the business object stays in sync with the form and vice 14 2016-06-05 18:00:00 6.9
versa. 15 2016-06-06 08:00:00 5.0
16 2016-06-06 12:00:00 6.1
Listing 11: Hydrating Todos and creating controls In the form, youll have variable called myForm of data 17 2016-06-06 18:00:00 4.9
ngOnInit() { type FormGroup representing the forms data. List- 18 2016-06-07 08:00:00 6.6
this.myForm = this._fb.group({ ing 10 shows some diagnostic databinding code that 19 2016-06-07 12:00:00 4.1
'todos': this._fb.array([]) helps you view both the databound object and the 20 2016-06-07 18:00:00 6.9
}); business object side-by-side. This code goes in the 21 2016-06-08 08:00:00 5.6
todos.component.html file. 22 2016-06-08 12:00:00 8.1
this._todoService.newTodo.subscribe((todo) => { 23 2016-06-08 18:00:00 10.9
const control = <FormArray>this.myForm.controls['todos']; In order to construct the myForm variable, make use of an 24 2016-06-09 08:00:00 5.2
control.push(this.initTodoControl(todo)); Angular service called FormBuilder. 25 2016-06-09 12:00:00 7.1
}); 26 2016-06-09 18:00:00 4.9
Start by injecting an instance of FormBuilder into the
this._todos = this._todoService.todos; constructor of TodosComponent, as shown in the next Visualizing the Data
} snippet: Lets now try to visualize the data by displaying a chart. Add
the following statements in bold to the existing Python script:
constructor(
private _todoService: TodoService, %matplotlib inline
Listing 12: The initTodoControl method
private _fb: FormBuilder) { } import pandas as pd
initTodoControl(todo: Todo) { Figure 15: Changing the color of the area chart
var formGroup = this._fb.group({ Now, use the life cycle hooks of the component, and le- data_frame = pd.read_csv('readings.csv',
id: [todo.id], verage the ngOnInit method to make a call to the service index_col=0, The chart is now displayed as an area chart (see Figure
title: [todo.title, Validators.required] to get the Todos. This can be seen in Listing 11. parse_dates=[1]) 14).
}); print data_frame
formGroup.valueChanges.subscribe((todo) => { Listing 11 does some really interesting things. First, it You can also set the color for the area chart by using the
this._todoService.updateTodo(todo); creates a control array called todos. Youre writing some data_frame.plot(x='DateTime', y='mmol/L') color parameter:
}); code here to mimic the business object and keep things
return formGroup; understandable, but your business object structure could The x parameter specifies the column to use for the x-axis data_frame.plot(kind='area', x='DateTime', y='mmol/L',
} be different from the UX if you desire it to be. Next, sub- and the y parameter specifies the column to use for the color='r')
scribe to the newTodo observable. Whenever a new Todo y-axis. This displays the chart as shown in Figure 11.
appears, youre adding a new control under the todos The area is now in red (see Figure 15).
Listing 13: The addTodo and removeTodo methods. control array. You can add a title to the chart by importing the matplot-
lib.pyplot module and using the title() function:
addTodo(todo: Todo) {
this._todoService.addTodo(todo); How does the code know that this new control is tied to Summary
} the TodoComponent? That information is embedded in %matplotlib inline In this article, Ive touched on the foundation of Data Sci-
the HTML template, which Ill discuss momentarily. First, import pandas as pd ence, using Python and its companion libraries, NumPy,
removeTodo(todoFormGroup: FormGroup, i: number) { I want to talk about the initTodoControl method. This can import matplotlib.pyplot as plt pandas, and matplotlib, and youve learned to manipulate
let deletedTodo: Todo = todoFormGroup.value; be seen in Listing 12. data and present them in a visual manner. In a future
const control = <FormArray>this.myForm.controls['todos']; data_frame = pd.read_csv('readings.csv', article, Ill delve deeper into the world of Data Science.
control.removeAt(i); As you saw in Listing 12, the initTodoControl method index_col=0,
this._todoService.removeTodo(deletedTodo); adds a Validator indicating that the title is required for parse_dates=[1]) Wei-Meng Lee
} the newly added Todo. But most interestingly, on this print data_frame
new FormControl, it subscribes the valueChanges. This
data_frame.plot(x='DateTime', y='mmol/L')
plt.title('Blood Glucose Readings for John',
Listing 14: The todos.component.html file for Model driven forms. color='Red')
<form [formGroup]="myForm" novalidate (ngSubmit)="onSubmit(myForm)"> </div>
<div formArrayName="todos"> </div> A title is now displayed for the chart (see Figure 12).
<div <hr/>
*ngFor="let todo of myForm.controls.todos.controls; let i=index"> <button By default, matplotlib displays a line chart. You can
<div [formGroupName]="i"> (click)= change the chart type by using the kind parameter:
<todo-control "addTodo({'id':myForm.controls.todos.controls.length,'title':''})">
[group]="myForm.controls.todos.controls[i]"> Add New data_frame.plot(kind='bar', x='DateTime', y='mmol/L')
</todo-control> </button>
<button <hr/> The chart is now changed to a bar chart (see Figure 13).
*ngIf="myForm.controls.todos.controls.length > 0" <button type="submit">Submit Form</button>
(click)="removeTodo(myForm.controls.todos.controls[i],i)"> </form> Besides displaying as a bar chart, you can also display an
Delete area chart:
</button>
</div> data_frame.plot(kind='area', x='DateTime', y='mmol/L')

20 Angular 2 Forms codemag.com codemag.com Introduction to Data Science using Python 57


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 Figure 4: The model-driven form
three columns: index, date and time, and blood glucose
readings in mmol/L.
Observable fires whenever the value of the underlying Listing 15: The TodoComponent for model-driven forms
Reading the Data in Python object changes. How interesting! Now, if only there <span [formGroup]="todoForm">
To read the data from the CSV file into your Python app, were a way to sync this to the business object. Thats <span *ngIf="!isEdit">
use the following code snippet: the next line of code, which you can see in the next {{todoForm.value.id}}.
snippet. {{todoForm.value.title}}
Figure 13: Displaying the chart as a bar chart import pandas as pd </span>
data_frame = pd.read_csv('readings.csv', this._todoService.updateTodo(todo); <span *ngIf="isEdit">
index_col=0, {{todoForm.value.id}}. <input formControlName="title"/>
parse_dates=[1]) Yeah, thats really it! Thats all it took to sync the form </span>
print data_frame 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
You first import the pandas module, then you use the this is a degree of magnitude simpler and more power- ..
read_csv() function to read the data from the CSV file ful than trying to do the same thing in template-driven ..
to create a DataFrame. The index_col parameter specifies forms. Do note that this approach works well with Ob- export class TodoComponent {
which column in the CSV file will be used as the index servables only, which is another reason Im a fan of Ob- @Input('group')
(column 0 in this case) and the parse_dates parameter servables. public todoForm: FormGroup;
specifies the column that should be parsed as a datetime private isEdit:boolean = false;
object (column 1 in this case). The logic for deletion and addition of new Todos is also
quite simple, and can be seen in Listing 13. toggleEdit($event) {
When you print out the dataframe, you should see the this.isEdit = !this.isEdit;
following: 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 }
DateTime mmol/L update to the Todo Observable on which the form is dat- }
0 2016-06-01 08:00:00 6.1 abound, and that refreshes the UI.
1 2016-06-01 12:00:00 6.5
2 2016-06-01 18:00:00 6.7 The delete method is slightly more complex if you intend by disassociating the UX with the business object and yet
3 2016-06-02 08:00:00 5.0 to delete the object only in the UX but not in the underly- keeping them linked via Observables.
4 2016-06-02 12:00:00 4.9 ing business object. Why are you doing this? Well, you
5 2016-06-02 18:00:00 5.5 dont have to! Most Web-based UIs are disconnected. You The update logic is encapsulated in the TodoComponent.
6 2016-06-03 08:00:00 5.6 want the UX to differ from the business object for one Before we go there, lets quickly look at the HTML tem-
7 2016-06-03 12:00:00 7.1 reason: You havent gone back to the server to save the plate for the TodosComponent first. This can be seen in
Figure 14: Displaying the chart as an area chart 8 2016-06-03 18:00:00 5.9 changes yet. This flexibility is yet another power you gain Listing 14.

56 Introduction to Data Science using Python codemag.com codemag.com Angular 2 Forms 21


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
SPONSORED SIDEBAR: is just a simple wrapper
CODE Framework: around pyplot.plot().
Free, Open Source, and
Fully Supported
CODE Framework is Plotting in Pandas
completely free and open Like NumPy arrays, you can directly plot using matplotlib
source with no strings from a Series or DataFrame. The following code snippet plots
attached. But that doesnt a line chart from a panda Series (see Figure 9 for the chart):
mean that the framework is
unsupported! Contact us with %matplotlib inline
any questions; well never import pandas as pd
charge you for answering a import numpy as np
few questions by email.
For those looking for more
series = pd.Series(np.random.randn(30),
sophisticated and hands-on
pd.date_range(end='2016-06-01',
support, we also offer
periods=30))
premium support options.
http://codeframework. series.plot()
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: Figure 12: Displaying a title for the chart

22 Angular 2 Forms codemag.com codemag.com Introduction to Data Science using Python 55


2015-05-27 -1.801745 -0.627653 0.017884 -0.294941 Selecting Data From DataFrames Because the business object and the form object perhaps an easy migration path. But model-driven forms
2015-05-28 -0.199777 -0.343533 -0.847143 0.230196 There are many ways to select data from a DataFrame. are separate, you gain a lot of flexibility here. are much more powerful and flexible, and end up requir-
2015-05-29 -0.470902 -1.882163 1.589637 0.041875 Let me highlight a few examples. First, to display a spe- Two-way data-binding isnt all that its cracked up ing less code for more complex applications, especially
2015-05-30 0.223365 -0.367830 0.901914 -1.574907 cific column, pass in the column header as the index, to be if you dont have a processing pipe in the when paired with reactive Extensions and Observables.
2015-05-31 -0.701686 2.185077 -0.787870 -1.014857 like this: middle. A good example is where deletion doesnt
2015-06-01 2.078889 0.467649 0.462715 0.731940 mean deletion; thats when it only means marked There are additional patterns such as Redux that can also
2015-06-02 -0.739564 0.055060 -0.414679 1.229497 print data_frame['A'] # prints column A for deletion. be used to manage and structure your applications. In
2015-06-03 1.086807 0.134102 -1.114484 -0.277467 Both the form and object are streams of values. They future articles, I hope to talk more about reactive pro-
''' This prints out the index as well as all of column A: 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!
2015-05-25 0.400942 to do because you can use the .filter method on Ob-
2015-05-26 0.553610 servables to help you out. How would you do this in Sahil Malik
2015-05-27 -1.772219 template-driven forms?
2015-05-28 0.298267 Your validation logic can also now be testable.
2015-05-29 -0.079830
2015-05-30 0.619363 I feel that theres no absolute way forward that suits all
2015-05-31 -0.217129 cases. If your form or application is very simple, perhaps
2015-06-01 -0.111042 template-driven forms are the right approach. They are
2015-06-02 1.080578 simple and they require less code if your needs are also
2015-06-03 1.937649 very simple. But as the application gets more complex
''' and TDD becomes a requirement, model-driven forms are
a far better alternative.
Because the index of the data_frame is a date range, you
can perform slicing, like this:
Summary
# prints rows with index from 2015-05-25 to 2015-05-28 Forms are complex and important. Thats why any good
print data_frame['2015-05-25':'2015-05-28'] framework, including Angular, provides you with rich
functionality to support forms. In this article, I showed
The result is as follows: 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
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 ADVERTISERS INDEX
'''
Advertisers Index
Figure 10: Plotting a line chart from a Pandas DataFrame
1&1 Internet, Inc. LEAD Technologies Angular, Lambdas, Python, C#, Azure Skyline
You can also perform slicing using row numbers:
www.1and1.com 7 www.leadtools.com 2
print data_frame[2:5] # prints row 3 through AppDevTrends Conference SSWUG Virtual Conference NOV
DEC
2016

# row 5 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#!
The above statement prints all the rows from index 2 to
www.codemag.com/consulting 38, 39, 76 www.sxsw.com 27
5 (not included in the result), which means from row 3
to row 5: CODE Divisions The MIT Press
www.codemag.com 75 www.mitpress.mit.edu 25
'''
CODE Framework

shutterstock.com/Scanrail1
A B C D
2015-05-27 -1.772219 -2.182172 -0.439986 -1.672310 www.codemag.com/framework 61
The Resurgence of XAML
2015-05-28 0.298267 1.049802 -2.093472 1.330577 CODE Magazine Data Science using Python

2015-05-29 -0.079830 1.169019 0.047177 -0.599912


Swiftly moving from Objective-C
www.codemag.com/advertise 17
'''
dtSearch Advertising Sales:
www.dtSearch.com 55 Tammy Ferguson
Very often when plotting charts, you need to flip the col- 832-717-4445 ext 026
umns and rows of the DataFrame, and this can be accom- tammy@codemag.com
plished using the T property:

print data_frame.T

The T property transposes (interchanges) the index and


columns of the DataFrame:
This listing is provided as a courtesy to
our readers and advertisers.
''' The publisher assumes no responsibility
Figure 11: Plotting blood glucose readings 2015-05-25 2015-05-26 2015-05-27 2015-05-28 for errors or omissions.

54 Introduction to Data Science using Python codemag.com codemag.com Angular 2 Forms 23


ONLINE QUICK ID 1611041

The Simplest Thing Possible:


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

You can also specify the frequency using the freq param-

Dynamic Lambda ExpressionsPart 3


eter:

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


freq='M')
In my previous two columns for CODE Magazine, I introduced you to how dynamic lambdas and expression trees work print dates2
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 DatetimeIndex(['2016-05-31', '2016-06-30',
'2016-07-31', '2016-08-31',
'2016-09-30', '2016-10-31',
lambda expressions, I strongly encourage you to read for dynamic lambda expressions and thats the use case '2016-11-30', '2016-12-31',
those articles before continuing with this one. Im going to tackle in this article. '2017-01-31', '2017-02-28',
'2017-03-31', '2017-04-30'],
The most common use case for lambda expressions is with dtype='datetime64[ns]', freq='M')
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- The default frequency is in days, but if you specified M for
itself should be usable as is. But what if your development out the need to understand how LINQ works. Lets step freq, the frequency is changed to monthly. You can even
staff isnt familiar with LINQ or if you need to generate through the code: change the frequency to hourly:
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> dates3 = pd.date_range('2016/05/17 09:00:00',
linkedin.com/in/johnvpetersen By less leaky, I mean an abstraction that doesnt expose periods=8,
@johnvpetersen more complexity than whats absolutely necessary to ac- You wont know at design time what the specific data type freq='H')
John is a graduate of the Rut-
complish the task at hand. Lets get started. will be. Thats precisely why generics exist in .NET. After print dates3 Figure 9: Plotting a line chart from a Panda Series
gers University School of Law you step through the code, the next section demonstrates '''
how to use this class. DatetimeIndex(['2016-05-17 09:00:00',
in Camden, NJ and has been
admitted to the courts of the
What Do You Need? '2016-05-17 10:00:00', Here, youre creating a list from a string (ABCD). The Pandas
Commonwealth of Pennsylvania To accomplish the task, you need the following: List<ExpressionCriterion> _expressionCriterion = new '2016-05-17 11:00:00', DataFrame created looks like this:
List<ExpressionCriterion>(); '2016-05-17 12:00:00', Pandas is a software library
and the state of New Jersey.
Defined criteria that specifies a property, some val- '2016-05-17 13:00:00', ''' written for the Python
For over 20 years, John has
ue to compare to, and a comparison type such as The Expression Criteria Class consists of one or more cri- '2016-05-17 14:00:00', A B C D programming language for data
developed, architected, and
equals, greater than, or equals, etc. teria elements. Each criteria element manifests as an in- '2016-05-17 15:00:00', 0 1.269108 -0.496408 -0.162528 0.432953 manipulation and analysis. In
designed software for a variety
particular, it offers data structures
of companies and industries. String multiple criteria that supports both And and stance of an Expression Criterion Class that are discussed '2016-05-17 16:00:00'], 1 -0.895156 -0.014969 0.383383 1.902658
and operations for manipulating
John is also a video course Or conjunctions later in this section. dtype='datetime64[ns]', freq='H') 2 -1.292945 0.656012 0.376739 0.875683
numerical tables and time series.
author for Lynda.com. Some level of validation ''' 3 0.456998 0.863970 1.155423 0.587762
His latest course, Foundations A lambda that can be used as the basis of a LINQ private string _andOr = "And"; 4 -0.630788 0.006764 0.734363 0.975344
of Programming, Open Source query Observe that in each of the above examples, the date_ 5 0.277726 0.947913 -0.838228 -0.318126
Licensing, teaches everything Each criterion can be grouped and joined with other cri- range() function is smart enough to detect the date for- 6 -2.095660 0.757282 -0.917780 -0.345179
you need to understand The following snippet illustrates these features: teria with an And or an Or conjunction. mat passed in (the first one uses YYYYMMDD, and the 7 -1.399808 -2.210822 -2.009842 -1.449238
about the legal aspects of second one uses YYYY-MM-DD, and the third one uses 8 -1.801125 0.463970 -0.817592 1.147401
open-source licensing. _people.Where(x => public ExpressionCriteria<T> And() YYYY/MM/DD). 9 -0.938238 0.028543 -0.774980 -0.195423
(x.Age > 60 && x.Address.City == "Paoli") || { '''
(x.Address.Street == "Market Street")); _andOr = "And"; DataFrame
return this; A DataFrame is a two-dimensional NumPy-like array. Notice that the index is automatically created for the
Read from left to right, the query fetches records where } Think of it as a table. Figure 8 shows the structure of a DataFrame. If you wish, you can change the index to
a persons age > 60 and the city is Paoli or if the street is public ExpressionCriteria<T> Or() DataFrame in pandas. something else, such as date and time. For example, the
Market Street. If the query structure is constant and the { following code snippet shows using a Series as the index
only variable parts are the comparison values, theres no _andOr = "Or"; The following code snippet shows how a DataFrame can for the DataFrame:
problem in referencing variables: return this; be created in pandas:
} days = pd.date_range('20150525', periods=10)
var age = 60; import pandas as pd data_frame = pd.DataFrame(np.random.randn(10,4),
var city = "Paoli"; import numpy as np index=days,
var street = "Market Street"; The Expression Criteria Class exposes a fluent interface. columns=list('ABCD'))
By invoking the And() or Or() methods, the criterion data_frame = pd.DataFrame(np.random.randn(10,4), print data_frame
_people.Where(x => specified will be joined with the And or Or conjunction columns=list('ABCD'))
(x.Age > age && x.Address.City == city) || respectively. print data_frame The index parameter is assigned a Series (days), which is
(x.Address.Street == street)); generated by the date_range() function. The DataFrame
public ExpressionCriteria<T> Add(string propertyName, First, you use the random.randn() function to generate now looks like this:
In the real world, of course, more flexibility is needed. object value, ExpressionType operator) an array of the specified shape (10 rows and four col-
You need some way to specify any field in the collection { umns; in this example) filled with random floating-point '''
as part of a query. You also need to be able to specify var newCriterion = new numbers sampled from a univariate normal (Gaussian) A B C D
multiple criteria elements that can be joined with any ExpressionCriterion(propertyName, value, operator,_ distribution of mean 0 and variance 1. The columns pa- 2015-05-25 -0.181824 -0.522341 -0.629486 -0.098926
combination of And/Or logic. This is the precise use case andOr); rameter specifies a list containing the column headers. 2015-05-26 -0.786451 0.270572 -0.007755 0.407279

24 The Simplest Thing Possible: Dynamic Lambda ExpressionsPart 3 codemag.com codemag.com Introduction to Data Science using Python 53
Series _expressionCriterion.Add(newCriterion);
A Series is a one-dimensional NumPy-like array, with each return this;
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. 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:
Although Python supports
Property Name: The property of the Expression
lists and dictionaries Criterias type that will be used as the basis of a
for manipulating structured criterion element.
data, its not well-suited Value: The value used, in conjunction with an ex-
for manipulating numerical pression type to compare to the property.
tables, such as the one stored Op: The Expression Type used to compare the Prop-
in the CSV file. erty Name with the Value.

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


tor relationship:
The following code snippet shows how a Series can be
created in pandas: x.Age > 60

import pandas as pd Property: Age


Value: 60
series = pd.Series([1,2,3,4,5]) Operator: Greater Than
print series
''' When the Add() Method is invoked, the current state of
0 1 the _andOr variable is applied as well. By default, the
Figure 6: Plotting the grades for a student for the various semesters 1 2 value is set to And.
2 3
3 4 The following is the private class definition for each cri-
4 5 terion:
dtype: int64
''' class ExpressionCriterion
{
Like NumPy, you need to import the pandas package be- public ExpressionCriterion(
fore using it. The Series() function creates a pandas se- string propertyName,
ries from a list of items. object value,
ExpressionType operator,
string andOr = "And")
{
One good use of AndOr = andOr;
Series is for generating PropertyName = propertyName;
date ranges. Value = value;
Operator = op;
Figure 7: The structure of a Series validateProperty(typeof(T), propertyName);
}
One good use of Series is for generating date ranges. Con-
sider the following example: PropertyInfo validateProperty(
Figure 8: The structure of a DataFrame Type type, string propertyName)
import pandas as pd {
string[] parts = propertyName.Split('.');
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 var info = (parts.Length > 1)
cose readings in mmol/L. ''' ? validateProperty(
DatetimeIndex(['2016-05-25', '2016-05-26', type.GetProperty(
To be able to deal with data stored as tables, you need '2016-05-27', '2016-05-28', parts[0]).PropertyType,
a new data type thats more suited to deal with it: That '2016-05-29', '2016-05-30', parts.Skip(1).Aggregate((a, i) =>
means that you want pandas. Pandas is a Python package '2016-05-31', '2016-06-01', a + "." + i))
providing fast, flexible, and expressive data structures '2016-06-02', '2016-06-03', : type.GetProperty(propertyName);
designed to make working with relational or labeled '2016-06-04', '2016-06-05'],
data both easy and intuitive. dtype='datetime64[ns]', freq='D') if (info == null)
''' throw new ArgumentException(propertyName,
Pandas supports two key data structures: Series and $"Property {propertyName}
DataFrame. Lets take a closer look at these two data The date_range() function creates a series representing is not a member of
structures before I come back to look at how to use pan- a series of dates. The periods parameter allows you to {type.Name}");
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 codemag.com The Simplest Thing Possible: Dynamic Lambda ExpressionsPart 3 25
return info; expression, Listing 2: Plotting a bar chart from data loaded from a CSV file
} GetExpression(parameterExpression, item));
from matplotlib import pyplot as plt label="Jim",
public string PropertyName { get; }
from matplotlib import style color = "m",
public object Value { get; } }
import numpy as np align= "center"
public ExpressionType Operator { get; } }
)
public string AndOr { get; }
style.use("ggplot")
} return expression != null ? plt.title("Results") # sets the title
Expression.Lambda<Func<T, semester,grade = np.loadtxt("results.csv", unpack=True, plt.xlabel("Semester") # sets the label for x-axis
Each criterion has four attributes: bool>>(expression, parameterExpression) : delimiter=",") plt.ylabel("Grade") # sets the label for y-axis
null;
Property Name } plt.bar( plt.legend() # shows the legend
Value semester, plt.grid(True, color="y") # shows and sets the grid color to yellow
Expression Type grade,
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. First, the %matplotlib inline statement tells Jupyter Listing 3: The readings of a persons blood glucose readings stored in a CSV file
var lambda = new ExpressionCriteria<Person>() Notebook to display the matplotlib chart inline, rather ,DateTime,mmol/L
The first step in creating a lambda expression is to first .Add("Age", 60, ExpressionType.GreaterThan) than in a separate window. To plot charts, use the mat- 0,2016-06-01 08:00:00,6.1
create an expression: And() plotlib librarys pyplot module and import it as plt (by 1,2016-06-01 12:00:00,6.5
Lambdas and .Add("Address.City", "Paoli", convention). The plot() function displays a default line 2,2016-06-01 18:00:00,6.7
Expression Trees Expression ExpressionType.Equal) chart with the first argument (a Python list) on the x-axis 3,2016-06-02 08:00:00,5.0
GetExpression(ParameterExpression Or() and the second argument (also a Python list) as the y- 4,2016-06-02 12:00:00,4.9
A good resource for further
parameter, ExpressionCriterion .Add("Address.Street", "Market Street", axis. The result is as shown in Figure 4. 5,2016-06-02 18:00:00,5.5
details on lambdas and
ExpressionCriteria) ExpressionType.Equal) 6,2016-06-03 08:00:00,5.6
expression trees can be
{ .GetLambda().Compile(); Although you can plot a matplotlib chart using Python 7,2016-06-03 12:00:00,7.1
found on the MSDN site:
Expression expression = parameter; lists, you can often plot it using NumPy arrays. Consider 8,2016-06-03 18:00:00,5.9
https://msdn.microsoft.com/
foreach (var member in another example, where youve recorded the number of 9,2016-06-04 09:00:00,6.6
en-us/library/bb397951.aspx.
ExpressionCriteria.PropertyName.Split('.')) var result = _people.Where(lambda); 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
expression = With the abstraction illustrated above, two important parison. 12,2016-06-05 08:00:00,7.6
Expression.PropertyOrField(expression, member); things are accomplished. First, in the event that your 13,2016-06-05 12:00:00,5.1
14,2016-06-05 18:00:00,6.9
} developers arent comfortable with LINQ syntax, those Listing 1 is the code to plot three line charts in a single
15,2016-06-06 08:00:00,5.0
Return issues are addressed with a user-friendly fluent-type in- figure, showing the number of rainy days per month for
16,2016-06-06 12:00:00,6.1
Expression.MakeBinary( terface. Second, the class illustrated here can support the past three years.
17,2016-06-06 18:00:00,4.9
ExpressionCriteria.Operator, on-the-fly LINQ queries. In other words, at run time, this 18,2016-06-07 08:00:00,6.6
expression, class can be leveraged to account for any field and any The xticks() function sets the locations and labels of the 19,2016-06-07 12:00:00,4.1
Expression.Constant(ExpressionCriteria.Value)); combination of criteria that are joined with And or Or ticks on the x-axis. In this example, Ive set it to display 20,2016-06-07 18:00:00,6.9
} conjunctions. 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
Once the expression is created, a lambda expression can In the next column, Ill extend the Expression Criteria 23,2016-06-08 18:00:00,10.9
be created: Class with the ability to leverage methods and arrays. 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
public Expression<Func<T, bool>> If you want a copy of the Expression Criteria Class, follow files. Suppose theres a CSV file named results.csv con- 26,2016-06-09 18:00:00,4.9
GetLambda() me on Twitter: @johnvpetersen and Ill send you a link taining the grade results of a student for 10 semesters:
{ to the code
Expression expression = null; 1,2
var parameterExpression = Enjoy!! 2,4.5 returned array is unpacked as individual arrays for each
Expression.Parameter(typeof(T), 3,1 field, and the delimiter argument specifies the delimiter
typeof(T).Name.ToLower()); John V. Petersen 4,2 used to separate the various fields in the text file. The
foreach (var item in 5,3.5 semester variable is now an array containing the values
_expressionCriterion) 6,2 from 1 to 10, and the grade variable is an array contain-
{ 7,1 ing the grades (2,4.5, ,2).
if (expression == null) 8,2
{ 9,3 Listing 2 shows the code to plot a bar chart using the
expression = 10,2 data loaded from the CSV file. The generated chart is as
GetExpression(parameterExpression, item); shown in Figure 6.
} You can load the file into a NumPy array as follows:
else
{ import numpy as np
Manipulating Data and Performing
expression = Data using Pandas
item.AndOr == "And" ? semester,grade = np.loadtxt("results.csv", unpack=True, Although NumPy arrays are a much improved version over
Expression.And( delimiter=",") Pythons list, its insufficient to meet the needs of data
expression, science. In the real world, data is often presented in table
GetExpression(parameterExpression, item)) : The loadtxt() function loads the data from the specified formats. For example, consider the content of the CSV file
Expression.Or( text file. The unpack argument indicates whether the shown in Listing 3.

26 The Simplest Thing Possible: Dynamic Lambda ExpressionsPart 3 codemag.com codemag.com Introduction to Data Science using Python 51
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


ONLINE QUICK ID 1611051

Moving Forward:
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,

The Transition from Objective-C to Swift


things are much easier. Look at the following example:

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

If you follow iOS development in any capacity, youve likely heard of Apples proprietary programming language called Swift. You first specify the condition, testing for even numbers,
Since its introduction in 2014, Swift has undergone several iterations and continues to grow in popularity among the iOS and then assign it to a variable: Figure 2: Generating the cumulative sums over the rows
developer community. RedMonk, a developer-focused analysis firm, assesses the popularity of programming languages by for each column
even_nums = nums % 2 == 0

analyzing the volume of conversation around a specific For instance, one specific area where Swift needs im- The even_nums variable is now a NumPy array, contain-
language on Stack Overflow in combination with the provement is tooling. As any iOS developer knows, Xcode ing a collection of Boolean values. If you print it out,
number of repositories created using that language on is the official IDE (Integrated Development Environment) youll see just that:
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- print (even_nums)
coming in at number 17 on the list. tax highlighting, auto-complete, memory leak detectors, '''
refactoring tools, runtime performance monitoring, and [False False True False False False True]
With this rise in popularity, developers who previously benchmarks, etc. These tools can often prove invaluable ''' Figure 3: Generating the cumulative sums over
worked with Objective-C (Apples original iOS program- to developers. Although you can get the same level of the columns for each row
Jason Bender ming language) must adapt to the shifting landscape in tooling support by using third-party products or by look- The True values indicate that the particular item is an
Jason.bender@rocksaucestudios.com order to stay relevant. Objective-C still remains a viable ing into alternative IDEs, Swift lacks much of the same even number. Using this Boolean array, you can now use
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. it as an index to the numbers array: Likewise, you can subtract, multiply, and divide arrays
www.twitter.com/TheCodeBender RedMonk list, but many industry jobs already require Swift Youll likely see additional tooling support in future itera- directly:
proficiency and it could eventually replace Objective-C as tions of Swift, but for the time being, this is one of Swifts print (nums[even_nums])
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 ''' print x1 - y1 # same as np.subtract(x1,y1)
Studios, an Austin, Texas-based mind as you transition to and/or experiment with Swift. [78 22] '''
Mobile Design and Development The transition from Objective-C to Swift wont require re- ''' [[-6 -6 -6]
Company. He has 11 years cod- learning everything you know because many of the same Library support should also be considered when transi- [ 2 2 2]]
ing experience in multiple lan- concepts you acquired while working with Objective-C tioning to Swift. Objective-C has been the de facto de- The above statements could be written succinctly like this: '''
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 print (nums[nums % 2 == 0]) print x1 * y1 # same as np.multiply(x1,y1)
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 The array boolean indexing feature makes it extremely useful [[ 7 16 27]
dozens of applications includ- libraries from within a Swift project, but it requires the to manipulate a large amount of data without worrying about [ 8 15 24]]
ing a #1 ranking reference app tedious and error-prone process of creating Objective-C the underlying implementation. Heres another example: '''
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 prices = np.array([45,23,56,89,12,48]) print x1 / y1 # same as np.divide(x1,y1)
an iOS application for his wildly Swift is likely the more future-proof option at this point, and technical debt for the project. reasonable = (prices > 20) & (prices < 50) '''
popular book and Youtube but that doesnt mean that it trumps Objective-C in every print prices[reasonable] [[0 0 0]
channel: SoulPancake. scenario. Each of these languages has their own pros and This same argument somewhat applies to learning ma- ''' [2 1 1]]
cons respectively. Choosing which option will suit your terial as well. Blog posts, tutorials, books, and online [45 23 48] '''
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- Very often, you need to generate the cumulative sum of
languages strengths and weaknesses. ery online self-learning code institution offers some form Array Math a series of numbers. NumPys array makes it really easy.
of Swift class (see the sidebar for class suggestions), Another area where the NumPy array excels is in array Suppose you have the following array:
youll find fewer practical examples of Swift implementa- math. Consider the following rank-2 arrays:
tions on sites like Stack Overflow and less library content a = np.array([(1,2,3), (4,5,6), (7,8,9)])
Swift is likely the more future- on sites like GitHub. x1 = np.array([[1,2,3],[4,5,6]]) print (a)
proof option at this point, y1 = np.array([[7,8,9],[2,3,4]]) '''
but that doesnt mean it trumps You should also consider the target operating system [[1 2 3]
Objective-C in every scenario. when choosing between the two languages. As time You can add each of the two arrays items by using the + [4 5 6]
passes, this issue becomes less and less relevant but cur- operator on the two arrays: [7 8 9]]
rently, in order to support Swift, you must target iOS 7.0+ '''
and Mac OS 10.9+. Anything prior to that and youll have print x1 + y1
Objective-C isnt IrrelevantYet to resort to Objective-C. Contrarily, all versions of tvOS ''' To generate the cumulative sum of all the numbers in the
Before you look at the improvements that Swift brings with and watchOS support Swift. [[ 8 10 12] array, use the cumsum() function:
it, lets take a look at Objective-Cs strengths and why it [ 6 8 10]]
still remains relevant. You can attribute that relevancy to Additionally, applications built using anything prior to ''' print (a.cumsum()) # prints the cumulative sum
the simple fact that Objective-C has been around consider- Swift 3.0 will likely be 10-20MB greater in size then their # of all the elements in
ably longer then Swift. As a result, there are tools, librar- respective Objective-C counterparts. This results from Alternatively, you can also use the add() function to add # the array
ies, support, and a surrounding community thats devel- needing to include all of the Swift runtime libraries within the two arrays: '''
oped and matured over many years. Swift will get to that the application, even if the application only has a single [ 1 3 6 10 15 21 28 36 45]
point eventually but it still has significant ground to cover. line of Swift code. np.add(x1,y1) '''

28 Moving Forward: The Transition from Objective-C to Swift codemag.com codemag.com Introduction to Data Science using Python 49
NumPy Array Basics zeroes, you can use the zeros() function with a number Swift is still very much in its maturation process. Apple also means that Swift resembles other popular modern
In NumPy, an array is of type ndarray (n-dimensional array). A indicating the size of the array: continues to iterate on the platform and each new version languages like JavaScript, Java, Python, and C#, mak-
NumPy array is an array of homogeneous values (all of the same seems to retire the previous one rather then simply add- ing it easier for newcomers to adopt.
type), and all items occupy a contiguous block of memory. a1 = np.zeros(2) # array of rank 1 with all 0s ing to it and maintaining backward compatibility. While Maintenance: Swift eliminates the two-file system
print a1.shape # (2,) Swift remains in its growth period, Objective-C still has a that Objective-C uses (.h header file paired with .m
To use NumPy, you first need to import the numpy package: print a1[0] # 0.0 place in iOS development. implementation file), which means less code and less
print a1[1] # 0.0 to manage. Previously, a developer needed to manu-
import numpy as np So why would you bother learning or switching to Swift at ally synchronize method and variable names between
If you want to create a rank 2 array, simply pass in a tuple: this point? Because if you plan on being an iOS developer the two files, but with Swift, you dont have that extra
Array operations are very similar to that of the Python for the long run, Swift will eventually become your primary overhead to worry about, giving you more time to fo-
list. For example, the following code snippet creates a a2 = np.zeros((2,3)) # array of rank 2 with all 0s; language for development. Its not a question of whether this cus on application logic. Keith Smiley, an iOS developer
Python list and then converts it to a NumPy array: # 2 rows and 3 columns will happen, but rather its a question of how long it will take. for Lyft, gave a talk about the company rewriting their
print a2.shape # (2,3) Sooner or later, Swift will supplant Objective-C and become application in Swift. He boasted that the code base
l1 = [1,2,3,4,5] print a2 the dominant, if not the only, development language used to shrunk by over 70%, going from an original 75,000
array1 = np.array(l1) # rank 1 array ''' build applications for iOS, MacOS, Apple Watch, and Apple TV. lines of code in Objective-C to a mere 22,000 in Swift
[[ 0. 0. 0.] As with learning anything, it takes time to perfect your craft while maintaining the same level of functionality and
In this case, array1 is known as a rank 1 (one dimen- [ 0. 0. 0.]] and failing to get started now could be detrimental later. performance (check the side bar for a link to the talk).
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: 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
For this article, Im using Jupyter lines of code in Objective-C to Although TeamTreehouse.com
You can print out the shape of the array using the shape a3 = np.full((2,3), 8) # array of rank 2 eventually become your primary
Notebook for all the examples. is one of my favorite online
To install Jupyter Notebook,
property: # with all 8s language for development. a mere 22,000 in Swift while coding education providers,
print a3 maintaining the same level of
download and install Anaconda Its not a question of whether it doesnt look like theyve
from https://www.continuum.io/ print (array1.shape) # (5,) ''' functionality and performance. updated their Swift courses
[[ 8. 8. 8.] this will happen, but rather a
downloads. Anaconda comes for Swift 3 yet. However,
with all the major packages that The shape property returns a tuple containing the dimen- [ 8. 8. 8.]] question of how long it will take. they do have 55 hours of
you need for Data Science, such sion of the array. In the above example, array1 is a 1-di- ''' excellent Swift 2 course material at
as NumPy and pandas. mensional array of five items. Playgrounds: Swift comes with an interactive en- https://teamtreehouse.com/
In linear algebra, you often need to deal with an identity vironment called Swift Playgrounds. Within a play- tracks/ios-development-with-
Just like Python list, you can access items in the NumPy matrix, and you can create this in NumPy easily with the The Strengths of Swift ground, developers can write and test code in real swift-20
array using indexing as well as slicing: eye() function: 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
print (array1.shape) # (5,) a4 = np.eye(4) # 4x4 identity matrix 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
print (array1[0]) # 1 print a4 key improvements and strengths of the platform. tion logic in small chunks, help programmers visual- 30 hour course
print (array1[1]) # 2 ''' ize data, and provide a stage for interactive learning. https://www.udemy.com/
print (array1[1:3]) # [2 3] [[ 1. 0. 0. 0.] Speed: Swift is generally faster then Objective- Open Source: Because Apple made Swift open complete-ios-10-developer-
course
print (array1[:-2]) # [1 2 3] [ 0. 1. 0. 0.] C for several reasons, including: Swift is a static source, there have already been initiatives to expand
print (array1[3:]) # [4 5] [ 0. 0. 1. 0.] typed language, it can use static dispatching, it has the platforms that Swift can run on. Its expanding to
[ 0. 0. 0. 1.]] improved dynamic dispatching, memory optimiza- build on Linux and you can currently find solutions
You can also pass in a list containing the index of the ''' tions, inline functions, and also because the LLVM that let you write backend code in Swift. Additionally
items you want to extract to the array: linker can optimize across source file boundaries. an effort is underway to make Swift Android compat-
And if you need to populate an array with some random Safety: Objective-C uses pointers and if you call an ob- ible (see the sidebar for more details).
print (array1[[2,3]]) # [3,4] values, you can use the random.random() function to jects method using an object that has yet to be initial-
generate random values between 0.0 and 1.0: ized (nil pointer), nothing happens. The line of code
The following code snippet shows how you can create a does nothing. Although at first glance it might seem
Moving from Objective-C
two-dimensional array: a5 = np.random.random((2,4)) # populate a rank 2 like a good idea that this doesnt cause the applica- to Swift in Code
# array (2 rows tion to crash, it can be the source of all sorts of bugs Now that youve looked at the philosophical differences
l2 = [6,7,8,9,0] # 4 columns) with and lead to many developer headaches as you try to between Objective-C and Swift, turn your attention to the
array2 = np.array([l1,l2]) # rank 2 array # random values pinpoint whats gone wrong. Swift introduces optional practical differences in implementation. How exactly does
print (array2) print a5 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
[[1 2 3 4 5] [[ 0.21135397 0.39570425 0.25548923 0.05606163] piler error. This consistent behavior results in errors as a look at this and more in the next sections.
[6 7 8 9 0]] [ 0.14495175 0.19093966 0.29366716 0.61189549]] you write the faulty code, shortcutting the feedback
''' ''' loop and letting you correct your errors in real time. It Syntax Differences
print (array2.shape) # (2,5) - 2 rows and ultimately leads to less time spent debugging. Although Swift contains most of the object types you
# 5 columns Finally, you can create a range of values from 0 to n-1 Readability: Swift is independent of the C foundation know in Objective-C, the syntax to use those objects has
print (array2[0,0]) # 1 using the arange() function: that Objective-C is tied to. This allows Swift to unify changed. In fact, most of the operations youve grown
print (array2[0,1]) # 2 keywords, drop legacy conventions, and depart from accustomed to in Objective-C have seen some syntax
print (array2[1,0]) # 6 a6 = np.arange(10) # creates a range from 0 to 9 more obscure syntax. Additionally, you no longer need changes, some more drastic then others. Lets run
print a6 # [0 1 2 3 4 5 6 7 8 9] semicolons to end a line, parenthesis to surround through some of the familiar objects and operations to
Creating and Initializing Arrays using NumPy conditionals, and the removal of nested method calls compare the Objective-C and Swift syntax.
NumPy contains a number of helper functions that make Boolean Array Indexing means you no longer have brackets inside of brackets
it easy to initialize arrays with some default values. For One of the many useful features of the NumPy array is its inside of brackets. You end up with an expressive lan- Variables and Constants: In Swift, variables are
example, if you want to create an array containing all support for array boolean indexing. Consider the following guage that more closely resembles natural English. It declared using the var keyword.

48 Introduction to Data Science using Python codemag.com 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) Figure 1: Understanding list slicing in Python
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. The following statement prints out all the items starting The following statement prints all of the items starting
let textConstant = "Hello World For instance, Swift enums can assign strings, characters, from index 1: from index 0 to 4, and a step of 2, which means that it
integers, or floats whereas Objective-C was limited to prints items at index 0 and 2:
// Declaring a constant in Swift (runtime) integers. Additionally, theyre also considered first-class print(lst[1:]) # ['Hello', 3.14, True]
var randomNumber = arc4random() types, adopting many of the same functionalities usually print(lst[0:4:2]) # [4, 3.14]
let numberConstant = randomNumber reserved for classes, such as computed properties and in- Notice that in this case, the end isnt specified. Its value
stance methods, which can provide additional context to defaults to the length of the list, which is four items. So If you have difficulty remembering how slicing works in
// Declaring a constant in Objective-C an enums current value. the above is essentially the same as: Python, you can use the method shown in Figure 1. Just
NSString *const textConstant = @Hello Worldd; imagine the index to be sandwiched between the ele-
// standard enum in Objective-C print(lst[1:4]) ments and it will be very easy for you to understand how
String Interpolation: Swift makes string interpolation enum carMakes { slicing works.
easier and more readable then its Objective-C counter- Honda, The following statement prints the first three elements:
parts. You can insert variables into the string directly, Toyota,
resulting in more readable code. Chevy, print(lst[:3]) # [4, 'Hello', 3.14]
Extending Pythons List DataType
Ford using NumPy
// String Interpolation in Swift }; In this case, the start isnt specified so it defaults to 0, The key problem with the Pythons list data type is its ef-
var firstName = "Jason which is essentially the same as: ficiency. A list allows you to have non-uniform type items;
var author = "The authors name is \(firstName) // example of how to utilize enum each item in the list is stored in a memory location, with
int carMake = Honda; print(lst[0:3]) the list containing an array of pointers to each of these
// String Interpolation in Objective-C locations. A Python list requires:
NSString* firstName = @Jason; This standard Objective-C enum, demonstrated in the The following statement prints all items in the list except
NSString* author = [NSString stringWithFormat: previous snippet, called carMakes contains a list of vari- the last two: At least 4 bytes per pointer
@The authors name is %@, firstName]; ous automobile manufacturers. By default, the system as- At least 16 bytes for the smallest Python object: 4
signs an integer to each of the listed types starting with print(lst[:-2]) # [4, 'Hello'] bytes for the pointer, 4 bytes for the reference count,
Functions: The function syntax in Swift differs pretty sig- 0 for Honda, 1 for Toyota, etc. You can change the default and 4 for the value. These round up to 16 bytes.
nificantly from Objective-C. The following snippet demon- system-assigned value of the enum types but beyond that, The following statement prints the last two items:
strates a function in Swift and compares it to the tradition- there isnt much additional functionality to take advantage Because of the way the Python list is implemented, ac-
al Objective-C syntax for the same function. Notice that the of. As mentioned previously, with Swift, you can use other print(lst[-2:]) # [3.14, True] cessing items in a large list is computationally expensive.
return type appears at the end of the function declaration data types and implement functions and computations To solve this problem, you can use NumPy. NumPy is an
in Swift, as opposed to the beginning in Objective-C. within the enum, as you can see illustrated in Listing 1. The following statement reverses all the items in the extension to the Python programming language, adding
Notice that in Listing 1, you have an enum called Car. list: support for large, multi-dimensional arrays and matri-
// Function declaration in Swift It has two cases that describe how you can create a Car: ces, along with a large library of high-level mathematical
func addTwoNumbers(a: Int, b: Int) -> Int { using make and model with the Make case or using color print(lst[::-1]) # [True, 3.14, 'Hello', 4] functions to operate on these arrays.

30 Moving Forward: The Transition from Objective-C to Swift codemag.com codemag.com Introduction to Data Science using Python 47
ONLINE QUICK ID 1611081

Introduction to Data Science Listing 1: Swift enumeration example


enum Car
{
case let .Appearance(color, size):
return color + " " + size

using Python
case Make(make:String, model:String) }
case Appearance(color:String, size:String) }
}
func description() -> String
{ let car1 = Car.Make(make: "Toyota", model: "Camry")
In my previous article (CODE Magazine, July/August 2016) on the Internet of Things (IoT), I mentioned the two components switch self let car2 = Car.Appearance(color: "Blue", size: "Sedan")
of IoT: Data Collection and Data Analysis. In that article, you learned how the Python language was used to program { print(car1.description()) // Toyota Camry
case let .Make(make, model): print(car2.description()) // Blue Sedan
your Raspberry Pi for data collection, talking to all the different sensors and at the same time allowing you to use it to return make + " " + model

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): Listing 2: Swift class example with setter method (required values)
Im going to turn my attention to the second component class NewCar
of IoT: Data Analysis. print(lst[0]) # 4 { func description() -> String
print(lst[1]) # Hello var condition: String = "New" {
In recent years, youve often heard the term Data Science. print(lst[2]) # 3.14 var make:String return "The \(make) \(model) is
According to Wikipedia, Data Science is an interdisciplin- print(lst[3]) # True var model:String in \(condition) condition"
ary field about processes and systems to extract knowl- }
edge or insights from data in various forms, either struc- Slicing Lists in Python init(make:String, model:String) }
Wei-Meng Lee tured or unstructured, which is a continuation of some of When youre dealing with lists, you usually want to extract {
the data analysis fields, such as statistics, data mining, a group of items from them, not just a single one. For this self.make = make var car = NewCar(make: "Toyota", model: "Corolla")
weimenglee@learn2develop.net self.model = model car.description() // The Toyota Corolla is in New Condition
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 and size with the Appearance case. It also contains a func- tializer, you could instantiate an instance of the class
www.learn2develop.net), a one or more elements tion called description, which looks to see what case was without assigning a value to make or model. Listing 2
technology company special- from a list. used to construct the respective Car enum and returns a also shows how you then create an instance of the class
izing in hands-on training string representation of the cars associated values. Below using that initializer method while assigning the class in-
In simple terms, Data Science the enum, you can see two examples of creating a Car stance to a variable at the same time. Once done, you can
on the latest technologies.
Wei-Meng has many years of involves using tools to derive using the different Make and Appearance cases. Regardless then access the description method on the class using
training experience and his meanings from a huge pool Slicing in Python has the following syntax: of which case you used to create car1 and car2, you can the assigned variable reference, as demonstrated.
training courses place special of data, allowing you to make call the description function on either and it uses the
emphasis on the learning-by- conclusions about the past or list[start:end:step] information to construct a string description and return it. What if you didnt want to set the make or model at the
doing approach. His hands-on time the class gets initialized? Listing 3 demonstrates
predict the future.
approach to learning program- As you can see in that snippet, start is the index of the Classes: An Objective-C class usually consists of two files: a how this is achieved using Optionals. Changing make and
ming makes understanding starting item, end is the index of the last item (which is .h header file and a .m implementation file. The structure, model to optional types allows you to remove the initial-
the subject much easier than not included in the answer), and step is the number of in most cases, resembles the following code snippet. izing method. Ill cover Optionals and Listing 3 in more
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, detail in the next section.
documentation. His name do it justice. But you need to start somewhere. In this the following defaults are assumed: // class .h file
regularly appears in online and article, Ill start by introducing you to some of the tools @interface ClassName : NSObject New Data Types: Optionals and Tuples
print publications such as DevX.
commonly used in Data Science. Youll see that because If start is omitted, its assumed to be 0. @end Swift expands on the data types you grew accustomed to
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 in Objective-C with the addition of Optionals and Tuples. As
Magazine.
an active community of Python libraries developers, its the list. // class .m file mentioned briefly in the previous section, Optionals provide
no coincidence that Python is a favorite language among If step is omitted, its assumed to be 1. @implementation ClassName a way to tell the system that its okay if this variable has a
data scientists. @end nil value at some point. Without the optional notation, a nil
Lets take a look at some examples. The following state- value results in a compiler error. You can declare a variable
ment prints out the items from index 0 to 1 (remember With Swift, the two-file system has disappeared and as an optional with the addition of a question mark after the
A Quick Introduction to Python that the item at index 2 isnt returned in the answer): theres no longer a need for header files. As a result, class variable type, as demonstrated in the following examples.
Before I get to the heart of Data Science using Python, definitions get simplified to now resemble the following:
its important to ground yourself in the basics of one of print(lst[0:2]) # [4, 'Hello'] // Swift Optionals
the key data types in Python: list. A lot of operations that // Swift Class Definition var integerOptional: Int? // starts as nil
you can perform on a list apply to the other data types An easy way to understand the above syntax is to interpret it class ClassName { var stringOptional: String? // starts as nil
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. Notice how you didnt have to assign any value at the
The following snippet prints out the items from index 1 to Listing 2 demonstrates a more robust class definition point that you declared the variable. Although you tech-
In Python, a list is a collection of values: 1 and only one item is returned: 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
lst = [4,"Hello", 3.14, True] print(lst[1:2]) # ['Hello'] and model. Notice that under the property declarations, an initial value of nil. Lets look at the following snippet
print(lst) # [4, 'Hello', 3.14, True] theres an initializer. This is important because with- to see how that makes a difference.
If you use this the way I showed you in the previous ex- out that initializer, the compiler throws an error. Swift
As you can see in the output above, the items in a list ample to interpret the syntax, thats: get (2-1) items from doesnt allow nil values unless you use an Optional data // Normal Swift Variable
need not be of the same type in that snippet, theres a the list starting from index 1. type (covered in the next section) and without that ini- var someNumber: Int

46 Introduction to Data Science using Python codemag.com codemag.com Moving Forward: The Transition from Objective-C to Swift 31
Listing 3: Swift class example using optional values 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
class NewCar in \(condition) condition"
expected system.
{ }
var condition: String = "New" }
Now, youll need to construct the outputs. In most cases,
var make:String? youll want a discriminated union. The first potential return The second case, Some (Output.ProductPriceCheckFailed e),
var model:String? var car = NewCar() type, ProductPriceNile, is the typical successful return. asks if you received a response that indicates a failure case.
car.make = "Toyota" Its a tuple type that returns the original Product infor- Because youll have access to the ProductPriceCheckFailed
func description() -> String car.model = "Corolla" mation back to you, with a decimal that contains the price information, you log the failure, then check to determine
{ car.description() // The Toyota Corolla is in New Condition on the Nile site. The second, ProductPriceCheckFailed, if theres a way to recover. Maybe there was a standard er-
return "The \(make!) \(model!) is 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.

print(someNumber) // this will cause a crash The tuple in the previous example groups together two type Output = Finally, None asks if you received no response at all. In
strings and an integer to give the used car three contextual | ProductPriceNile of Product * decimal this case, you still might want to log the failure, but you
// Swift Optional Variable values: make, model, and total mileage on the vehicle. No- | ProductPriceCheckFailed of PriceCheckFailed wouldnt have the additional information contained in
var someNumber: Int? tice that the tuples data types dont have to be consistent. the Message statement.
print(someNumber) // prints nil There you have (String, String, Int) but you could have (Int, Transforming Inputs into Outputs
someNumber = 20 Bool) or any other permutation. Once you create a tuple Once you know the inputs and outputs, you need to think let resolve id output =
print(someNumber) //prints Optional(20) like usedCar, you can deconstruct it into individual vari- about how to transform the inputs into the outputs. You match output with
ables at any point, as shown in the next example. Further- next create the transform function. Remember that to | Some (Output.ProductPriceNile (e, price)) ->
In the first example, the variable was declared but accessed more, that code snippet also shows that if you want to de- use the filters module described above, you want the async {()} // write to event store
SPONSORED SIDEBAR:
before it has been assigned a value, causing the applica- construct the tuple but only need access to part of the data functions to have type Input -> Async<Output>. In | Some (Output.ProductPriceCheckFailed e) ->
tion to crash. In the second example, because you declared set it contains, you can use an underscore to let the system this case, youre constructing a successful case to return, async {()} // log, and attempt to recover Need Help?
someNumber as an Optional, it starts as nil until its later know to ignore the remaining values. Lastly, the snippet but this is really the meat of the microservice. Here, you | None ->
assigned the value of 20. Notice that when you go to print also demonstrates that you can reference the values of might connect out to an API, then process some informa- async.Return () // log failure Looking to convert your
someNumber after assigning it a value of 20, the result of usedCar using dot notation with the index of the value. tion, or otherwise do the work of converting from your application to a new
the operation is Optional(20). What does this mean? Be- inputs into your outputs. By using the Option type here, youre able to handle an language, or need help
cause an Optional can technically be nil and accessing nil // 1. deconstruct entire tuple additional failure case, the one where you receive no re- optimizing your application?
values directly can cause runtime errors, theres a layer of let (make, model, mileage) = usedCar let transform input = sponse at all, very naturally. The experts at CODE
safety in between the program and the value that the Op- print("the make is \(make)) async { Consulting are here to
tional contains. Think of the Optional as a wrapper around print("the model is \(model)) return Some(ProductPriceNile( Consuming the Service help with your projects needs!
the value. In order to access the raw value, you need to print("the mileage is \(mileage)) {Sku="343434"; Finally, you need to gather the decoded input and the From desktop to mobile
unwrap it. Unwrapping an Optional is as easy as adding an ProductId = 17; two functions to send to a consume function that youve applications, CODE developers
have a plethora of
exclamation point after the variable name, but take special // 2. deconstruct single value ProductDescription="My amazing product"; created internally. This function will then be called for
experience in developing
care, because unwrapping a nil Optional causes a runtime let (make, _, _) = usedCar CostPer=1.96M}, each event in an event stream to which youre subscribed.
software and programs
error as the exclamation point essentially translates to I print("the make is \(make)) 3.96M))
for different platforms.
know this variable definitely has a value; please use it. } consume (decode Input.Product) resolve interpret For more information visit
Consider the following examples. // 3. access tuple values using dot notation www.codemag.com/consulting
print("the make is \(usedCar.0)) Note that youre also returning an Option type. This is
// Incorrect optional unwrapping print("the model is \(usedCar.1)) similar to C#s Nullable, but more powerful in the fol- Conclusion or email us at
info@codemag.com.
var someNumber: Int? = Int("abc) lowing ways: The tools and techniques outlined in this article have
print(someNumber!) // value nil, fatal error Refer back to the initial creation of the usedCar tuple. You introduced you to functional programming and microser-
assigned it a tuple containing (Toyota, Corolla, 45109). Although C#s nullable can be used on an Integer, vices and helped clear up some misconceptions you may
// Correct optional unwrapping Most of us could deduce that Toyota and Corolla refer to a a Boolean, or a few other fundamental types, Op- have had. Ideally, theyve also helped show you a suc-
var someNumber: Int? = Int("abc) brand of automobile. Using that context, its a logical assump- tion is available to use on any type: a string, a cus- cessful, real-world case of functional programming that
if (someNumber != nil) { tion that the last set of numbers might be mileage. However, tom type, or even a whole function. you can use as an example to help your company get
print(someNumber!) not all data sets have the same level of transparency. If you Its possible to nest Option, and create an started with microservices in F#. Good luck!
} wish to give your tuple additional context when you create it, Option<Option<string>>.
you can provide element names, as shown in the next snippet. You can use Map, Filter, and other functions to op- Rachel Reese
As you can likely deduce from the example, you should con- erate on your Option type.
firm that the Optional doesnt contain a nil value before var usedCar = (make: "Toyota", model: "Corolla", Possibly most importantly, in order to use the value
you unwrap it. Additionally, if you know that the Optional mileage: 45109) thats returned, you must pattern match on the Op-
will contain a value at the time you plan to access it, you print("the make is \(usedCar.make)) tion type. In doing so, you have a forced built-in
can have it automatically unwrap itself by swapping the print("the model is \(usedCar.model)) null check that can save you from NullReference-
question mark in the variable declaration for an exclama- print("the mileage is \(usedCar.mileage)) Exceptions.
tion point.
Creating a New Project Interpreting the Output
The other new data type found in Swift is called tuples. Creating a new Swift project is essentially the same process Now that youve obtained output from the transform
Tuples provide a way to group many values into a single as creating an Objective-C project. In Xcode, go to File -> function, you need to process, interpret, and resolve it.
compound value. The values that a tuple contains can be of New -> Project to trigger the New Project dialog. Choose Was it successful or was there a failure? Heres where the
any type and you can mix and match types within a single the project template and youll get presented with the form Option type comes in handy. The resolve function isnt
tuple. Consider the following example containing a tuple pictured in Figure 1. Notice the language selection box il- much more than one large pattern match statement.
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 The first case that you want to check, Some
var usedCar = ("Toyota, "Corolla, 45109) choose a location to save the project into, and then press (Output.ProductPriceNile (e, price)), asks if you re-
// usedCar is of type (String, String, Int) Create to launch into your new Swift project. ceived a response that indicates a successful case. A

32 Moving Forward: The Transition from Objective-C to Swift codemag.com codemag.com Case Study: Writing Microservices with F# 45
a functional-based architecture. Second, well, the origi- Independent Releasability The project structure of a standard single-view Swift ap-
nal team didnt actually choose microservices. They chose Although its possible to release a single service at once, plication resembles its Objective-C counterpart, as shown
F#. They intentionally wrote idiomatic F#, in the form of we organize ourselves into teams, and our microservices in Figure 2. Figure 2 demonstrates a traditional Objective-
small, functional scripts with well-defined inputs and out- into groups within our teams. Because were using F#, C project file structure on the left-hand side and a Swift
puts. Rather than naming the scripts with titles similar to each group of microservices is usually within the same starting structure on the right. Each has an application
SkuScript or SkuService, they named them ImportSkus. Visual Studio solution. When we talk about independent delegate, an initial view controller, and a main storyboard.
The team didnt aim for a microservices architecture, and releasability, we usually mean that well promote an en- Even the files contents are nearly identical from a method
because Jet.com is a new product, they werent breaking tire solution of related servicesoften a group of five to standpoint. Controllers each have their initial viewDidLoad
pieces off of a larger monolithic app to work their way tenat the same time. and didReceiveMemoryWarning canned functions and the
into a microservices architecture. The team just woke up app delegate has all the standard method calls that youre
one day and realized that they had been naturally build- More Even Distribution of Complexity used to seeing. Once you understand the fundamental syn-
ing toward one all along. By a more even distribution of complexity, I mean that tax differences between the two languages, jumping into
using microservices generally makes it much more simple to Xcode shouldnt present a big challenge to anyone whos
There has been much discussion around whether to cre- create, maintain, and update your services, but also that it used to using the IDE for writing Objective-C applications.
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 Practice Makes Perfect
first group, but only by accident. over some especially large projects Ive worked on. Think Lets take what you just learned in the previous sections and
of 46 projects loaded into a single solution that were cre- put it into practice to make a simple application. Often the
Microservices First ated by a team of 27 developers over three years, all to be best way to learn a new language in programming is to get
The microservices-first folks warn that splitting up a released one dark and stormy evening, if the fates allowed. your hands on it and work with it. Here, youll continue the Figure 1: Swift language selection during new Xcode project creation
monolithic application is a huge amount of effort, especial- car theme to create an application that lets users look up the
ly if youre splitting one that wasnt designed to be loosely As Ive mentioned, we happened into the microservices mileage of a used car by searching for a license plate num-
coupled. If your application has messy service boundaries, first camp. Regardless of which side you choose, its ber. Figure 3 demonstrates what the end result will look like.
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 The Set Up
that work is best done at the very beginning of the project front before you start to create or break off those ser- The set up for this application is simple. First, create a
so that it can be architected in correctly. vices, because of the additional layers of complexity gen- new Swift project as described in the last section, choos-
erated with needing to manage everything. 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
If your application has messy Show Me the Code! can find the art assets from the screenshots in the sample
service boundaries, Lets check out an example microservice. Ive created one code provided with this article. Add the background im-
youll need to tighten these here that performs a price comparison check for a specific age, the logo, and the text field to the view and position
up first before you can even product on a made-up Nile website. them accordingly. You can set the background image to
begin to work on a conversion AspectFill so it looks good on any resolution device. Once
path for microservices. Inputs and Outputs done, youre ready to switch over to the ViewController.
I mentioned previously that an important part of the defi- swift file and implement the application logic, which will
nition of a microservice at Jet.com is having well-defined get covered in the next section.
inputs and outputs. So lets define some F# types to use Figure 2: Objective-C versus Swift starting project file structure
Monolith First for the inputs and outputs for this microservice. Application Logic
The monolith-first camp tends to caution developers The applications main function is to let the user input a
about two things. First, that because there are layers Youll need to input some product information, so that license plate number, at which point the app searches its car1.licensePlate = "12345
of unnecessary complexity that microservices generate, you know which product youre comparing. Set up a Prod- data store (local mock data in this case) for a used car car1.mileage = 17564
this slows down your project in the early stages, when uct type that has a SKU, an ID, a description of the prod- that matches the entered plate. If the application locates a
rapid iteration is the most important. Second, that there uct, and a cost for a single unit of the item. match, it displays a dialog pop up with the car information Moving past the UsedCar class declaration, youll notice sev-
is tremendous difficulty in determining, at the beginning and mileage, as shown in the far right screenshot in Figure eral variable declarations. These variable declarations appear
of a project, where the natural microservice boundaries type Product = { 3. Listing 4 shows the entire ViewController.swift source outside of any one function so that the entire controller has
should lie. Because of these two concerns, breaking apart Sku : string from this completed application. Lets walk through it so access to them. In this example, var is used instead of let
an established monolithic application at the now stabi- ProductId : int that you understand exactly whats happening. because it makes sense that the inventory of used cars could
lized, natural microservice boundaries becomes a much ProductDescription : string change over time. In a practical, real world example, that
easier approach. CostPer : decimal 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
Benefits of Using a Microservices Youll also need a failure type, ProductCheckFailed, that izer function takes all four as input, meaning that its not an array. In addition to those variables, you create an IBOut-
Architecture will contain the product ID and a message indicating the possible to declare an instance of UsedCar with a nil value let that corresponds to the UITextField that you already
The benefits of using a microservices architecture tend to type of failure, and containing additional information for any of the class properties. If you hadnt used an ini- added to your main storyboard. Once you add that variable,
fall into three main groups: Easy scalability, Independent about the failure. tializer there, youd have needed to declare all the prop- jump over to the storyboard and link it to the field.
releasability, and a more even distribution of complexity. erties as Optionals using the ? notation. Furthermore,
type PriceCheckFailed = { instead of creating the class with a single line as shown Now, you arrive at the standard controller function view-
Easy Scalability ProductId : int later in Listing 4, youd have needed to first initialize it DidLoad. Here, youll instantiate the four car objects and
Easy scalability is a matter of scaling a single service as Message : string and then later assign the values, as follows: add them to the carList array so you can iterate on them
needed. Did we receive a large shipment to the warehouse } later when searching for a matching license plate. No-
today, putting the related services and people under var car1 = UsedCar() tice how the initializer function that you created in the
heavy load? We can scale only those services without af- Using these two, you can construct our inputs. In this car1.make = "Toyota class definition insures all properties of the UsedCar class
fecting the rest of the system. case, a single Product: car1.model = "Corolla get assigned with the creation of each object. Once you

44 Case Study: Writing Microservices with F# codemag.com 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 likely to be correct. Bonus: You dont need to understand
array with a new array containing the four car objects. You in Figure 4. the mathematics involved!
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 Cross-Cutting Concerns
In most cases, you need to confirm that the object you function. The function takes no direct input because What are cross-cutting concerns? Consider issues such
unwrap isnt nil, but since you just physically assigned its going to reference the text entered into the search as logging and validation, that necessarily touch several
values to all four cars, you know its safe. field. You start by declaring a constant variable that rep- Figure 1: The type signature for the Add function. parts of the system and often require code to be dupli-
resents the result of the search. Because the context of cated across these pieces of the system. Theres often no
The next function gets called when the user presses the the search result is local to the search function, its only easy way to isolate this code nicely. Perhaps most impor-
return key on the keyboard, indicating that theyve con- assigned a value once per search performed, so let works tantly to Jet.com, we needed a way to handle our cross-
cluded their input and wish to search for a used car based here. The lookup function compares the license plate that cutting concerns. In ASP.NET MVC, this is traditionally
on the value they entered. @IBAction precedes the func- the user entered with the carList you created earlier. If done through the use of Action Filters. To apply a filter
tion declaration so that it can be linked to the text field it finds a match, the matching UsedCar object gets re- to a single function (or a controller), you decorate it with
in the storyboard. To link the action to the return key, go turned. If it fails to find a match, nil gets returned. This the relevant attribute. ASP.NET injects an extra call before
to the storyboard and drag the action to the text field and causes searchResult to become an Optional even though 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.
Listing 4: ViewController.swift from sample car application
// call lookup with the text entered in field
Once youve constructed this Add function, you can think In Jet.coms case, we needed this same ability to handle
import UIKit
let searchResult = of it as a base function. Then, making use of a partial cross-cutting concerns for services not based on HTTP.
class ViewController: UIViewController { lookupUsedCar(licensePlate: (searchField?.text)!) 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.
// a used car object to manage car data // show appropriate message depending on Once we began to look to F#, we realized that we could
class UsedCar { // result that was found let add1 = add 1 handle cross-cutting concerns with no difficulty. Plus, we
var make: String if(searchResult != nil) { let add2 = add 2 realized that we could do it in a way that neither pollut-
var model: String showAlertPrompt(message: "The car with ed the codebase with fabricated interfaces nor required
var licensePlate: String license plate \(searchResult!.licensePlate) Even though these two functions take no explicit param- adapting a specific architecture. We simply took a more
var mileage: Int is a \(searchResult!.make) eters, their type signatures (see Figure 2) show that they functional and composable approach. Any filter in our
\(searchResult!.model) with still expect the (now unnamed) num2 parameter. The module can be used with functions that have type Input
init (make: String, model: String, \(searchResult!.mileage) miles")
second parameter (num2) is inherited from the original -> Async<Output>, and all filters in our module are com-
licensePlate: String, mileage: Int) { }
Add function. Just as inheriting a class can save you from posable, using our andThen operation, like so:
self.make = make else {
self.model = model showAlertPrompt(message: "car not found"); repeating several lines of code, inheriting a function can
self.licensePlate = licensePlate } as well. let compositeFilter = filter1
self.mileage = mileage } |> Filter.andThen filter2
} Although having fewer lines of code isnt necessarily an
} // takes license plate and searches for a car that matches end goal in and of itself, of course, it does mean that For example, if you have a service that simply echoes its
func lookupUsedCar (licensePlate: String) -> UsedCar? { youll be able to more easily keep track of several key output:
// variables available to whole controller pieces of code at once. This leads to an increased under-
var car1: UsedCar? for car in carList { standing of the code, which leads directly to fewer bugs. let echoService : Service<string, string> =
var car2: UsedCar? if(car.licensePlate == licensePlate) { It just makes sense: If you can understand and process fun str -> async.Return str
var car3: UsedCar? return car; more code at once, youll naturally make fewer mistakes.
var car4: UsedCar? }
And you have a filter that will print messages before and
var carList = [UsedCar]() }
after a service is run:
@IBOutlet weak var searchField: UITextField? return nil;
} Theres a saying in let printBeforeAfter:Filter<string, string> =
the F# community: Filter.beforeAfterSync
override func viewDidLoad() { // show an alert modal with a custom message Once your code compiles, (fun _ -> printfn "before")
super.viewDidLoad() func showAlertPrompt (message: String) { it works. (fun _ -> printfn "after")
let alertController =
// simulate a data source with some mock cars UIAlertController( title: "Lookup Results", Then, you can simply compose the two, and the messages
car1 = UsedCar(make: "Toyota", model: "Corolla", message: message, print before and after the service is invoked:
licensePlate: "12345", mileage: 17564) preferredStyle: .alert) Correct Code
car2 = UsedCar(make: "Dodge", model: "Durango", F#s strict typing makes writing correct code easy. With let filteredEchoService:Service<string, string>=
licensePlate: "abcdef", mileage: 22465) let cancelAction =
each new line of code thats added, the compiler infers printBeforeAfter
car3 = UsedCar(make: "Nissan", model: "Maxima", UIAlertAction(title:"Ok", style: .cancel, handler: nil)
the types for the new code, and then double-checks that |> Filter.apply echoService
licensePlate: "123abc", mileage: 503) alertController.addAction(cancelAction)
car4 = UsedCar(make: "Ford", model: "F150", self.present(alertController, animated: true, these types perfectly fit into your program. If theres a
licensePlate: "abc123", mileage: 49078) completion: nil) 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-
// add the cars to the array family of programming languages were originally cre- ing a series of custom filters for either ASP.NET MVC or
carList = [car1!, car2!, car3!, car4!] override func didReceiveMemoryWarning() { ated to work closely with mathematical theorem-proving ASP.NET Web API.
super.didReceiveMemoryWarning() software, which has led to a type inference system that
} // Dispose of any resources that can be recreated can be mathematically proven. Theres a saying in the F#
} community: Once your code compiles, it works. Although
Why Did Jet.com Choose
// function that is called when that isnt always true because humans can get in the way, Microservices?
// return is pressed on the keyboard } once your code compiles, its passed several rigorous There are two answers to the question of why Jet.com
@IBAction func searchForCar() { mathematical tests of consistency, and its much more chose microservices. First, because theyre a perfect fit for

34 Moving Forward: The Transition from Objective-C to Swift codemag.com codemag.com Case Study: Writing Microservices with F# 43
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- Figure 3: Screenshots from the sample application youll create
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- you didnt explicitly tell it to. Its important to note that
Rachel Reese is a long-time
software engineer and math ciple, it means that a microservice should have one, and if the value you assign to a variable (in this case, the
Microservices are intentionally only one, reason to exist. This doesnt necessarily mean function return value, which is an Optional: UsedCar?)
geek who can often be found
talking to random strangers small, but people argue that there should be only one function within the service, has the potential to be nil, the variable you assign it to
about the joys of functional about how small is small only that the microservice should have only one job. becomes an optional.
programming and F#. She enough.
currently handles training and Because the searchResult has the potential to be nil, you
evangelism for Jet.com in the
Why Use F#? need to check whether it contains a value before you un-
NYC area, and has a habit of Early on in Jet.coms history, we hadnt fully decided yet wrap it. If it has a value, you call a function to display
starting user groups, so far, From a technology standpoint, were heavy users of F#, on either microservices or F#. Our CTO, Mike Hanrahan, an alert dialog with the car information, passing a mes-
in Hoboken, NJ (Pluralsight Go, Azure, Kafka, EventStore, and microservices. In fact, had attended one of the early F# conferences in NYC and sage that you compose by combining unwrapped values
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- of the corresponding UsedCar class object via string in-
(@NashFSharp) and Burling- over 700 cloud-based, event-driven, functional microser- gine, and some of the early hires were F# engineers. As terpolation. If it doesnt have a value, you call a dialog
ton, VT (@VTFun). Shes also vices in production. Using this architecture, we were able the site started to develop and the early engineers had to inform the user that no results were found. How do
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# you determine if a used car exists corresponding to the
Xamarin MVP, a community lion in October 2015, and barely stress our systems. fit into more places than the team had originally antici- users entry? The lookupUsedCar function in Listing 4 de-
enthusiast, one of the founding pated. After exploring F# even more, they decided to split 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
@lambdaladies, and a Rachii. and start working on two completely separate solutions, for-in loop. Each loop iteration checks to see whether the
You can find her on twitter, @ What are Microservices? one entirely in C# and one entirely in F#, to compare corresponding car matches the users entry by performing
rachelreese, or on her blog:
First, let me define what Im going to be talking about. approaches. Eventually (and obviously), the F# solution a string comparison on the respective license plates. If a youve completed the logic for the application and can
rachelree.se
Over the last year or so, as Ive started to read about won out. Several key reasons drove this choice. match is found, it gets returned. If you reach the end of run it to test your work. Entering a license plate corre-
microservices, Ive come to realize that theres no one the loop with no match found, nil gets returned. sponding to 12345, abcdef, 123abc, or abc123
definition for what they are. Even how large a single mi- Fewer Lines of Code should find a match, whereas anything else should re-
croservice should be is a contentious topic, with several In general, F# has significantly fewer lines of code than turn no results.
different camps arguing for vastly different sizes. One C#. In some cases, this is merely a reflection of the lack
Its important to note that
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 if the initial value you assign Wrapping Up
teams currently using a microservices approach include: F# patterns. For example, discriminated unions (covered to a variable has the potential Hopefully, over the course of this article you gained an
in my last article). I showed how just a few lines of code to be nil, the variable you understanding of the basic differences between Objec-
Being able to rewrite each service in fewer than six can be used to represent a simple object hierarchy in C#. assign becomes an Optional tive-C and Swift. Although the examples in this article
weeks There are other patterns though, such as partial applica- even if you didnt declare may seem elementary, they represent the fundamental
Using DDD, wherein there should be one service per tion. You can think of partial application as inheritance it using the ? notation. building blocks of knowledge that youll need to tackle
bounded context for functions. Consider a very simple, if somewhat con- Swift effectively. As with anything, practice makes per-
That each microservice has fewer than 300 lines of trived case: a function that adds two numbers. fect. If youre interested in learning more about Swift,
code check the sidebar for additional educational material.
That each microservice is a single function let add num1 num2 = num1 + num2 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.
There are additional metrics that should be considered; This Add function has a type signature showing that it a default system alert dialog to display the passed mes-
some folks have offered up the size of the team that takes in two integers (num1 and num2), and returns an sage. The searchForCar function uses this to display Jason Bender
builds and maintains each service as relevant (the two- integer. Look at Figure 1 to see it in action. the results of the search effort. With that implemented

42 Case Study: Writing Microservices with F# codemag.com codemag.com Moving Forward: The Transition from Objective-C to Swift 35
ONLINE QUICK ID 1611061

The Resurgence of XAML


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.
At the Build 2015 conference in April 2015, when Windows 10 was on the verge of release, Microsoft revealed a significant its height. That height is calculated to leave enough of The data template for the ListBox or ListView con-
shift in strategy. Microsoft made it clear that they were betting heavily on the Universal Windows Platform (UWP) and 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
that XAML was back as the centerpiece of native-Windows user interface development. In the keynote at that conference, 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.
I saw the most innovation packed into a Microsoft key- But we also know the power of XAML, and have built many earlier layers show through.
note that Ive seen since PDC 2000. The vast majority of modern apps leveraging that power. For most of those Finally, the TextBlock showing the percent full is This example contains only about 150 lines of XAML and
the keynote demonstrations used XAML as the UI stack. applications, it would have been too costly, or even im- layered on top of everything else. 120 lines of code. A production version with top-notch
possible in some cases, to give them the sophisticated in- aesthetics might need double that amount of XAML.
At the Build 2016 conference a year later, Microsoft teractions and visualizations we needed using HTML5/JS. As the team continued to design, the need for different
continued this track, rolling out the UWP and XAML to colors to represent different fuel types became apparent. Figure 4 shows a final example of a list that presents infor-
HoloLens, Xbox, and embedded devices. Microsoft didnt Also, fuel tanks vary in shape, and the user may need to mation to the user in a highly visual way using the capa-
build much hype around the UWP. They just used it a lot How About WPF? know the capacity of the tank. All of these were added, bilities of XAML. The list contains contacts for a healthcare
and there were lots of sessions about it. It was casually Although XAML on the UWP is getting most of the love again with very modest amounts of XAML, giving results application. Some contacts are physicians and others are
Billy Hollis mentioned in a couple of sessions that the Windows 10 right now, out in the real world, most companies still like those shown in Figure 2. not. The data contains information on the last date I talked
billyhollis@gmail.com shell is written in XAML. So are various parts of the Office have some users on Windows 7. Microsoft recognized this, to them and on their satisfaction level with the services.
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 The team ended up creating a XAML control for this func-
@billyhollis Windows 10 and for the vast majority of third-party apps new features, and is a quite viable choice if you have no tionality because it was used over and over, but that This screen requires no training to see the most important
in the Windows Store. idea when your users might all be on Windows 10. control wasnt conceptually much more complex than the information. The archetypal figure for physician is used,
Billy Hollis and his team of
world-class XAML developers examples in Figure 1 and Figure 2. along with a face to communicate the contacts satisfac-
specialize in producing in- In essence, if you want to do new native development tion with our services. The layering capabilities of XAML
novative applications on native that runs on Windows 7, WPF is the last man standing. XAML is also a great fit for information that has some sort are again used to compose those elements.
XAML is the default choice Windows Forms has been quiescent for over ten years. Sil- of spatial positioning in the real world. Ive done that for a
Microsoft platforms. You can
for the built-in apps for verlight was mortally wounded during Microsofts political number of clients, from managing helicopters in the air to The human brain is optimized to gain information from faces,
see examples of their work at
www.nextver.com. Windows 10 and for the vast infighting and is rapidly fading away. arranging cattle feedlots on open ground. Figure 3 shows so the satisfaction level is much more quickly understood
majority of third-party apps a simplified example of using XAML to work with data that with a smile or frown than from an equivalent number in the
Billy has also presented at over in the Windows Store. WPF applications also run on the Windows 10 desktop, of corresponds to positions in the real world. Its an airport database. The last contacted information is presented as a
100 major conferences, and is course. So you have a pretty good medium-term shelf-life terminal with planes shown at gates. I often use it as an ex- timespan rather than a date, because thats the way users
the author of dozens of books, for new WPF applications. Plus, although learning any fla- ample in conference sessions, because I can explain every want to see it. Inactive contacts are shown with a muted gray
articles, and video training vor of XAML is a steep climb, once you learn WPF, switch- part of it to an audience in about ten minutes. foreground, which most users intuitively think of as inactive.
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, Exposing the data as shown in Figure 4 was about an hour
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. of work. With that kind of productivity, the bottleneck in
over forty teams at companies The same XAML controls used
for leveraging the most innovative parts of the Windows getting to better UX with XAML isnt usually time or cost.
from medium sized businesses to get a boring vertical list of
10 world. The challenge is breaking free from past habits rooted in
to Fortune 100 companies. Applications for Tablets data items can also be used experience with older technologies, and learning how to
This was quite a reversal in Microsofts attitude from late Although WPF is fine for typical corporate desktop appli- to show items positioned in a design the right experience for your data and your users.
2010 to 2014. During those days, I was sagely assured by cations, I honestly cant recommend it for mobile apps on coordinate system with colors
various people within Microsoft that XAML was on the way tablet form factors such as the Surface. Getting a smooth and shapes for visualization.
out. HTML was The One True Waythe only viable technol- touch experience on WPF is quite hard, while touch is el- Wrap up
ogy for user interfaces. I was told that virtually all busi- egantly handled in UWP apps. Even for WPF shops, I gen- Even in a Web-based world, a lot of the economy still runs
ness software UIs will be done in HTML5/JS in eighteen erally recommend that mobile apps for tablets be done in on complex, data-heavy desktop applications. Touch-
months (thats a direct quote from a Microsoft Product Windows 10 /UWP. Those devices come with Windows 10 I have both WPF and UWP versions of the example in Fig- based mobile applications have been added for many
Manager in 2012). Open systems and all that, and you installed, so compatibility with Windows 7 is generally a ure 3. The planes are shown in a ListBox in WPF and a business scenarios, and in the future, well use devices
just cant resist it, so give in. Come on Billy. Let the pod non-issue for mobile apps. ListView in UWP. In other words, the same XAML controls like the HoloLens to raise innovation to new levels.
settle in on your brain and turn you into one of us. 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-
I doubted all of that because I knew that XAML was a Getting Value Out of XAML system, with colors and shapes for visualization. narios. It allows you to quickly and cost-effectively create
powerful and innovative technology. I found it hard to I must admit something about XAML, though. Most teams intuitive, compelling, and innovative applications that of-
believe that Microsoft would simply throw it away. XAMLs who adopt XAML dont really take advantage of its power. The layering capabilities of XAML are an essential part of the fer higher productivity, lower training, better decisions,
decline was caused much more by political infighting in- They tend to write XAML apps that are colorized versions of planes-at-gates example, along with some other capabilities and fewer errors.
side Microsoft than by any technological considerations. desktop apps that they would have written ten or twenty rarely used by XAML developers. You can download the com-
So I felt vindicated by Microsofts re-emphasis on XAML years ago. plete code examples for both UWP and WPF versions of the Theres a lot more Id like to discussdeployment, state
as a key technology. example in Figure 3 from my website (www.nextver.com), management, security, layered service architecture, and
Leveraging XAML means thinking about how you interact but here are some of the techniques used in the example: other factors that influence the platform choice for an
Please dont misunderstand. I dont hate HTML/JS; not with the user at a different, deeper level. Heres an example. application. But Im out of space, and right now, my main
at all. I just dont think its a magic bullet or universal One Canvas panel is used to contain the rectangles message is that XAML is back, and you should know what
answer. Most systems that we build have a Web-facing I recently began work on an application that manages and text elements that make up the concourse. it can do so that you can make the best decisions for your
portion built in HTML/JS, along with a desktop or mo- fuel deliveries to tanks. Each tank has a fuel level, which Another Canvas is used as the ItemsPanel of the List- own applications.
bile interface in native technologies. We understand what might be from a remote sensing gauge or from a projec- Box or ListView. That allows the items in the ListBox or
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 ListView to be precisely positioned. That second Can- Billy Hollis
have broad reach, thats the platform of choice. locations, the user needs to see that level. vas is layered right on top of the first Canvas. The List-

36 The Resurgence of XAML codemag.com codemag.com The Resurgence of XAML 41


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.

Figure 3: A simple example of a XAML ListBox or ListView that shows planes positioned at their respective gates 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
Figure 4: The template for a contact allows intuitive visualization of useful information, such as End If End Function
customer satisfaction and the time since last contact. Dim h As Double End Class

40 The Resurgence of XAML codemag.com codemag.com The Resurgence of XAML 37


38 Title article codemag.com codemag.com Title article 39

You might also like