Rebuilding DoubleClick with AngularJS (NYC meetup)


Welcome. This is our fourth meet-up for
New York City for AngularJS. If you don’t know, AngularJS is
an open source JavaScript framework by Google. The motto is HTML enhanced. I think you’ll see that in
Mark’s presentation. We usually have Igor up here
from Mountain View, but he is presenting on Angular in San
Francisco right now, so he couldn’t be here. But that’s OK, because
we have an awesome presentation from Mark. And Carl is around somewhere. He’s going to answer
questions– AUDIENCE: [INAUDIBLE]
introduce yourself? ANDREW: Oh, I’m Andrew. I am a web developer at Google,
and we use AngularJS on my project. And I help organize
these meet-ups. Mark is the tech lead for
DoubleClick for Advertisers, and Carl is on his team. And he just rebuilt
DFA on AngularJS. Started 18 months ago. And he’s going to present
about that. We’ll have questions after. Anybody have any
questions now? AUDIENCE: [INAUDIBLE] MARK JACOBS: That and more
will be revealed. ANDREW: But DoubleClick for
Advertisers, right? MARK JACOBS: Yes. Yes. DoubleClick for Advertisers. ANDREW: So here’s Mark. MARK JACOBS: Hi, everyone. Can you all hear me just fine? All right. Yes, today’s talk is about
rebuilding DFA with AngularJS. First, let me tell you
a bit about myself. My name is Mark Jacobs. I am an engineer at Google. Been there about two and
a half years or so. I’m also the Tech Lead Manager,
that’s the TLM, for a product called DDMM
Trafficking FE. And I will explain what that
means, in case it wasn’t patently obvious from
the get-go. So what is this talk about? About 18 months ago– actually, go back a bit further. Back in 2008, Google acquired a
company called DoubleClick. DoubleClick was a large player
in display advertising. And when Google acquired
DoubleClick, they also acquired all of their products,
many of which, in Google language, are
quite legacy. And we’ll talk a little
bit about that. But back about 18 months ago,
my team was tasked with rewriting this platform and
bringing into the fold of Google technologies. And we chose to use AngularJS
for that rewrite. In this talk, I’ll talk
about who we are, what our product is. I’ll talk about how we made the
choice for Angular, what are the things we looked at. And also we’ll dig into what
were some of the architectural and design decisions we made
after choosing to use Angular. And finally, what we
thought worked and didn’t work about Angular. The first thing you ought to
know is that DFA is pretty big for an AngularJS application. In fact, we believe it’s
the largest AngularJS application out there. Who knows what somebody’s
doing in some basement somewhere, but we think
it’s the largest. It’s about 200,000
lines of code. And this number is inclusive
of views and tests. But even if you just take into
account non-tests, non-views, we’re nearly at 100,000
lines of code. So it’s quite large for an
AngularJS application. All right. What is this mysterious term,
DDMM Trafficking FE? The first thing you have to know
is that our product was recently re-branded. It used to be called DFA,
DoubleClick for Advertisers. So throughout this talk,
I may go back and forth between DFA and DDMM. Just know that they’re the same
thing, broadly speaking. One is a re-branding. DDMM stands for DoubleClick
Digital Marketing Manager, and is the re-branded new name for
what was recently called DoubleClick for Advertisers. What is this DDMM? It is Google’s buy side online
display advertising platform for large advertisers
and agencies. Let me break this down. In all advertising, there is a
publisher side and a buy side, a sell side and a buy side. The sell side represents
publishers. These are the websites that
have been advertising inventory to sell. Your New York Times, your blog
article, your ESPN, your IGN, whatever it is. On the flip side, you’ve got
advertisers who are figuring out how to optimize for some
outcome, whether it’s buying widgets or downloading brochures
or growing their brand recognition. And they’re using advertisements
on this publisher inventory to
serve their purpose. Our product, DoubleClick Digital
Marketing Manager, represents the advertiser
side of that equation. Google has a whole other set of
products that represent the publisher side of
that equation. Specifically, we’re dealing
with online display advertising. Advertising in the online
world comes in many different flavors. You’ve got video advertising,
you’ve got social advertising. That is, advertising that works
within LinkedIn and Facebook and Google+, and
that kind of thing. You’ve got rich media, which
is basically highly interactive ads that can be
embedded in movies and games and can fly out and do
all kinds of things. We’re specifically dealing
with display advertising. That’s like the classical
advertising you see when you went onto a webpage 10 years
ago, went to New York Times. There’d be a banner across
the top, there’d be an interstitial page that comes on
before you read an article. That’s basically the nut
of display advertising. And, unlike Google’s other side,
the AdWords, which deals with text ads and search ads,
our customers are not like mom and pops. If you’re a small business,
you’re probably not going to use our product. We’re really catering to the
world’s largest advertisers and their advertising
agencies. Think like, Nike, Apple, Mark
Jacobs the famous fashion designer, not me. And of course, their agencies. As I alluded to a little bit
earlier, when we began, the state of the world was, Google
acquired DoubleClick. There was a product at that
time, it’s still in fact out there, It’s what most of our
customers are using as of right today, called DFA6,
DoubleClick for Advertisers, version 6. Just to put this in context, it
is an ASP.NET application. It is written in C#, at least
the front-end portion of it. The middle tier is
Java-run JBoss. The whole thing runs
on Windows. It runs in a data center in
Colorado somewhere that’s very unlike any Google data
center out there. It’s data stored in Oracle. This is not Googly in any
way, shape, or form. We worked with that for quite
some time, and then about 18 months ago, we were tasked with
bringing the whole thing into the Google fold. Choosing new technologies to
rewrite this platform. And we did this for a number
of different reasons. I’ll talk a little bit
on the next slide. But ultimately, we knew going
forward that we wanted to build product faster. We also wanted to improve the
look and feel and user experience of these
applications. We also had a lot of desire to
have more integrations with other products inside
of Google. And that was very difficult to
do when you’re operating inside a silo data center at
the other end of the world, Colorado, and you’re trying to
work with Google APIs and stuff that work in a different
data center. So, there’s a whole host of
reasons why we were asked to do this challenge, to rewrite
the whole thing. At that time, the predominant
solution for rewriting a UI technology at Google, certainly
within ads, at least, was GWT. How many people are
familiar with GWT? OK. So this is a Google
Web Toolkit. It basically is a Java-like
simulation that targets JavaScript as a run-time
environment. So you can basically, in
Eclipse, write Java, or almost Java, and compile it. And what you get is a JavaScript
application that runs in a browser. This was really the default
solution for ads. And when we began 18 months
ago, it seemed obvious we’d use GWT. And then we looked at it and GWT
wasn’t a great fit for us, for a number of different
reasons. I’m not really going to
get into a technical comparison about GWT. I’m just going to look at some
of the other reasons. For example, on our team,
we none of us knew GWT. None of us were really Java
programmers, so to speak. We were more focused on
JavaScript, HTML, modern web development. There was also the reality that
with GWT, it was very difficult to go out into
the marketplace and find good GWT engineers. Just like in DFA6, when Google
acquired the legacy product, Google couldn’t go out and
get .NET engineers. The thing with GWT is that,
while you can find many Java programmers, you can find many
UI programmers, the few rarely collide into a single person. So as I was growing my team from
two people to, it’s about 14 and change nowadays, it
didn’t seem reasonable that I’d be able to scale quickly
building a team, expecting to find those rare gems
that are both Java experts and UI experts. And there’s a host of other
technical reasons. But ultimately, we
started looking at different solutions. We looked at things
like Backbone, JavaScript MVC Knockout. We thought about writing our
own JavaScript framework. We looked at a number of
different solutions. We knew we wanted to pick
something that was client side, something based on
JavaScript, ideally MVC. But that’s where it stood. About that time, we’re talking
about Q4, 2010, Misko, who’s the TL for AngularJS, gave a
tech talk in New York City talking about this
early idea for a product called AngularJS. And I caught this tech
talk and was really blown away by it. There was a lot of things that
I really liked about it. One, it was a declarative
solution. In order to define your app
using AngularJS, much of the high-level wiring actually
happens in the HTML. Unlike solutions like Knockout
or Backbone, where a lot of it is defined in JavaScript and
you’re trying to figure out how would the UI map to some
series of JavaScript classes, I think at Angular it was
really front and center. You could do things trivial,
like here’s a div and you would ng:click on it, now
we do a ClickHandler. But you could also have higher
level expressions. For example, you can define
this entire section is controlled by a controller,
which is a JavaScript class. And anything in that section
of code can call methods on that controller. One of the other things that was
quite different from other products at the time was
it had two-way binding. So data binding is
not unusual. In fact, if any of you have done
UI development in other platforms like .NET or whatever,
we get data binding. But I think what was interesting
in JavaScript at that time is much of it was
one-way data binding. You could go from a model into
the view, and then if you modified your input and you
wanted to update the model, you were pretty much on
your own to figure out how to do that. I think AngularJS was really
the first one that made two-way data binding out
of the box really easy. I just simply say, this input
box is bound to this particular property on a model,
and whether you update the model programmatically or
update the input by typing, the model will always be kept
in sync with the UI. So I thought that was
really great. Another thing is, it used plain
old JavaScript objects. Another framework, Knockout,
has a lot of nice qualities to it. Especially its dependency
tracking framework. But what you end up with is a
bunch of class overheads. Same thing with Backbone. You have to derive your
controller from this class. In Knockout, you have to sort of
wrap all your properties as dependency objects. I had done some Microsoft
work, too. Anybody familiar with
WPF for Silverlight? Same kind of idea. Knockout was very attractive. But ultimately, when you’re
trying to figure out how am I going to grow a team, how am I
going to teach a bunch of new people this technology, the idea
that you have just plain old JavaScript classes without
a lot of base classes and without a lot of artifice,
seemed to be a really good idea. As well, at that time a lot of
the team was very familiar with jQuery. And Angular– I’ll talk more about this
later, but Angular has embedded in it a jQuery
compatibility layer. And furthermore, if you actually
use the real jQuery, it can use that, too. And it’s pretty much the
documented way of interacting with the DOM, within widgets
and directives. And for us, that seemed
very comfortable. We knew how to use jQuery. And the fact that it worked
with that seemed to be a good payoff. And one of the other things
that just blew me away, probably more than anything,
was that Angular had a full testing story. This is very unusual for many
of the other frameworks. From the very get-go of Misko’s
talk way back when, he was showing, this is how
I run my unit test. This is how I do test-driven
development. This is how I do an integrated,
end-to-end test using Angular scenarios. This is how we do Dependency
Injection so we can mock out particular classes. These were not novel ideas, but
it was a novel integration of those ideas into a
JavaScript world. And I think more than anything
else, when you’re thinking about building a very large
application, like 200,000 lines of code, having something
out of the box that tells you, all right, this is
going to be OK, this is how you’re going to test it, this
is how you’re going to run your test suite, I
think that was a very compelling argument. And lastly, it’s a
straightforward architectural model. We can debate whether or not
it’s truly MVC, or whether a lot of the demos
are truly MVC. It could be more NVP,
or more and MVVM. But whatever it is, I think it
established some good patterns that other teams could follow. And that was sort of
compelling to us. So the next step was to
build a prototype. Way back when– this was
in January of 2011– we decided to take the front
page of our application, which I’ll show you in a little bit,
and convert it to Angular. What we did, we had some
preexisting web services, so we didn’t mess with those. We used those. We used our existing
mark-up, basically. We just annotated it with
Angular attributes. We also kept most of our CSS. And, as it says here, that
took us about two days to build this prototype. The real amazing thing about
this was, the prototype ended up being about a tenth of the
code size, about 10 times faster, than we had in
our ASP.NET version. Now obviously, we spent a lot
more time building that into a real application, and
our stats actually got a little better. But the key point is, we got
immediate positive feedback from the experience
using Angular. Yeah. AUDIENCE: When you measure that,
are you talking just about the code that you wrote,
or is it the code that [INAUDIBLE], as well? MARK JACOBS: We’re talking about
the code that we wrote in order to achieve
the same effect. So, in the ASP.NET side, we’re
taking all the C# code, plus the template code, plus any
JavaScript they were sending to the client, and comparing
that to in Angular, the code that actually retrieves the
data, that has the marked-up view, and whatever controller
we used to bind everything together. At the end of the day, it’s
the same net effect. It’s the same UI. But it just required less
code to get there. Yep. AUDIENCE: [INAUDIBLE] MARK JACOBS: Sorry? AUDIENCE: What kind of
[INAUDIBLE] is it? MARK JACOBS: I will demo
it in a few minutes. And I can show you that. I also should say that, at
the same time, we also– just because there was this
environment of GWT– we also did a GWT prototype. Or should I say, attempted
a GWT prototype. We worked on it for about
two and a half weeks. Something basically working. But at that point, we started
to see diminishing returns. We’d already successfully
deployed something in AngularJS. It was a couple hours perusing
the documentation, we had a working app. With GWT, we really felt like we
could have spent a month on this prototype. Now, granted, we’re
not GWT experts. I’m sure a GWT expert can come
in tomorrow and rewrite something much quicker
than we did. But that was the point. I’m bringing in new engineers,
I’m building out a team. I don’t want to have each of
them have a month or longer ramp-up time just to get
a basic page working. With AngularJS, we were able
to do that pretty much straight out of the way. So our initial strategy– again, I’ll demo the app
in a little bit. But it’s a large app. It has multiple sections. Each section has
multiple tabs. Each tab has multiple
dialogues. There’s lots of information
in it. And we were trying to figure out
a strategy where, maybe we weren’t putting all our
eggs in one basket. It wasn’t going to be a rewrite
from scratch and then we’d wake up 18 months later
and it would just be, we’d flip the switch. Our original strategy was
actually around updating the application page by page,
view by view. So we would take a section of
the app, and that might have multiple pages in it. And we would just make that page
in Angular and co-deploy these two applications. And essentially by using a
smart routing mechanism, depending on the URL, you’d
either go to Angular version or the old version. So we did this. We actually took an entire third
of our app, upgraded to Angular in place, and was
co-deploying this with the old ASP.NET, working against the
same web services, web services written in a
combination of C# and Java, and we deployed this
last September. Almost a year ago. And it worked. It was really cool. But in the end, we decided
not to continue pursuing that strategy. And we ended up pursuing a
strategy of rewriting the whole thing from scratch. But it was wonderful. We were able to reuse
practically everything we had done. Because our views were clean,
our controllers were the same, and because there was a layer of
abstraction around our back end APIs, which I’ll talk about
a little bit later, realistically, in about a month
we had kind of rewired all of our existing third
of the app over to the new tech stack. And then we just kind of went
greenfields for the rest the application. Why do we make this change? Ultimately it had nothing to
do with the technology. When we began this, we were
thinking about updating DFA6, which was just a
trafficking UI. But now we were really thinking about updating a platform. DoubleClick Digital Marketing
Manager is a platform that has many things in it. It’s got trafficking
as one component. Serving, reporting. And ultimately you can’t just
update one part of that platform and expect that to
be a business success. You have to update the entire
platform, have it all integrated, and provide
a better product for the customer. So in the end, we decided,
you know what? Let’s take a clean
approach to this. Let’s have it all be
consolidated, new code. And where we are is, we just
launched this about a month and a half, two months ago. And we are migrating
over customers. One thing that was really
interesting is that, when we began this effort to use
Angular, there was an incredible amount of FUD. Fear, uncertainty, and doubt. A lot of reasons for this. One was that I think at that
time, everyone was GWT, and you’re going, you’re not
GWT, you’re crazy. GWT is it, you’re crazy. I think the second reason is
that, even today AngularJS team is small. I think today it’s four
or five people, depending on how you count. Back then it was two. Still, the idea of having a big
ads application depend on a small team of two seemed
a little crazy. And I think some other reasons
just had to do with the idea that everyone is zigging,
and we’re zagging. And that freaked people out. So what did we do? We tried convincing them, and
then we just simply started lying about it. [LAUGHTER] MARK JACOBS: We went for about
six months and we never used the word Angular. We’re coding on Angular
every day, we’re having a great old time. We’re training new developers. And when people asked,
how’s it going? What are you using? We’re using a JavaScript
framework. A custom JavaScript framework. That’s not necessarily
the political strategy I would recommend. Except that at the end of that
six months, we released that first version, that sort of
side-by-side version. It worked perfectly. Nobody thought we could do it
that quickly, and we had trained a bunch of new people. And at that point, AngularJS
was no longer a dirty word. And the story gets
even better. Now flash forward 18 months
after we started, 12 months after it was a dirty word. We have multiple teams in Google
switching to Angular. From GWT to Angular. So across our entire platform
and beyond, AngularJS has kind of been latched in. So it’s really a good outcome. AUDIENCE: So you killed GWT. [LAUGHTER] MARK JACOBS: I’d love to take
credit for that but I [INAUDIBLE]. I’m going to be giving two
demos, a before and after picture, if you will. The first one is DFA6. It’s not sexy, it’s
not wonderful. I’m just showing it to you
to give you a sense of where we came from. And then I’ll do a longer
demo about the DFA7. Again, I don’t want to bore
you with the details of an advertising application. I just want to give you a sense
of some of the pieces of work that we did in
the application. Reusable widgets and
that kind of thing. All right. So we first look at DFA– Yeah? AUDIENCE: [INAUDIBLE] DFA6. Is that coming out of
DoubleClick [INAUDIBLE] supplied by Google [INAUDIBLE] MARK JACOBS: Yes. AUDIENCE: [INAUDIBLE] MARK JACOBS: Yes. In fact, at the time of
acquisition, the DoubleClick team was just finishing a full
rewrite from DFA5, which was yet a different technology. So the DFA6 team was allowed
to finish their upgrade. And now we’re doing
it all over again. AUDIENCE: It actually shows
that [INAUDIBLE] stack of Java, C#, and [INAUDIBLE]. MARK JACOBS: Yes. Yes. AUDIENCE: [INAUDIBLE]. MARK JACOBS: Yeah. Yeah. All right. This will be DFA6. I’ll just guide you through
this a little bit. Again, this application, its
user-base is traffickers. These traffickers are people
at these agencies or advertisers. And their sole job is to receive
instructions from people called media planners,
who are figuring out, where should I put my advertising
spend, how will I get the most people clicking on my ads,
buying my cameras. They receive these instructions from the media planners. And their goal is to upload all
the artwork they receive from the creative agency, and
create all these objects that sort of define how this
campaign will play out on the internet. In this app, this trafficking
front-end, is really all about those actions. Creating the campaigns. Creating the ads. Creating the placements. Creating the creatives. These are our objects
that we deal with. And in essence, this trafficking
application, certainly in the older version,
is nothing more than forms over data. I’ll go to, for example, this
is a list of campaigns. And I will click on a
particular campaign. And inside that campaign,
I have lists of ads, lists of creatives. Every one of these things
has a properties page. So, for example, the media
plan refers to a list of placements. In fact, that’s what we call
it in the new thing. And a placement is nothing more
than a piece of inventory on the publisher’s site. I can click on that. It has this really
horrible thing. But one thing you might notice
is DFA6 is quite slow. We’ll see in DFA7 how we’ve
actually been able to improve that quite a bit. We’ve got forms. And the one thing I’ll point out
before moving to DFA7, is that the page you’re looking at
right now, right here, is the campaign’s list page. This is our application
landing page. This was the page we did
for our prototype. And again, we took the exact
same markup, exact same CSS, adorned it with Angular, wired
it to the same web services. And this is where we began. Now let’s go to DFA 7. There we are. OK. Much is the same, yet
much is different. For at least in the older part
of, even the DFA7, we’re still forms over data. But we have a lot of cool
little features we add. First when you look and
see, if I scroll– I apologize. The GVC is a little
slow here– you’ll see that the header of
the table sticks to the top. This was actually a feature of
our custom grid control, which I’ll demo a few more features
a little bit later. It’s pretty wild and woolly. And we go into a campaign. Another thing you’ll notice,
there’s that little loading at the top. We wrote directives for
dealing with ephemeral messages and sticky messages. And that’s a service. How many people actually
program in Angular? OK. A good many of you. I’m not assuming in this talk
much in the way of Angular knowledge, but for those
out there, I’ll throw out a couple words. We have that little butter bar
message represented as a combination of a servicing
widget. Tabs again, are reusable. Widget directive. Let me go in and show you
some other cool stuff. Probably the coolest thing
is a new feature that was just launched. Let me go to a better
campaign. One second. As I mentioned, the workflow
historically was, all right, I go to this list, create
an object. Then I go to that object, go
to its related list for something else and create
another object. This is not great
for workflow. One of the things we’ve done in
DFA 7 is we introduced this new thing– Sorry. One second– This new thing called
Campaign Explorer. And if I can find a campaign
with data in it, this will be an awesome– There we go. OK. The key idea here was that,
since we don’t know all the different ways that people work,
let’s give them a UI that lets them reassemble
the UI around their particular needs. As I said, we have this
hierarchy of objects, sites, placements, ads and creatives. One of the things that this new
feature does, it allows us to hide and remove dimensions. So I could say, I just want to
see which creatives are on which sites. I can hide the dimensions
and then show them. Another thing is, I can add
and remove columns. Not a big deal, but one of the
things we did in our custom omnigrid control is, we
added the ability– I don’t know if you
can see this– to create slidable panels. Again, this is all done
pure Angular. I’m scrolling here and you can
see there’s a little shadow showing that there’s stuff,
columns, not being hidden. And this all just updates
[INAUDIBLE], and so forth. One of the other major pieces,
if I go to, for example, a particular ad. These little widgets are
actually embedded jQuery date/time controls, which we
hope to get rid of very soon. But another thing that’s pretty
cool is we wrote– that grid control we
call an omnigrid. And we also have support for
something called an omnilist. Let’s see if I can
find a better example of this in action. Let’s go to campaigns. Let’s say I want to filter
this list of campaigns by advertiser. This omnilist control– again,
pure Angular, no other jQuery or anything like that– lets me do things like
search for– Here we go. Auto. I can filter that down. I’ve got keyboard support. This supports single select,
multiselect. There’s a bunch of other
controls in here, as well. For example, we have this
carousel control, which is very cool. For example, let’s say I’m
filtering by Auto. This particular advertiser– oops. Maybe I’ll find one with
an advertiser in it. One minute. Give me one more chance. Trying to find an advertiser
with more than one– AUDIENCE: Maybe you should
just filter by status. MARK JACOBS: Oh. Excellent idea. [LAUGHTER] MARK JACOBS: So let’s do– Wow. Getting no love. How about this? How about this? There we go. OK. What I wanted to demonstrate
is, I’ve got a filter applied to a list. And I can go into this
particular campaign. Now I have a carousel up here
that I can go through different campaigns. It’s referring to the
previous list. We’re doing this in Angular by
encapsulating carousel state in a combination of the location
bar and service. And then this carousel is a
widget that interacts with that service. That’s all I’m going to demo
of the application. Just to give you a sense
of what it is. Let’s talk a little bit about
the architecture of this application. The application really
has two teams. We’ve got a back-end team
and a front-end team. The back end was also rewritten
from scratch. It used to be Java on JBoss
against an Oracle back end. Now it’s Java on Linux. And it is using a proprietary
Google data store. The key point is– it’s really
kind of outside the scope of this conversation, but– it’s a fresh, fast, new back
end, and it works great. But this back end is using
an RPC method that’s not exposable on the internet. It only works inside
of Google. So one of the first design
questions we had is, how are we going to expose this data
to a JavaScript client application? What we did architecturally
is introduce a REST API. RESTful JSON Web Services API. We wrote this in Java. Again, it’s deployed in Linux
and Google’s fancy cloud infrastructure. It uses something called
Jersey, which is just a reference implementation for
building easy REST APIs using Java annotations. And it lets us do things like
POST/ campaigns would create a new campaign, GET/ campaigns
gets a list of campaigns, and so forth. The key point is, this REST API
sits above the back end. It’s part of the front end. And it gives us a bunch
of different things. It gives us authentication,
allows us to aggregate data, transform data. For example, we have
more than– our main back end is
trafficking, but we also pull in data from reporting,
from other integrations within Google. And the REST API is essentially
that integration layer for that type of work. Above that, we have our UI. And there were a number of
different design issues that we had to think through as we
were building out this UI. One of the first things that
we had to grapple with was single-page architecture. This was something very foreign
to the ASP.NET world. We’re dealing with an
application where there really is an index.html, and everything
else is happening on the client. And this affected our
architecture in two ways. One is, how do you deal with
common view content? So in .NET, we had this notion
of master pages, nested master pages. So that if you look at our
app, we have this header, which is true for the
entire application. I’m sorry. GVC’s a little slow. Keep going. Keep going. OK. We’ve got this section up
here, which is sort of a common header across the
entire application. We’ve got this second section
here, which is a common header within a section. And then we’ve got the tabs. Then within each section we’ve
got an action bar that’s repeatable. The question was, in the
single-page architecture, if we don’t have nested master
pages, how do we figure out how to get usability
across the app? And the second area of concern
was bookmarkability. In DFA 6, you could not really
bookmark a page. In fact, it was even
worse than that. You couldn’t even open two tabs
to the same data without screwing it up. So in DFA 7, we were very much
concerned with, how do we make it deep-linkable? And how do we surface states
of the application? And trying to figure out which
states should be bookmarkable. We’ve had lots of debates with
UX and in [INAUDIBLE] engineering. For example, if I’ve got a page
that opens up a dialogue, should that state of the
application be bookmarked? If I send you that bookmark,
should the dialogue appear? Ultimately, we decided
absolutely not. Should not. Similarly, there are states of
the application, for example, if I apply a filter, and
then I go to Edit, those things in batch– that’s a feature we have
in Campaign Explorer– when I bookmark that and I send
it to you, the same items should be in the result
but I should not be in that edit mode. Anything that’s a mode or a
dialogue is not bookmarkable. But things like the set of
things you’re working on are. So this is some of the things
we had to work through. Again, for common view content,
ultimately, in Angular, you’re allowed to fit
some stuff in the index.HTML. That’s common through. But the rest of the way, we
ended up using directives as a means for our usability. And trying to figure out the
right mix of directives, and how to make sure that they
adapt to the surrounding content, was something that we
talked about for awhile. So jQuery. When we’re started we were very
excited about jQuery and it’s still something we use
throughout our directives. But as time has gone on, we try
to figure out how much of jQuery do we really want to use,
and what are its limits? We’ve used jQuery UI components
for a while. And we still have a couple
in there, like the date/time widget. And I think we also have
dialogue widget. But ultimately, we ended up
using less and less of the broad jQuery, and more and more
of those things that are actually in the compatibility
layer. As well, I’ll talk about a
little bit later, we use a range of different libraries. And so many of the things that
we may have used to use for jQuery in the past, we don’t
seem to use anymore. I can imagine a future where
we’ve eliminated all jQuery UI dependencies, and also
potentially a glimmer of eliminating a dependency
on jQuery proper. But that still remains
a hope and a goal. Not really something
we’ve achieved yet. In our UI, we also mixed in
a bunch of other things. For example, we use something
called Underscore.js. How many people have
used Underscore? It’s a really wonderful library
that brings in a lot of functional programming
and utility functions. We’ve found it to be hugely
useful for us. It’s probably the number one
third-party JavaScript. What’s nice is it just
works perfectly fine with everything else. One of the things we had to
figure out is, another thing we use is Closure. And Closure, Underscore,
jQuery, Angular, have significant overlapping
in functionality. Like all of them implement
the equivalent of, Is String, Is Number. And so, one of the things we had
to figure out is, because we didn’t want a code base where
one developer uses the jQuery version, another one uses
the Underscore version, another one uses the
Closure version. So we debated this, and we
ultimately settled on using Closure for all of those
core utility functions. And why? Well, because we ultimately
have to use a bit of Closure anyway. Because, I’ll talk about our
build a little bit, we rely on the Closure Compiler, we rely on
it for package independency map management. We do goog.require and
goog.provide throughout our application so that we
know which things require which things. And the Closure Compiler,
actually when it does static analysis of your JavaScript, it
leverages the fact when you use the Goog version. So if you do Goog Is Number, the
Closure Compiler actually says, oh, that means, in the If
block after this thing, I can assume it’s a number. Whereas if you use Underscore
Is Number, or like that, or Angular Is Number, it has
no additional knowledge. It can do whatever its static
wants to do, but it doesn’t benefit from that extra
hint it gets from the Goog versions. So while we don’t use Closure
at all for UI widgets or anything like that, we do use
Closure sprinkled throughout for certain data structures and
core utility functions. Another thing we introduced
recently that we really like is LESS, the CSS compiler. Google has its own
CSS compiler. We don’t use it. [LAUGHTER] MARK JACOBS: LESS made
a lot more sense. A, it’s very similar to CSS. A valid CSS file is also
a valid LESS file. Although the reverse
is not true. The other thing is, I
think again, we’re trying to grow our team. A lot of people out in the
industry were already familiar with LESS. The benefits were huge. I’m getting into a very
large application. And one of the things you’d
struggle with is, how do I make the Properties page in one
part of the app look like the Properties page in the
other part of the app? How is it that when a UX guy
says, oh, I’ve got the most fabulous new blue we should
change to, how do we make sure that blue actually gets rolled
out across the entire app correctly, not just on some
pages or some controls? So the LESS CSS compiler allows
us to define functions and constants and other things
like that that help us get all those things applied correctly
throughout the entire application. As well, something we’ve started
to do recently is, we’ve worked harder and harder
at making reusable libraries for Angular controls and
directives and services that can be picked up and used by
Angular teams at Google. And the LESS CSS compiler gave
us some ability to essentially compile just the set of CSS
that needs to go with that package, versus having to pick
apart an entire CSS file and figure out which needs to
go with which package. The last thing I’ll call out is
we use HTML5 Boilerplate. This basically defines what
our index.HTML looks like. It gives us certain flags for
feature detection, for IE, and things like that. And that’s about it. Build, compilation,
and minification. We used Closure Compiler
as our compiler. Our build system is based on a
Google internal build system. If you’ve used Drake or Make or
anything like that, it’s a little different, but still it
serves the same end goals. I think that some of the
interesting things we do here in our build is really
around localization. I’ll come back to this point
when I talk about localization. The other key decision we
had is, what server-side templating and server-side
rendering do we do, if any? For approximately the first 17
months or so of the project, we said none. Absolutely none. We launched [? our other ?]
application, and we served all files statically. So essentially, index.HTML
was a static file. All the JavaScript,
all the CSS. Everything was a static file. The thinking behind
this was, that maximizes our use of caching. Essentially, with all static
files, if we could properly encode the URLs with immutable
URLs, we could basically put this all on Google’s
edge servers. And no matter where you were,
if you had loaded that application once, and we hadn’t
updated the version, you wouldn’t have to download
any of the files at all. So that was basically
the idea. In practice, we never got the
full payoff of that, for a couple reasons. One is, solving the problem of
versioned immutable URLs without any kind of server-side
help, is actually pretty challenging. The second thing is, we realized
that there were things that we wanted to do on
the server side ultimately that forced our hand. So as of today, we actually
render our index.HTML on the server. We use Soy, which is the server-side templating language. Publicly it’s known as
closure templates. What we do in there is, A, we
used to, when it came to authentication, we’d serve
up index.HTML to authenticated users. And the very first time the page
booted up, we would ask for, hey, who’s logged
in to the REST API? And if that returned
Forbidden– 403 Forbidden– then we would go and redirect
the user to log in with their [INAUDIBLE] credentials. Their Google credentials. What we do now, though, is
that, in index.soy, we actually authenticate the user
before we return anything. As well, we, at that time,
determine all of the permissions and features that
they have available to them. So one of the other reasons
that forced our hand on server-side templating is, we
wanted the ability to show or hide features. For example, let’s say the
product managers say, we’re releasing this awesome Campaign
Explorer feature, and we want to do it exactly
on October 1. But our production release isn’t
on October 1, it’s on September 26. And we want to figure out, how
do we make this feature apply without redeploying? One of the ways we can do that
is through feature flags. As well, we can say, OK, I want
this feature to be live in Dev and QA, but
not in Product. The way we ended up implementing
this is, on the server, when we render
index.soy, we look up all the different features that are
enabled for you, and we encode them all into the
HTML response. It’s just like a little
payload in there. Then, we can conditionally also
load bundles, so we can conditionally include script
tags and load bundles. So that when you finally get the
application, we can strip out a whole portion
of code that’s not enabled for you live. There’s no view source
hack on that. It’s just not there. That’s why we ultimately did server-side rendering index.soy. We don’t expect it to go much
beyond that, though. Third-party controls. Like I said, we have
a few in there. We used to have a few more. But they’re gradually
dwindling away. The few that we are forced to
use are some internal ones based on Closure. For example, there’s a Google
Feedback feature. It’s really cool. You can say, Send Feedback. You get a little dialogue that
comes up and says, hey, let me help you take a screenshot of
this page and blank out anything that’s sensitive data,
and we’ll send it in to our support staff. So that Google Feedback widget
comes internally. It’s a Closure widget which
we’ve wrapped as Angular. We also use a small number of
things like the date/time widget, and so forth. But our goal ultimately is to
do more and more of these as fresh, clean, Angular widgets. That’s why we’ve invested a lot
in our grid control, our custom list control. We’re going to be doing a
date/time widget soon, because the existing ones just don’t
serve our needs. Yep? AUDIENCE: Can you tell
me what kind of browsers are you targeting? Is there a specific version
that you’re just considering invalid? MARK JACOBS: Google Consumer
Apps has a public policy of browser support that says, the
two most recent released versions of any browser. Not any. Not Konqueror, for example. But Safari, Internet Explorer,
Firefox, and Chrome. We follow that almost
to the letter. We do support IE8, and when IE10
comes out, we’re going to have a tussle with product
management to hopefully get rid of IE8. But that’s not set in stone. But meanwhile, everything else,
we’re basically keeping the two most recent versions. The only one we really fight
with nowadays is IE8. AUDIENCE: What about
Angular itself? [INAUDIBLE]. MARK JACOBS: I can’t
speak for Angular. Basically, like I said, we’re
their biggest customer. And if we’re supporting IE8, I’m
just going to keep IMing with Igor all day long until
it works with IE8. [LAUGHTER] MARK JACOBS: Like I said,
we’ve implemented a lot of our controls. How many people in the room
have international applications? Like, they’re translated into
different languages? OK. So you know,
internationalization falls into two categories. It’s translation, and
localization. Translation is actually pretty straightforward for us at Google. We do two things. One is, Closure gives us the
ability to mark up in JavaScript any messages. There’s a goog.message, and we
can say, all right, this is something that needs
to be extracted. Furthermore, we’ve created
our own little syntax that’s used in HTML. Oop. All right, I’m going to finish
this talk quick. [LAUGHTER] MARK JACOBS: Yeah. Except I’ve got a new MacBook
Air that doesn’t have the right power port. Let’s see if I can– this [INAUDIBLE] custom syntax is based
off of Wiki Syntax. So it’s this bracket,
bracket, vertical bar, bracket, bracket. The first part here is the
message to be translated. The second part is the
description that’s sent to the translator. Is that a new one? Awesome. You’re a rock star. Can you find a plug? Thank you. Both of these JavaScript
messages and these custom messages are extracted
during our build. The first part, the
goog.messages, is extracted by the Closure Compiler. This part is extracted
by a custom Python script that we wrote. During our build, all these
messages get pulled out, they get formatted into a database
file, and they get sent to our internal translation database. Then, when we complete the
build, we pull down the database of translated
messages. And for each language, we create
a clone of all our static files, all of our
JavaScript and views, and put them in localed sub-directories. So if you actually were to go
onto our web server and look at our static files, there’s
going to be an ENUS subdirectory, an ES
subdirectory, a DE subdirectory, and so forth. And then, through some magic
of our REST API, as soon as you log in, we set a cookie
that says, oh, yeah, this person is interested in
the Spanish version. And so then when they come in,
that cookie is used to detect your locale. Then we set that locale and then
our static file servelet that serves up these files, just
simply redirects to the subdirectory and serves all
the files out of there. What we do for development
time– this is actually kind
of a cool insight– is this mark up here,
this Wiki– thank you very much. If we didn’t do anything, when
you’re in development mode, not looking at the compile
version but the one you’re actually– you would normally see all
this additional bracket, bracket and translate
messages. So we wrote an Angular
interpolation service that actually fixes this up. An interpolation service in
Angular is what implements the binding syntax. Like the [? SQLy ?] brackets. It knows at that particular
time how to read that, translate that, into
something else. So that when you view the page
in development mode, you’re not seeing the binding syntax. You’re actually seeing
what it evaluated to. We used the same idea. We extended the interpolation
service, so that whenever it sees this translation syntax, it
just strips it all off and just keeps the message. It works both in production
where it gets translated to real messages, and development,
where it just strips off the extra syntax. For localization– by this I mean formatting dates,
times and numbers– it’s a little bit
more difficult. In fact, it’s a lot more
difficult in a JavaScript application. The main reason is, most browser
applications can deal well with the invariant locale,
and they can deal with the current locale. Whatever the operating
system is set at. Dealing with other locales
is where it gets a little challenging. Because there’s not a lot of
libraries that just shipped out all the world’s locale
information to every browser app. Doing this on the server it
would be much easier. In fact, we do a lot of– there’s a use case for our
application where you’ve got the poor trafficker sitting
in New York. His client is in London,
but the campaign is running in Germany. All of which have different
time zones. So when the guy in New York– normally he’s looking at things
in Eastern time, but the guy in London says, no, I
want this to start at 1:00 AM my time, and I want you to
verify that that’s at the lunchtime in Germany. And so, they need to switch
between all those time zones. That we tried to do
in the client. It just got too hard. Now we actually ask the REST
API, hey, when I ask you for data, here’s an explicit time
zone, and you send it back to me in a ISO 8601 date that has
that time zone offset. For number formatting, again,
AngularJS recently released a bunch of localization tools that
help with this somewhat. We haven’t switched
to them yet. We currently rely on Closure. But Closure is a little
problematic because, again, those things are determined
statically. So when we create a copy, a
sub-folder for Spain and the US, the locale version
of format.number is predefined at that time. So we get into weird situations
where, in the UI, in some states where it’s
formatted by Closure it’s done correctly, but then if you click
on it and put it into editing mode, the underlying
browser formats it incorrectly. So we’ve got a little bit more
work to do in getting this exactly right. And the last, I think, major
design issue was how to achieve caching. With an app like ours, you can
actually do caching on a lot of different levels. So we do it at the server. So every time our REST API
calls the back end, if it knows that you have data that’s
slowly changing, it will store it in memory
and just cache it. The next level up
is HTTP caching. Every time the REST API sends
data, it does two things. One, it sets last
modified header. As well, it sets an e-tag. It essentially hashes all
the JSON data and sends it out there. So the next time the browser
says hey, I want this particular piece of data, the
REST API will rehash the response from the back end,
the term doesn’t match. And if it does match,
it’ll just go and set a Not Modified. Yeah. AUDIENCE: Why would you
send a [INAUDIBLE]? MARK JACOBS: I think we do
it based on resource. I think most of the time
we used the e-tag. I think there just may be a
last few stranglers, for example, where it just
wasn’t convenient to calculate the e-tag. AUDIENCE: [INAUDIBLE] MARK JACOBS: No, no, no. It’s mostly e-tag
for the data. I just believe that there are a
few stragglers where they’re still using Last Modified. Of course, there’s browser-level
caching, which is related to what we
were talking about. One of the other things we
talked about is edge caching. To the extent possible, we
always set caching expiry, it can be based on anywhere
from zero to 24 hours. In Dev, we set it all
to zero hours. In production we try to set it
to four hours, I think, most of the time. And we can do better at that
if we have these immutable version URLs, for which
we would need service-side support. So we’re working on that, too. The HTTP service in Angular also
has support for caching. And finally, at the application
level, too, we hold on to some data. So there’s a lot of different
levels where we can do caching and get the right kind of
refresh rates that we need. OK. Just very quickly, a little
bit about how my team gets stuff done. We have 14 software engineers. A few of them are trickled
through here as spies. [LAUGHTER] MARK JACOBS: We have four test
engineers, a mixture of software engineers in tests,
and actual test engineers. We have four UX folks, two
researchers, two designers. A documentation writer. And of course, there’s a whole
bunch of people that we rely on, as well. Product managers, localization
project managers, service support, and lots of great
folks, including the Angular team, who we are in constant
contact with, and help us a lot. Yeah? AUDIENCE: How does that 14
break out [INAUDIBLE]? MARK JACOBS: This is
all front end. We have three folks that are
dedicated to the REST API, which again, is part
of the front end. And then all the rest are UI
and JavaScript engineers. The back end itself has,
oh, I think, 10 people. So, our division of labor is– yes? AUDIENCE: I had a question
[INAUDIBLE] Recently I lost a [INAUDIBLE] MARK JACOBS: I’ll talk about
it in a couple of minutes. The short answer is, we’re
in transition. We currently rely on
JsTestDriver, and we have a working version on Testacular,
but, for various reasons, it doesn’t yet fully integrate
into our continuous integration server, and stuff. But Voita, who’s also on the
AngularJS team, is working feverishly to help us
get on Testacular. AUDIENCE: OK, so I have
another question. MARK JACOBS: Sure. AUDIENCE: [INAUDIBLE] MARK JACOBS: No. But we do run them as
separate test runs. So we run our unit tests, and
then separately, we run our integration tests. I’ll talk a little
about that, too. One of the things that’s
troubled me and a lot of the team, is development
environment. Across our team of 14 folks, we
still don’t have a standard development environment. Some of us use Eclipse, some of
us use WebStorm, some of us use IntelliJ, some of
us use [INAUDIBLE]. I use [INAUDIBLE]. Some of us use Sublime
Text, some of us use Terminal Window. I think, while all of us
individually are fine with that, I think a recurring piece
of feedback that I’ve heard from people joining the
team is, I’m trying to learn so much stuff. Why can’t you just tell me what
environment I should use and let that work, and then
let me customize my workflow later on? And I think that the real reason
we haven’t done that is because we haven’t found
one that seems to work really well. So I think there’s an area of
investment that Google is working on. But also some of the
other teams. Automated testing. This comes to your point. We use the standard AngularJS
test suite, for the most part. We use Jasmine against
TestDriver. We have 99% plus unit
test coverage. The one area where I think
AngularJS kind of failed us a little bit– and I’ll talk
about this later on– is Angular Scenarios was their
solution for end-to-end integration testing. It just never worked with us. We tried. It was an area where we
felt like it was not well-documented. It required a high level
of understanding. It is possible to
write AngularJS scenario tests that worked. But to do so, I think, requires
more thought and skill than on average. So right now, all of our
integration tests are written in Java on WebDriver. We have a few remaining on
AngularJS and we’re trying to get rid of them. I just found out there’s
actually a JavaScript adapter for WebDriver, so we might
actually use that instead. Sorry. Question? AUDIENCE: What is [INAUDIBLE]? MARK JACOBS: When we run
our test suite, we generate code coverage. And that code coverage gives
us a report that says, all this source code was executed
at line-by-line level. So with our internal tools, we
can load up any JavaScript file and it’ll paint all the
lines green that actually were executed by a test, and any
line that was not executed will be painted red. And they aggregate those
up into reports. Line by line. AUDIENCE: [INAUDIBLE] branch. Do they color those
green, or red? MARK JACOBS: It’ll count the one
branch that went down as green, and then the
other branch, red. AUDIENCE: [INAUDIBLE] MARK JACOBS: Yeah. It’s not a perfect
measure, but– AUDIENCE: [INAUDIBLE] MARK JACOBS: Closure
Compiler itself generates the code data. But the visualization of it is
an internal Google tool. But there’s a lot of CI tools
that, given the code coverage date and the correct form, will
display it correctly. AUDIENCE: [INAUDIBLE] MARK JACOBS: I do. I can’t share it with you. [LAUGHTER] MARK JACOBS: Question
in the back? AUDIENCE: [INAUDIBLE] MARK JACOBS: We have a very
large set of test doubles. We have fake objects, we
have spies that help. We also have mock objects
to return some of these test fakes. We use Angular’s Dependency
Injection to help inject alternate versions
of services. So our unit tests are,
in fact, unit tests. We try to insulate them
as much as possible. AUDIENCE: [INAUDIBLE] MARK JACOBS: Yeah. Mainly because we’re working on
a document fragment that we create in the Jasmine test, and
then validating that the fragment gets mutated
in the correct way. Coming down the home
stretch here. Thanks for staying awake. Quickly, looking back at our
experience, what were some of the pros and cons and other
realities of Angular? I think one of the key
advantages, even after using this for a year and a half, is
that, the fact that it sticks to standard web technologies
has really been a payoff for us. One is, any time somebody comes
up with a new technique in CSS or JavaScript, we
can readily advance. There is no major integration
work. When we go out to the
marketplace to find people, there’s a lot of people
already aware of these technologies. I think that’s all very key. As well, as browsers improve,
our implementation improves, as well. I think the other advantage that
has paid dividends many times over is, testing is just
deeply ingrained in the Angular way. I think, you spend any time
talking with Igor or Misko from the Angular team, and
they’re always talking about how they run tests. I think one of the
big payoffs– fortunately, many of you have
not had to go through this. But because we adopted Angular
back at version 0.7. We’ve had many painful upgrades
along the way. 0.7 to 0.8 hurt. 0.8 to 0.9 was absolutely
brutal. Going to 1.0 was bad. But– [LAUGHTER] MARK JACOBS: –the thing that
actually worked really well for us is that we had a really
strong test suite. And without that test suite, it
would have been impossible to do these upgrades. What actually happened is, a
couple folks from the Angular team came down with us to
help do this upgrade. And we had, I don’t
know, 3,000 tests. And we did the upgrade
and 2,999 failed. [LAUGHTER] MARK JACOBS: And over the course
of, I guess it was about a week and a half, it’s
just making the test pass, making the test pass. And ultimately, we got all
the tests to pass. That’s just a testament to the
value of testing in general. I think just because so much
of the Angular zen, the Angular approach, is, how do
I test my controllers and services and directives? And having a story for all that
made sure that, even as we did these painful upgrades,
we were able to assert our quality. Velocity of development,
totally awesome. We can write stuff
really quickly. Much quicker than
any of the other technologies we looked at. We have had developers write
entire pages in a few hours, and it’s really quite nice. Huge boon for the team. Really passionate and attentive
AngularJS team. They’ve been very
helpful to us. But they’re also helpful to
the entire community. That’s the last part. It used to be, I could keep up
with all the Angular lists. Now I can’t. I blink and there’s 500
unread threads. There’s a tremendous
amount of activity. And not only is people like Igor
or Misko very active in that community, but there’s
a lot of people outside of Google who have no relationship
to the project, who are very insightful
in responding and building that community. So looking back, I’m really
sold on AngularJS. Just almost purely for its
community as well as its technology. A few disadvantages. Angular Scenarios. Don’t like it. I wish I did. I would love to write my
end-to-end integration tests in JavaScript. But Scenarios itself, I think,
just has too high a conceptual count, it’s too poorly
documented, and it just doesn’t work the way
we want it to. Unit testing technologies. I hear it’s in flux. This is the whole JsTestDriver
moving to Testacular and there’s some attempts
to use PhantomJS and other things like that. Whatever Angular ends up with,
I’m sure it’s fine. But if you’re starting something
today, the story’s a little muddy. You’re supposed to use
Testacular, but, like a lot of other projects you’ll see in
the wild, are still using JsTestDriver. I think this is just a phase
it’ll hopefully get out of. And then finally, one
disadvantage is, I find that AngularJS documentation still,
even though it’s markedly improved over where it used to
be, it’s still quite buggy and missing a lot of conceptual
content. I think the API level reference
is not bad, but you don’t really get that advice
that you get from somebody who’s worked with Angular
for a year. There’s none of that stuff in
the documentation that really says, this is the Angular way,
these are the key ideas, this is the philosophy. I think that’s still to come. Maybe one of you guys will
write a book someday. That’d be great. And finally, just
a few realities. Angular used to be
much simpler. Back when we started,
I think the scope of Angular was much smaller. It tried to do fewer things. As we flash forward to the
current day, Angular is much more flexible, much
more powerful. And if you ask Igor– I’m sorry. It’s much more flexible
and more powerful. But it’s also become
a lot more complex. And if you ask Igor,
it’s our fault. [LAUGHTER] MARK JACOBS: DFA made
it this way. Because we essentially kept
saying, why can’t I do this? Why can’t I do that? And we’ve grown it. I don’t know if I totally
agree it’s our fault. This next line kind of puts
a fine point on it. Dependency Injection is
an awesome thing. But if you’re a typical
JavaScript developer, you may not have had a lot of
exposure to it. If you came from Java or .NET,
and you’ve used Spring or Juice or Inject, or one of these
other things, Dependency Injection will make complete
sense to you. But if you’re just trying
to get a standard, run-of-the-mill JavaScript
developer to write an AngularJS application, the first
thing that just hits you in the face is, what’s
a module? Why do I need these modules? It’s presented in the
documentation as just a bit of boilerplate that
you have to do. There’s actually no rhyme
or reason to it. In fact, the Angular module
system is cloned almost entirely off of Juice, which
is the Java version. You understand Juice, you
understand pretty much the Angular version, Dependency
Injection. But this is a level of
complexity that I think it raises the barrier of entry
to this application. And that didn’t exist in
the same way as before. Yep. AUDIENCE: [INAUDIBLE] MARK JACOBS: Which is
totally different. [LAUGHTER] MARK JACOBS: The AMD modules
world is really about how to take a large body of JavaScript
and create bundles out of it that can be
conditionally loaded, or asynchronously loaded. That’s not at all– In fact I was talking with one
of my developers on my team about this this morning. That’s not at all what Angular
modules are about. Angular modules are about classical Dependency Injection. Given a bunch of interfaces,
which copy classes should I plug into those interfaces? So an Angular module, in a
sense, its main function is just simply saying, which
concrete service that’s already loaded, will I plug into
a class that’s asking for that service? Like $HTTP. HDP. Which implementation of $HTTP
should I hand off to a class that’s [INAUDIBLE]. And it also deals with how to
fill in all those different [? structure ?] parameters. The other thing Angular modules
does, which is not really as much part of Juice,
is, it gives you a place to put a little bit of code when
the application bootstraps. But the main thing is all
about configuration. When I was talking about it with
my engineer this morning, he said, but the Angular doesn’t
actually conditionally load anything. I could have two HDP
implementations, but the Angular doesn’t help
me conditionally load one or the other. You’re right. It doesn’t do that. It’d just simply say, given that
both are loaded, or both their names are valid, which
one I can plug in? So that is a little confusing. But that goes to my point, which
is that this stuff has gotten a little bit
more complex. And that’s a risk. AUDIENCE: [INAUDIBLE] Angular integrate well with
normal [? conveyance ?] or [INAUDIBLE] models? MARK JACOBS: Sure. It’s just they’re completely
orthogonal to each other. AUDIENCE: [INAUDIBLE] MARK JACOBS: No. As a perfect example– this is a concrete example of
what we’re talking about. Let’s say that I had a
major feature like our Campaign Explorer. And in the future, I have
two versions of it. I’ve got a v.1 and a v.2 And
let’s say there were some services around that. I have a particular class that
wants a campaigns resource. Well, depending on the state of
how the application loaded, I either want the
v.1 or the v.2. So if both are compiled into
the application, then the Angular will deal with, oh,
which one do you want? But if you actually want to
conditionally load one of those two, you can define them
as AMD modules, and then have some other mechanism to say, I
want one loaded or the other, and just the Angular module has
to be in sync with that, and not try to reference the
one that wasn’t loaded. Angular does not attempt to
solve all key problems in large-scale web application
design. It’s not everything
to everyone. You still have to figure out
caching and performance and that kind of stuff. As well, there’s a real danger
in Angular to fall into the trap of monolithic
applications. For example, we have a very
large feature where we’ve got a controller with nearly
3,000 lines of code. That’s not a great outcome. I don’t care how sophisticated
your controller is. I think, unless you’re very
careful, you need to figure out how to prevent that
type of outcome. And AngularJS doesn’t really
give you that kind of pattern. They don’t know the answer
to these things. And trying to figure
out, how do we make an application scale? If I keeping adding features
on to this thing, how do I prevent a 5,000 line
controller? So there’s a lot of things that
still have to use your own thinking about. Finally, mixing client-side and
server-side templating is pretty messy. We’re doing a little bit now,
but we’re trying to limit it. But in the future, it
may be unavoidable. There may be a reality where– A lot of things we’re talking
about at Google right now is, how do I make my application
indexable by a web crawler? It’s all rendered in client-side
server script. There is nothing to index
effectively, right? Unless you’ve got a very
smart web crawler. So one of the things that people
are talking about is, how do I get the server to at
least partially render HTML and be able to respond to that,
shift that HTML out to the client, and then
overlay JavaScript behavior on top of that? Coming down the pike, I’m sure
there’s going to be some need, some solution proposed, where
you’re mixing these two modes. And I think that stuff is still
not well understood. You had a question? AUDIENCE: Yeah. More of a comment
than a question. [INAUDIBLE] conversation about AMD. MARK JACOBS: Yep. AUDIENCE: When I first started
using Angular, one of the first [? questions ?] I had was how are these
modules [INAUDIBLE] differently than I think
they’re supposed to. And I think one of the ways
people often use them is to isolate [INAUDIBLE] asynchronous
loading [INAUDIBLE] secondary. And so what I’ve found in a
couple of the applications that I’m working on with
AngularJS is the Angular modules let me separate concerns
in the way that we often do with AMD [INAUDIBLE] and it does that so well that
it made me think twice about whether or not I really need
asynchronous loading– MARK JACOBS: Yeah. AUDIENCE: –in my application
that I’m working on personally. And the one I’m working
for at work. And we ended up doing a little
bit of conditional loading [INAUDIBLE] but we found that there’s enough
of a small overlap between what Angular modules
do and what [INAUDIBLE] that you may not need
that extra stuff. And so I’d imagine there’s other
developers who’ve seen that and experienced
that [INAUDIBLE]. AUDIENCE: [INAUDIBLE] back and forth [INAUDIBLE] to isolate your [INAUDIBLE] and
asynchronous loading is very secondary [INAUDIBLE] But for me [INAUDIBLE] That’s why I was scared
with Angular. It’s like, [INAUDIBLE] MARK JACOBS: I’ll give you
one other little gem of information. I was talking with Igor this
morning, and I asked the question, when you break up your
app into modules, should you break it by type, like
controller, services, [INAUDIBLE] or by feature? Like this service widget
or whatever. It seemed obvious to me it
should be by feature. And when I asked Igor, he said,
oh, clearly by feature. And then I said, well, why does
the Angular documentation say the opposite? And why does this email from
Misko say the opposite? And the answer was, the
Angular team is still figuring it out. They used to feel that this was
just the simplest way to use the module system. But now, having seen much larger
applications like ours and others, it does hew more
closely to our traditional conception of Dependency
Injection, where the modules really should be defined
around features. Yep. AUDIENCE: Number one, congratulations on your product– MARK JACOBS: Thank you. AUDIENCE: –and all the
hard work you and your team have done. One of my thoughts from
listening to your presentation is that the Angular team
is under-resourced. Particularly, first,
documentation. I’m sure there’s other things. You’ve listed some things. Also, my question is is moving
up the stack a bit, YUI from the Yahoo! guys when they’ve had
a similar type of project for corporate level– MARK JACOBS: Yep. AUDIENCE: –they very much
included widgets. And the Angular, sure, it’s got
tabs and a couple, one or two things. But the YUI they’ve spoken about
this over the years now that it’s an older project, that
they found a lot faster or let’s say positive bumps in
uptake within the corporation as they introduced widgets
that they had worked very hard on. And clearly, you’ve done hard
work on Omnigrid and Omnilist. So, thoughts about moving
that into– well, one is moving it,
or the Angular team picking up higher levels– MARK JACOBS: Yep. AUDIENCE: –and an obviously
related question is, your plans for that IP out, either
publicly or within Google? MARK JACOBS: The first
question is about Angular staffing. And I think that they’re
working very hard on that right now. I don’t think that it’s ever
going to be a 40-person team. But they’re trying to grow, and
I know they’re trying to grow writers, as well. I think the reality is, until
recently, it was just, even within Google, an experimental
technology. It’s not until products like
mine, and now we’ve got an entire growing number of
products that have given that team some gravitas to go out and
say, hey, we deserve three more engineers. And so that’s happening. I think that’s a good thing. As far as moving up
the stack, Misko’s talked a lot about that. For example, you’ve all
seen that Gmail has a new look and feel. And Google Search has
a new look and feel. A lot of it was a result of an
internal project where there’s a lot of controls of
widgets designed. And Misko’s talked a lot about,
oh, we’d love to do Angular versions of that, or
Angular wrappers of that. Just the reality is, they have
to make choices every day as to what they work on, and I
know that they’re still spending a lot of time and
effort really trying to improve the testing story. JsTestDriver is flaky and
slow, and whatever. So they’re investing in that. And they’re investing in
some other things. So I think it will come. But the third part about moving
up the stack and will we ever share our controls? To be honest, I’d love to. We’re not in the business
of reselling software. We sell service. I would love to put Omnigrid and
Omnilist out in the open. I think the big open question,
though, is, there’s no defined best practice for packaging
Angular controls. And that’s a real challenge
for us. Even, we’re trying to share
Omnigrid and Omnilist within multiple teams. And, for the most part, we do
that today by making a lot of unsafe assumptions. Yeah, you’re going to have
the same look and feel. We could put a lot more work
into it and figure out how to make it stylable. But even still, every Angular
directive requires sometimes a bit of service, a bit
of widget, a bit of CSS, a bit of markup. There’s no clear way as
how to package that. And even if we did, how you
would consume that package? I think that’s the biggest
challenge right now to the Angular team rolling out a bunch
of widgets, is, we don’t know yet what that packaging
mechanism looks like. And until we do, I don’t
really see how that’s going to change. AUDIENCE: [INAUDIBLE] MARK JACOBS: Yeah. AUDIENCE: [INAUDIBLE] MARK JACOBS: I am recording
these names and I’ll look up them afterwards. I’ve never heard
of them before. This is a problem that we’ll
need to solve in order to get past this hump. But if there’s good ideas out
there, or good technologies, we’re certainly open to them. I haven’t seen a solution yet. AUDIENCE: [INAUDIBLE] This is actually a really
active area for debate [INAUDIBLE] JS community [INAUDIBLE] all these servicing people
are coming [INAUDIBLE] our best practices [INAUDIBLE] responding to each other. How much [INAUDIBLE] do this,
and should we [INAUDIBLE] MARK JACOBS: And anyway, that’s
a simpler problem, because when we’re talking
JS files– AUDIENCE: No, no, no. they’re talking about how
client-side HTML CSS JavaScript, and they’re like,
should we take the CSS and HTML and turn it into JavaScript
[INAUDIBLE] There’s a lot of interesting
talk [INAUDIBLE]. So, yeah. I think this is a big area. Everybody’s thinking it. MARK JACOBS: Totally. So that is all of my talk. I’ll take questions
in a second. I just want to make one
point before I forget. My team is hiring. If any of you are totally
awesome AngularJS developers, come see me. I could hook you up
with a recruiter. And with that, questions. AUDIENCE: [INAUDIBLE] about how hard it was
to [INAUDIBLE] conversions. MARK JACOBS: Yep. AUDIENCE: How much code would
he or she have to write [INAUDIBLE] MARK JACOBS: Yeah. Carl is on my team out there. He’s one of our senior
engineers. Google [? transports ?] 20% project. A lot of you can debate
that percentage. He is a 20% engineer
on Angular. We try to contribute
back to them. I don’t think we have a huge
stamp on the actual code. We have a huge stamp on a lot
of the requirements and some of the direction it’s taken. AUDIENCE: Second question. Do you have any [INAUDIBLE] throw up code [INAUDIBLE] slower [INAUDIBLE]. MARK JACOBS: No. And the reason is that, I think
we have something like 0.013% of our traffic
is on a tablet. It’s not that– I would love to better support
mobile devices, but it’s just not part of our product
road map. And we haven’t spent any time,
really, looking into it. AUDIENCE: [INAUDIBLE] MARK JACOBS: I was just reading
an article today about a team that’s using Angular– I think it was Zepto, or
something like that– that’s doing it online. I’m trying to remember
what it was. Good Films, or something
like that? AUDIENCE: Igor, he should go
on Google+ [INAUDIBLE] MARK JACOBS: Yep. AUDIENCE: [INAUDIBLE] MARK JACOBS: OK. AUDIENCE: Also [INAUDIBLE]. MARK JACOBS: It is
for this purpose. It actually has a tiny
amount of memory. And the YouTube team had to work
very hard to get it to be performant in that
environment. So just because you’ve
got to sell the processor doesn’t actually– Yes. AUDIENCE: I’m curious what
browsers that DFA 5 supported, and if there were
any [INAUDIBLE] MARK JACOBS: DFA 5, which is
two versions ago, only supported IE6. Period. And the reason was because
DFA 5 used IE6’s built-in XSL processor. So it just received XML from
the server and did all this [INAUDIBLE]. Kind of a cool, before
its time design. Except it just didn’t have
a lot of browser support. DFA 6, which, again, is the
previous version, is basically supported– it definitely supports
IE6 and later. It supports Firefox
3 and later. So it has much broader
browser support. But also it’s a much
simpler API. It can’t take advantage
of CSS transitions and all this other stuff. So in our current version for
DDMM Trafficking, a/k/a DFA 7, we tried to limit the number of
browsers, A, to make sure we have better automated
testing. Just limit the number of
environments you have to test. As well, so we can take better
advantage of web technology and push the quality
of user experience. AUDIENCE: So did you get
pushback from a client that said, hey, we’re using IE
7 or 6 or whatever? MARK JACOBS: No, we fretted
about this for about six to nine months. Then we just watched the
Google Analytics on the DFA 6 version. And a lot of the older
IE versions have just dropped out. Things have been moving
towards Chrome. And so, I think by the time we
actually hit a critical mass– we have to migrate users
from DFA 6 to DFA 7. It’s not just a switch. So I think by the time we hit
a critical mass on DFA 7, I think most of the thorniest
browsers will have nominal traffic. So I’m not too worried
about it. Yeah. AUDIENCE: One of your
disadvantages [INAUDIBLE] MARK JACOBS: Yep. AUDIENCE: [INAUDIBLE] did you spend more, less, or
about the same amount of time you expected in the upgrades
between each version? MARK JACOBS: Well, I always
hoped it would be totally painless, and we’d just be
compiled, and it would just magically work. So if that was my expectation,
it took way more than that. I think our worst and most
brutal one was the upgrade from 0.8 to 0.9. Is that the right– AUDIENCE: [INAUDIBLE] MARK JACOBS: Or .07 to .09? AUDIENCE: [INAUDIBLE] MARK JACOBS: There
was one where– AUDIENCE: I think we were
going from [INAUDIBLE]. MARK JACOBS: 0.9 to .10. AUDIENCE: [INAUDIBLE] we went
from 9-point- whatever to [INAUDIBLE] MARK JACOBS: Yes. That– AUDIENCE: [INAUDIBLE] MARK JACOBS: All the
other ones– AUDIENCE: [INAUDIBLE] MARK JACOBS: Yeah, that was by
far the most brutal one. And the reason was, the Angular
team was trying to shove in as many breaking
changes before labeling it .10 as possible. And more power to them. But that was really bad. I think, before that, though,
yeah, there was a day or two of pain, but nothing
too brutal. They did some changes where
there used to be this thing called ng:autobind or
auto-something. And they [? rewrote ?]
that and added ng:bootstrap or ng:app. And then they changed it,
ng:thing to ng:model. So, like a lot of those things,
some of them were mechanical. But there were some
other ones. For example, in the current
version, the idea of a scope and a controller are separate. And that is just a
huge, massive, breaking change for us. And we still are using a
backwards compatibility model to try to figure out
how to get there. Largely, we’re shackled by a
number of different things. Like, for example, we have a
large family of controllers in a classical object hierarchy. If I had to do it all
over again, we would not have done that. We would have used mix-ins
or some other method of code reuse. Because of that, we can’t
actually separate scope and control unless we do the entire
object hierarchy. We can’t just do parts of it. So there are things like that
which, maybe we’re not paying the fee for those upgrades
now, but it’s a bit of a technical debt that we’re
carrying with us in the quarters to come. AUDIENCE: You mentioned that
you use [INAUDIBLE] quite a bit. Which style are you using? Are you using [INAUDIBLE] MARK JACOBS: Yep. In fact, this was one of the
things that we helped massage into shape. I used Vim, and I have this
plugin called Syntastic. And it complains every time you
use an element it doesn’t understand. And it annoyed the
hell out of me. So I kept complaining
to Misko. It’s like, why can’t I do data
dash something, so that I can get this stupid Syntastic
thing off my back? And he, of course, one-upped me
and came up with a solution where you can do it four
different ways. You can do it as an attribute,
with or without the data, with or without the colon, as an
element, or whatever. And so we exclusively use Data
Dash on a div or a span. And again, we want
our stuff to go through an HTML validator. If you have all this stuff, it
just creates noise during validation. AUDIENCE: And another
question. Have people on your team ever
looked at using CoffeeScript with [? Angular? ?] MARK JACOBS: I’m sure. CoffeeScript doesn’t work
within a Google place. But I know that CoffeeScript
works just fine with Angular. I’ve messed with it at home,
and I know that other people have, too. It just doesn’t work
in Google. AUDIENCE: You use [INAUDIBLE] [LAUGHTER] MARK JACOBS: Yeah. Right. Exactly. AUDIENCE: [INAUDIBLE] [LAUGHTER] AUDIENCE: [INAUDIBLE] MARK JACOBS: Yep. You had a question? AUDIENCE: I [INAUDIBLE] MARK JACOBS: Yep. AUDIENCE: [INAUDIBLE] MARK JACOBS: I have
a good friend. A guy named Charlie Robbins. He’s the CEO of a company
called Nodejitsu. I don’t know if anybody
knows it. And that company– basically Charlie– he wrote this alternate
framework called Flatiron. And over beers one day with
Charlie, I was telling him, we’re using AngularJS, and he
goes, oh, I can’t stand AngularJS because it’s too much
like Silverlight and WPF and there’s too much
crap in the markup. And Flatiron takes the opposite
point of view. It’s sort of like, all you need
in your markup is just IDs and classes. Right? And then we’ll handle all
the binding and stuff in JavaScript. And the payoff, of course, is,
if you have designers who are working in Dreamweaver or
Coda, or what have you, nothing will get lost
in translation. It’s a great idea, but Flatiron
has struggled to deliver the type of
functionality, like the two-way binding and all
that kind of stuff. There’s just so much distance
between the JavaScript and the HTML. So it’s great for the designer,
but the developer has to go back and forth between
these two things and make sure the classes line up,
and make sure the designer wants to use a different class,
because it doesn’t have a semantic meaning now. It just has purely
visual meaning. Things will break. This is kind of roundabout
to your question. I look at our views today and
they have a lot of Angular cruft on them. But on the other hand, you
look at those views and they’re very informative. I can read the view without
going to a JavaScript and get a pretty good sense of
what’s happening. It’s like, oh, this area is
controlled by this control. You click on this button, it’s
going to call the save method on that controller. And this particular thing’s
show or hide, based on the value of this property. It’s fairly descriptive. So I can see either way. But, of course, no one’s going
to load one of their Angular files up in Dreamweaver and have
great success with it. AUDIENCE: When you’re building
a small project, when does it make sense to use jQuery over
Angular or vice versa? MARK JACOBS: I gave this meetup
talk in San Francisco last week, and somebody asked
a very similar question. And I’ll say that the one thing
is, classical jQuery development is almost completely
opposite from Angular development. The two don’t mix together. When we write Angular apps, we
use jQuery in a very limited, sandbox way. But if you’re a typical jQuery
developer, you’ve been operating on completely
different assumptions than those that hold up in Angular. So what do I mean? The typical jQuery app is
constantly pushing changes on to the dom. So you click on something to an
event, and jQuery is then reaching out to the dom,
stripping something out, inserting another element,
modifying its inner HTML, doing all this type of work. That’s not at all how
Angular works. And I think when you have a
developer go with that mindset into Angular, they get very
confused right away. In fact, I had a new engineer
who, as a test project, tried to do a control. And his project ended up in
between these two worlds. In Angular, everything flows
through the model. So, if I want to have the visual
change, the view is simply binding to
all interesting properties on the model. When I want the view change,
I just change the model. If you come from an MVC world,
that’s a kind of a duh, but it’s definitely not the way
things are done in typical jQuery world. So if you’re a developer working
on a small app, it doesn’t really matter. They’re both going to have
pretty much the same value. I would just say that you
have to pick one. They’re not blendable. And they’re not really
evolvable, either. You can’t go from a jQuery and
evolve it into an Angular app. So it doesn’t really answer
your question, but– AUDIENCE: [INAUDIBLE] I was wondering how
[INAUDIBLE] MARK JACOBS: Just to sum up,
for people in the room, the only place in an Angular app
where you’re supposed to interact with the dom is
inside a directive. A directive is the place,
the vehicle, for interacting with a dom. And so inside of there, you’re
free to use whatever jQuery you want, or Closure,
or what have you. And you can do binding events
and stuff like that. But once you leave the confines
of that directive, jQuery’s an unwanted stranger. You do not want it in your
controllers, you do not want it anywhere else. We were excited about the fact
that, inside the context of a directive, we could use all of
our mad jQuery skills, but we had to train ourselves, just do
not use jQuery and do not interact with the dom at all,
in any way, shape or form, once you get outside
of directives. AUDIENCE: I actually
have another question about caching. I notice [INAUDIBLE] MARK JACOBS: That $HTTP
is an Angular service. So it does provide caching. So it’s, well– I can’t remember. Is this in $resource, or
$HTTP where it does– AUDIENCE: [INAUDIBLE] MARK JACOBS: Yeah. So in $HTTP, Angular
itself will do caching of resource calls. And in fact, we did some recent
work where we were trying to manipulate that cache
and transform some of that stuff before it got
saved in Angular cache. But I don’t have much
more about it. AUDIENCE: [INAUDIBLE] MARK JACOBS: Yeah, we did. Because we couldn’t really
control the Angular cache. This is a long time ago,
well before 1.0. And we found things were getting
cached or not cached, not only wanted to. But I haven’t noticed any
recent problems with it. Yeah. AUDIENCE: You mentioned
you had [INAUDIBLE] 99% code coverage. I was just curious if your
engineers are practicing classic [INAUDIBLE]. MARK JACOBS: Carly? No. I mean, I think a lot of
engineers on the team talk a good TDD game, but
don’t actually practice on a daily basis. I can– AUDIENCE: You get into
99% [INAUDIBLE] MARK JACOBS: Yes. AUDIENCE: [INAUDIBLE] MARK JACOBS: It’s
not the same. I mean, I’m a huge test-driven
development fan. I would say that what you hear
a lot of times on my team is, oh, I just finished the code. It’ll take me about four or five
days to write the test. Then I’ll be done. And again, there’s a lot
of reasons for that. And not all of them are wrong. For example, I think when you
are new to this particular platform, or new to UI,
it’s really hard to write tests first. Because you don’t even know
what it is you’re testing. What’s your first test when
you’re writing new AngularJS? Is it of a service? Is it of a directive? Do you even know what
those things– so I think it requires a bit of
fiddling and exploration. And test-driven development
doesn’t really help with that. But, to your second point,
oh, you got 99%. It’s 99%. What are you complaining
about? Well, part of the reason for
test-driven development is, it helps control the shape
of the code. It can actually forestall lots
of code that may be tested, but doesn’t even need to be
written at all if you had actually approached it from,
what is the minimal interface I need for this behavior
to work? I also think that some of our
test coverage could be claimed as empty testing. Like, yeah, this was just a
piece of JavaScript I had to write to get the code coverage
tool to mark this thing as green. But is it really conceptually
the right thing to test? So, very proud of our code
coverage numbers. I think it’s something of a
hollow claim, because not all of our tests really capture
the real conceptual understanding. I think in the ideal, you would
read your tests and you would learn what the app does
and what its behavior is, just by reading the test. Not all of our tests are written
with that clarity. They’re not always descriptive
of the behavior. They just simply say, OK, when
I set X to whatever, and read that value back out,
it’s the same. AUDIENCE: I also wonder about
those [INAUDIBLE] MARK JACOBS: Yeah. AUDIENCE: Did you guys start
outside in, testing first, did you do integration [INAUDIBLE]
drop down to unit tests [INAUDIBLE]. MARK JACOBS: No, we did
unit tests first. And again, part of the reason
for that is because Angular Scenarios was such a bore. On our team, we want
the developers to write all the tests. And so they’re writing, they’re cranking out unit tests. And then we just had a
conceptual block with getting into Angular Scenarios. So while we had 99% unit test
coverage, our end-to-end testing was hovering
around 3, 4, 5%. Really out of whack. And then our test engineers
basically stepped in and said, OK. If you guys won’t do
it, we’ll do it. We’re writing them in Java,
we’re doing them in WebDriver. Now our integration test
coverage is north of 65, 70%. Which is great, and they’re
probably going to get all the way there. But the core problem is,
I still have all these JavaScript developers who are
not going to write Java WebDriver tests. The responsibility is
in the wrong place. So it’s a bit out of whack,
and we need to fix it. Yes AUDIENCE: [INAUDIBLE] number one UI framework
[INAUDIBLE] MARK JACOBS: What do you
mean, UI framework? What do you mean? AUDIENCE: [INAUDIBLE] MARK JACOBS: It’s really hard
to answer that question. I think the key thing I would
say, in AngularJS, you can wrap anything. So you want to use Sencha, you
want to use jQuery, you want to use whatever, you can. AUDIENCE: [INAUDIBLE] MARK JACOBS: Yes. But in the context of a
directive, that’s not necessarily an evil thing. It just depends on if you
confine its dom manipulation to a directive, and make sure
it’s not doing other stuff into your dom, it
works out fine. AUDIENCE: [INAUDIBLE] by directly finding those
affected by the [INAUDIBLE] MARK JACOBS: Right. This is where you get into
more vagaries of Angular. Like, you can say, I want to run
this stuff in Apply scope. I need to manually
call digest. There’s ways of telling
Angular, oh, sorry. I need to jiggle the handle
here, because somebody else messed with– who moved my cheese, I
think is the phrase? Somebody else moved my cheese. And you can tell Angular that. AUDIENCE: [INAUDIBLE] MARK JACOBS: Then write
controls in Angular. AUDIENCE: [INAUDIBLE] AUDIENCE: That’s what
I heard, yeah. MARK JACOBS: There’s a fear
amongst the Angular team of that being not very well
maintained yet. AUDIENCE: [INAUDIBLE] AUDIENCE: I don’t know. [INAUDIBLE] jQuery [INAUDIBLE] enough of it that you can
listen to [INAUDIBLE] in Angular UI [INAUDIBLE]. MARK JACOBS: Yep. AUDIENCE: Most of
the controllers have a scope parameter. Is that something that’s
specific to the app, or to each controller? MARK JACOBS: This is the thing
I was talking about, the scope-controller separation,
the feature that was added in .10. Prior to Angular .10, the scope
and controller were one and the same. So what does this mean? If I said this part of your
markup was bound to this JavaScript object, that was
always the controller. So if I want to say, this
input is bound to this property, it’s going to be a
property of the controller. Well, as time went
on, we realized this was kind of limiting. Because I may want
to represent– for example, let’s
say I want to– I have a form. I edited a bunch of stuff and
I do validation on it. But I want to implement
Discard Changes. I want to throw everything
out. So they started to say, well,
what if I can actually have scope be a separate thing? It’s just a property
of the controller. And then I could swap out
scopes, and I don’t need to have a one-to-one
correspondence, necessarily, to scope and controller. If you come from a .NET world,
in WPF there’s this idea of data context. Which is the exact same idea. You don’t want the controller
to really hold that state. You want the view state to be
stored in something else. And so, that was this idea. So the scope is– you’re
in control of it. You basically define what that
thing is, how it’s passed in. The only real design is– ultimately, since the control is
where all the actions are, your scope has to mirror
those actions. Because you’re no longer binding
to the controller. You’re binding to the scope. And the scope essentially has
to forward those calls on to the controller. Which is kind of a pain. But the payoff is, you now
have some insulation. You can represent view state as
different from controller state and mediate when and how
information flows to and from the control. AUDIENCE: So if you have two
different parts of your form, are you carrying the same
scope between those two different controllers that are
acting on those different parts of your form? MARK JACOBS: You can. That’s the other flexibility,
is that I can actually share the same scope amongst multiple controllers, and vice versa. AUDIENCE: Will that mess up
the dependency tracking? MARK JACOBS: Will that mess up
the dependency tracking? AUDIENCE: [INAUDIBLE] somebody else’s controller
[INAUDIBLE] MARK JACOBS: It should. I don’t see why not. But don’t quote me on that. Yes. AUDIENCE: To piggy-back on
the digest [INAUDIBLE] did you guys have to use
too much of that? Meaning, [INAUDIBLE] jQuery happening outside
of [INAUDIBLE] Angular [INAUDIBLE] digest? MARK JACOBS: Yeah. Well, so we used a lot of it. And then we’re gradually
pruning it out. I think there was a moment in
time where we were like, oh, it’s not working correctly. Let me throw a digest
in there. See if that fixes the problem. Of course, at the time, I think
we learned more about how and when it works. We’re using– Apply is actually the
recommended way. It’s like, here’s a
function block. And somewhere in that function
block, something is going to happen and you need to jiggle
the handle in Angular. And as soon as it leaves that
Apply block, it works. In some cases, we tried to
move to that, mostly. In some cases, we needed to
manually call digest. But as time goes on, we rely
less and less on third-party controls that mess
with our dom. There’s less of that
type of low-level work with the digests. AUDIENCE: Did you use
jQuery [INAUDIBLE] MARK JACOBS: We did for
a very brief time. But now we’re not. We just use the Angular one. Although, again, this is
something you can think about. We don’t love the $resource
service, and we’re going to start handcrafting our
own resources. We’re still, I think, planning
on relying on the HTTP service of Angular. But that’s somewhere where you
could put in your own jQuery implementation there,
if you wanted to. Any other questions? Well, thanks everybody. I really appreciate
your patience. Again, my team is hiring, so
if anybody’s interested, [INAUDIBLE]. Thanks.

, , , , , , ,

Post navigation

2 thoughts on “Rebuilding DoubleClick with AngularJS (NYC meetup)

Leave a Reply

Your email address will not be published. Required fields are marked *