23841

advertisement
1
>>: I guess we can start. Welcome, everybody. Welcome to our consecutive
XAPFest event. Now we have Jason Short. He's from the SQL group, but will
talk about just data and how you can present it in the Windows phone. Without
further ado, Jason.
>> Jason Short: Thanks, [indiscernible]. Hello, everyone. Like
[indiscernible] said, I work in SQL server, but we're not talking about SQL
server tonight. Most of what we're going to be talking about is just data
management within your application on the phone. And I'm going to go through a
bunch of different frameworks and different principles that you can use to
apply on to your application.
Just a little bit about my background. I do work for SQL server and manage
ability. I've been at Microsoft about two years now. Prior to that, I was in
ISV for 13 years. I worked on a lot of different projects from Windows CE
stuff, I was actually at the very first Windows CE developer conference, which
I can tell you was a very different developer experience than what we have
today. I also wrote apps for Palm, iPhone, Android, and now I'm doing Windows
phone development on the side.
Some of these pictures you see here on the far left here, this is a magical
moment pin from Disney. I moved here from Orlando, and I think just about
everyone within Orlando works for Disney at some point. I actually worked on
these little embedded chips that actually were a little game that kids could
play like Simon Says on the chip. And a lot of the same principles that you
use in your phone apps today, we use in embedded environments as well.
The hat there in the middle is actually a big, it's a 260-foot tall icon at
Hollywood studios at Disney World, and I actually did the lighting controls for
that, that actually control how the lights spin, depending upon how many people
around. The people who are wearing the pins, it actually emits a near field
communication to let the hat know how many people are around.
So a lot of embedded development that you're doing on your phone, it applies to
a lot of other environments. Don't just think about your phone when you're
writing your apps.
I also wrote the control for the E.T. adventure at Universal Studios. The E.T.
character actually says good-bye to every single person on the ride, and he
2
knows their names. That's a four terabyte database that's actually recorded
with actors for E.T.'s voice, and we actually have to pan that across audio.
That's all SQL server that we actually do all that with.
So, you know, when you're doing this type of development, don't just think hey,
this is my phone today, this is what I'm going to do, you know. You never know
where this stuff will go.
Mostly what we're going to go through today is your core data scenarios.
Anyone who's worked with databases probably has seen the acronym CRUD. And, of
course, I get a meeting. And CRUD stands for just create, retrieve, update,
delete. And we're going to go through each one of those for the phone, how you
might think about it in the context of your application.
And then we're going to go through some frameworks you can use or tools you can
use to actually help you implement this within your application. AGFX,
SterlingDB, SQLCE, and I'll basically go through different scenarios where each
one is applicable and how you might apply them. Sometimes you'll end up using
all three within an application.
When you're looking at application data, you really need to go through. Ask
yourselves some questions about your application, you know. Where you're
getting your data. What are the APIs that you're using, what are the
protocols, you know. In today's modern, you know, web connected, a lot of
people think java script, JSON first. Nothing wrong with that. Some people
think Odata first. There's pros and cons to both, but you need to make those
decisions before you start building your app.
In a lot of cases, you're consuming third party APIs. You need to make sure
you get those APIs, actually play around with them a little bit, make sure you
understand how they work before you build your app so you can actually
understand the pros and cons to using that.
When do you need your data? This is actually probably the biggest problem I
see with most apps is that they don't think about when they need the data until
the user's already there and waiting. So they wait until the user's sitting
there and they pop up a nice busy dialoguer or the animation, and at that point
it's kind of too late. The user's already sitting there impatiently and you
have, you know, literally milliseconds to get their attention or they're going
to leave. They'll close the app, they'll hit back, they'll do whatever.
3
So we're going to talk about that, thinking about when you need the app. How
much data do you need and can you cache it. A lot of times, people don't think
about what they can cache, and a lot of times they think, well, it's going to
be too hard to implement, I don't want to go through all the hassle. It's
really, really easy. But we're going to talk about that also. Sometimes you
can cache stuff for hours.
In the case of some apps, you want to cache it per run, or you may even cache
it based on location. Look at 4th & Mayor, some of those type applications
where it's okay to cache data that's around you, like people's addresses don't
change that often. That may be something you can hold on to for a long period
of time. When you those are things you need to think about.
And then how long can that cache data live. Is there a maximum size? Are you
willing to say, I only want to have one meg of cache. Whatever it is, after it
overflows that, that's acceptable, or do you want to say, you know, I want to
have a maximum age, like if I've been here within the last 30 days, the last
ten hours, whatever it is. But you need to think about those while you're
building your application.
Just to give you a little context, a lot of what I'm going to be talking about
today is around this specific application. It's called Microsoft Partner Info,
and it's for Microsoft ISVs on the phone. So it has over 200 feeds of data.
This data comes from RSS, from Twitter, from flicker, from all different kinds
of data sources. Most of the feeds have over 12 items added to them per day,
and we have about 2,400 items per day that we have to basically get to your
phone somehow.
And right now, if we were to just keep one day's data, it's five megs. That's
not bad, but most people aren't willing to let you, you know, take up, you
know, 150, 200 megs of data just for reading something on their phone. So
you've got to think, you know, how do I pivot on this data. How do I determine
what do I grab, when do I grab those type things.
But this app was originally developed by someone else in [indiscernible]
Microsoft. Because I've been in ISV for so long, I actually talked to one of
the directors there and said, hey, can I help? Is there something here, you
know, that I can actually help you guys with, because I wasn't very happy with
the experience that I was seeing, and I was like, I can help you guys out.
4
So a lot of what we're going to talk about today are lessons that I've been
learning as I've been applying this to this specific app.
The biggest problems that I had with this app originally were start-up time.
You know, when the user first downloaded the app, the initial data hit was
very, very long in the order of 60 to 90 seconds. And that's assuming you were
on WiFi. If you were on 3G, forget it. The user would have given up way
before they ever got any of their data. So that, you know, initial launch time
was something that wasn't thought about when the app was designed and that's
something I'm going to go through. You really do need to think about that.
The user responsiveness, every update was loaded on demand as a user pivoted,
because there's just so many feeds. You don't want to go grab them all, and
how do you determine which ones to go grab. And it's just a poor experience.
When every time someone pivot, every time someone drills down, you go back to
the internet. They're like, you were just there. You just got data. Why are
you going back to this all over again.
And then filtering data. You know, you don't want to overwhelm the user with
data. You want to think about what's relevant. A good example is I have a
feed of Twitter, you know. CES is going on, there's a whole bunch of Twitter
streams going on. And then I have a feed from an RSS off of a blog. The
Twitter's going to totally overwhelm whatever's happening in that blog. You're
never going to see it because there are so many entries happening for Twitter
that the user's going to just, you know, they're either going to miss it
because there's so much data there, or they're not going to pay any attention
to it because they just get overwhelmed.
And a big part of what we've been doing with it for this app is actually
looking at context and seeing, okay, there's an event going on. We should
probably roll all that up, present it differently. So CES gets rolled up under
an event. That way, it doesn't interfere with the rest of your data stream.
So those are sometimes things that you should think about.
And users are not very patient, you know. Cache first, and then load the data
on demand. I'm sure everybody here's probably used a Twitter client, and you
scroll up to the top and you do that force refresh. I want new data right now,
and that's something that you should also think about. Sometimes users do know
there's newer data there. Let me go get it. Don't make them exit your app and
5
come all the way back in in order to reload data. Sometimes it is as simple as
that drag to the top type of thing. Sometimes you need to add a refresh
button. Just think about it.
So thinking about CRUD, when you go to build an app, you should think through
your user scenarios and I tend to lump them into two big buckets. There's the
core scenario. These are must-have, like we have to load data. We have to be
able to display feeds. And then there's the optional, the nice to have. Like
the ability to take all these feeds that are happening at CES and roll them up.
It's nice feature, but what's that's going to cost? You need to go back and
look. Like this particular app, just like you guys, I'm working on that on my
spare time at home. And so I really have to stop and think. Okay. What's
this going to cost in terms of time for me to implement, and then what about
maintenance going forward. What's this really going to take to tune it, so
deal with user feedback. How are you going to get the user feedback. All
these types of things. You need to think about that data.
And I think that's one thing that a lot of times I see developers go into apps
and they start off with this great plan, and they haven't really categorized
must-have versus what would be nice to have. And end up kind of floundering
around and never finish their app. They never ship it.
And some advice that I actually got here at XAPFest last year was ship. You
know, no matter what, ship your app. You can't finish it, you'll never be
done. Especially if it's a hobby type of project. You know, it's okay not to
be done. If you're not a little bit embarrassed when you ship that first app,
you probably waited too long. You know go ahead, ship it. Once you have
something out there and you're getting feedback from people, you'll be a lot
more motivated to add those new features, to go fix bugs, to actually go back
and keep making your app better.
That's one thing that I've done forever is just ship, ship, ship, ship. You
know, you'll work it out. It's just as soon as you have actual users, you feel
much more committed to the app. I mean, there's actually a couple of guys here
that I know that I talked to a year ago who weren't shipping because, oh, it's
not good enough. Haven't added this, I haven't added that. And now they have,
and they have a very different perspective. Yeah, [indiscernible].
So we're going to go through each of the CRUD, the C-R-U-D, and I've basically
6
broken out each one of the titles to the slides based upon that. So thinking
about create, you need to think about your initial data. That first time run
experience is so vital to the user. You have nothing loaded. You have zero
data there. What is the user going to get? Maybe they downloaded the app from
the marketplace and they didn't launch it immediately. Now they're sitting on
a plane, they're in airplane mode. They have no data access. What's that
experience going to look like?
There are a lot of apps in the marketplace today that if you do that, download
it, turn on airplane mode and then go launch the app, you get a really poor
experience. It's like a blank thing saying no data available. That's it.
That's not a very good user experience. The user's probably going to tap,
hold, uninstall right after that. They're not going to want to come back to
your app.
You need to think about what is that very, very first-time experience.
In most cases, that initial data needs to be updatable. You need to think
about, you know, where do I store that data, how do I get that data out. And
we're going to go through some specific examples. But there are certain
mechanisms in the phone, like you can bundle initial data with your ZAPP. You
can put it as a content or a resource, but those are read-only. They're
signed. So you can't update that. You can read it, but now what do you do
with it?
If you think, okay, look, I have my initial data here, but now I'm stuck,
because I actually go and down load the data and now have to replace it. You
can't do that within your ZAPP. So we're going to talk a little bit about
that.
And I can't stress this enough. Your initial assembly size really matters.
You need to keep it as small as possible. The EXE that is actually loaded,
everything that's in there is going to be jitted. So you need to think about,
okay, if I keep this small, it's going to load a lot faster.
As an example, this specific app, the MS partner
bunch of bit maps, initial data feeds and things
app. And it was taking three and a half seconds
cover that up with a splash screen or something.
putting them in an initial load assembly so that
app, initially had a whole
all just bundled into the base
to load. Not bad. You could
But by taking those out and
we got the EXE up and running
7
as fast as possible, got the UI up and then got the data, we actually cut that
down to less than half a second. So the makes a huge difference in the user
experience for them to be able to get their data as quickly as possible. So
really, keep it as small as possible.
So to that, let's create a separate assembly. In the Microsoft Partner Info, I
just created an assembly that I called initial data, and there's really,
there's no code there. It's just data. That's all I have there. Because I
know I'm only ever going to need this at initial run time. So why bother to
put all this stuff in my base assembly? I have XML files there. Actually, I
have JSON that is identical to what's going to come back from the server if the
server's up. If I can reach it. If I can't reach it, I have something to fall
back to. I hand it to the exact same routine. I don't need to special code
anything, and the user has a good experience.
So in my case, we have some systems that pull and get XML and some that get
JSON. And so I just said fine, let's just take whatever it is we're going to
get initially, put it within there. It's acceptable. You don't have to think,
oh, I got to put this in a database and I got to be able to install the
database. There's a couple people that I've talked to who got hung up on this,
you know, I need a database, because that's what I'm going to have eventually
once the app is up and running.
No, you don't have to have a database. You just need to have somebody to get
the data. You can gen the database. You can create the database. You can do
it while the user is there. You just need some way to get that data to them.
So think about compact format, keep it as small as possible. You could jeez up
this data. You could do a lot of other things. In my case, it wasn't that big
of a deal. This particular assembly is only 32K, and it cut that two and a
half second off our load time. Huge difference. Yeah?
>>:
Is it the [inaudible]?
>> Jason Short:
>>:
These are, it doesn't really matter.
It could be either one.
Question, please?
>> Jason Short: The question was do I store these as resources or content?
this particular example, I do store them as resources, but it really didn't
In
8
matter, because I'm not using this assembly for anything but getting that data
out and then I never touch it again. Question?
>>:
So just 32 kilobytes saved three seconds on every startup?
>> Jason Short:
>>:
Every startup?
>> Jason Short:
>>:
Yes.
Or the first startup?
>> Jason Short:
>>:
Yes.
Every startup.
Every startup.
>> Jason Short: Because all of it was bundled into the core assembly before.
Now that I'm separated it out into a separate assembly, it actually loads a lot
faster.
>>:
And there's only 32K of data?
>> Jason Short: Yeah. Well, what was stored in the base assembly was actually
slightly larger than this, because we weren't storing it as JSON or XML. It
was trying to encode the data as it's going to live on the drive eventually.
But there was no reason for that so I just took it down to JSON.
it's not identical data. Yes?
You know.
So
>>: So talk a little bit more about what data is in this separate assembly and
how current it is or if it gets old or how you would refresh that down the
road.
>> Jason Short: Sure. The question was talk a little bit about what lives
here, how old is that data, and how do you refresh it later. I literally have
a flag in the app that says go look at the isolated storage and check for a
flag called we've run before. If the flag's not there, we've never run before.
So then you set it.
9
As soon as you hit that logic, then I basically spin-off a background worker
thread to go gen my actual data on the drive. That background worker thread
actually goes out and pulls all this data and calls it just like as if it had
come from the web. So this is just my initial data load.
After that, all my normal caching rules apply. So if I say any data that we
download from the web is valid for seven days, this will be valid for seven
days after you initially launched. It's all time sensitive based on when the
user runs.
Now, in some cases, some of this data, like the feed model data, the list
actual feeds, those don't change that often. We only check like every 30 days
for those.
Now, I take this data, I gen it on to the drive in the SterlingDB for that the
that we use. But then I do actually kick off a background thread to say, hey,
let's go check and see if there is an update, because you don't know when this
ZAPP was published. It could have been published six months ago. So I don't
treat this as it's the only data that we're going to have. I expect to throw
it away as soon as possible.
But if the user doesn't have WiFi, doesn't have whatever, you know, any type of
data, we need to make sure they get a good experience. We need to make sure
they get something there. Every data feed comes with a default article that
says refresh to see the latest news. So when they hit a page, they don't just
see a blank page, they see a little article that tells you, you know, refresh
in order to get the most current news.
>>: I guess just
you refresh it, I
point. I mean, I
to republish your
one quick follow-up. I guess when I was thinking about how
was thinking about new users installing the app at some
guess if you were going to refresh the data in here, you have
ZAPP, is that true?
>> Jason Short: Correct. The question is if you want to have a new, initial
data load, you have to republish the app, absolutely. And that is something
that we do periodically. We'll go back through and say, hey, we have, you
know, a hundred new feeds have been added or whatever so let's actually
republish the assembly. You can probably do other changes in the interim
anyway. But if we didn't republish, this is going to get thrown away anyway,
and we will actually refresh live.
10
So it's okay. It's just this is your good initial data set to get started
from. And you're not actually using this for anything other than genning.
you load this, and then you actually go out and you actually generate your
database, you actually write your isolated storage files, you do whatever.
don't use this for anything except that initial load.
So
You
And another nice thing about having it as a separate assembly, you can actually
create this assembly and let someone else edit it. Like in my case, I don't
actually edit all the feeds. There's actually a person on the ISV team that
actually does that. So I actually wrote him a Silverlight tool that he can use
to go through and edit these and then just send me back. So then I just
include it, rebuild. There we go, there's a ZAPP. You know, sometimes that's
nice.
This specific assembly, like I said, it saves over three seconds on startup
each and every time you start up the app. But that initial data load, it saves
over 30 seconds.
>>:
How does it do that?
>> Jason Short: The question was how did it do that? It was when we used to
start up, we used to have to go to the web in order to actually pull down that
initial data feed. That was taking over 30 seconds in order to go get that
data, because there's so many different feeds that it had to pull from. We're
going to talk about that, like, round trips and how expensive all this stuff
is. We'll get to that in a few more slides.
But just because I didn't have to go make round trips and go out to the web, I
saved over 30 seconds of that first user experience, which is so vital. You
know, if the user doesn't like your app immediately, they're north going to
come back. You need to make sure you think about that.
Like I said, I'm literally taking this and using this for data generation. The
code snippet here, this is what the JSON looks like. And if you were actually
to connect to the live service that feeds this, it's identical. I literally
just took a browser, connected to it, right click, save as, wrote to JSON.
That's it.
JSON is already a pretty sparse format, but you can do the same thing with XML.
11
You could do the same thing, you know. I've actually seen some apps where they
do almost like screen scraping. They actually go get an HTML page and then
they disassemble it and look for content on it. You could do the same thing.
You just store the initial HTML file. You don't have already pre-split it
apart and try to write a database. Because especially on the phone, the only
database that I know of that has compatibility between the desktop and the
phone is SterlingDB.
So if you want to, you know, pre-populate a real database, and we're going to
cover that much later down in the talk, you can actually do that with
SterlingDB. So you don't have to do it this way, but this is actually just
your easiest way. You treat it just like as if it was coming from the web.
Sometimes you can actually use a seed algorithm. In one specific instance a
gentleman that I was talking to had an app where he was actually pulling data
from the web, but it was pretty predictable in terms of, you know, it was X and
then a bunch of, you know, derivatives off of X kind of thing. So it was very
algorithmic. So I'm like why don't you just take the first 10 or 15 values
someone is going to use, pre-populate it. Build that, put it on to the drive
and then you can actually start making your round trips later.
So think about, you know, sometimes you do have things that are -- you know,
you actually have to go get them live. Like Twitter, obviously, you're not
going to be able to store a lot of data there because it's going to be so stale
by the time the user installs. But you could always put an article there that
basically says, you know, you're out of date. Please synch. Please get
online. You can always give the user something.
In this specific case, I'm just taking the JSON and building the database.
This specific database is SterlingDB, which we'll cover later on down. But I
literally just write routines like this. Generate the feed models. Take my
SterlingDB container, loop over it, and go get, you know from the initial
resource stream off of that JSON file, deserializes it just like as if it came
from the web and then loop around and save it.
So I didn't have to write an initial data gen routine and my data update from
the web, then I have twice as many things to test, twice as many things to
maintain. I don't like doing that. So to me, it just made perfect sense. I
just want to write this once so it doesn't really matter where the data comes
from. I'm going to use the exact same routines. Just encapsulate as much as
12
you can.
Retrieve. And this is something that I'm actually surprised a lot of people,
when you think about it, it makes sense. But a lot of times, you're just
thinking, oh, it's like a desktop or a wireless. I'm over WiFi. But round
trips on a phone are just flat-out evil. I mean, they are so slow, it's that
you have very good bandwidth on a phone. Like you can download a megabyte per
second. That's not the big deal. It's going to get that data, making the
initial hand shake. Finding the server, doing all that initial round trip
that's so expensive.
It's not unusual when you're on 3G to see 250 millisecond network latency.
That is very, very expensive. If you think about we have 200 feeds we pull in
the Microsoft [indiscernible]. 200 feeds times 250 millisecond each DNS
lookup, that's -- you're spending seconds just waiting on DNS at that point.
So think about every round trip. If you can bundle that data up somehow. If
you can make fewer round trip calls or hold a connection open for some period
of time and continue to stream data, you have excellent bandwidth to get data
down. But think about every round trip.
And this is something that I see a lot of people make mistakes in their -they'll build view models or data models and they'll actually bind them to some
service call. When they could have got the whole data in one chunk and stored
it somewhere. But they'll actually go back and say, okay, orders and then
order details. So get the order, and they know it has 12 order details. Then
when the person goes to hit orders, he has to make a whole 'nother round trip.
Try to collapse all that as much as you possibly can. Make it in one round
trip instead of making, you know, a round trip for every single order detail.
You'll see huge performance gains.
And always think about your number of data sources. The more locations you're
hitting, every time you hit a different service, it's not a point of failure.
If you hit, like, we do 200 different feeds, any one of them could be down at
any specific time. You have to plan for that, which means you have to build a
lot more robust code. And I'm going to talk a little bit about how you
mitigate that a little later.
You need to think about that. Every service you connect to is a dependency.
What happens if that service goes down? What happens if that service changes
at the API? You really do need to think about those things. If your app is
13
broken because some third party changed their API, your users don't care.
your app. They're going to blame you.
It's
So this is actually an example of in the IVS app, our initial load, we were
grabbing 12 files from remote sources. By changing that to grab a single file
that I aggregate every hour on a central server that we control, I actually
made it 7.8 times faster. Just because of the network latency. Just the round
trips, having to go look up each one of those locations. You know, you went
from, I believe that's like six seconds down to under a second to be able to
get that data. Huge difference from the user perspective.
Same amount of data.
It's just how long did it take to get it.
This is what we're doing right now is consolidating at the server. Your server
usually has a very high speed network connection. You know, your server
usually knows everything that's happening. It can perform caching. It can
perform filtering. Sometimes, you can actually say, hey, I have 200 feeds.
Can you pull the most recent feed from that. You're actually saving each one
of those 200 feeds from every single phone client hitting them.
Now, you are actually paying that bandwidth cost. So there's always a
trade-off there. But in a lot of cases, you can prebuild that data set, you
can compress it, you can do other things to save your user bandwidth, to save
them time. And in some cases, it makes sense to use a content delivery
network. Content delivery networks are basically -- Microsoft runs one,
Akamai. You know, there are several third parties. Amazon runs one.
And it's basically where you put the content once and they take care of
replicating it to Geo locations. They'll put a copy in Europe. They'll put a
copy in Asia. They'll put multiple copies in the U.S. and then the person's
phone grabs it from wherever the closest network is automatically, just through
DNS. So you gain a faster response time for your user without having to
actually go build ten servers all over the world.
And sometimes, content delivery networks, especially like our feed list, for
example, doesn't change that often. If my server were to go down, what happens
to my app? Well, if I prebuild that and put it in a content delivery network,
I don't have to worry about my server going down. It could be down.
Everyone's going to grab it from the CDN anyway. Doesn't matter. My app will
stay running. Everyone will have data. Maybe an hour out of date, big deal.
14
That's okay.
>>:
It's acceptable.
Yeah?
What does this cost?
>> Jason Short: The question was, what does it cost. For some, it varies by
provider. I can only speak to the ones I've used. I've used Amazon and I've
used the Microsoft CDN. Microsoft CDN, you have to be an internal app in order
to use it. Like you can't use it as a third party. Amazon, you can actually
use it as a third party, and the price is, it's pennies per gigabyte. I mean,
it is really, really incredibly cheap.
For static content, in some cases, I've seen people where they'll pay Akamai -I believe the starting cost there is hundreds of dollars per month. So that
may not be feasible for small apps. But with Amazon, you literally only pay
for what you use. So, you know, it's very, very affordable.
>>: Can I correct something that you said?
access Azure can actually use the CDN now.
The Azure, third parties who
>> Jason Short: That's actually an excellent point. Ben just brought up a
point, that Azure does actually have content delivery network now that period
parties can use. And I forgot about that. You can actually declare static
content within Azure to say I want this Geo replicated and you only pay per
gigabyte of actually data that's downloaded.
>>:
12 cents per gig.
>> Jason Short: Thank you. Sometimes you can approximate what the customer
wants. The data size is not as important as the round trips. In our case, we
will actually take an aggregate, you know, let's say ISV feed for Australia,
for example. We'll actually take all the feed data for Australia, pack it into
one file, because people can get it quickly, and then filter client side to
determine what to show and what not to show.
There's, I believe, 17 feeds in Australia and if we were to give every person a
separate feed for every one of those, we'd have to make a lot more round trips.
Instead, we just smack it all together, let everybody download it and then
filter in client side. It's not that big of a difference.
A difference between you have 16 of the 17 is, you know, a kilobyte.
You know,
15
it's why bother having all those round trips when you can actually just
consolidate the data on the server. And sometimes it makes sense. Sometimes
it doesn't. Depends upon your specific scenario.
Lazy load your data. This has got to be the most important, if you don't take
anything else away from this, take this away. Lazy load. When you look at,
like, a list box in Windows phone, the list box itself is virtualized meaning
if you see seven items on your screen, there are only seven plus or minus a
couple dangling off the ends of your Silverlight XAML that's replicated in
memory.
Even if you have a million items, there's only those seven there, because
you're actually windowing through that data content. But the data you bound to
it, the data bound data is all loaded. So if you have a million items, all
million are loaded. That's horrendous.
I've seen a lot of apps that end up exceeding the amount of memory you can fit
on a phone just because they're data binding. They're data binding absolutely
everything to the list and they don't realize the fact that it's all being
pinned in memory because you have it data bound to that list.
I'm actually going to go through a couple code examples, ways you can actually
implement this really, really easily. You can actually write your own very
lightweight wrapper around IList of T. You don't have to implement everything
that's in IList. List box actually only pulls three things that you need. You
need a count, the total number of items that are in that list. That's so that
you have a scroll bar that has a correct proportion. You know, if you're on
item ten of ten, it shows you're at the bottom. If you're on item 10 of a
million, it shows a little tiny dot there along the side.
That you usually have somewhere anyway. You need an index of. So that it can
actually request a specific item, like a user's jumping to it or the selected
item index. And then you have to implement the this indexer. And that's where
you actually do your loading and returning of data. And there are some tools
to help with that. But it, like with SterlingDB, it actually already does a
lazy loading for you, but we'll cover that when we talk about Sterling.
Here's actually an example of the this indexer. And literally, right here
where I'm actually -- in this little example, I'm just allocating the object
there. You actually would go to disk and get the specific object.
16
Now, I talk to people and they say, well, but aren't I going to take an IO hit
here? And the answer is yes, you are going to take an IO hit. So what do you
do there? If the user -- if a normal behavior of your application is to scroll
up and down wildly within your app, then you need to load everything. You
know, there's nothing you can do about that, because you're going to be loading
and unloading things constantly.
But most applications don't have that user pattern. If your user pattern is
we're going to rarely scroll down past 20 items, 30 items, wherever that number
is, we only need to keep the last 20 items in memory then. You know, you can
go grab, like if you're doing a Twitter feed type example, if you have 12 items
on the screen and you think they might scroll back to get the next 12, load 24.
That's okay. 24 is not going to kill your app. Loading a million will kill
your app.
So you can implement really easy here and I actually have a sample project that
I actually implement this in that I'll give to [indiscernible] so he can
actually attach with the notes. It's a real simple demo of how this works.
Another thing that you can think about is refreshing your data in the
background. Now, this is kind of a double-edged sword with me. Background
agents are fantastic. I mean, I am so happy that they're there and I think
that they have their place. But I think where a lot of apps abuse them is that
they don't think about the fact that while I'm out and about and my phone is on
my hip and I don't have WiFi, they're using my data. They're grabbing GPS.
All that's expensive. It costs battery. So you really need to kind of balance
that. You know, it's fantastic to have a background agent to update your live
tile. Hey, we grabbed 20 new items, update your live tile so you have some
more information to give the user.
But you don't want to be, you know, trying to grab huge amounts of data while
you're there. Sometimes it's enough to know there's new data, and the user
launches your app and then you go get it. Sometimes that's okay. Sometimes
you do say, oh, well, I'm going to grab, you know, the top ten posts of
whatever's there. Don't try to grab the last 12 hours. If the user hasn't
launched your app in the last 12 hours, they probably don't care about all that
data. So think about how much data you're grabbing and when you're grabbing
it.
17
The background agent data transfer will be turned off if the battery level gets
too low. I'm sure you guys have all seen in Mango now, they have all the
little heart sign on your phone when it goes into smart mode to save your
battery. Once that happens, background agents don't run anymore. So to me,
that means the phone team pretty much acknowledged that background agents suck
battery. So as soon as the battery starts getting low, we need to turn these
things off.
So just be a good citizen of the phone and try not to be, you know, be the
reason why that user's turning off their background data.
And the last one here is something that is not hard, but a lot of people don't
think about it. Adjust with your user behavior. If your app is a football
app, and you're pulling down scores for Sunday, probably need faster updates on
Sundays. You probably don't on Wednesday. You know, there's not a lot going
on for football scores on Wednesday. It's okay to launch, say okay, it's
Wednesday. I'm going to only pull data every 12 times I run or something.
Because the one thing about the background data agents, you don't really get to
schedule when it's going to run. You just get to register to run and you get
to say, hey, I want to be a background agent. The OS calls you approximately
every 30 minutes. You don't really have a lot of control. It's not like you
could time it and say, you know, I'm going to run every 29.5 minutes. You
don't have that level of control. So it's period Iraq.
The OS will also look at how much background agents the user has on their
system. If they have a hundred, they're not going to run all of them. They
run some small portion of them. The next window, they run another small
portion. Don't count on the fact you're going to be called the same number as
on your phone, because different phones, people may have a different number of
agents running.
But if you have an app where people are using it every single day, you do need
to go grab data. If it's something you're only using once a week, think about
the fact I don't really need to go get this data, or I can pull it at slower
intervals.
You can also monitor your actual user's behavior. You can say, hey, this guy
is, you know, he's on Twitter all the time. He's launching this app 22 times a
day. He's checking stuff. I need to make sure I have the best user experience
18
possible and grab that data every time the background agent runs so when he
launches, he's ready.
Sometimes that's acceptable. But you wouldn't want to do that all the time.
If the user is a hard core user, obviously they want that. They're will be to
pay the battery hit for that. But if the user is only launching every two or
three days, why bother pulling every single time you get run. Just think about
it.
>>:
Can background tasks share storage with the main app?
>> Jason Short: The question was can background tasks share storage with the
main app. Absolutely. You have the exact same isolated storage. You have to
build a separate assembly for the background agent, but you can share code. So
you can actually build a third assembly that's kind of the shared code between
the two and so your background agent calls the exact same code as what's
running in your UI.
There's inter-process communication. There's no way to say is my background
agent running right now, you know, and while my app is running. But you can
kind of work around that by, you know, save a flag when your app is actually
running that says UI up. Or UI loaded. And when you actually close the UI,
delete it.
You know, that's okay. In this specific screen, you know, we have the behavior
of the Facebook, Twitter, scroll to top, go grab new data. But we also added a
refresh button there. And I added some analytics to look at that, and it's
actually kind of amazing the number of users who hit refresh. I mean, don't
assume that everyone knows that behavior of drag to top. You know, there's
different cultural issues. There's different, you know, a lot of Windows phone
users are not really that tech savvy. Sometimes they got it given to them by
work or by their husband or spouse or whatever. So don't assume that all these
behaviors we take for granted are, you know, common to everyone. Think about
how can I allow other users to do this who may not necessarily find that.
And I've seen a couple apps that, they actually put like the first time they
run the app, they actually put a little notice up there to say hey, you can
scroll to top in order to update. I think that's fantastic. Anything you can
19
give the user to let them discover your features better, then users are going
to have a better experience, and that's what your app is all about.
When you go to delete your data, you know, you need to think about the cache
policy. Caching data on the phone is so vital for when you're in airplane
mode, when you're offline, when someone's in a parking garage or when they're
in a meeting that doesn't have WiFi, whatever.
You know, you should think about, you know, when it's stale data too stale. A
good example of this is addresses. If you're a 4th & Mayor type of app,
addresses don't change that often. You could probably cache that data for a
fairly long period of time before you absolutely have to go back and look it up
again. If you're a NASDAQ stock exchange, you know that that data, if it's 20
minutes old, it's out of date. You need, you need to throw that data away.
And you need to really decide how you're going to clean that data up. In most
applications on the phone, you just delete the file. You know, if you have
multiple files, you may time stamp them. You may use a naming convention,
whatever. You just delete the file. In databases, typically, you don't want
to do that, because deleting it actually causes a lot of expensive IO. It may
try to reorder the pages, a lot of things. A lot of times you just update a
flag to say it is deleted.
But that complicates your logic. Now your lodger, every time you go to load an
[indiscernible], say is it not deleted. So, you know, it can be a pain. But
looking at some things like AGFX that we're going to talk about it, it actually
makes this whole process -- you don't even have to think about it. It actually
adds a nice facade on top of your object that you just say, I want this cache
policy. This is how long you want it to live and you don't have to think about
it again.
Every time you try to get an object, it handles all of that in the background
for you. So you should be conscious of it, but in most cases, you know, try to
make your life easier. Use tools.
Delete for background cleanup. This is actually, I think, a fantastic use of
background agents. If you know that you can actually do things in the
background, you free up the UI. You know, you free up the user experience.
But sometimes, you have to think about this. Like I said a few minutes ago,
you can't tell if a background agent's running at the same time as a UI. So if
20
you go through and delete a bunch of stuff but the UI just loaded and it showed
it to the user and they click on it and blow up, that's not a good experience.
So you should think about those types of things as well. How are you going to
clean something up, when are you going to determine that something is cached,
it's not valid. If you use something like AGFX, it's easier because it's
arbitrating that stuff for you. But I think agents are a fantastic way to
clean stuff up in the background.
Delete. This is actually another one of my pet peeves. Sometimes, a user
wants to start over. They screwed up. They got settings somewhere that they
don't know what it is, you know, whatever. They haven't run your app in six
months. You know, they're like, I just want to start over without having to
uninstall the app and go regrab it again. You may put this in a settings page.
You may put this in an about page. It doesn't need to be in their face all the
time. But think about that, I want a clean experience. I want to start over.
I messed up, you know. I've done a bunch of stuff and I don't know what I did
or my kids played with my phone. You want to start over. Think about that.
Sometimes you can just truncate the data.
Sometimes you can actually go back to the initial data load assembly and say
let me just re-gen all over again. Delete everything that's there, re-gen
again. User has a clean experience, they're back off and running. I think
that's something that a lot of apps don't have today.
I actually had a to-do list app that for whatever reason, my pocket decided to
launch one day, and I ended up with about, I think it was 10,000 items in the
to-do list. And to delete them, it was six steps because I counted them
because it was so painful I had to go through all of them. Even after the it
deleted, it put it in a log area. And I had to go delete each one individually
from the log area. I finally ended up uninstalling the app and reinstalling so
I could get a clean experience.
It's like so think about that. Think about users who have done things that
they want to undo, but, you know, how do you wipe that out.
Now we're going to go through some example data tools that you can use. Each
one of these has its own use, its own scenario. AGFX is primarily a caching
framework. But it also handles things for you like data storage and
expiration. You just think in terms of your objects, and you say, this object
21
I want to have this cache policy. And you're done. Like you don't have to
actually think about where's it stored, what's it named, how long is it going
to live, all that type stuff. It does it for you.
SterlingDB is a lightweight isolated storage database. It puts your objects in
isolated storage. You don't have to think about what the file is called. You
don't have to think about where is it stored and I have links to these later in
the presentation, where you can go get them.
And then SQLCE is a fully relational database. And it's built into Mango.
It's a single file. So you have one file in your isolated storage, but you
can't really just back that up and put it back. That's, you know, we'll talk
about that a little bit. But, you know, that's something to think about.
AGFX, data cache, data manager, it is a fantastic way to encapsulate your
network API. There is an I data loader interface that you implement with AGFX,
and then every object you can actually say, hey, here's how I'm going to go
load this. In my specific example, I actually implemented two data loaders,
one that actually goes to the web, and one that grabs from the local file.
In some cases, it's really easy to just encapsulate that data for, like, in
expression, as an example. Sometimes you want design time data. And you can
actually, I just overrode that to say here's a static, you know, one, two,
three, four. It's good enough for me to get something in design time so I can
work with and I just implemented a static data loader.
It also handles lazy loading for you, which is I think an under appreciated
function of AGFX is the fact that when you load an object, you're not actually
loading an object. You're loading the indexes for the object. So if you index
two properties on an object that has a hundred, you only get those two loaded
into ram until you actually grab the lazy load object. And then you actually
get the full load. It goes to disk, it does everything. So the more indexes
you add you, can actually really speed things up within your app.
It also automates cache expiration for you. Every time you load the app and
you touch one of these objects, it will automatically take care of going
through and cleaning things up for you, which is fantastic. And it does it all
in the background. You don't have to worry about data binding, because
everything is lazy loaded. If something is currently pinned into memory, it
won't delete it.
22
This is actually a fantastic framework. Here's actually, this is one of their
diagrams from -- this is a code plex project, by the way. It's totally open
source. You can download the code. There's also a new-get package for it to
include it inside your application really easily and update. And it's out
there on code plex. This is one of their diagrams. It has a generic load of T
for on-demand load. So you can say when you go to load something, I want it
now and it goes through and says, hey, we'll go get it for you from disk if you
already have it, obviously, we don't need to go back to disk. It's very
intelligent in that regard of how much it's caching in memory. There's also
cache validation. You can customize the policies. You can override the way
things are written. You can override the way things are loaded. It's very,
very open. It's very, very flexible.
It also has async handling. You can actually say, hey, I need the list of
feeds, but I also want you to start updating this thing in the background.
Give me what you got now so I can display something to the user and start a
background fetch. Fantastic.
This is what the class declaration looks like on the -- you have to implement
an IDataLoader interface. In this specific -- this is my ParkList view model.
And I basically implemented an IDataLoader for the ParkList context. Your
ParkList is where you're getting the data from. And when you actually have the
load context, the load context is what does the work. So I have this ParkList
load contact so we'll actually go in and get the data or return the static data
or it could go get it from disk or, you know, whatever you want to do there.
But now you're totally encapsulated. When you want to get something, you just
use this last line. I want a ParkList from my data manager. I have current
context load the view. Go. You don't have to think about what about
expiration, what if I don't have a local one, what if, you know, if it needs to
go update it. It's all handled for you. And because all the objects
underneath are observables, if it does get an update to it, you get a nice
change notification. The UI knows how to refresh itself. Everything works
very, very seamlessly.
This is an example of what the cache policy looks like. When you're caching
things in AGFX, there's a bunch of different pre-canned settings that you can
set up. The cache then refresh is the one that I use most often. Which is
basically give me back whatever's in the cache first and then go get whatever
23
it is you need to do. You can also say don't cache this thing ever, you know.
Just I don't want it cached. Give me live data loads at all times.
You can say valid from the cache only. This is actually fantastic when you
have a specific feed or specific object that you want to make sure, like in
between your background agent and the main UI, you want to make sure they're in
synch. You can say I don't want cache data. I need it to be live at all
times. Every time I hit this thing, make sure I have an absolutely current
copy.
Cached and refresh is what I use and then auto refresh. Auto refresh basically
looks at the timeout that you have set there and says is this data older than
what you said is valid. Yes? I'm going to go ahead and kick off a refresh in
the background for you. It's going to call your ILoader. It's going to go
back. You'll update everything, and because everything is again observable,
your whole UI nicely updates. You don't have to worry about, oh, I got, you
know, some new data. I need to go invalidate my UI. You don't have to do any
of that.
So just kind of a summary that the automatic cache is really, really a saver
for almost any type of app. It is fantastic to just encapsulate whatever it is
you're loading your data inside of there, and then you don't have to think
about it. You implement it there, and you're done. The automatic expiration
saves you a ton of work of having to walk through everything that's on your
disk and say is this out of date, is it within date, especially if you have
different contexts you want to apply to different objects. You just apply it
at the object level and you're done.
And the pattern of complexity here, it's not as simple as some other solutions,
but it's doing a lot for you. It does take a little bit of work. They have a
really fantastic tutorial on their sight of pulling weather data down from a
national weather service somewhere. It is -- it's a lot of work to get set up,
that initial wrap your brain around the problem, why am I setting this thing
up.
But once you get to the end of that tutorial, things start to click, and then
you're like wow, now everywhere I need to touch this thing, it's just one line
and I'm done.
So it's really easy to test.
It's really easy to automate.
And once you get
24
the pattern down, it's really, really simple.
than other solutions.
It is a little bit more complex
So now we're going to talk about SterlingDB. SterlingDB is another -- it's
open source as well. It's done by Jeremy Likness at Wintellect. Yes?
>>: So internally, this AGFX, does it have database or objects in the file
system.
>> Jason Short: Good question. The question is internally, is AGFX doing a
database or a file system. It is an object store. So it's up to you. If you
implement an object that encapsulates a feed, that's what gets cached. If you
say, I don't want to cache that. I want to cache the individual entries,
that's what gets cached. It's up to you when you implement the data loader,
you say what objects you want to create out of that. It handles the actual
storage of them.
Underneath the hood, it is actually storing individual files in the isolated
storage, but they're based by object types. So if you have ten objects that
you're caching, there will be ten files. And it will also, if you say I want
this thing to never expire, it will actually create another entry for you
there. So it handles that under the hood, but it's not a database underneath
the hood.
Another interesting thing that it does there, the indexes that you create and
the querying that you do is own LINQ so you don't have to learn SQL. You don't
have to think about, you know, how do I get this data out. It's all LINQ
expressions, which is kind of nice. Which I think I have a demo of that later
on in here. If not, we can actually go through it afterward, if you'd like,
some of the how do you query it and that type of stuff.
SterlingDB, it's lightweight, it's in memory indexes, so it's very, very fast.
It is not always a single file. The underlying implementation is, you know,
you're supposed to be encapsulated from it. You don't have to worry about it.
It also uses LINQ in order to do your queries. You don't need any SQL
knowledge whatsoever.
The kind of unique thing here is that all your indexes are also expressed as
LINQ. So when you define an index, you have to actually say, here's my LINQ
expression to generate that index off of your object model, which is very nice.
25
This is the only solution that I know of that has the same database for the
desktop and Silverlight so you can actually gen your database using desktop
Silverlight, take that and put it in your initial data load and all you have to
do is copy it out of there, store it on the drive and load it. You're done.
That's fantastic. Just for being able to say, hey, I got a same database here
and I can use it in multiple locations.
It also is the only one I know of that has a really clean backup API. You can
call it, it's just dot backup, and you back it up to another file, and you can
go store that in sky drive. You can go put that wherever you want. It's just
a file at that point.
So then your
account with
restore your
is open it.
really nice.
user comes back, maybe they uninstall and reinstall. They have an
you, something like that. You can actually say do you want to
previous entries. Go get the database, put it down and all you do
You just open it like a file and off you go, which is really,
And just to make clear, I am not saying any of these are either/or. I combine
them. Like I use AGFX with SterlingDB. I use AGFX for the data caching of the
feeds. About when you break out the individual feed items, I store them in
Sterling. So you don't have to have one or the other. You can actually
combine these approaches.
So this is an example of what the setup looks like when you go to register a
database. You can actually customize these loggers. There's a Sterling
default logger that only logs data when you're running in debug with an under
the emulator but when you actually compiled a release, nothing gets logged so
it's much faster. But you can actually customize that if you want to. If you
want it to say I want to log this to a separate file but then I'm uploading to
some service, you can do that.
I've actually used this before with error reporting within an app, keeping
track of analytics within an app. You know, you can use it for a lot of
different scenarios. But all you have to do is basically, this is it. You
call the engine activate and then you register a database.
In this specific case, I'm using the isolated storage driver. You could even
override that and create your own driver if you wanted to. You could create a
26
sky drive, you know, your own custom object there if you wanted to.
really, really powerful.
It's
Every object that you store in Sterling is just POCO, plain old CLR object.
You don't need to go decorate it with data member attributes and here's my
index and here's the key and here's all these other things. This is literally
one of the classes that I use. The only thing that is, you know, unique here
is that you do have to have a default public constructer, because Sterling has
to be able to allocate the object with nothing in it before it hydrates it.
You can't have custom private constructers and things. Yes?
>>:
So is this equivalent to an entity framework type stuff?
>> Jason Short: Good question. The question is, is this equivalent to entity
framework. No. The entity framework is a mapping capability to say, I have
data stored in this, but I want my entities to look different than that. They
may be a subset of that. They may combine multiple entities. Entity framework
is definitely much more powerful. There's no equivalent to entity framework on
the phone yet. Entity framework also gives you nice things like change
tracking and the ability to undo changes.
You know, that's not on the phone yet. I haven't seen anything like that yet.
That would actually be incredible if someone did do that. But it's not there
yet. Even SQLCE today is linked to SQL. It's not EF. So this is what your
indexes look like in Sterling. When you create a table, I'm literally just
saying it's a feed group model and I want my key to be an INT. In my case, I'm
actually using IDs for each feed to say what the primary key, if you want to
think of it that way.
In this case, I just say hey, I have a table definition and because this is all
link, I just do the dot with index and you give it a name. You say what type
it is, and then you write your lambda expression to say T dot category ID.
That's my index. That's it.
The very bottom one is actually an interesting way you can actually, where the
A lambda true is basically is basically, I only ever want one instance of this
object. Like in this case, it's just the app configuration, like how many
feeds do they have, what do they want to do with them. I only ever want one of
those. I don't want ten of them laying around. So you can just say true,
which means basically always give me back the exact same entity. Which is
27
very, very handy.
You can also define custom indexes using Tuples. So if you have a composite
key would be the SQL analogy for that. If you have like an ID and a name that
you want to use as a compound key, you can do that through Tuples, which is,
they actually do give some very good examples of that, doing some more complex
stuff, but I didn't want to put it in here.
When you go to create your database, and you have an object and you want to
save it, all you have to do is you call the object and you try to load it. If
the object doesn't exist, you have a new one. Set whatever the options are
that you want on it and you just call it dot save with the object.
You don't have to go through each individual property and say, you know, I need
to serialize this and serialize that. It handles all of it for you. You can
actually decorate your objects. Let's say you have a computed field.
Something like a sum of an order type of problem. You can actually say don't
serialize this specific field, but you don't have to do that. That's up to
you.
This is what it looks like when you go to load. It's just a dot query and you
write LINQ. Like in this case, I'm looking for a feed model where the index
matches the group that I'm looking for. And I actually want to -- remember, I
said they have a nice lazy value. It's literally just called lazy value. And
you dot lazy value, get the value, and now you have the actual object fully
loaded.
If you just returned the select F here, you only have the Sterling instance of
that object, which only gives you back the indexed fields. So if you have, you
know, a hundred properties within your object, you only have two of them
indexes, you only have those two loaded, which is fantastic for things like
data binding, where if you know I'm going to use these four things to display
in a list box, but everything else I only need to go get from disk later, you
can actually create an index with all four of them so you get them immediately
without having to touch the full object.
This is an example of how you back up and restore, and you literally just call
the Sterling database dot backup. Give it the object that you want, which is
my specific database instance, which contains every table within my database.
Give it like in this case, I'm actually backing it up to a memory stream and
28
then returning back the buffer.
And then to restore it, you just call dot restore. You have to unload the
engine and then just reinitialize it. Use Sterling engine and dot activate.
Normally you do this, I didn't actually show this. I should have. Normally,
you would do this dot activate and the actual register database during your app
startup. So in your app, initialize, load, unload, those type things. That's
where you normally put just little Sterling functions to say initialize,
unload, those type of things.
SterlingDB is all about LINQ. If you're not comfortable with LINQ which, you
know, it can get complicated, you know, like this specific link Q query
actually gives you that screen on the right, which is a long list selector with
a jump, which if any of you ever tried to build that up by hand, it gets to be
a real pain in the butt in order to figure I have a group and I have these
grouped items and I need to create groupable items that are collections of
these things. Single LINQ statement gives it back to you entirely.
This was actually, I was talking to another developer that I met here at
XAPFest and I was specifically having problems with the long list selector
trying to get this grouped UI. To be performing, because I just had so many
feeds I was loading. And he actually pointed me to his app that he had where
he was using this, and I was like man, this is so much easier than what I was
doing before, when I was trying to iterate over everything and built it up in
memory and you just get it all in one shot. Really, really nice.
Another -- I actually skipped over that. LinqPad. LinqPad is your best friend
in these things. If you've never used LinqPad, LinqPad is a free tool for
writing lambda expressions. You can use it against a SQL server. You can use
it against a back-in database, but you can actually just write code and write
the lambda expressions, execute it without having to go through the whole
compile, edit, launch, you know, go through the whole cycle. Which I actually
do have some demos we could do at the end of LinqPad if you guys are interested
of how to actually generate this in LinqPad without having to go through the
full cycle and load your browser and everything. Because LinqPad is a dot net
app, you can actually just point to it your assemblies and it will load them.
So you can actually call your real assemblies from LinqPad. It's fantastic.
If you never used it, I highly recommend. I don't know why we haven't bought
them yet.
29
I'm not going to go into too much detail on SQLCE. I actually be don't use
SQLCE very often. Not because it's not a good product. Just because most
applications on the phone are not that heavy for relational data. Most of the
time, you have lightweight data. You have less than, you know, 10,000 records
of whatever it is. You don't need a lot of join with join and join and join
and you're trying to answer BI type logic on your phone. Normally, if you have
anything like that, you're actually calling back to a server and the server's
doing all that type stuff, talking to the server. Talking to a SQL back-in.
But I wanted to include it here just for completeness so that everyone's aware.
It is included in the phone in Mango and above. It's a single file database,
but it's not the same as a desktop SQLCE app. So you can't use the same
database and just copy it to your phone. It doesn't work. There are actually
different formats.
The one thing that just kind of grates me the wrong way is there's no schema
version story for upgrades. So if you have V1 of your database and suddenly
your app comes out with V2, the EXE gets upgraded, but your database doesn't.
There's no automated way to say, hey, take my database from this, that version
up to this version. You have to write all that code manually by yourself.
Which can be complicated and you're going to end up writing a lot of SQL. And
if you get it wrong, you just corrupted all your users' data. Which is very,
very bad. Yes?
>>:
How about SQL light.
>> Jason Short: The question was what about SQL light. There is an
implementation, a C-sharp implementation of SQL light. SQL light's unmanaged
code. But there is a C-sharp version of SQL light that you can use. Yeah.
>>: I actually [inaudible] the wrappers. It was like a crappy wrapper and
then there's another wrapper. I think it's on code plex. So it had bugs.
>> Jason Short: My biggest problem with SQL light is you're also going to have
to learn SQL. You're going to have to know SQL. And any problem that you're
trying to solve in SQL, you're probably doing something wrong. You probably
have too big of a problem to fit on your phone.
>>:
You also have to know SQL light SQL.
30
>> Jason Short: Well, there's always that. SQL light actually uses a
different syntax than SQL server SQL, which is a whole 'nother -- we're not
going to go there.
I think it's interesting to note that the entity framework and LINQ are both
query mechanisms. Like you use LINQ with entity framework. But on the phone,
with SQL CE, you cannot write raw SQL. You can't say select star from table.
It's not allowed. You have to use LINQ to SQL and build up with LINQ, which is
something that confuses a lot of people, because it's like I've written all
these SQLCE apps on the desktop and I can actually just execute a command. Why
can't I do that on the phone? I don't know what the answer to that is. But
you can't. Yes?
>>: Is there a story of updating data [indiscernible], is that easier on
SterlingDB?
>> Jason Short: The question was, what about upgrading the data model in
SterlingDB. If you've modified your objects, it is up to you to maintain that.
And normally, the way I do that is I'll have like application configuration B1
is what I'll called the object. So if I'm going to modify that object, I treat
it like an interface. You can't modify it. I create a new one and I call it
application interface V2. And then you just have to loop through and say load
the V1. Save as V2. As long as you provide an assignment mechanism in your
code, you don't have to migrate the data. But you do have to think about it.
It is true. It's not handled for you automatically. There's no solution that
I know of that handles it for you automatically. Same thing with serializing
even just dot net objects in general. If you serialize them and reload them,
if you've changed anything, you have to handle that yourself.
Another interesting thing to note with the phone is ADO.net is not supported.
So there are a lot of desktop developers that come to the phone and think I
already know how to write data apps because I use ADO.net. I know how to
allocate objects this way. I know how to load data sets. None of that exists.
So you can't use, you know, data readers and data writers. There's none of
that type of stuff there. You have to work to LINQ to SQL. That is your only
choice.
Another thing with SQLCE, it's fairly rough developer UI experience, compared
to the desktop. On the desktop, you have a nice UI, you can say I want to
31
create a table. You can get a nice table designer, you can drag things over.
You get none of that with the phone right now. Hopefully, they're working on
that for the next version. There's no designer, there's no EF layout tool.
There's no way to build up that type of stuff. You have to actually build it
from hand.
And it is LINQ to SQL, not entity framework. Entity framework allows you to
map your entities across multiple tables. LINQ to SQL is a much lighter
weight, simpler. There's one object per table. So if you have ten tables, you
have ten objects. That's what you get. You have ten columns on each one of
those, you have ten properties. It's a much simpler mapping, but you end up
having to manage a lot of that stuff yourself.
So in summary, which one of these is best? I get asked that question. You
know, which one is best, and it's like a lot of things, you know, in the
software world. It depends upon your application. You know, AGFX, I think, is
fantastic. If your server uses a rest API, they actually provide a web request
object that makes the whole process of allocating an HTTP reader, going and
connecting and all that. He handles all that for you and he just hands you the
raw output of what happened. So that's fantastic. If you have a real simple
rest API, it's brain dead simple to go implement.
For small data applications where you're generating data, like note
applications or the user's actively doing something, I think SterlingDB is
fantastic. I've actually run SterlingDB with up to 14 million entries in the
database and had no performance issues. No memory issues. I was actually
very, very impressed that you could actually do that on the phone and not have
a bunch of problems.
And if you're doing heavy relational data, like you have an existing data model
in an enterprise where they have orders and order details or manufacturing
scenario where you have salesmen and you're actually just trying to get that
data to the phone and they need to be able to access in the field, relational
data is the only way you're going to do that unless you're willing to invest a
lot of time in building facades and building interfaces for that. You know, it
is sometimes easier just to say I have the same structure on my server as I do
on my client.
And there are some tools out there to do synchronization from SQL server to
your client. All of them are pretty rough, I would say. Like all of them that
32
I've tested, I wouldn't use. So I can't actually endorse any of them. But I'm
sure that's going to come in time, actually synching, you know, relational
data. I'm sure it will get there.
So these are the links to AGFX, SterlingDB and LinqPad. Like I said, LinqPad
is a free tool. LinqPad is not open source, but it is a free tool. He does
have a premium version, like it actually will give you ought to complete and
nice dropdown list, but you have to pay for that if you want that. But all the
base functionality is all there.
If you want to actually query an O-data service and actually write link against
it, it's all basically built in, you don't have to pay for any of that. It's
just if you want nice intelli-sense and things like that, which, you know, I'm
dependent upon so I paid for it.
The AGFX is built by -- it's just a couple guys, Shawn Wildermuth, I think, is
the main guy who works on it, but he's very responsive. I've submitted bugs to
him and patches and he's taken stuff and rolled it in. It's fantastic.
SterlingDB is, like
official project of
it does have a desk
I think that's very
I said, Jeremy Likness and Wintellect. But it's not an
the company. It's, you know, a side project from him. But
stop Silverlight version and the Windows phone version. So
handy in a lot of scenarios.
So when you're building your apps, always remember CRUD. Think about how
you're going to create your data, where is it going to come from, where you're
going to, you know, store this data. Think about how do you retrieve data, how
do you query the data. How are you going to update the data and how are you
going to delete it.
It's a real simple acronym to remember as you're going through and thinking
about your application. You know, what are you going to do here.
I personally think, you know, be a good phone citizen. Your application is -that is the user's experience on the phone. If they have a crappy app on their
phone, they think they have a crappy phone. That's not the case. You know,
the phone's fantastic. Because I'm sure all you guys know, it comes down a lot
of times to apps.
And you need to be conscious of device memory.
You need to be conscious of
33
battery and you really need to think about those things while you're building
your app. Don't build something that's going to give of the phone a bad rep.
Always ensure you have a good user experience and remember that they're the
reason why your app is there. If you build something for yourself, fantastic.
Load it, you don't ever have to sell it or put it up in a store or whatever.
But if you're building stuff for other people, you know, you need to think
about what their needs are, their desires.
And any questions? One thing I would like to bring up is that if you guys want
more detailed talks like when I originally approached the XAPFest guys about
doing this talk, I was actually going to go into a lot more code and much more
lower level how do you store this data. But as I built that slide deck and I
showed it to someone, he's like I have no idea what you're talking about. So I
was like okay, that's a good reality check. I need to back up and set the
stage first before I could go any deeper.
So if you guys are interested in more in-depth talks about any of these things,
talk to the XAPFest sponsors. Talk to us. You know, we're very open to doing
whatever it is, you know. It's a community-driven thing. Whatever you guys
want to hear, we'll do more of.
>>:
Are you saying you want to come back?
>> Jason Short: I'm here every time anyway.
talking. You know, doesn't faze me.
>>:
So I don't mind coming and
Request for your next is more codes.
>> Jason Short: More codes. Well I have some code if you guys want to come
look at stuff after we're done recording. I actually have a sample projectile
give to [indiscernible]. He can put up on the blog that shows how to implement
the scrollable lists with a virtual data set. It loads a million items and you
can scroll through them like literally you see no hiccups. You see no
anything.
And we can go through other stuff.
>>:
Yes?
The next question, is this going to be available for download somewhere?
>> Jason Short:
Yes.
This is recording right now as we speak and it will be
34
available on resonant, I believe.
>>:
I think like we have two, three days turnaround.
>>:
And the samples will be there also.
>> Jason Short:
The samples, I don't know.
I will post it.
Can you post the samples on there?
>>:
We'll have the [indiscernible] and you'll get it.
>>:
Great.
>> Jason Short: And if the samples change over time, which I'm sure they will,
I'm also planning on doing some of these samples on my blog so the
infinitecodex.com site, I have a blog there. I update on just random junk,
whatever it is I'm working on at the time, but I'll also be posting a lot of
this stuff on data virtualization, because it's just very interesting to me.
>>: So there's some question of how about some of the Telerik controls for
Windows?
>> Jason Short: Good point, the question was what about Telerik controls for
the Windows phone. Telerik actually implements the virtualization for you so
you can give it a list of data and data bind and it builds that little wrapper
for you.
So it doesn't keep everything loaded into memory. Telerik is actually the only
controls that do that. Like most of the other vendors presume you know what
you're doing. And if you hand them a million items, you really did want all
million items intent into memory. So Telerik actually does have some very good
controls. I've actually played around with them and I was very impressed with
memory footprint and how they actually managed to virtualize around what you
were doing.
Yes?
>>: So I'm curious, is there a graph that says how big your ZAPP file is and
how long it's going to take for it to load? Is there like a tipping point? So
if you have big slash screen images, that's going to cost two and things like
that I'm guessing?
35
>> Jason Short: The question is, is there some graph or some algorithmic way
to determine what your startup time is going to be based upon your ZAPP size.
No. It's not about the ZAPP size. Remember, the ZAPP is a nice convenient
package that the marketplace hands to your phone, but your phone explodes that
and puts it in the isolated storage. So it's not actually stored as a zip
file. That's all zaps are is zip files. So it actually does unzip it and
store it there. From what I can tell, the big determining factor in your
launch time is the amount of code, the code path that you take, and what you
touch.
Because it's jitting, right. I mean, it's all dot net code, so it has to walk
that path and jit everything and do the security checks, you know, do
absolutely everything before it starts the execution path.
So the more objects you try to touch in your start screen, if you touch
absolutely everything in your app object, you touch every screen you have in
your app and you try to, like, preset the IDs or something like that, that's
going to take a heck of a lot longer to start.
Try to minimize that startup path through your app. The app object, the
application object so that you're only touching the minimum number of things
you need to in order to get the screen up. That seems to be the biggest
limiter that I've seen. Yes?
>>: I was going to add on to this, because the app performance, separating out
all your code, whether it's pages or images into different assemblies will give
you a big load increase. Because what the phone does, to load the app, it will
load only the assemblies it needs so if Jeff Wilcox blogged about this. So he
has an about page. He puts all of that in a separate project. And all that
stuff isn't loaded into memory when an app loads.
>> Jason Short:
That's actually a very good point.
>>: The images and everything like that, you want to do the same thing that he
was doing with initial data.
>> Jason Short: Yeah, Jeff Wilcox has a really good blog post about looking at
your app and seeing things that you rarely touch, separate them out. Like he
takes his about screen, you know, very few users ever go to the about screen.
36
Get that out of there. Put it in a separate assembly so that it doesn't have
to be jitted. It doesn't have to do the security check, doesn't have to do all
that stuff on it.
And only load it when you need it. You can still reference it. It's not
reference. You can still hard code the references. You don't have to do
reflection loading. You don't have to do any of that. Putting it in a
separate assembly, you've gained the benefit of not having to load it. Yes?
>>: I'm thinking about securing the [inaudible] is there any way to like
[inaudible] encryption for you on SterlingDB or something.
>> Jason Short: The question was what about security of the data or encrypting
the data. All applications on the phone are already in their own isolated
storage. No one else can touch your specific application. So you don't have
to worry about another app on the phone. Although there are some tools you can
put at your desktop to get at the isolated storage data.
No, none of them actually handle the encryption for you. With SterlingDB, you
can actually customize a serializer to say I want to call this first. And, you
know, do some bit masking or whatever it is you want to do to obfuscate the
data or encrypt the data.
You can also implement G-zip there or whatever you want to do. SQLCE does have
a password type option where you set a password on the file and it encrypts
everything with that. I believe it's just using a simple SHA over some
algorithm to -- it's using that as a key to actually encrypt your data. But as
far as I know, there are no built-in encryption for the file IO. You have to
do that yourself.
>>: There is a method in Mango now to do the encryption. Mango has an
approved way to do encryption on the phones without storing any caches or any
Ks from the server to separate the data. I don't remember the space or the
method, but I [indiscernible] about it.
>>:
A topic for another talk?
>>:
Yes.
>>:
[inaudible].
I was just thinking that an hour and a half, and I just
37
wondered a pin number or something I can secure those.
[inaudible] you might want to have something.
[inaudible] or higher,
>> Jason Short: That's an excellent point. The point was that if you're
touching sensitive data, pin data, those type things you, you may need to
encrypt it for legal reasons or for corporate reasons, and as far as I know,
all of the encryption algorithms in dot net are not available on the phone and
I know that I had saw in the discussion list a while back when SQLCE was first
coming out with Mango that SQLCE on the desktop, you can change the encryption
algorithm by setting something in the connection string. You can't do that on
the phone. It's not available.
There's the built-in encryption, whatever that is, and that's all you got.
Like you can't change it. I don't know what the specifically algorithm is that
they use, but you only have one. That's all you have right now.
>>:
Is this [inaudible].
>> Jason Short: The question is does the phone support HTTPS. Absolutely,
yes. Although it does not support NT land manager authentication which I found
kind of puzzling. So if you need to authenticate to the domain, you can't.
There's no code way to do that. Yes?
>>: With SterlingDB, so you have a database schema update between version one
and version two. Does it just support adding new stuff, or can we just like
really go to town or you really shouldn't do that. How do you know that you're
operating your version just in case you had a major schema change.
>> Jason Short: The question was about SterlingDB and schema changes across
application versions, like maybe major versions. The way I do it is I
literally name my object application config V1, and basically, I treat that
like it's chiselled in concrete. There's no changes to that file. If I change
that file, it's got to be called application config V2.
But I will always build an assignment operator to let me assign a V1 object to
the V2 object and then I'll take care of, you know, hey, this property moved to
here, we changed its name or we added these new things. When I go to load the
object, I actually store in my app config what the last run version of the app
was. And I compare that against the current version of the app.
38
And I'm running a different version than what ran last time we ran, I may need
to do some upgrade logic or I may need to upgrade things.
>>: You upgrade the whole database or just on the fly you read from old storer
into new storer and then save?
>> Jason Short: I actually have an upgrade class that I built that I actually
just put a K statement in there that says what was the last version or what,
you know, whatever the last version was that they said and what's my logic to
get to the next -- the current, major version. And I just put it all in there.
And, of course, that's in a separate assembly.
>>:
What if someone has like one and then three?
>> Jason Short: Then basically I add the logic to say load from one to two and
then go from two to three, yeah, because I always make sure that I'm only going
N and N minus one in my assignments. I don't want to have to assign version
one to version five objects that just, you know, it's bad compat problems. But
you can keep those old, you know, back compat, you know, the V1 versions of
those objects, you can move them out to a separate assembly. If you never use
them, they never get loaded.
>>: So even additive changes, you would add a new version, like if you add
three columns and you have four column, you would ->> Jason Short: I treat them like they're concrete.
They're fixed. Yes?
You can't change them.
>>: Would you like to see the functionality of AGFX and SterlingDB built into
a platform or do you think they should remain, functionally remain separate?
>> Jason Short: That's an excellent question. The question is do I think AGFX
and SterlingDB should be built into the platform. Yes, I do think that we need
an object store. Some sort of no SQL type storage that provides caching built
into the platform. Of course, I would also like to see an isolated storage
object that lets me write to my sky drive without having to actually go all
this off stuff either.
But I think that that is a -- it's a more difficult problem when we're trying
to solve a general purpose for every developer who might possibly use a
39
platform rather than saying you have to go make these specific code changes to
support us. Now you've already got it into the mindset. You're willing to
spend that commitment. To say any object in your Silverlight could be stored
and cached, I think that's a little harder. But I think it's doable. I think
you could definitely say here's the pattern. Here's the way you extend it.
And here's the best practices and now it's a DLL that's built into the system.
I totally think that we could do that. I would like it.
I think that's it.
Thank you very much.
Download