>> Yevor Georgiev: Okay. Yeah, my name's Yevor. I'm... Windows Azure team. So that's on the Windows Azure Mobile...

advertisement
>> Yevor Georgiev: Okay. Yeah, my name's Yevor. I'm a program manager on the
Windows Azure team. So that's on the Windows Azure Mobile Services team and that's
the team that delivers a backend as a service solution for mobile built using Windows,
Windows Phone, even iOS and Android, even all those platforms.
>>: [inaudible]
>> Yevor Georgiev: I think I'm on, yeah.
>>: Now you're on.
>> Yevor Georgiev: Okay. Great. Can you guys hear me?
>>: Yes.
>> Yevor Georgiev: Okay. So I work on the Azure Mobile Services. We let you create
an easy backend for your Windows 8 or Windows Phone app, also iOS and Android.
How many of you have heard about Mobile Services before?
Oh, okay. How many of you have actually played with mobile services? Okay, so my
demo is going to be interesting to at least half of you. The rest of you, there's pizza in the
back. And then, Jeff's going to come in after me. So Jeff wrote 4th and Mayor; you've
probably heard of him. And so I'm going to show you how to get started building an app
in a very easy, straightforward turnkey sort of way.
Jeff's app is not turnkey. Jeff's app is pretty involved and rather complex, so he'll show
you how to go from like a simple app to like actually a really advanced full production
app. So Mobile Services is a great way to get started. When you grow up to a full app,
you might have slightly different needs and Jeff's going to talk about that.
I already talked about this, but basically we provide you an easy way to add a backend
in minutes. So if you're a client developer or if you're not used to writing Azure code,
you're not used to writing server code, Mobile Services is for you. We try to make adding
a backend extremely easy. You can compare these two pictures, right? So you can
follow directions and kind of end up with a nice easy product, you know, kind of put the
Legos together, do exactly what they tell you. That's kind of Mobile Services for you,
right? It's very straightforward; it's very step by step and turnkey. It's very productive, not
necessarily as flexible.
If you're Jeff, you'd go and build something like that basically. You'd be like, "Oh screw
the manual. I'm going to go and put all these pieces of Azure together, different comm
providers and actually put them together and arrive at something flexible tailored to my
needs," right?
So first we're going to talk about this and then, we're going to talk about that. So what do
you get from your Mobile Services backend? What are the things that we provide for
you? I already mentioned we provide a backend, so that's basically a SQL database for
you with tables for, you know, the entities you'd like to store. We support a variety of
clients, like I mentioned. We just, today, released to production our HTML client. And by
the time this recording is live the HTML client will also be in production, so I'm allowed to
talk about that. So you can now target websites and also phone gap. So you can actually
do other native development across all these platforms. You can even do phone gap or
you can even embed your code as part of a website, all using the same backend. Yeah?
>>: [inaudible]
>> Yevor Georgiev: Okay, great. Yeah? And the key thing is we share the same
backend across all these services, so you only write the backend once which is a good
thing. We allow authentication and authorization to be done very easily using a set of
support auth providers. We support all the major ones, you know, Microsoft Account,
Facebook, Twitter and Google. So you can go ahead and configure your app very easily
and then authenticate your users, and we manage their identity on the server. It's very
easy to do authorization against their identity. So that's a common problem we've gone
out to solve. Go ahead.
>>: And we can also do custom.
>> Yevor Georgiev: Right. So you can also do custom auth. There's a blog post by Josh
Twist from our team. So you can even do your own auth if you'd like. We also make
push notifications really easy. If you've read a lot of the documentation for push
notifications, they'll spend like 15 pages talking about, "Okay, here's different tile
templates. It's so pretty." But they never talk about -- And then their rest API doc and you
have to figure out yourself how to write a client, wrap it in a dot net service or something,
host it on Azure. You have to do all those steps to actually send the notifications to the
app.
You know, displaying them is the easy part. Actually sending them? That's the hard part.
So that's the thing we make really easy. and I'll show that in a little bit. Then we all
support scheduled tasks; so if you want to run a task against your backend you know
every 15 minutes to clean up some data or to pull Twitter and pull some information, we
let you do that.
And we also integrate with the store, right, so if you would like to use Pusher, for
example, for WebSocket connectivity, you can do that. You don't have to do anything
weird. Just go and add them as part of the Azure Store. And I've been authorized by
VP's high above me to give you ten for free for each of you today. Isn't that super
exciting?
You're not excited because you know they are free. Ten are free for everyone. So you
can start for ten for free. Then, you can start buying reserved ones if your app grows
really large. Back there?
>>: Oh, so they can really expand their services once we get popular.
>> Yevor Georgiev: Yeah, exactly. So the ten are shared hosting, right? So they're
going to take a little bit of time to warm up when -- And, you know, you might get evicted
sooner because there's other ten's on that machine, but their free. Now if you really want
to stay always hot and you want to have the whole VM to yourself in case you're doing
crazy computation in the backend, you can flip a switch in the portal and get a reserve
VM for you. And of course then you have to pay.
>>: So we really pay just for the storage use?
>> Yevor Georgiev: Yeah, yeah. So the mobile service itself is free. You're going to
need to associate with a SQL backend and you have to pay for SQL. If you're Microsoft
employees, you're MSDN subscription or if you have a MSDN subscription, it's going to
cover well more than ten sites. I'm running a bunch of them and I haven't gotten the bill
yet.
>>: I think you also pay for the bandwidth, right, after a certain point in time?
>> Yevor Georgiev: In the free mode you're going to get capped. In the free mode
you're not going to pay anything; you're going to get capped.
>>: So it's actually the same thing as a paid [inaudible]...
>> Yevor Georgiev: Yeah, if you want to get -- So at some point if you...
>>: [inaudible]
>> Yevor Georgiev: It's the same -- I have to go check what the exact cap is. But, yeah,
we're not going to start charging your credit card; unless you explicitly flip that toggle,
we're going to start charging you then. So the good thing about Mobile Services is we've
made it super easy and we have a great dev center with a lot of content that -- I've
written a lot of it and we have a team of writers writing a lot of it as well. And we cover a
lot of the main scenarios with nice tutorials with lots of screen shots. We've been heavily
inspired by Scott Guthrie's blog; if you notice how he does, he puts like red things
around his screen shots, like step by step, very clear so great tutorials.
Also our SDK is on GitHub. Actually everything, even iOS and Android, it's all in our
GitHub repository. So you can go ahead and read the code. You can file bugs in the
issue tracker. You'll notice we have only four bugs when I took that screen shot, so let's
get that count up. You guys can go file your own bugs. And the best part is you can
actually fix the bugs yourself. So if you find something that's really annoying you, you
can actually forward it to our repository, send us a pool request. We're going to review it
and if you then try to check in garbage, we'll probably merge it in. So you can very easily
actually fix the bugs you find which is great. You know, [inaudible] the dot net framework.
You can go and fix stuff if you find it.
So that's pretty much all my slides today. I'll do a little demo. And I've written a game. So
games are something we're seeing. Quite a few people actually write with mobile
service. Even though we'd like to think of our sweet spot as, you know, say something
like a to-do list application, something that needs a backend not real time, not a shooter
or something like but maybe like a leaderboard to your game. In this case I'm powering
my entire game off of Mobile Services.
So let's go ahead and try it out here. So for example I'm already -- Do you have your
phone? All right. So Jeff and I started a game earlier. Which game is that?
>> Jeff Wilcox: Game Six.
>> Yevor Georgiev: Game Six. All right, so let's see if I'm in Game Six. All right, so now
let's see if it's my move. Okay, it was my move. Now go ahead and try and make a move
on the phone version of the app. I should get a push notification. There you go; it's my
turn. And I’m not very good at writing these apps so you have to go and actually refresh
to see [laughter] Jeff's move. There you go, okay, so you made a move. And the way
this works is we're sharing the same backend, right? Both of these are going against the
same server data.
So that's how this app works. So I'm showing you the Windows 8 version. We're going to
switch over and look at how to actually build the phone version of this app. So I'll go over
to Visual Studio here. And so this is just the blank app. It has a bunch of hard-coded
data in it; it doesn't actually connect to Azure at all.
So you guys can see okay? The lights are okay? Cool. So the first thing is I'll go to the
Azure portal, and I've created a Mobile Services already. It's called Align 5. So basically
up here is where we give you kind of the getting started information. If you want to add
this backend to your Windows Phone 8 app, you go to the section here. We let you
download our SDK, add it to your app. We give you sort of the connection string to your
mobile service which is basically this line here with the URL and your access key for
your application to talk to your backend. It'll let you create a table and just kind of get on
your way.
We have a very nice, easy quick start experience. I'm not going to follow this because
you've probably seen the demo of the quick start a million times, but I'll go ahead and
add this information to my app. So you'll notice if you go to the data tab here, I'll already
have a games table and a players table, so you'll see me that reference that as I build
my application.
So let's go back to the app. We'll go to code-behind here, and I'm going to add that first
snipit which basically defines my mobile service. So I have basically this config file here.
This is just to make my life easy because this is checked into a public repo. I didn't want
to check in my secrets, but basically this one file here contains the secrets. I've just
checked them in separately so I don't have to keep them as part of my source. All right,
so I have this mobile service variable.
Then, the next thing we're going to do is we're going to go inside our main page here
and we're going to look for this authenticate method. And that's the first step we do in
this game. That's the thing you didn't see. But Jeff and I are already both logged in, so
we have to make sure the user, the first thing they do when they come to the app, we've
got to get their identity so we're going to ask them to log in.
So I'll drag my authenticate method in here. And this is pretty much -- I'm pretty much
just taking advantage of the live SDK or it's called Live Connect SDK now. So this SDK
basically lets you sign users in with their Live ID on the phone. It basically pops up a little
browser control and navigates over to Live ID, let's them type in their credentials and it
gets you back an authorization token. So this code is actually copy-pasted from their
SDK.
So you'll notice I have this check registration method missing here. So once I've
authenticated the user, I want to make sure that I've registered their push channel so I
can send them push notifications. So that's what I'll do in that method and I can go
ahead and add that.
Oh, I think before that I actually have to go inside of this because I need to actually call
the authenticate method. So I'll just put it in here. Oops, sorry. Oh sorry, I have to put
inside of Onload It, I think, right here. Okay. And then, the next thing is that -- Oh,
another change. Before I drag in check registration we need to basically get the current
user identity. So that one I currently hard-coded to this blank string but I can actually get
that from the Live SDK. I'll just paste that in here.
So this is basically getting the user identity from within my SDK. Now we're going to do
the check registration stuff to register the push channels. And do you guys know how do
you -- I got to make this a little bit bigger so you can see? Oh is it -- ? Oh, I can just
minimize this thing I guess.
Right, so you'll notice it starts with just a push channel registration code that's stolen off
of the SDK, for the phone SDK. The one thing you'll notice that I do differently here is
once I go ahead and get the push channel, I actually add it to my player table. So this is
how I'm actually going and storing the user's push channel up in the cloud, right? That's
basically my client-side reference to this server table here.
And if you notice, Jeff and I have already played the game so in here you'll see, you
know, here's my Microsoft account user ID, here's Jeff's and then, here are our push
channels. And in my case I'm using WNS for my Windows app. Jeff has -- And I also
have a phone app as well. And Jeff just has phone just because he's logged in only the
phone, but as he logs in on more devices we're going to update this user object for him
here and store all of his push channels. So whenever we make a move in the game, we
can deliver a notification table.
Okay, so now -- Yep, go ahead.
>>: Are you identifying the device from the device itself or are you on a second server?
>> Yevor Georgiev: So currently we're identifying them by -- Well, what do you mean?
So we have the user's identity if they're logged in. If they're not logged in we don't have a
notion of their identity.
>>: [inaudible] application -- Oh, sorry. How do you know which device [inaudible] two
separate columns, one for [inaudible]...
>> Yevor Georgiev: Yeah, so I would have to -- If they have multiple devices, this would
break, right? If they have multiple phones then it'll break because I'll just keep overriding
the push channel. So I have to be smart then. You're right. I have to basically start
adding a list of push channels....
>>: [inaudible]. I get the push coded in the app?
>> Yevor Georgiev: Yeah, I always push to both.
>>: How do you know what the [inaudible] is? Is it [inaudible] or is it...
>>: Is it...
>> Yevor Georgiev: Oh, well notice like I had to actually manually do this registration,
right? Like this registration stuff like I had to go here and manually set this property on
my player, like MPNS channel. Right? Like in my Windows code it actually says "WNS
property." So I had to write custom code based on the platform. But you have to write
custom code anyway because the push channel registration logic is different anyway on
the different platforms. So, yeah, you have to know.
Now you'll notice my table reference is missing so I have to basically add my table
reference. So here are the references to my two tables. Mobile Services, that thing we
[inaudible] off of the app object that's still there. That's how you get the references table.
You say, "Get table," and you give it the type you want to work with.
Okay, so now let's look at the refresh method wherever that is. All right, so currently the
refresh method is kind of bare bones, actually. You'll notice I'm just saying data context
null for all my UI controls. They're not really doing much, right? They're just showing
blank data. So let's add the implementation for refresh. Let's get rid of this. And so here's
some interesting code, right? Here's me actually querying the server to get some data
back. So in my UI you noticed when I showed you the app -- And I can switch over again
real quick so you guys can see -- I had two columns. I had Open Games and I had My
Games. And so, these are different queries against that server table. The Open Games
is basically games that don't have any players assigned to them yet. And My Games are
games where either Player 1 or Player 2 is my ID. So I have to write that logic on the
client, right, to do the right query.
So Open Games basically you noticed I'm just using link. I'm saying, "Okay, Open
Games are games where Player 2 is null." Right? Because Player 1 is always the guy
who created a game. So when you create a game you always set Player 1. Player 2 will
be null if the game is waiting for another player. So I query these things and you'll notice
I'm using link. That's one of the nice things about our C sharp SDK is we let you query
your server using link on the client which is nice and easy.
Then, the My Games query is a little bit more advanced. So I'll say, you know, where
either of the players is null and then one of them is me, that's what this query says. So
that's how My Games work.
So where none of the players are null and one of the players is me; that's what this
query says. It's a bit scary but it's linked so it's easy writing. It's just hard to read it back.
And then I set these two collections to my data context objects so they can pop up in the
UI. One thing I remembered actually: so refresh, that should get called only after I'm
authenticated and registered. Right? So somewhere down here it should call refresh. Or
maybe -- Yeah.
>>: [inaudible]
>> Yevor Georgiev: Yeah, so I'm just wondering if that's the right place for it because do
we want to refresh before we authenticated? I think I need to put that somewhere else,
to move that out of there. Actually let's keep it for now and se if it fails. Okay, so then
how do you actually join a game?
So I currently have just an empty button that does nothing. So join game on tab, so that's
that button here in the UI that let's you join. So go ahead and drag the implementation
here. So you'll notice like the way I join the game is actually I get the game table and I
get a game object and I stuff it into the game table. And that's going to be interesting,
right? Like how does updating something actually make me join the game? So that's just
a little convention [inaudible] with the server. So let's look at the Mobile Services
backend because obviously that doesn't make sense. If it was just a simple update, it's
not really doing anything. It's not even touching any properties in the object, so how does
that even work?
Well, we have this notion of server scripts and that's something that you actually need
when you're doing a game, right? You need to have all the logic encapsulated in a
method on a server. You can't run your game loop in the client. So actually you'll notice I
have some smarts in a lot of these methods. I'm not going to cover this one, but let's go
with this update method in my games table. Let's see what happened here. So you'll
notice when I go ahead and insert a game first it checks, "Okay, well, does this game
exist already?" And if it does then I'll either join the game or I'll make a move. And that's
really where my game loop lives is inside this update method.
So I'll send an updated instance of the game back to this update method, and depending
on what it sees it'll know what to do. So if I sent to the game that doesn't have a Player
2, it will call this join method. I join game method here and it'll set my user ID as Player
2. So it'll register me for the game. If I send it to the game and I’m already Player 2 on
that game, it'll call this make move method. And the make move method basically goes
through a bunch of validations. It wants to make sure, "Okay, is it your turn?" right,
because it may be the other player's turn. You know, "Are you trying to move in a
column that doesn't exist?" So I'm trying to place a move in Column 15 and this only has
7 columns. It's a bunch of server validation that, you know, the code needs to live
somewhere, so this is basically our way to let you encapsulate a little bit of server logic
when you work with your data. So any questions?
>>: What engine are you running off of?
>> Yevor Georgiev: So this is actually running Node JS on the server.
>>: Okay.
>> Yevor Georgiev: Yeah, so there's a bit of disconnect. For C sharp developers a lot of
the time you'll look at this and you'll be like, "Oh, I have to write Java Script now?" But I
mean if you think about the bigger picture, right, first we're definitely looking at adding C
sharp support, but if you look at the breadth of developers we're targeting, we're also
targeting people that do iOS, Android and HTML. So it's not just for C sharp developers;
it's for a much bigger community. So we try to pick a language that makes sense across
everyone. And so Node was pretty lightweight and pretty well received so that's what
we've used.
All right. So going back here, going back to -- Oops, sorry -- Visual Studio we hooked up
the logic to do join game on [inaudible], so that's when I go ahead and join a game. Now
how do I create a game? I'm going to replace this other handler. You notice I insert
basically a blank game object into the game table, so I can go ahead and take a look at
that. So let's look at the insert method. And it'll populate some of the properties. It'll
populate my ID as Player 1. It will create a new board; it'll create an empty new board
and you'll see that basically that's how we represent the board on the server.
So like all that logic has to be on the server side so people can't cheat, so that's why I
create my new empty game. Okay, and now the last thing is my make move method
which his when the user goes inside the actual grid of the game and taps one of the
columns to try and make a move. So let's go inside this game board, code behind, and
there should be a make move method. Maybe it's not there.
Board moved. And I need my reference. Oops. Whoa, how did I do that? Okay. Okay,
and this. Well, actually I'm placing this in the wrong method that's why it's not working.
So I'm placing it inside my game board class which is a UI-only class. I just need to
place it inside my game page. Okay, that makes a lot more sense. Here's my empty
method. All right. Oh, sorry. Oh yeah, thank you.
All right, great. So board move: so this is when people actually tab a column. You know,
again, I referenced in my game table the same way we did it before using our client. I will
do some checks, is the game in progress? Is it my turn? And these are constraints that
are also enforced on the server as well, so instead of getting a weird response from the
server like a 500-error or something, they'll get a nice response within the game. Then,
I'll take the game object. I'll use this move property to indicate which column they try to
move into. And then, I'll call an update to insert the game into my table on the server.
So that's all I had to do. I mean it's a bit of code but I have a full game working. So let's
go ahead and just run it to convince you guys it's the right thing. So I'll go ahead and
start an emulator. Okay.
These should be here somewhere. Oh, anyway, I have an easy way of cheating actually
because this is in version control. Oops. Oh, wrong folder. [inaudible] trying to fix your
demo. Do you guys have any questions while I do this?
>>: Everyone's interested in the results, I guess.
>> Yevor Georgiev: It's going too work I promise. Jeff has it working on his phone. All
right. So here's my app. So the first thing is we did build the authentication, so this is
basically that call to authenticate using the Live SDK coming up to ask me. And in this
case actually I've already logged in because typing the password on the emulator, it
actually reveals your password. So I've logged in beforehand. It's asking me to give the
app some permissions, you know, nothing scary so I say, "Okay." Let's do that. And then
the next screen should just basically present the same information I saw in the Windows
8 version of the app. So here's the open games; here's my games. Here's the game I
was playing as Jeff. I can go back. I can go ahead and start a new game. You know, I
can check in on that game.
And you'll notice actually like I have this interesting bug which I have kept for demo
purposes. You'll notice the Windows 8 version of the game gave me notification it's my
turn because now it thinks I'm actually playing as two separate players which is nice for
demo purposes. So Win 8 just gave me a push notification saying, "Okay, it's your turn. I
can go ahead and make a move." And it gives me a notification again. So it's very fun to
play this with yourself.
I also want to show you toast notifications on the phone. So if I actually go to the
Windows 8 version of the app. And that's not what I wanted. I need to close the app
because toasts only show up when the app is hidden. So I go to my Windows version of
the app here. Let me find it. Let me actually bring it up again. So here's the game I was
playing. And if I make a move, we should be able to see a toast going up in the phone.
There you go. It's your turn. So I was able to deliver the push notifications both to the
Windows 8 client and to the phone client.
I want to spend a minute on -- Because I have three minutes left. I want to spend a
minute on how I actually configured push notifications and how did I send them. For
Windows 8 you can't just send unauthenticated push notifications. You need to register
on their developer portal. So on the push tab here I had to go and add my client secret
and my package SID, so that's how they identify the guy who's trying to push.
For Windows Phone, actually, if you're under 500 notifications, you don't need to
authenticate at all. You can send up to 500 unauthenticated pushes per device I think,
so I didn't need to do any auth for that.
Let's find the script where we actually send those notifications, and that's going to be
inside my games table here. It's going to be inside of update.
>>: Hey, quick question here.
>> Yevor Georgiev: Yep?
>>: So is there -- Okay, so do I do anything to set up authentication [inaudible] for
Windows Phone?
>> Yevor Georgiev: For Windows Phone you don't have to do anything. For Windows 8
you had to go and configure those two things. You have to go to the Windows 8 dev
portal.
>>: So Windows automatically [inaudible]...
>> Yevor Georgiev: Yeah, start [inaudible] and then I'll show you the code you have to
write.
>>: So after that there is -- Okay, so then, I guess, [inaudible].
>> Yevor Georgiev: Yeah. Yeah, yeah, that's the whole point this takes the part of
writing that, really, yourself. Okay, so here's how I send push to WNS. I get the WNS
channel; that's the thing we sent on our client when our client registered. So, you know, I
send a toast, you know, to the Windows 8 app. And then for MPNS I have a very similar
API; I just give it the channel and then I give it the text I want it to push.
So it's as easy as this to actually send the push notifications. Again, for Windows 8 I had
to configure those two values. For MPNS I didn't have to do anything at all. So I'll take a
quick pause and take any questions. Yeah, Hugo?
>>: Hi. For someone like me who has never done any Cloud thing and probably doesn't
even understand most of the concepts necessary, where would I go to see a
walkthrough or just to start? Just the simplest thing?
>> Yevor Georgiev: Yep. So the -- Oh, sorry, can you repeat the question. If you've
never done any Cloud development where do you go to get started? So this is our dev
center which I showed a slide of previously. I guess it didn't come up.
Yeah, basically you'd go to our developer's center and then you can go ahead and pick
mobile up here. Or if you can memorize the URL even better, you can start this tutorial.
So you're a Phone developer, you'd pick Windows Phone 8 here. And you say, "Start
tutorial."
When you create your mobile service there's a project there. And that quick start page I
showed you, there's a project that downloads the zip file. You run the zip file inside a VS,
you get your starter app running. So there's one button to create a table, one button to
create this starter app and download it. It's very easy. And we show you how to do it in
this tutorial as well, so very straightforward and easy. You have a question?
>>: So I've done a bit of MVC and database stuff, and I'm comparing this with how that
works. And specifically if you have associated data, so let's say you have a game with
multiple players or an array of players, so the way you do it in MVC is you have a
navigation property.
>> Yevor Georgiev: Right.
>>: And then, you know, you have a list of players associated with the game object that
would just take care of it. Is there any easy way to do this? It seems here you just have
Player 1, Player 2 as properties.
>> Yevor Georgiev: Right.
>>: But what if you have a list of players?
>> Yevor Georgiev: Right. Yeah, so we don't support navigation properties. It's like
ORN thing, right? So ideally you would have basically the idea of a join. You'd be able to
join on something. You can do that currently. You can drop down to sort of raw SQL. If
you want the second table to be queryable and you want it to actually be a table, you
can drop to raw SQL and write a join and bring up the appropriate players.
So in your actual table you'd store like a list of them, a list of their ID's from different
tables and you write a join, pull them in. That's if you actually want them to be in a
separate table and you want them to be [inaudible]. If you don't care, there's actually a
really neat trick which is you just take the adjacent blob that came on the wire and you
stick it inside the property as a text string. If you never need to search through those
players or list them separately, that's a nice trick you can do.
>>: Okay, in Josh Twist's talk from Build, he had alluded to that trick but he didn't
actually talk about it. So is that trick documented somewhere?
>> Yevor Georgiev: It's not in the official docs because we hope one day to actually do
proper joins, but I can point you to the blog post or yeah. Just hold up. We have it
somewhere. Question back there?
>>: How is concurrency [inaudible] on the server site?
>> Yevor Georgiev: Concurrency?
>>: Yeah.
>>: Yevor Georgiev: So our server script is basically -- You have to sort of understand
a little bit of how Node works. So Node had an event loop that's single-threaded. So
there's basically a cue of HTP requests that pile in, and they get pulled in one at a time
and executed. So basically you only have one request running at a time in your server
script, so you don't have worry about locking or anything like that. The Node event loop
takes care of that for you.
>>: So I guess I'm confused. So you said only one script is running. I guess [inaudible]
is off your one script may be running [inaudible] is just that each one is running a single
program [inaudible]. Is that right?
>> Yevor Georgiev: There's only one thing on the thread at any given time.
>>: No, that I understand. Let's say 500 requests come in at the same time.
>> Yevor Georgiev: Yeah.
>>: And the server has the capacity so it starts 500 instances of your script. They don't
share any data or [inaudible]...
>> Yevor Georgiev: It's not going to start 500 instances of the script. As this starts out...
>>: [inaudible]?
>> Yevor Georgiev: No.
>>: Okay. So I guess there's no [inaudible]...
>> Yevor Georgiev: It's going to start one instance of the script but it's going to cue up
500 of these callbacks. But, yeah, there're no static variables or anything.
>>: [inaudible] you said the full regimen would be cued up [inaudible]?
>> Yevor Georgiev: Yeah. Yeah, yeah. And they'll be picked up one at a time.
>>: So let me ask you about the way you guys [inaudible]. So you have a bunch of
servers, right? Is this group running on [inaudible]?
>> Yevor Georgiev: Yeah, yeah.
>>: With log being [inaudible]...
>> Yevor Georgiev: No, no, no. You're always on the same machine.
>>: You are always on the same...
>> Yevor Georgiev: Yeah, yeah. Yeah, yeah, you're always on the same machine.
You're always in the same process actually.
>>: Okay.
>> Yevor Georgiev: So you're next question is going to be, I'm going to peg that thread
and then my app is going to stop responding. Right? That's kind of your next question.
>>: Actually not really. I thought [inaudible] running in a pool, shared pool.
>> Yevor Georgiev: Uh-huh.
>>: I thought [inaudible] servers and, you know, if they have capacity, they run your
script on all of them [inaudible] only one.
>> Yevor Georgiev: Yeah, you have one instance of the app running by default. Now if
you can figure multiple instances yourself, if you go to the configure tab in the portal you
can go ahead and say, "How many instances would you like to run?" And then in that
case it will get load balance to one of the instances.
>>: Okay. So by default [inaudible].
>> Yevor Georgiev: Yeah, by default now. But if you go here to this configure tab -- or is
it the scale tab? Sorry. Go to the scale tab. You can go ahead and switch to reserve
mode and then you can start dragging this slider and adding instances.
>>: [inaudible]
>> Yevor Georgiev: Any more questions?
>>: Can we do authorization like if...
>> Yevor Georgiev: Yeah. The question is how do you do authorization? We don't have
a nice declarative way like maybe you're used to in the framework where you can put
some attribute on the method. Basically whenever you have any script here coming in -So let's say inside of our game, games table -- inside all operations you'll get this user
object passed to you and then, you can do validation based on the user ID or
authorization based on the user ID.
But you have to write imperative code to do that yourself. We don't have anything like,
you know, rolls or anything like that.
>>: [inaudible] for instance like...
>> Yevor Georgiev: Sorry?
>>: Can we do sharing in the same way? Like a user-created like let's say a blog but
you want to share it with another user. Can we do the code there and it says, "It's this
user," or...
>> Yevor Georgiev: Yeah, by default all users can access everything that's being
created. And unless you manually put a check to block someone -- You have to
manually build the authorization [inaudible]. I think you'd have maybe like a list of users
and their permission level or something like that. And then, add them to some kind of
group and then check for the group. But it's a manual deal at this point.
We are thinking of doing a user's feature, a first class user's feature which would have
authorization built in. Had a question back there?
>>: Yeah. I read [inaudible] somewhere that you can use a mobile service and Cloud
service together.
>> Yevor Georgiev: Uh-huh.
>>: Can you just briefly describe how?
>> Yevor Georgiev: The question is how to use a mobile serve and a Cloud service
together. So basically the same way your client talks to your mobile service; it uses a
JWT, a JSON Web Token. So that's basically something that gets generated -- the token
gets generated by the server and the client sends it over every time. Like they both
generate that token using that master key -- that application key, sorry. So if you're able
to extract that token -- We don't provide you an out-of-the-box way but there's plenty of
blog posts and work-arounds. If you're able to extract that token and use it as part of
your dot net app to send requests then you can do it that way. Basically figure out a way
to generate the token or steal the token and use that to authenticate and talk to the
backend.
>>: So if you're secret gets compromised, is it [inaudible] because your token is from
one key [inaudible]?
>> Yevor Georgiev: Yeah, so we give you I think two at any given time, and you can go
ahead and regenerate any of them independently.
>>: So then for your [inaudible], will my users get my data [inaudible] because I mean
once I...
>> Yevor Georgiev: No they won't. They will not, no.
>>: Is it possible to write a script through that?
>> Yevor Georgiev: No. But that's the thing, like so...
>>: Like [inaudible].
>> Yevor Georgiev: Well, no. So actually we always get questions about the application
key. So the application key it's really not a security measure because it's very easy to
open any app using a reflector and get the application key out.
>>: [inaudible] you also have the master key, right?
>> Yevor Georgiev: Yeah, the master key is something you shouldn't ever give to your
users.
>>: Let's say for whatever reason it gets compromised and [inaudible] and I have some
custom art. So now I have those user privileges encrypted [inaudible] my [inaudible]
service, right?
>> Yevor Georgiev: Yeah.
>>: And I want to [inaudible] all those users, can I just [inaudible]...
>> Yevor Georgiev: Are you doing the encryption yourself in this case?
>>: I have...
>> Yevor Georgiev: For that master key? It sounds like an advanced question.
>>: Okay. [inaudible]...
>> Yevor Georgiev: We should take it offline. But if you regenerate the master key, the
service it would turn off the old key within seconds. So...
>>: [inaudible] is the new master key used?
>> Yevor Georgiev: I have to go read through Josh's thing, but you shouldn't ever have
the master key on a client application.
>>: Right, right. [inaudible].
>> Yevor Georgiev: I want to leave time for Jeff so I can take any questions after. All
right, great. Thank you, guys.
[applause]
>> Jeff Wilcox: My name is Jeff Wilcox, and I am kind of the most successful failure on
the Windows Phone. So my application has net me no money and cost about fifteen
thousand dollars. But the good news is I'm sharing my experiences there with everyone.
So you win some and you lose some.
In the past I was on the Silverlight team. I worked on Windows Phone 7 and 7.5, and
these days you'll find me in Windows Azure. I run the open source dev team; I'm like the
SDKs. And I work with Yevor's team quite a bit.
That said I didn't build application, 4th and Mayor, with any of these cool things because
I built it two years ago, about two years ago last week actually. So this is my list of
laundry topics to go over, and we'll see what time we have for going through this. Feel
free to interrupt me at some point, but hopefully I can get through some of it. I'll probably
go for about 20 minutes here.
First of all, what the heck is my Cloud environment? When I launched my app for the first
six months I actually did not have a Cloud store at all. And so my application, it's actually
based on the Foursquare API and so if you want to check into a bar or you check into
work, to do that you actually use the Foursquare API. And that's not an API I run;
Foursquare runs it. And so my application just went direct with O auth against their
service.
So super easy for me because it didn't cost me any money. Foursquare allows me to do
this for free. And it was easy to code up. The trouble is, I can't add value on top of that
and so if you look at things like Live Tiles, toast notifications, you know, doing work for
my users I can't do any of that since my app just went direct to their service.
And so eventually I started building up this crazy set of, you know, independent
components. And to be clear, this is me as my non-Microsoft self. So as employers,
Microsoft is nice enough to let us moonlight, let us do some stuff on the side and
hopefully we're being kosher there. That said, at the time I was looking at Amazon Web
Services. Gosh, the price was great; it was like 30 percent cheaper and since I wasn't
going to charge for my app this mattered to me. And it was a good time to learn about
some competitors products.
So V1 was built completely on Amazon. And that sounds great but it turns out when you
work in Windows Azure you should maybe just be able to answer to your CVP, "How
would you run your service on Azure?" And so I'm actually in the middle right now of kind
of moving my entire app over to Azure just to prove I can. I have a couple, actually,
unique reasons economically that Amazon is cheaper for my very specific app but
everything runs in Azure great for the most part.
And apologies: if you're a phone developer, you probably don't care about most to any of
these things but some day maybe you will. On the Amazon side I used them for all my
DNS hosting and that's because today Windows Azure doesn't have kind of custom
arbitrary DNS hosting. And so, even when I move over to Windows Azure I'll still be
using that product. But the other classics on the Amazon side -- EC2 is their Linux virtual
machines, load-balancing storage, text notifications -- all of these things are great; that's
kind of what the app was built on. And so the infrastructure was a couple of EC2
instances, mostly small or micro-instances, that were running Node.JS, running web
servers, doing push notifications, all these fun things.
And then, one unique service I use in Amazon is I'm talking to Foursquare because my
application is a Foursquare application. And it happens that Foursquare is located in the
US East Amazon Data Center, the same data center as my app and Amazon. So I can
talk to Foursquare for zero dollars. I can download terabytes of data. I can send them
terabytes of data for zero bucks. That's actually a pretty big driver for one the reasons
that I'm running on Amazon today because Foursquare is not in the Azure Data Center.
So in my case that's kind of a unique reason where today my production service is still in
Amazon, and that probably won't change in the short term. But I'm finding ways to move
it all over and piece in things. And so I'm actually running some of my web service API
servers and my website off of Windows Azure. And the nice thing with DNS is you can
move providers; you can even do round robin. I could have website some days be
hosted by Amazon and some days by Azure and, you know, kind of smoothly work that
through until I fix all my bugs.
On the Mongo side I'm using Mongo's no-SQL database solution, and it's mostly
because I'm written in Java Script. Java Scrip is super sexy right now, and Mongo gives
you Java Script JSON back. And so, it's really simple. In the Amazon Data Center I pay
MongoLab. It's a third-party company that hosts Mongo. I don't want to worry about
administrating the server. I don't want to worry about instances. I pay them 40 bucks a
month, and in return I get a pretty large amount of data just completely hosted, backed
up. It just works. No worries.
Now on the Windows Azure side, in the Windows Azure Store we actually also have
MongoLab, the same exact company, the same servers, the same smart guys. They're
actually hosted in Windows Azure as well. And the cool thing here is that they're actually
not charging right now because they want to get test users, and so in Azure this costs
me zero bucks. So it's kind of an interesting thing where each provider has its own pros
and cons, and one pro on Azure right now is it's free in this specific case.
And the big list on the right: Windows Azure. Websites is the big feature that was
launched last June.
>>: Excuse me. Would you mind trying to share the slides if possible? It's not shared in
the [inaudible].
>> Jeff Wilcox: Sorry, we're [inaudible]. Share to the desktop. Sounds good. Okay, is
that better.
>>: All right.
>> Jeff Wilcox: Okay, great. So on the Windows Azure side, Windows Azure websites is
a super simple way to host your website. So on Amazon I have to actually spin up entire
EC2 instances. I have to install the web server. I actually go through the crazy steps of
building Node.JS from source and crazy stuff. I can automate it but it takes a while to
kind of launch things. And with Azure websites I literally just get deploy my code and like
20 seconds later all of my instances are running the latest version. And so I'm actually
running both a production instance and then staging instances in my backend there
through Azure Websites. And it's super cheap. I run a whole bunch of different services
and they're all independent. And so the idea is that if my Live Tile generator goes down,
well, you know that kind of sucks but it turns out the rest of the app is going to work just
fine.
And so I've kind of done a little bit of hedging here on my environments, and so I'll
actually watch the load over month to month to see how the load is doing. And the Live
Tile server is pretty much the most expensive part. It's a lot of CPU to generate PNG
images, but it's actually the best part of the app. You know, Live Tiles are kind of a great
Windows Phone value add. And my code actually also generates Windows 8 Live Tiles,
although, I haven't released that app yet.
Other things that go on: I'm actually using the classic Cloud services. It's kind of the
traditional way in Windows Azure that you push code, and this is the thing that
sometimes takes, you know, like ten, fifteen minutes to spin up an instance. And it's
doing a full Windows VM. It's extremely fault tolerant. And so I'm doing this for e-mail
processing. If you send me a crash report, my code actually will parse your e-mail, figure
out what the bug is. And today I get that information but one thing that I'm looking at for
the future is actually e-mailing you back and saying, "Thank you so much for your bug
report. Here's the ID of the issue; it's already been logged." Or, you know, "Ten
thousand other people have sadly had the same issue today," kind of some value add on
the side of crash reporting. I'm doing that there.
And then, Azure Websites today doesn't actually support having a custom SSL
certificate and so I have a wildcard cert for anything dot 4th and Mayor dot com. And
Websites doesn't support this today, but according to Scott Gu's blog some day it will.
So until that time I'm actually running my own SSL load balancer in Azure. And so it's a
bunch of instances that have my certificates so I get the incoming requests. I will actually
re-encrypt on the backend with Azure Websites, do the magical things and then push it
back out.
This is actually like 20 lines of code in some web config file. It's pretty easy to set up
actually but it's important because I'm looking at customer data. I'm getting information
on GPS locations. I don't want this stuff just free form on the Internet. So I try to respect
my users a little bit.
I'm also using the Azure Table Store, so I have a logger built into my Node app. It's kind
of like the equivalent of [inaudible] log. It would really be painful -- Honestly I have over
two hundred thousand downloads of the app and about a hundred thousand active
users, and I cannot look at logs. There's no way I can do that because I have a day job
as it turns out and a girlfriend and other things that don't really compete very well with
looking at log files. But if I need to I can kind of pull up the log for a specific user, and I
store all that in Azure Table Store. It's awesome because Table Store costs the same
amount as Azure Blob Store, so it's super cheap but I can actually query that data. And
so I actually partition it by a whole bunch of crazy values, but the magical thing is it's
quick. I can query it quickly and it just kind of works.
I'm also using virtual machines for some statics stuff and of course the Azure Store for
Mongo. The fun thing is, how much does this cost to run a hundred thousand plus
users? This is kind of like the fuzzy math on it. Again, Mongo's 40 bucks a month.
Amazon used to be about 150 a month, but as I moved more services to Azure my last
bill was about 27 dollars. I'm finally seeing some reduction there as I kind of move my
spend for the Cloud over to Azure. And on Azure there're all sorts of free trials and
things. I think one of my accounts is currently on the three-month free trial, so I get 750
free compute hours. And there's crazy things that happen on that. I honestly haven't
been able to estimate my spend because it keeps going down somehow.
But I'm paying for all these things. And so for me I'm kind of watching my cost, and so
that's a great reason to actually instrument my app and figure out what the heck is
actually going on. And I'm actually trying to be redundant too. You know, you don't want
a hundred thousand really bad reviews of your app on the app store. And right now I
have tons of great reviews. The average score is about 4.5 stars. I would like to keep it
that way, and so I need to run redundant services. I need to run reserved instances. I
need to kind of do the right thing from redundancy, but I'm just one guy. You know? So
thankfully the Cloud lets this happen.
Before I actually started using the Cloud, I was using dedicated servers. And went they
went down, you know, you'd have two days downtime while they try to figure out how to
get things running. So the world is better. Here is kind of a look at some recent bills.
So on the top, I couldn't find the break off for the Azure one. But you can see recently I
paid 46 bucks there on one of the accounts. Amazon kind of breaks down your compute
hours. You know, I've got 300 hours of a couple instances here from whatever this bills
is. I guess this is the current month right now. But you can see that, you know, it's real
cost. I'm using real services. And I honestly can't figure out day to day what's happening,
but I can do some estimations to at least figure out what my spend will be.
When you're running Cloud bills you often think, "Hey, it's only costing me two dollars
this month to run my service," but it could easily be the next, you know -- I won't say
Instagram because that would be awesome, but your app could really kind of take off.
And when that happens, at least with the Cloud you can scale some but cost is going to
matter. And so I don't have any silver bullets there to share with you.
But here's a look at the Azure Portal. This is the 4th and Mayor set for my subscription
here. And so this resolution makes it painful, but there's a bunch of websites. I'm running
both the standard websites and then the staging website. And it's a hundred percent
identical code in these cases; it's just different branches on Github where the code's
hosted. And so when I push an update into my Github staging branch, within a few
seconds Windows Azure actually pulls that update and it goes live.
And then, in my app when I have my debug configuration set up it uses staging, and
when I hit release then it hits production. So that's a good way for me to kind of know
that I'm testing against a current version. And when I get my app looking pretty good, I'll
go ahead and flip things over to release in Visual Studio and then I'll hit production for a
while until I'm really happy of course and then I'll get my bits ready for the marketplace.
Other services in here you can just see as Cloud Services. There're some storage
accounts, pretty typical view. This looks way cooler than Amazon's Portal so Azure's
doing some good work.
On the right you can kind of see an example. You can see some graphs of how the
load's going over time, and so it's really nice to pull up a week worth and kind of see
what the data looks like. Now these are things that today at least Windows Azure Mobile
Services doesn't support, or at least not all of them.
Clearly the most important thing I do is push notifications, and so that is sending toast to
users. So if I check in here at Building 99, my friend should get a toast on their phone
saying, "Jeff just checked in at Building 99." That's an extremely expensive service for
me to provide because I actually have to do a little bit of computing in the backend. I
know where your phone knows you were or where your friends were earlier and I can
look for changes and differences, but that's all Cloud computing time.
So clearly it's something you don't want to do on your phone device; it would just waste
the battery on the phone. But also, it's not a cheap service to provide. Crash reporting,
Live Tiles: Live Tiles, again, are super expensive compared to like parsing an e-mail at
least.
And then the magic is this continuous processing queue that I have, and so I have some
Node code. It is Java Script but it is quick; you know, I can process about fifty thousand
people in thirty seconds. It'll go through; it'll turn through. It'll talk to Foursquare. It'll look
at the database tables in Mongo. It'll figure out what the heck changed. And it's actually
some impressive code and this is all open source on my GitHub account. I doubt the
open source would help you because you're not running my app. But if you want to look
at what these things look like, you'll see the disgusting code that it becomes at times.
Since I don't have time to do the code right always, there's a lot of code where it's
temporary bug fixes and lots of to-do statements like all good code. This is kind of the
magic, though. It's really simple, like, the primary code is maybe 20 lines of code. It kind
of pulls a little bit of work off of the Mongo queue. It says, "Who haven't I seen, who
haven't I processed in the last two minutes?" And it's going to pull that data off and
temporarily kind of reserve it. And then, I know that even if this machine goes down or
something happens I'll at least see that person again in two minutes. So I don't worry too
much about down time there, but the good thing is, is if I scale, I can scale out from what
I have right now are three reserved instances. But if I want to scale out to 30 if I get
popular, I know that each machine will pull, you know, the 20 or so people for that work
and I don't have to worry about other machines pulling work and competing for, you
know, duplications and all these fun things.
But this code is super easy in Node and in Java Script because one machine is just
doing one little piece of work at a time and so, it's actually pretty fun.
There're some storage-hosted services, and these are really important things that I don't
want my web server to ever have to worry about really. And so, when the app notices
that it's been upgraded from like Version 3 to 3.1 there's actually a file that I store in
storage that I can pretty much guarantee is going to be up more often than my website
is. And so the app actually goes directly to storage looking for that version information,
and it'll pop this information it finds.
And in my case I actually store it on a CDN. And so, I'll have what's new in this version. I
fixed some bugs. You know, I added an Easter egg or something. I can put these things
in the "what's new" content. I upload it into the storage blob and then the app just hits the
CDN. And so it's really fast for users but also there's zero worry on my side. I can spin
down all these services on the left side and people will still get information about what's
new, the basic Live Tiles in the app that aren't customized, you know, all these nice
things.
Then, on the other side there're some other services I use. This is mostly for interacting
with users whether it's running a blog or letting people report bugs. Just, you know,
everyone kind of has their own tool box and this is the tool box I use for my app.
I've already mentioned staging so I don't want to drone on too much about this, but I will
say that one of the nice things I do is that I literally have all of my keys and certificates
that are different for staging dev and production. They're just literally a JSON file that I
don't check into my source control; I actually push it separately, but it's kind of a
standard practice. Yevor did it in his app as well.
And so that's nice because I can easily roll these things just by changing the file, and I
don't have to worry too much. In terms of production challenges I've had, the biggest one
is that I am sometimes a sloppy coder. And, I don't want to regress my users especially if
I have sometimes twenty thousand-some people using older versions of my app. And so
I'm actually doing version-done points.
And so if I go to my API URL, I'll have slash V2.1 slash V2.2. So each new client app I
build I will actually for the most part clone or in my application expose the same endpoint
if I don't change anything. And if I do change things I'll do kind of like quirks mode
checks.
And in the first version of my app I didn't do that, and I found that it's really painful
because don't always know to upgrade your app. So that's one challenge I've had there.
Other stuff: obviously moving between Azure and Amazon is a challenge. It's a fun
challenge. It turns out vendor lock in is not real but it's definitely work at some point, and
it's actually really helped me, I think, think more about the Cloud in that as much as we
like to think that all of the Cloud is a commodity there's definitely a lot of work involved in
making an app that runs everywhere.
The last two challenges: you know, things happen. Cloud providers go down. Nobody,
you know, says it's a 100 percent guarantee; there's a guarantee that's under that
number. And so what I found is that in my app one thing I do is I always go directly to
Foursquare when I can. And if I need to share that data with my Cloud service, once the
Foursquare request comes back then I do my processing with my Cloud that way the
core essentially part of my app, which is completely separate from my services, will still
work even if, you know, I do something and my Cloud goes down.
That's really the best way for me to mitigate it. Of course, you know, if your app is using
just your one single first-party service, you're going to have issues there. And you'll have
down time and so that's going to be about what you show your users. I actually have
some code here I'd like to pull up on that.
And that's way too big. So a few different things for how I do air processing in my app:
the first thing I use is a thing called JSON-P. And it's kind of a specialized version of
JSON that actually wraps the entire request in an http 200 response. And so it'll actually
say, "Everything's great. Everything worked." And then, you'll notice that there's this
request perimeter. It'll have this information about the request that actually says the real
http status code. And this was actually a work around from Windows Phone 7 back when
we kind of had Silverlight-style http status codes and things came back as 404 even
when they weren't really 404.
And so this is a hack that's been in there for years now. It just proves that code never
gets updated a little bit. But what I actually do is I can parse both the http status
information as well as special things that Foursquare provides for me. And this is the real
code right now for the production app. And I apologize because there're things
commented out and I'm trying localize. But what you can see here is that I kind of have a
different exception handling in my app depending on the severity. And so user-intended
exception is something that, at the root of my app, I definitely want the user to see and
so clearly I want to tell them here that their credentials are invalid. There's really no
smart way for me to handle this except let the user know it's invalid; they probably need
to install again.
And along with this, I'll actually sign them out of the application. But that's one kind of
thing where clearly I can't do much. Now this parameter error is a bug on my side. If it
happens, it's nothing my user did. It's either a bug on the server side or it's a bug in my
client code and so, I'm going to throw the standard invalid operation exception. That's
something that I'll get notified about either in my crash reports through the marketplace
or crash reports built into the app. But I found that kind of differentiating a few of these is
good. Here's one that Foursquare sends saying that someone has used the app a whole
lot in the last hour because "you've exceeded the rate limit." So, again, that's something
that's intended for the user, pretty standard there.
The other on I have is I kind of do the same stuff right here. Here's a note from probably
a few years ago, "Before ingestion, figure out this air handling." I don't know how many
of you have applications out there on the marketplace or have code that looks like this.
But this made it through ingestion so I guess it works more often than not. But here I
kind of do things; I've got some nice notes. So some day I should probably sign out and
inform the user to do something different. Today I just break.
You know, you can see here that I've got all the notes. I know exactly how I want to do
air handling but I'm a lazy coder. So, apologies. In your app, though, you should totally
do cool things with these status codes and inform users -- the right thing to do. [laughter]
This also proves that your app might be a horrible code base but, you know, fine in
popularity. So, go figure.
This stuff is not too exciting but, again, I'm just literally using an environment variable to
kind of switch mode my app thinks it is and it makes it really easy to test on my machine,
on another machine or in the Cloud.
But here's the good stuff for how you hook your app up. And the nicest thing is actually
the first one is the HttpClient library. This is something that CLR BCL team shipped
maybe two or three weeks ago. And HttpClient itself is kind of the basis for using http in
Dot Net 4.5, so like in a Windows Store app that's what you use. And it actually hasn't
been available for Windows Phone until recently, but there's a portable class library and
you can definitely use it.
It's got Async, Await, all the cool methods you'd expect to use. Windows Phone also
supports the classic Web Client and Http Web Request that is really painful to code once
you've used Web Client. So definitely use that.
In my case I have three versions of my app. I have the current version. I have a
complete rewrite that I'm doing that compiles for Windows Phone 7.5, 8 and Windows 8,
and I'm not done with it yet because it turns out that's difficult to do. But it's building and
it works. And then, I kind of have a future version where I incubate new features and
special features. In the two later versions, that's where I'm actually using HttpClient, and
the code is so pretty now. It's the way that things are supposed to be.
You should always think about retry policies when you're doing phone apps. Some
people will actually say that what you want to do is go ahead and always do like two or
three back off requests if you have a failure. I don't do that in my app because as you've
see I don't really even handle errors properly. But the best apps out there do that. I have
a friend who worked on the Twitter app recently, the brand new one, and they did a lot of
work in retry policies to make sure that the right things happen there.
Another thing that today HttpClient doesn't support is actually GZip compression. And it
turns out this is huge. When I finally added GZip to my app -- There's a couple NuGet
libraries out there that do it -- I literally saw just crazy, crazy improvements in download
speed. Because, if I'm downloading a huge download of Foursquare people I'm looking
at probably 150K of data, and in GZip that's often down to about 15K. And so it just kind
of flies down the wire. And so GZip is definitely something you should look at using.
Unfortunately it's not built into the framework today, but it's not even built into Android by
default. I mean, you have to enable it typically, so definitely enable it in your apps if
you're doing lots of downloading on the wire.
In terms of the technologies, RestSharp is a framework that makes it very easy to hook
into the Cloud. And I have some code here that kind of demonstrates that. So right here
is a user request, and this is where I'm trying to get information about a user. And so
using RestSharp I literally say, "I want to make a new rest request." The resource is to
the user slash whatever the ID endpoint is. And this is a get request. Here I'm getting
some information about what their ID is that I need to pop in there, and then you just
kind of call methods for adding segments, resource names. It's all API driven and so it's
a lot nice than, you know -- You'll see applications where you have lots of string math
and string concatenation.
>>: [inaudible]
>> Jeff Wilcox: This is on the client, yes. This is the Windows Phone, the Legacy
version that I haven't had time to touch. So here is the wrong way to do it. And this is my
push notifications connection in the Live application, so it works for a hundred thousand
people but very poorly. And so you can see here I have some goo to kind of get some
URI, but the URI that I want to send to I'm doing complete string formatting for. And this
is dirty. This is what happens when you don't use RestSharp; it's air prone. It's ugly. It's
tough to maintain. But the information I send might be interesting, so I send a ton of data
when I connect to the client through https. I'm sending their push URI; that's the most
important part. I am sending their OAuth token so that I can do work on their behalf on
the server. I'm getting information about their user ID, the version of Windows Phone
that they're using, the version of my application, how many times they've checked in with
my app, how many times they've used the app, who the manufacturer and the OS
version are for the phone. So this is the awesome data I need to actually debug for
users. If you're using Azure Mobile Services, some of this is available and you can plug it
into your app yourself.
But this is what I've found useful. I don't find it useful to have like unique identifiers or
anything like that. It turns out this is pretty much all I need. But it's a ton of stuff and on
the server's side, unfortunately I don't -- maybe I can -- There we go. On the server's
side this here is NodeJS code and this is kind of the inverse of this call. And so it's really
basic. I am hooking up to this connection URL. It comes in this way. I just literally pull all
the values out and then, I'm going to go ahead and actually do some verification and
what not. And then, I will actually shove it into my Mongo database. And this is the data I
use for every user, so it's pretty straight forward.
Of course the thing about caching, my app starts up really quick because I cache this
data. I don't really have time to go into too much of that, but I'll answer questions if folks
like. Logging, statistics: logging is impossible is my message on the left. You can do it.
You should do logging. It's helpful for debugging, but realistically once your service is in
production you may not even need to do too much logging. Instead you want to think
about statistics. And so I have a server that's called Statsd, Graphite; there're some
technologies built there. It's running on Node and Python and some other tech. And I'm
running all this on a Linux VM in Azure. And Statsd is awesome because it listens on a
UDP socket. And so from my server I'll send these UDP sockets that are fire and forget.
They're super lightweight. They'll say things like, "Hey, I have a log in," or, "I just had an
exception," or some other error. And the beauty of Statsd is that, you know, if it never
gets recorded statistically you can hope that you still have that data but your app is not
affected in any way, shape or form. And so I actually use this data whenever I push
updates or if I switch temporarily from Amazon to Azure, I can actually see my bug and
error counts change in real time using Statsd. And so that's actually the best way for me
to do testing is I'll actually switch from Amazon Web Services to Azure for like five
minutes, see what changes in my bug count, and then I'll flip back to Amazon.
And so it's kind of funny, people have no idea that they're changing hosting providers on
my side but it's the same source on both sides for the most part. So it's pretty cool.
>>: Then why don't you use that service at [inaudible] or somebody?
>> Jeff Wilcox: There're plenty of services that want like 30 dollars a month for it and I'd
rather not spend that 30 dollars a month if the Azure VM is like 3 to 5, right now.
>>: [inaudible] five million hits or something. I mean you probably exceed that but most
people don't.
>> Jeff Wilcox: Yeah, I guess I just use what I use today. I have a bunch of migration
challenges that I'll jump through, but I'm pretty much out of time. Do you have a
question?
>>: Yeah. I just missed the part where you were showing the URL, the [inaudible] URL
with all the different [inaudible] you were making.
>> Jeff Wilcox: Yep.
>>: What are you using instead of that right now? Are you still using that?
>> Jeff Wilcox: I am still using this.
>>: Because you...
>> Jeff Wilcox: However...
>>: ...[inaudible]
>> Jeff Wilcox: Yes. I'm saying this is a horrible way. You should not do this, and this is
in production right now. So, yeah.
[multiple inaudible comments]
>> Jeff Wilcox: So I think that the RestSharp library is the ideal way to do it.
>>: What [inaudible]?
>> Jeff Wilcox: RestSharp. And so with RestSharp it would look more like this where it
would have a single definition of what it looks like, and then I would replace these
segments saying like user version, the value I have. And it's just cleaner code. It's
probably slower code as well but, you know, it's just going to hopefully maintain changes
over the years instead of having to dig my way through these strings. So RestSharp is
really beautiful. I would definitely recommend trying to use that. And in my new version I
definitely am doing that.
>>: Or you can use your own [inaudible].
>> Jeff Wilcox: Or you can use your own, yeah. Definitely, yeah. Just don't -- Yeah,
strings are dirty. When it comes to scaling, my biggest comment here is that I actually
treat every user a little bit differently. And so, if you use my app every single day I
basically give you the highest priority. I will do push notification work for you basically
every minute. I will do all the work I can. I will give you the best Live Tiles.
If you use my app once every two days, I'll do just about the same amount of work. I will
do work for you maybe every two minutes, not every minute, every two minutes. But that
really scales back my traffic and my cost. If you use my app once a week, I don't really
care as much about you, I'll be honest, because you should be using it more often. And
so I will do work for you every 15 minutes. And so I have a back off algorithm based on
how often you use my application. And so I kind of just assume that people that use my
app, they're going to use it often and in return I'll give them really good response times,
you know, their push notifications and updates. But it's actually expensive for me to do
this work all the time. And so by tracking how often people use the app, just based on
when they connect push notifications. I can use that to scale back my cost. And I've had
people on the web, when I blogged about this, say that it's the worst thing ever; I
shouldn't treat users that way.
It turns out you need to make a call at some point on what you're doing. And for me, this
really, really saved me quite a bit of cost. And just a side note if you're Node.JS
development, you know, Dot Net is beautiful but on the Node side it's really quick and it's
fun and it's Java Script. And I wrote the push notification module for Windows Phone for
Node; it's just a module called MPNS. And it's actually what also powers the Azure
Mobile Services.
And then one of my developers created the one for Windows 8. And unfortunately
there're some differences between the frameworks; that's why it's not the same library.
But they're both open source, you can check it out, and these are those URL's.
My final little plug here is open source on Azure is awesome. Check out this website that
we have up at GitHub. You can actually look in Fork and open issues and learn about
the team. And you'll actually find the source then for things like the MPNS and Windows
Notification Servers as well. So questions? Yeah.
>>: How have you found that your cost scales along with your users?
>> Jeff Wilcox: So the question is how have I found that my cost has scaled with the
users? For me it's definitely -- I see the users come in, but it's not like an exponential
growth. For me if I look at download count, it's almost really just a static line. So there's
growth that's pretty much well defined. And whenever I get featured in the Windows
Phone Marketplace I'll see probably a thousand-fold increase for that day. And so I
actually appreciate when people send me Tweets saying, "Hey, your app is featured in
the U.S. Marketplace." I'll actually and I'll scale up in Azure; I'll add one or two more
instances just to make sure that it's quick.
That might not actually be necessary but I definitely see the spikes. And then long term
it's really Live Tiles where my cost is. So for that I don't have a good solution. Literally it's
costing me more for more users in that feature, and so you know I think things about
pulling back how often I update tiles is really what will save me money there. So again I
think favoring the most popular users might be the best thing there. But that's where my
cost truly is.
>>: Or you could charge for a premium.
>> Jeff Wilcox: Or I could charge a premium. Yeah, I've looked into that too. Maybe
someday, yeah.
>>: How about from the inception, when you first published this and there were no
users, as you gained users what did you see your cost -- how did that grow?
>> Jeff Wilcox: So when it comes to cost the question is really over time how has the
change in my build been really. And for me it's almost been flat since the start because I
kind of went big from the start, and I already had about fifty thousand users when I went
to the Cloud. Before that I didn't actually have my own Cloud service. And I decided to
build it kind of to be somewhat redundant and somewhat efficient from the start. And so
I'd be running four VM's in Amazon when I probably could've been running one. And so
for me I had more capacity than I needed, but it also let me get a ton of bugs out of my
code when it came to consistency in the code. Yeah? Any other questions? Or we can
end it right there.
>>: [inaudible] there is actually one key thing that I'm almost seeing which is this may be
the wrong way to do it, [inaudible]. So when I look [inaudible]. That's not how it should
be. But it almost feels like it's better to build stuff that works and worry about [inaudible]
later.
>> Jeff Wilcox: Yeah, so...
>>: [inaudible] of course you are saying, "Do as I say instead of do as I do." But...
>> Jeff Wilcox: So the question is, "Jeff, why is your code bad?" And...
>>: No, that's my question.
>> Jeff Wilcox: That's the way I'm reading it.
[laughter]
>>: The question is basically would it be right to surmise that don't worry about the code
quality, just go ahead and build it. And as long as it works, you can fix it later?
>> Jeff Wilcox: I think everyone has a different situation. In mine, I wish that I had
written some of my code better. And so if I look at my JSON objects, I was hand-parsing
JSON in my first version. And there're still parts of my app where I still hand-parse
JSON. There's no reason to do that. And so that's just a silly mistake. I was just hacking
code real quick late at night. I shipped it. And I have some weird bugs as a result. And
so it's a bane of my existence now is fixing bugs that were from sloppy code. If I
would've maybe spent an extra 20 percent, maybe I'd sleep better now. I think it's a call
you need to make yourself. But I think today there're a lot better tools than there were
two years ago for Windows Phone developers. There's a profiler built into Visual Studio
now; there's a ton of good features there. And so I think Windows Phone development in
this era is much cleaner, much nicer. There're new-, get-modules. When I started my
app I didn't have those niceties. So, you know, write some bad code because bad code
feels good to fix but not all bad code.
>>: So when you are creating a new service for each and every app, is it saying Version
2.1, 2.2?
>> Jeff Wilcox: Yep.
>>: So are you planning to take them down or [inaudible]?
>> Jeff Wilcox: So actually in my current -- The question is basically for versioning on
the server, how do you maintain that? So I'm not actually forking the code because I
don't want to, you know, copy my code for no reason. Today I actually exposed pretty
much all the endpoints through the same node module. And so, it's literally just one line
of code that says like "App dot connect, V 1.1, the module." And so right now it's like no
cost for me to do that. You know? It's very simple.
I have had one version where I had to have a slightly different implementation and so I
kind of do a two different code pass there, but for now I'm not worried about it too much.
My app has a kill bit built into it, so at some point I can actually say that, "Version 2.5 is
dead. You can't use that any more." And I store that file in storage. And so the app
basically every once in a while will ping that location, and if a file comes back with a
specific piece of data, it'll display the message in that file. And so I could say, you know,
"Please update your app. This version has been deprecated." And so that's kind of my
solution. At that point I'd be happy to delete it. I've actually only used the kill bit on a few
versions right now, and sadly all the really old versions of my app don't have a kill bit.
And so I still see tests running. I think maybe the Windows Phone team has versions of it
in a test harness somewhere because I still have people using a version that I know for a
fact doesn't actually work.
But it is what it is.
>>: [inaudible]. How do you know whether your app has been [inaudible]? Is there any
way that you are going to track it and if I need to know that 2.5 is not used...?
>> Jeff Wilcox: So the connection code I had actually sends the actual application
version that is in the client package, I send that to the Cloud. And so I can actually do a
query on my Mongo database to say, you know, "What are the versions? Give me that
list." And so I do look at that. Another thing I do, though, is I actually do prune my list.
And so if someone doesn't use the app for a month, I'll prune that data off of the
database. And so I don't have long term stats there but I know today what the versions
are. And it's a little script I ran to do that. And then I also do have analytics that will show
me maps of where users connect from and what version they use.
>>: So the followup question is that do you have any sort of random graph saying
number of users versus version? Like how long do people not update?
>> Jeff Wilcox: I haven't had the time for that. So the question is do you have historical
trends and data? And I don't have enough. I have the Marketplace data but that's about
it.
Question in the back?
>>: What's the security [inaudible]?
>> Jeff Wilcox: Yeah, security measures. That's a tough one. So for me -- I'm just going
to open these analytics real quick. For me when it comes to security I'm doing quite a bit
of work when it comes to actually protecting my endpoints. And so, sure, Azure is secure
or whatever but I protect my credential files and then I always validate the data when it
comes in. And so on the server side, everything is coming in through SSL but I'm
actually checking every parameter to make sure that it actually conforms. And I'll punt
the data that I don't think, you know, should go into the data table. So that's a little
measure there.
When it comes to the client side, you know, people can get your OAuth token, and if they
were to like steal your phone and be a computer geek -- But it turns our your OAuth
token can be revoked. And I don't store any other data on the phone that would be an
issue there. So that's what I've done. But I also know that if I were to build this app at
Microsoft, my manager would have a very different opinion about privacy and security.
So you have to kind of make your own call. On my server side I do have a small amount
of user-identifiable data since my app has to actually know where you were recently. I
basically know for any user I could look up this information, and I've kind of tried to
abstract that out so my logs don't have the data. But it is actually in that Mongo table.
There's really no way around that one without doing a lot of work.
Question on the left?
>>: Do you protect your endpoints?
>> Jeff Wilcox: How do I or do I protect my endpoints?
>>: Yeah like can anyone just write an app and talk to your endpoints?
>> Jeff Wilcox: Yep. Anyone can write an app and talk to mine, but if I can't find your
legitimate push URI which is given by the Windows Phone notification service on the
phone then they're not going to get anything. It'll just punt the request. And that's like -- A
huge encryption question is: how do you protect your web service endpoints on the
client? And the answer is usually, you don't.
You know? And people will write these Instagram apps that hit Instagram when they're
not allowed to. They have ways of identifying it but in general it's really hard to protect
those things. Yep?
>>: Have you done any work around convergence between your Windows Phone and
you said you have something in the works for Windows 8?
>> Jeff Wilcox: Yeah, so I do have a version of my application which I build across all
these different things. So if I go to my source code, if I drop into the future version of the
app, so Windows Phone 8 -- It's kind of hard to see but visually there're links here.
These are all Visual Studio links. So I shared the same exact source file with every
single version of the app whether it's Windows 8, Windows Phone 8 and whatever else.
That's taken work to maintain but it does build. So that's the convergence story but it's
very slow. So I wouldn't recommend it for everyone. And I haven't shipped the app yet
because it's been a big challenge.
>>: So you're not using a PCL?
>> Jeff Wilcox: PCL's are great in some situations but for me the way I'm structuring my
data, portable class libraries don't work for me. But I'm also a little bit over-engineered in
some things. Okay, well I don't want to keep you guys too much. I'm happy to answer
more questions but we have an "Ask the Experts" thing. And this was just to show folks
that on the analytics side, it is useful to know where your users are. If I zoom in on
Washington State, you'll notice that most users are in the Seattle/Redmond area.
They're must be a lot of Windows Phones here.
So anyway, thanks a lot, and I'll be around for questions.
[applause]
Download