65
Feels Like Ruby Sarah Mei Pivotal Labs @sarahmei [email protected] 1 すみませんーはじまりましょうか。

Feels Like Ruby - Ruby Kaigi 2010

  • View
    1.804

  • Download
    1

Embed Size (px)

DESCRIPTION

Making JavaScript development suck less.

Citation preview

Page 1: Feels Like Ruby - Ruby Kaigi 2010

Feels Like RubySarah Mei

Pivotal Labs

@sarahmei [email protected]

1

すみませんーはじまりましょうか。

Page 2: Feels Like Ruby - Ruby Kaigi 2010

皆さん、こんにちは

Hi everybody

2

みんなさん、こんにち は。

Page 3: Feels Like Ruby - Ruby Kaigi 2010

名前は MEI Sarah です。

I’m Sarah Mei.

メイ サラ

3

なまえ は Mei Sarah です。はじめまして、どうぞう よろしく おねがいします。

Page 4: Feels Like Ruby - Ruby Kaigi 2010

日本語がよく話せないですから、すみません。

I don’t speak Japanese very well, so thanks in advance for your patience.

4

にほんご が よく はなせない です から、すみません。

Page 5: Feels Like Ruby - Ruby Kaigi 2010

http://www.flickr.com/photos/sunrise/4064417/5

San Franciscoにすんでいます。

Page 6: Feels Like Ruby - Ruby Kaigi 2010

I’m American.アメリカ人です。

http://www.flickr.com/photos/junewess/3756778580/6

Americaじんです。

Page 7: Feels Like Ruby - Ruby Kaigi 2010

I’m a Ruby & Rails developer.

RubyとRailsの開発者です。

Image copyright 2006-2010 Yukihiro Matsumoto7

Ruby の かいはつしゃ です。

Page 8: Feels Like Ruby - Ruby Kaigi 2010

I work at

に勤めています。ピヴォタルラブス

8

Pivotal Labs に つとめて います。Pivotal Labs は Pivotal Tracker を せいさく して います。でも、ほとんど の Pivotal Labs の しゃいん は コンソルタンット です. 

Page 9: Feels Like Ruby - Ruby Kaigi 2010

I work at

に勤めています。ピヴォタルラブス

ピヴォタルトラッカー

8

Pivotal Labs に つとめて います。Pivotal Labs は Pivotal Tracker を せいさく して います。でも、ほとんど の Pivotal Labs の しゃいん は コンソルタンット です. 

Page 10: Feels Like Ruby - Ruby Kaigi 2010

(この先から英語です。ごめんね)

9

じこしょうかい が おわり です から、この さき から 英語 です。ごめん ねえ。。。

Page 11: Feels Like Ruby - Ruby Kaigi 2010

Feels Like Ruby

(この先から英語です。ごめんね)

9

じこしょうかい が おわり です から、この さき から 英語 です。ごめん ねえ。。。

Page 12: Feels Like Ruby - Ruby Kaigi 2010

Feels Like RubyMaking JavaScript a

Real Language

(この先から英語です。ごめんね)

9

じこしょうかい が おわり です から、この さき から 英語 です。ごめん ねえ。。。

Page 13: Feels Like Ruby - Ruby Kaigi 2010

What I like about Ruby

10

I want to set the stage by talking about what I enjoy about Ruby. First and foremost, it’s 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.

Page 14: Feels Like Ruby - Ruby Kaigi 2010

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, it’s 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.

Page 15: Feels Like Ruby - Ruby Kaigi 2010

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, it’s 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.

Page 16: Feels Like Ruby - Ruby Kaigi 2010

What I like about Ruby

• The language itself.

• I can test-drive everything.

JavaScript

JavaScript

11

So let’s see how these options stack up in JavaScript. The language itself...?

Page 17: Feels Like Ruby - Ruby Kaigi 2010

What I like about Ruby

• The language itself.

• I can test-drive everything.

JavaScriptXJavaScript

12

Well, I’m never going to be able to change that. I don’t dislike JavaScript, but Ruby fits my personality better. But what about test-driving?

Page 18: Feels Like Ruby - Ruby Kaigi 2010

What I like about Ruby

• The language itself.

• I can test-drive everything.

JavaScriptXJavaScriptO

13

We should be able to test-drive JavaScript. But until earlier this year, I didn’t. And some of the best Rails developers I know, who test-drive all their Ruby code, still don’t test-drive their JavaScript. So the question is...

Page 19: Feels Like Ruby - Ruby Kaigi 2010

http://www.flickr.com/photos/petereed/49639295614

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.

Page 20: Feels Like Ruby - Ruby Kaigi 2010

15

Web applications are fundamentally written in multiple languages. Here’s a very generic representation of a Ruby web application. On the front end, there’s 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 can’t 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. That’s what Rails does.

Page 21: Feels Like Ruby - Ruby Kaigi 2010

Rails

ActiveRecord

16

For example, Rails extends this direction, and abstracts away SQL with ActiveRecord. It’s pretty successful with that. Even on really complex applications, I can get away with the generated SQL most of the time.

Page 22: Feels Like Ruby - Ruby Kaigi 2010

ActiveRecord

Rails/gems

erb

rjssass

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. I’ll show you an example in moment.

But first 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 significant changes, we’ll have five years’ notice. Moreover, the database products that implement SQL have committees, so as SQL end-users, we’re exceedingly well-insulated from any language churn.

Page 23: Feels Like Ruby - Ruby Kaigi 2010

JavaScript Developers

http://www.flickr.com/photos/gem66/38740030618

But Javascript...is the wild west. It’s 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?

Page 24: Feels Like Ruby - Ruby Kaigi 2010

ActiveRecord

Rails/gems

erb

rjssass

Rails

19

It means we need to opt-out, to make an exception, and to handle JavaScript differently. Now, that’s the philosophical reason - now I want to show you the practical reason.

Page 25: Feels Like Ruby - Ruby Kaigi 2010

20

In Rails 2, using RJS means you have little bits of Javascript all over your code.

Here’s 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 textfields, but you can add another one by clicking “Add a task”, and you can delete one by clicking the “remove” link that’s next to it. Both of these are implemented as simple JavaScript that modified the DOM. For the purposes of this example, we’re going to focus on the remove link.

So let’s look at how that’s implemented.

Page 26: Feels Like Ruby - Ruby Kaigi 2010

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.

Page 27: Feels Like Ruby - Ruby Kaigi 2010

22

Here’s what the rendered HTML looks like. You’ve got that little bit of inline javascript, which on its own, is fairly simple. But it’s 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, there’s likely to be dozens of these on one page, if not hundreds. Testing them all with Selenium would mean you’d have a test suite that never stopped running.

Plus, Selenium is an integration test. If all you’re doing is integration tests, you’re 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?

Page 28: Feels Like Ruby - Ruby Kaigi 2010

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. I’ll show you what that looks like in a moment. 3. Organize your JS by behavior, and by location.4. Test-drive all your JS.

Page 29: Feels Like Ruby - Ruby Kaigi 2010

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. I’ll show you what that looks like in a moment. 3. Organize your JS by behavior, and by location.4. Test-drive all your JS.

Page 30: Feels Like Ruby - Ruby Kaigi 2010

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. I’ll show you what that looks like in a moment. 3. Organize your JS by behavior, and by location.4. Test-drive all your JS.

Page 31: Feels Like Ruby - Ruby Kaigi 2010

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. I’ll show you what that looks like in a moment. 3. Organize your JS by behavior, and by location.4. Test-drive all your JS.

Page 32: Feels Like Ruby - Ruby Kaigi 2010

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. I’ll show you what that looks like in a moment. 3. Organize your JS by behavior, and by location.4. Test-drive all your JS.

Page 33: Feels Like Ruby - Ruby Kaigi 2010

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 first 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.” Let’s look at how we’d do it.

Page 34: Feels Like Ruby - Ruby Kaigi 2010

25

Here’s our original example, with the remove link. How we could re-implement it? Before, the code looked like this...

Page 35: Feels Like Ruby - Ruby Kaigi 2010

26

But we can simplify this now. All we really have here is a link that we want to add a behavior to.

Page 36: Feels Like Ruby - Ruby Kaigi 2010

27

So in the erb template, we’ll just make a link with a class on it. No reference to JavaScript anywhere here. And here is...

Page 37: Feels Like Ruby - Ruby Kaigi 2010

28

...the HTML it generates. So. If we don’t put our Javascript in the HTML...where should we put it?

Page 38: Feels Like Ruby - Ruby Kaigi 2010

public/javascripts !

29

In general, I keep my JavaScript files in public/javascripts. So we’ll create a file in public/javascripts called project_form.js

Page 39: Feels Like Ruby - Ruby Kaigi 2010

project_form.js

30

In this file, we create a class called RubyKaigi.ProjectForm, and we put in two functions. The two functions are initialize and remove_task.

Page 40: Feels Like Ruby - Ruby Kaigi 2010

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.

Page 41: Feels Like Ruby - Ruby Kaigi 2010

project_form.js

32

That function, remove_task, actually removes the element with class ‘task’ from the DOM.

Page 42: Feels Like Ruby - Ruby Kaigi 2010

project_form.js

33

The last thing that’s important here is the document.ready, which calls initialize, which sets up the click events, once the page is loaded.

Page 43: Feels Like Ruby - Ruby Kaigi 2010

34

So I’ve 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.

Page 44: Feels Like Ruby - Ruby Kaigi 2010

35

Then it might look something like this, with a new function at the bottom, and some extra initialization at the top.

Page 45: Feels Like Ruby - Ruby Kaigi 2010

Organizing by page

What if you use the ProjectForm JS on more than one page?

36

Page 46: Feels Like Ruby - Ruby Kaigi 2010

Organizing by page

Move ProjectForm.initialize to a page class initializer

What if you use the ProjectForm JS on more than one page?

36

Page 47: Feels Like Ruby - Ruby Kaigi 2010

37

Page 48: Feels Like Ruby - Ruby Kaigi 2010

project_edit_page.js

38

Page 49: Feels Like Ruby - Ruby Kaigi 2010

project_new_page.js

39

Page 50: Feels Like Ruby - Ruby Kaigi 2010

http://www.flickr.com/photos/uwehermann/13224482640

So that’s how you organize your JavaScript so it’s all in one place. But what about testing?

Page 51: Feels Like Ruby - Ruby Kaigi 2010

Jasmine

@jasminebdd

41

That’s where Jasmine comes in. Jasmine is Pivotal’s 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 first-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.

Page 52: Feels Like Ruby - Ruby Kaigi 2010

Jasmine• Open-source JavaScript test

framework from Pivotal

@jasminebdd

41

That’s where Jasmine comes in. Jasmine is Pivotal’s 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 first-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.

Page 53: Feels Like Ruby - Ruby Kaigi 2010

Jasmine• Open-source JavaScript test

framework from Pivotal

• BDD in the style of rspec

@jasminebdd

41

That’s where Jasmine comes in. Jasmine is Pivotal’s 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 first-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.

Page 54: Feels Like Ruby - Ruby Kaigi 2010

Jasmine• Open-source JavaScript test

framework from Pivotal

• BDD in the style of rspec

• Philosophy:

@jasminebdd

41

That’s where Jasmine comes in. Jasmine is Pivotal’s 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 first-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.

Page 55: Feels Like Ruby - Ruby Kaigi 2010

Jasmine• Open-source JavaScript test

framework from Pivotal

• BDD in the style of rspec

• Philosophy:

• Test JavaScript with JavaScript

@jasminebdd

41

That’s where Jasmine comes in. Jasmine is Pivotal’s 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 first-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.

Page 56: Feels Like Ruby - Ruby Kaigi 2010

Jasmine• Open-source JavaScript test

framework from Pivotal

• BDD in the style of rspec

• Philosophy:

• Test JavaScript with JavaScript

• No DOM dependency

@jasminebdd

41

That’s where Jasmine comes in. Jasmine is Pivotal’s 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 first-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.

Page 57: Feels Like Ruby - Ruby Kaigi 2010

gem install jasmine

42

Page 58: Feels Like Ruby - Ruby Kaigi 2010

43

When you install jasmine, it comes with a rake task that creates a javascripts directory under spec.

Page 59: Feels Like Ruby - Ruby Kaigi 2010

44

I create a new file called project_form_spec.js. In this file I describe the behavior of the functions in the RubyKaigi.ProjectForm class. Here’s the spec for removeTask.

Page 60: Feels Like Ruby - Ruby Kaigi 2010

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 you’re expecting.

Jasmine comes with a small set of matchers - here you see expect().toEqual(). You can also write custom matchers, as in rspec.

Page 61: Feels Like Ruby - Ruby Kaigi 2010

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.

Page 62: Feels Like Ruby - Ruby Kaigi 2010

Summary

• Respect your JavaScript!

• Test-drive

47

Page 65: Feels Like Ruby - Ruby Kaigi 2010

Questions?質問がありますか。

@[email protected]

@jasminebdd

http://www.flickr.com/photos/rappensuncle/248625025

50

じゃ、これは いじょう です。