Вы находитесь на странице: 1из 65

Feels Like Ruby

Sarah Mei
Pivotal Labs
@sarahmei
sarah@pivotallabs.com
1
v=I/''=='D,
,
Hi everybody
2
v/6/./! ',
( MEI Sarah ,
Im Sarah Mei.
.
3
= ' Mei Sarah ,''7='.: e' :'=,
']/'//,
7',
I dont speak Japanese very well, so
thanks in advance for your patience.
4
!/ e 'I D:.v=I/,
http://www.ickr.com/photos/sunrise/4064417/
5
San Francisco!/=,
Im American. `//,
http://www.ickr.com/photos/junewess/3756778580/
6
America'/,
Im a Ruby & Rails
developer.
Ruby`Railsv|(,
Image copyright 2006-2010 Yukihiro Matsumoto
7
Ruby D''\ ,
I work at
)",
''
8
Pivotal Labs ! :7 =,Pivotal Labs ' Pivotal Tracker I6 '
=,.:/: Pivotal Labs '\/ ' ``.^` .
I work at
)",
''
''/
8
Pivotal Labs ! :7 =,Pivotal Labs ' Pivotal Tracker I6 '
=,.:/: Pivotal Labs '\/ ' ``.^` .
v/],"!)
9
''D : D:. 67 D: 9 ,7/ ,,,
Feels Like Ruby
v/],"!)
9
''D : D:. 67 D: 9 ,7/ ,,,
Feels Like Ruby
Making JavaScript a
Real Language
v/],"!)
9
''D : D:. 67 D: 9 ,7/ ,,,
What I like about Ruby
10
I want to set the stage by talking about what I enjoy about Ruby. First and foremost, its the
language itself. I love the expressiveness and accessibility.
But as a working developer, what I appreciate the most is the ability to test-drive everything.
Between rspec, test::unit, cucumber, capybara, webrat, shoulda, steak....I can pick the most
appropriate test tools for each project.
What I like about Ruby

The language itself.


10
I want to set the stage by talking about what I enjoy about Ruby. First and foremost, its the
language itself. I love the expressiveness and accessibility.
But as a working developer, what I appreciate the most is the ability to test-drive everything.
Between rspec, test::unit, cucumber, capybara, webrat, shoulda, steak....I can pick the most
appropriate test tools for each project.
What I like about Ruby

The language itself.

I can test-drive everything.


10
I want to set the stage by talking about what I enjoy about Ruby. First and foremost, its the
language itself. I love the expressiveness and accessibility.
But as a working developer, what I appreciate the most is the ability to test-drive everything.
Between rspec, test::unit, cucumber, capybara, webrat, shoulda, steak....I can pick the most
appropriate test tools for each project.
What I like about Ruby

The language itself.

I can test-drive everything.


JavaScript
JavaScript
11
So lets see how these options stack up in JavaScript. The language itself...?
What I like about Ruby

The language itself.

I can test-drive everything.


JavaScript
X
JavaScript
12
Well, Im never going to be able to change that. I dont dislike JavaScript, but Ruby ts my
personality better. But what about test-driving?
What I like about Ruby

The language itself.

I can test-drive everything.


JavaScript
X
JavaScript
O
13
We should be able to test-drive JavaScript. But until earlier this year, I didnt. And some of the
best Rails developers I know, who test-drive all their Ruby code, still dont test-drive their
JavaScript. So the question is...
http://www.ickr.com/photos/petereed/496392956
14
Why not? Why do we make JavaScript development so painful?
I think part of it is a philosophical mismatch in the way Rails treats JavaScript.
15
Web applications are fundamentally written in multiple languages. Heres a very generic
representation of a Ruby web application. On the front end, theres HTML, CSS, and
Javascript, and on the back end there is one (or more!) server languages, plus SQL. And of
course, normal applications have other front-end languages too, like ActionScript or
Objective-J, and other back-end languages interacting with Ruby, and usually additional data
stores as well. I cant remember the last time I worked on an application that had ONLY a
relational database for storage.
But traditionally, in this setup, programming languages sit here in the middle. But
frameworks try to extend on either side. Thats what Rails does.
Rails
ActiveRecord
16
For example, Rails extends this direction, and abstracts away SQL with ActiveRecord. Its
pretty successful with that. Even on really complex applications, I can get away with the
generated SQL most of the time.
ActiveRecord
Rails/gems
erb
rjs
sass
Rails
17
But it also extends the way with erb and rjs to generate HTML and JavaScript. And with other
gems, you can generate CSS too. And although this was a good idea with SQL and
ActiveRecord, and it works decently well with HTML and CSS, RJS is kind of a disaster. Ill show
you an example in moment.
But rst I want to point out that this is not a failing of Rails, or of the people who wrote it.
This is the nature of Javascript. It might be the one language whose use is evolving even
faster than Ruby. SQL has an ISO standard and a committee, and if they make any signicant
changes, well have ve years notice. Moreover, the database products that implement SQL
have committees, so as SQL end-users, were exceedingly well-insulated from any language
churn.
JavaScript Developers
http://www.ickr.com/photos/gem66/387400306
18
But Javascript...is the wild west. Its the frontier. While the language itself is relatively stable,
its libraries and usage patterns are changing faster than that of Ruby, or of Rails, or of any
other framework.
What does that mean for us as web application developers, as multi-lingual programmers?
ActiveRecord
Rails/gems
erb
rjs
sass
Rails
19
It means we need to opt-out, to make an exception, and to handle JavaScript di!erently.
Now, thats the philosophical reason - now I want to show you the practical reason.
20
In Rails 2, using RJS means you have little bits of Javascript all over your code.
Heres an example I adapted from the complex forms railscast. This is a to-do list app, in
which you can create a project with any number of tasks attached. This is the new project
form. It has 3 task textelds, but you can add another one by clicking Add a task, and you
can delete one by clicking the remove link thats next to it. Both of these are implemented
as simple JavaScript that modied the DOM. For the purposes of this example, were going to
focus on the remove link.
So lets look at how thats implemented.
21
This is the partial that is rendered for each task. The important part is the link_to_function,
where when we click remove, it calls that little piece of javascript.
22
Heres what the rendered HTML looks like. Youve got that little bit of inline javascript, which
on its own, is fairly simple. But its not really testable.
Sure, you could write a selenium test that tests that it actually removes the dom element.
However, Selenium is slow. This is one simple interaction - in a typical modern web
application, theres likely to be dozens of these on one page, if not hundreds. Testing them
all with Selenium would mean youd have a test suite that never stopped running.
Plus, Selenium is an integration test. If all youre doing is integration tests, youre doing it
wrong. You need both unit tests and integration tests to probe all the behavior of your code.
So how can we re-do this in a way that is testable and repeatable?
A different approach
23
1. Forget RJS - it gets in your way once you do anything beyond the very simple.
2. Put your JS in classes - of course JS is a prototype-based language instead of an
inheritance-based language, but you can still organize your functions into sets. Ill show you
what that looks like in a moment.
3. Organize your JS by behavior, and by location.
4. Test-drive all your JS.
A different approach

Forget RJS - write functions


23
1. Forget RJS - it gets in your way once you do anything beyond the very simple.
2. Put your JS in classes - of course JS is a prototype-based language instead of an
inheritance-based language, but you can still organize your functions into sets. Ill show you
what that looks like in a moment.
3. Organize your JS by behavior, and by location.
4. Test-drive all your JS.
A different approach

Forget RJS - write functions

Put your functions in classes


23
1. Forget RJS - it gets in your way once you do anything beyond the very simple.
2. Put your JS in classes - of course JS is a prototype-based language instead of an
inheritance-based language, but you can still organize your functions into sets. Ill show you
what that looks like in a moment.
3. Organize your JS by behavior, and by location.
4. Test-drive all your JS.
A different approach

Forget RJS - write functions

Put your functions in classes

Organize classes by behavior and


location
23
1. Forget RJS - it gets in your way once you do anything beyond the very simple.
2. Put your JS in classes - of course JS is a prototype-based language instead of an
inheritance-based language, but you can still organize your functions into sets. Ill show you
what that looks like in a moment.
3. Organize your JS by behavior, and by location.
4. Test-drive all your JS.
A different approach

Forget RJS - write functions

Put your functions in classes

Organize classes by behavior and


location

Test-drive your classes.


23
1. Forget RJS - it gets in your way once you do anything beyond the very simple.
2. Put your JS in classes - of course JS is a prototype-based language instead of an
inheritance-based language, but you can still organize your functions into sets. Ill show you
what that looks like in a moment.
3. Organize your JS by behavior, and by location.
4. Test-drive all your JS.
A different approach

Forget RJS - write functions

Put your functions in classes

Organize classes by behavior and


location

Test-drive your classes.


Unobtrusive JavaScript
24
These rst two techniques are collectively known as unobtrusive JavaScript. I am happy to
report that Rails 3 is moving to unobtrusive JavaScript. So Rails 3 will help this problem quite
a bit, but, as you can see, there is more to do beyond unobtrusiveizing. Lets look at how
wed do it.
25
Heres our original example, with the remove link. How we could re-implement it? Before, the
code looked like this...
26
But we can simplify this now. All we really have here is a link that we want to add a behavior
to.
27
So in the erb template, well just make a link with a class on it. No reference to JavaScript
anywhere here. And here is...
28
...the HTML it generates. So. If we dont put our Javascript in the HTML...where should we put
it?
public/javascripts !
29
In general, I keep my JavaScript les in public/javascripts. So well create a le in public/
javascripts called project_form.js
project_form.js
30
In this le, we create a class called RubyKaigi.ProjectForm, and we put in two functions. The
two functions are initialize and remove_task.
project_form.js
31
In initialize, we add a click event to all links with class .remove-link. When that link is clicked,
our other function is called.
project_form.js
32
That function, remove_task, actually removes the element with class task from the DOM.
project_form.js
33
The last thing thats important here is the document.ready, which calls initialize, which sets
up the click events, once the page is loaded.
34
So Ive created a JavaScript class that encapsulates the behavior of the project form. Once I
implement the Add a task link, that behavior will go in the same class.
35
Then it might look something like this, with a new function at the bottom, and some extra
initialization at the top.
Organizing by page
What if you use the ProjectForm JS on
more than one page?
36
Organizing by page
Move ProjectForm.initialize to a page
class initializer
What if you use the ProjectForm JS on
more than one page?
36
37
project_edit_page.js
38
project_new_page.js
39
http://www.ickr.com/photos/uwehermann/132244826
40
So thats how you organize your JavaScript so its all in one place. But what about testing?
Jasmine
@jasminebdd
41
Thats where Jasmine comes in. Jasmine is Pivotals open-source JavaScript testing
framework.
It lets you do rspec-style testing.
The philosophy of Jasmine is that JavaScript should be tested with JavaScript. There are gems
out there such as harmony that let you test JavaScript with Ruby, but that just adds another
layer of indirection. JavaScript should be a rst-class language in web applications.
Also, it is not dependent on the DOM, so it can be used to test other types of JavaScript, such
as for WebOS.
Jasmine

Open-source JavaScript test


framework from Pivotal
@jasminebdd
41
Thats where Jasmine comes in. Jasmine is Pivotals open-source JavaScript testing
framework.
It lets you do rspec-style testing.
The philosophy of Jasmine is that JavaScript should be tested with JavaScript. There are gems
out there such as harmony that let you test JavaScript with Ruby, but that just adds another
layer of indirection. JavaScript should be a rst-class language in web applications.
Also, it is not dependent on the DOM, so it can be used to test other types of JavaScript, such
as for WebOS.
Jasmine

Open-source JavaScript test


framework from Pivotal

BDD in the style of rspec


@jasminebdd
41
Thats where Jasmine comes in. Jasmine is Pivotals open-source JavaScript testing
framework.
It lets you do rspec-style testing.
The philosophy of Jasmine is that JavaScript should be tested with JavaScript. There are gems
out there such as harmony that let you test JavaScript with Ruby, but that just adds another
layer of indirection. JavaScript should be a rst-class language in web applications.
Also, it is not dependent on the DOM, so it can be used to test other types of JavaScript, such
as for WebOS.
Jasmine

Open-source JavaScript test


framework from Pivotal

BDD in the style of rspec

Philosophy:
@jasminebdd
41
Thats where Jasmine comes in. Jasmine is Pivotals open-source JavaScript testing
framework.
It lets you do rspec-style testing.
The philosophy of Jasmine is that JavaScript should be tested with JavaScript. There are gems
out there such as harmony that let you test JavaScript with Ruby, but that just adds another
layer of indirection. JavaScript should be a rst-class language in web applications.
Also, it is not dependent on the DOM, so it can be used to test other types of JavaScript, such
as for WebOS.
Jasmine

Open-source JavaScript test


framework from Pivotal

BDD in the style of rspec

Philosophy:

Test JavaScript with JavaScript


@jasminebdd
41
Thats where Jasmine comes in. Jasmine is Pivotals open-source JavaScript testing
framework.
It lets you do rspec-style testing.
The philosophy of Jasmine is that JavaScript should be tested with JavaScript. There are gems
out there such as harmony that let you test JavaScript with Ruby, but that just adds another
layer of indirection. JavaScript should be a rst-class language in web applications.
Also, it is not dependent on the DOM, so it can be used to test other types of JavaScript, such
as for WebOS.
Jasmine

Open-source JavaScript test


framework from Pivotal

BDD in the style of rspec

Philosophy:

Test JavaScript with JavaScript

No DOM dependency
@jasminebdd
41
Thats where Jasmine comes in. Jasmine is Pivotals open-source JavaScript testing
framework.
It lets you do rspec-style testing.
The philosophy of Jasmine is that JavaScript should be tested with JavaScript. There are gems
out there such as harmony that let you test JavaScript with Ruby, but that just adds another
layer of indirection. JavaScript should be a rst-class language in web applications.
Also, it is not dependent on the DOM, so it can be used to test other types of JavaScript, such
as for WebOS.
gem install jasmine
42
43
When you install jasmine, it comes with a rake task that creates a javascripts directory under
spec.
44
I create a new le called project_form_spec.js. In this le I describe the behavior of the
functions in the RubyKaigi.ProjectForm class. Heres the spec for removeTask.
45
It starts with a describe, like rspec, and the describe contains an it block. Both the
describe and the it take a string describing the behavior youre expecting.
Jasmine comes with a small set of matchers - here you see expect().toEqual(). You can also
write custom matchers, as in rspec.
46
It comes with a little server built in, that starts on port 8888 by default, where you can run
your specs in a browser.
To re-run them, just reload the page.
Jasmine also comes with a continuous integration task that runs the specs in a browser and
uses selenium to determine whether they pass or fail. There are plug-ins that run your specs
headlessly.
Summary

Respect your JavaScript!

Test-drive
47
http://www.ickr.com/photos/zachklein/54389823
48
http://www.ickr.com/photos/rappensuncle/248625025
49
Questions?
\|//,
@sarahmei
sarah@pivotallabs.com
@jasminebdd
http://www.ickr.com/photos/rappensuncle/248625025
50
'\.' ' ,

Вам также может понравиться