Professional Documents
Culture Documents
NOV
DEC
2016
shutterstock.com/Scanrail1
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)
progress of the long running jobs so that the end mon problems facing modern application devel-
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.
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
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-
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
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" />
<li ng-show="productForm.Url.$error.microsoft">
Url cannot have the word 'microsoft' in it
</li>
<div ng-show="uiState.isMessageAreaVisible"
class="row"> Figure 2: The message area doesnt completely disappear.
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;
} }
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();
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);
}); }
}
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.
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.
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.
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>
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')
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.
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
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
print data_frame.T
You can also specify the frequency using the freq param-
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.
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.
%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')
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,
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
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
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
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