Slide 1

Slide 1 text

jQuery to Backbone アーキテクチャを意識したJavaScript入門 Frontrend Vol.4 さとう歩 / @ahomu CyberAgent, Inc.

Slide 2

Slide 2 text

さとう歩 @ahomu

Slide 3

Slide 3 text

2012年8月以前 名古屋でWebプログラマ(PHP・JSなど) 2012年9月〜 CAでフロントエンド専業にシフト new!

Slide 4

Slide 4 text

2012年後半 Gruntと自動化について 2013年1月 Stylus・CSSプリプロセッサ 2013年2月 jQuery to Backbone new!

Slide 5

Slide 5 text

詳しくは http://aho.mu

Slide 6

Slide 6 text

1. はじめに 2. jQueryについて 3. Backboneについて 4. jQuery to Backbone 5. まとめ 流れ

Slide 7

Slide 7 text

はじめに

Slide 8

Slide 8 text

jQueryは無くなりません 関心のフォーカスを移す機会 易しめに聞ける内容(のつもり)

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

BACKBONE.JS http://backbonejs.org/

Slide 11

Slide 11 text

Initial Release 2010/10/13 Gzipped Size 6.3KB Latest Version 0.9.10 ❓

Slide 12

Slide 12 text

構造化の手段を提供する モダンライブラリ View, Model, Collection等を備える

Slide 13

Slide 13 text

1500行程度の軽量さと いじりやすい柔軟さ 国内外を問わず利用が広がっている

Slide 14

Slide 14 text

依存するライブラリ ✓ jQuery ✓ Zepto.js (lightweight clone) ✓ Underscore.js ✓ Lodash (more faster) Utility Belt Library Selector Based Library _. $.

Slide 15

Slide 15 text

jQueryの 特徴と役割を振り返る jQueryについて

Slide 16

Slide 16 text

jQuery http://jquery.com/

Slide 17

Slide 17 text

特徴と役割、3つのポイント

Slide 18

Slide 18 text

①DOM APIを隠蔽して 簡潔に記述する write less, do more.

Slide 19

Slide 19 text

DOM API は煩雑すぎた elemNode.parentNode.removeChild(elemNode); ! $(elemNode).remove();

Slide 20

Slide 20 text

②クロスブラウザ対応の 諸問題を解決する IE, Firefox, Safari, Opera, Chrome...

Slide 21

Slide 21 text

かつての立役者の功罪ほか細々 Msxml.XMLHTTP? attachEvent? ! $.ajax, $.bind/$.on

Slide 22

Slide 22 text

③プラグインの充実と エコシステム形成 Useful and Awesome Plugins!

Slide 23

Slide 23 text

プラグインがあれば何でもできる User / Community / Ecosystem ! $.fn.awesomePlguin(‘feel good!’);

Slide 24

Slide 24 text

jQueryが生まれた頃の 問題を解決してくれた 意識することは少なくなってきている

Slide 25

Slide 25 text

jQueryに ついての所感 http://havelog.ayumusato.com/ develop/javascript/e333- jquery_thiking_misc.html

Slide 26

Slide 26 text

フロントエンド実装の 現状と変化 今、求められるスキルと取り巻く状況

Slide 27

Slide 27 text

Web サイト 従来の Webサービス Webアプリ 新しめな Webサービス Webアプリ ややリッチな インターフェース 静的HTML CMS利用 シングルページ リッチ&シームレスなUI RESTful API

Slide 28

Slide 28 text

Web サイト 従来の Webサービス Webアプリ 新しめな Webサービス Webアプリ サーバーサイドで 画面遷移を設計 静的HTML CMS利用 シングルページ リッチインターフェース RESTful API 次第に高まってきた フロントエンド実装の比重

Slide 29

Slide 29 text

フロントエンドに 生まれる新たな問題 Another new problems...

Slide 30

Slide 30 text

jQueryが解決しない問題 アプリケーションコードの肥大化 スパゲティコードの技術的負債 テスタビリティーの確保 メンテナンスのたびに深まる業

Slide 31

Slide 31 text

新しい問題のために向けるべき関心?

Slide 32

Slide 32 text

Most Developers realize that structured, maintainable code is important. via. Digesting JavaScript MVC https://speakerdeck.com/addyosmani/digesting-javascript-mvc?slide=10 ディベロッパーにとって、構造的で メンテナンスしやすいコードが何たるかを知ることが重要。 “

Slide 33

Slide 33 text

MV*なJavaScriptと アーキテクチャ云々 Backbone.jsについて

Slide 34

Slide 34 text

アーキテクチャと言えば 猫も杓子もMVC みんな1度は聞いたことあるはず

Slide 35

Slide 35 text

MVC since 1979 From: Trygve Reenskaug

Slide 36

Slide 36 text

古典 of Smalltalk Smalltalk(スモールトーク)は、Simulaのオブジェクト(およびクラス) Lispの機能、LOGOのエッセンスを組み合わせて作られたクラスベースの純粋 オブジェクト指向プログラミング言語、および、それによって記述構築された 統合化プログラミング環境の呼称。 via. Smalltalk - Wikipedia http://ja.wikipedia.org/wiki/Smalltalk

Slide 37

Slide 37 text

⚠ JavaScriptにおける MVCまたはMV*の現状 普及してるとは言いがたいが...

Slide 38

Slide 38 text

Todo MVC http://addyosmani.github.com/ todomvc/

Slide 39

Slide 39 text

Backbone.js AngularJS Ember.js KnockoutJS Dojo YUI Agility.js Knockback.js CanJS Maria cujo.js dermis Montage Ext.js Sammy.js Stapes Epitome soma.js DUEL PureMVC Olives PlastronJS Dijon rAppid.js Funnyface.js Spine Batman.js GWT Closure MVC Extension Frameworks MarionetteJS Thorax Chaplin 巷に溢れかえる MV*フレームワーク TodoMVCだけで30以上が列挙される

Slide 40

Slide 40 text

MV*なアーキテクチャは 身近になってきている MV*に限らず、色々考え出されている

Slide 41

Slide 41 text

Knockout http://knockoutjs.com/

Slide 42

Slide 42 text

batman.js http://batmanjs.org/

Slide 43

Slide 43 text

Ember.js http://emberjs.com/

Slide 44

Slide 44 text

AngularJS http://angularjs.org/

Slide 45

Slide 45 text

aura https://github.com/aurajs/aura

Slide 46

Slide 46 text

Flight http://twitter.github.com/ flight/

Slide 47

Slide 47 text

MV*に関した議論は 定期的に盛り上がる そして常に変化しつづけている

Slide 48

Slide 48 text

サバクラ両方で動く JavaScript の大規模 開発を行うために https://gist.github.com/tily/ 1362110

Slide 49

Slide 49 text

flatiron http://flatironjs.org/

Slide 50

Slide 50 text

おまえのMVCは 間違っている! おれは新しい パターンを作る!

Slide 51

Slide 51 text

このテの議論に 今回はあまり触れません Backbone的にも厳密すぎなくてOK

Slide 52

Slide 52 text

͸ɺ

Slide 53

Slide 53 text

厳格さと多機能で生産性を 担保する強いフレームワーク やさしい構造化を サポートする薄いライブラリ × ◎ です。

Slide 54

Slide 54 text

1500行あまりの軽いコード View Model Collection Router Controllerの不在 Not MVCフレームワーク 

Slide 55

Slide 55 text

“ it serves as a foundation for your application, you're meant to extend and enhance it in the ways you see fit 方法は1つではないし、柔軟に拡張できる via. Backbone.js FAQ http://backbonejs.org/#FAQ-why-backbone

Slide 56

Slide 56 text

MVCを気にしすぎることはない と、思います。 “

Slide 57

Slide 57 text

デザインパターンは 知っておいて損はない アーキテクチャと併せて意識したい

Slide 58

Slide 58 text

Abstract Factory Builder Factory Method Prototype Singleton Adapter Bridge Composite Decorator Facade Flyweight Proxy Chain of Responsibility Command Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor GoFに代表される 様々なデザインパターン 一般に共有できるボキャブラリ

Slide 59

Slide 59 text

⚠ しかし現実は 独自パターンが跋扈する Everyone have own pattern

Slide 60

Slide 60 text

デザインパターンから 一般的なパターンを学ぶ JSの例で、有名どころを少し紹介

Slide 61

Slide 61 text

JavaScript Design Patterns http://www.joezimjs.com/ javascript/javascript-design- patterns-singleton/

Slide 62

Slide 62 text

Facade 一番簡単な構造のパターン

Slide 63

Slide 63 text

{} Facade - 複数の処理をまとめる // ΫϦοΫͨ͠ͱ͖ʹෳ਺ͷૢ࡞Λಉ࣌ʹߦ͏ // ࠷΋޿ٛʹ͸୭΋͕͋ͨΓ·͑ʹߦ͏ύλʔϯ onLikeClick: function() { this.likeModel.save(); this.changeState(‘liked’); this.$el.addClass(‘animate’); // ... // .. // . }

Slide 64

Slide 64 text

Singleton/Flyweight 生成および構造のパターン

Slide 65

Slide 65 text

{} Singleton - ただひとつのオブジェクト // ؆қʹ͸ɺෆมతΦϒδΣΫτʹͳΔͨΊʹ // ίϯετϥΫλͳ͠ͰΦϒδΣΫτϦςϥϧͰදݱ var singletonClass = { init: function() { // initialize logic }, method: function() { // some logic } } singletonClass.init();

Slide 66

Slide 66 text

{} Flyweight - インスタンス生成 // ಈతʹΠϯελϯεΛ࡞Γ͍ͨ৔߹ͳͲ // ಉ͡໾ׂͷΠϯελϯε͸ෳ਺ੜ੒ͤͣ͞ʹ࢖͍ճ͢ var factory1 = Flyweight.getFactory('model'); var factory2 = Flyweight.getFactory('view'); var factory3 = Flyweight.getFactory('model'); // ظ଴͢Δಈ࡞ͱͯ͠ɺmodelͱͯ͠ݺΜͩΒಉҰͰ͋Δ͜ͱ console.log(factory1 === factory2); //=> false console.log(factory1 === factory3); //=> true

Slide 67

Slide 67 text

Observer/Mediator 振る舞いのパターン

Slide 68

Slide 68 text

{} Observer - イベントを監視 // ؂ࢹ͞ΕΔଆͷModelͱɺ؂ࢹ͢ΔଆͷView var model = new FooModel(); var view = new BarView(); // Modelʹ௚઀ɺViewͷϝιουΛϦεφʔͰొ࿥ model.on('change', view.render); // fetch()ʹΑͬͯɺchangeΠϕϯτ͕τϦΨʔ model.fetch(); // view.render()͕࣮ߦ͞ΕΔ

Slide 69

Slide 69 text

{} Mediator - イベントを仲介 // MediatorΛ࡞੒ʢBackboneͷྫʣ var mediator = _.clone(Backbone.Events); // MediatorʹϦεφʔΛొ࿥ mediator.on('model:change', view.render); // MediatorΛ௨ͯ͠ΠϕϯτΛτϦΨʔ mediator.trigger('model:change', this);

Slide 70

Slide 70 text

急に当てはめるのは 難しいことがほとんど 何らかの取っかかりが必要、そこで...

Slide 71

Slide 71 text

やさしい構造化を サポートするBackboneで パターンやアーキテクチャの 実践を始めてみると吉 ◎

Slide 72

Slide 72 text

jQuery to Backbone コードを構造化する 学ぶためのリファクタリング

Slide 73

Slide 73 text

Backbone.jsにおける コンポーネント View, Model, Collection, Router

Slide 74

Slide 74 text

 Backbone.View View 見た目とUIにおける入出力 DOM要素の管理 ユーザー操作(イベント)制御

Slide 75

Slide 75 text

{} 典型的なView var ViewClass = Backbone.View.extend({ el: ‘#main’, initialize: function() { // process... }, render: function() { this.$el.html(‘rendering html strings’); } }); var view = new ViewClass(); // `initalize` view.render(); // `render`

Slide 76

Slide 76 text

Backbone.Model Model 取り扱うデータの一単位 ストレージとの通信・同期 APIや情報のレコードを表現

Slide 77

Slide 77 text

{} 典型的なModel var ModelClass = Backbone.Model.extend({ defaults: {}, url: ‘api/v1/path/to’, initialize: function() { // process... } }); var model = new ModelClass(); // `initalize` var view = new ViewClass({model: model}); model.fetch({ success: view.render });

Slide 78

Slide 78 text

 Backbone.Collection Collection Modelが集合したリスト リスト操作...where, filterなど Modelと同様の通信・同期

Slide 79

Slide 79 text

{} 典型的なCollection var Persons = Backbone.Collection.extend({ url: ‘api/v1/path/to’, model: Person }); var persons = new Persons(); persons.fetch({ success: function() { this.where({ name: ‘anonymous’ })[0].sayName(); // ‘anonymous!’ } });

Slide 80

Slide 80 text

 Router Backbone.Router URLによるルーティング hashchange, pushstate 遷移処理のnavigate

Slide 81

Slide 81 text

{} 典型的なRouter var Router = Backbone.Router.extend({ routes: { 'store/:storeId': 'gotoStore' }, gotoStore: function(storeId) { new StoreView({ model: new Store(storeId); }); } }); var app = new Router(); Backbone.history.start();

Slide 82

Slide 82 text

Backbone  Router     Views Models Collection via. Backbonification - Migrating NewsBlur From DOM Spaghetti to Backbone.js https://speakerdeck.com/samuelclay/backbonification-migrating-newsblur-from-dom-spaghetti-to-backbone-dot-js?slide=12

Slide 83

Slide 83 text

Backbone.jsを 実際に使ってみる Viewの分離とメソッドの抽出  

Slide 84

Slide 84 text

GitHub APIを使った Gistビューワー 実用性はさておき、あくまでサンプル

Slide 85

Slide 85 text

DEMO 1.Backbone.Viewを作成 2.renderメソッドを抽出 3.テンプレートの分離 4.イベントの定義 

Slide 86

Slide 86 text

{} ピュアなjQueryコードからスタート var $list = $('#js-gists'); $.ajax({ method: 'GET', url: 'https://api.github.com/gists', data: oauthData, dataType: 'json' }).done(function(data) { var i = 0, html = '', item; while (item = data[i++]) { html += '
  • '+ ''+item.description+''+ 'Show in gists'+ '
  • '; } $list.html(html); }); $list.on('click', '[data-src]', previewGist);

    Slide 87

    Slide 87 text

    {} おもむろにViewを作成 var GistsListView = Backbone.View.extend({ el: '#js-gists', initialize: function() { var $list = this.$el; $.ajax({ method: 'GET', url: 'https://api.github.com/gists', data: oauthData, dataType: 'json' }).done(function(data) { var i = 0, html = '', item; while (item = data[i++]) { html += '
  • '+ ''+item.description+''+ 'Show in gists'+ '
  • '; } $list.html(html); }); $list.on('click', '[data-src]', previewGist); } }); var gistsList = new GistsListView();

    Slide 88

    Slide 88 text

    {} renderメソッドを抽出 var GistsListView = Backbone.View.extend({ el: '#js-gists', initialize: function() { _.bindAll(this); $.ajax({ method: 'GET', url: 'https://api.github.com/gists', data: oauthData, dataType: 'json' }).done(this.render); this.$el.on('click', '[data-src]', previewGist); }, render: function(data) { var i = 0, html = '', item; while (item = data[i++]) { html += '
  • '+ ''+item.description+''+ 'Show in gists'+ '
  • '; } this.$el.html(html); return this; } }); var gistsList = new GistsListView();

    Slide 89

    Slide 89 text

    {} テンプレートの分離 var GistsListView = Backbone.View.extend({ el: '#js-gists', tmpl: _.template($('#tmpl-js-gists').html()), initialize: function() { _.bindAll(this); $.ajax({ method: 'GET', url: 'https://api.github.com/gists', data: oauthData, dataType: 'json' }).done(this.render); this.$el.on('click', '[data-src]', previewGist); }, render: function(data) { this.$el.html(this.tmpl({items: data})); return this; } }); var gistsList = new GistsListView();

    Slide 90

    Slide 90 text

    {} Underscoreテンプレート <% _.each(items, function(item) { %> <li> <a data-id="<%= item.id %>" data-src="<%= item.url %>"> <%= item.description %> </a> <a href="<%= item.html_url %>">Show in gists</a> </li> <% }); %>

    Slide 91

    Slide 91 text

    {} イベントの定義 var GistsListView = Backbone.View.extend({ el: '#js-gists', tmpl: _.template($('#tmpl-js-gists').html()), events: { 'click [data-src]': previewGist }, initialize: function() { _.bindAll(this); $.ajax({ method: 'GET', url: 'https://api.github.com/gists', data: oauthData, dataType: 'json' }).done(this.render); }, render: function(data) { this.$el.html(this.tmpl({items: data})); return this; } }); var gistsList = new GistsListView();

    Slide 92

    Slide 92 text

    コンポーネントで 分割すれば構造化される 自然とTestableなコードにもなる

    Slide 93

    Slide 93 text

    モジュラーなJavaScript 依存性の低さによる変更のしやすさ 個々が独立していることによる交換のしやすさ 継続的なメンテナンスのしやすさ リファクタリングとテスト ■  ➡

    Slide 94

    Slide 94 text

    大きな現実 小さな実装 細かい実装を構造化して現実の要件へ ⤢

    Slide 95

    Slide 95 text

    Modelと Collectionの利用 GitHub APIの関連処理を抽出 

    Slide 96

    Slide 96 text

    Model Collection Gist Gists

    Slide 97

    Slide 97 text

    DEMO ModelとCollection 

    Slide 98

    Slide 98 text

    {} Collectionを作成 var Gists = Backbone.Collection.extend({ url: 'https://api.github.com/gists?' + $.param(oauthData) }); var GistsListView = Backbone.View.extend({ el: '#js-gists', tmpl: _.template($('#tmpl-js-gists').html()), events: { 'click [data-src]': 'preview' }, initialize: function() { _.bindAll(this); this.collection.fetch({ success: this.render }); }, render: function() { this.$el.html(this.tmpl({items: this.collection.toJSON()})); return this; } }); var gistsList = new GistsListView({ collection: new Gists() });

    Slide 99

    Slide 99 text

    {} Modelを作成 // Model & Collection var Gist = Backbone.Model.extend({ url: function() { return this.get('url'); } }); var Gists = Backbone.Collection.extend({ url: 'https://api.github.com/gists?' + $.param(oauthData), model: Gist }); // GistListView#preview preview: function(event) { gistPreview.model = this.collection.where({ id: $(event.currentTarget).attr('data-id') })[0]; gistPreview.show(); return false; },

    Slide 100

    Slide 100 text

    {} Collectionのソート var Gists = Backbone.Collection.extend({ url: 'https://api.github.com/gists?' + $.param(oauthData), model: Gist, order_by: 'updated_at', comparator: function(gist) { switch(this.order_by) { case 'updated_at': return - new Date(gist.get('updated_at')).getTime(); } } }); // GistListView events: { 'click #js-sort-updated': 'sortByUpdatedAt', }, initialize: function() { _.bindAll(this); this.collection.fetch({success: this.render}); this.collection.on('sort', this.render); }, sortByUpdatedAt: function() { this.collection.order_by = 'updated_at'; this.collection.sort(); },

    Slide 101

    Slide 101 text

     ライブラリの利用強度と パフォーマンス ぶっちゃけパフォーマンスに影響は?

    Slide 102

    Slide 102 text

    jQueryにも言えるが 使い方によっては簡単に重くなる // ϧʔϓ಺Ͱappend͢ΜͳɺຖճηϨΫλ૸ΒͤΜͳ!! $.each(persons, function(person) { $(‘ul’).append(‘
  • ’+person.name+’
  • ’); });

    Slide 103

    Slide 103 text

    パフォーマンスを考えて 慎重に使うことが重要 ライブラリの努力を無駄にしないため

    Slide 104

    Slide 104 text

    まとめ より良い学びのために、その他

    Slide 105

    Slide 105 text

    アーキテクチャを 考えるためのBackbone 学習手段としてのライブラリ

    Slide 106

    Slide 106 text

    Backbone has made me a better programmer via. Backbone has made me a better programmer | Float Left http://floatleft.com/notebook/backbone-has-made-me-a-better-programmer “

    Slide 107

    Slide 107 text

    フルスタックでないので 学習コストは低い もちろんデフォルトの機能は限られる

    Slide 108

    Slide 108 text

    良い習慣のために とりあえず分けてみる 「ものはためし」が一番大事

    Slide 109

    Slide 109 text

    ライブラリの利用が 学習につながる フレームワークで言語に入る例もある

    Slide 110

    Slide 110 text

    RequireJS http://requirejs.org/

    Slide 111

    Slide 111 text

    Dependencies? AMD? 勉強会資料シェア Getting Started with RequireJS http://havelog.ayumusato.com/develop/javascript/e525-into_requirejs.html

    Slide 112

    Slide 112 text

    to から with へ Backbone with jQuery あらためて次の関心へ

    Slide 113

    Slide 113 text

    アーキテクチャや デザインパターンは 手を動かしてみるのが一番 自分で良い方法を選んで 書けるようになるのが これから大事になる(と思う)

    Slide 114

    Slide 114 text

    参考リソース 手を動かすときのお供に

    Slide 115

    Slide 115 text

    en.ja OSS Backbone 日本語訳 https://github.com/enja-oss/ Backbone/

    Slide 116

    Slide 116 text

    Developing Backbone.js Applications http://addyosmani.github.com/ backbone-fundamentals/

    Slide 117

    Slide 117 text

    Advent Calendar http://www.adventar.org/ calendars/15

    Slide 118

    Slide 118 text

    その他の 参考情報 http://havelog.ayumusato.com/ develop/javascript/e544- backbone_learning_resources.html

    Slide 119

    Slide 119 text

    最後に派生ライブラリ There's More Than One Way To Do It 用途に合わせて拡張された具体例

    Slide 120

    Slide 120 text

    Marionette http://marionettejs.com/

    Slide 121

    Slide 121 text

    Chaplin http://chaplinjs.org/

    Slide 122

    Slide 122 text

    Thorax http://thoraxjs.org/

    Slide 123

    Slide 123 text

    Vertebrae https://github.com/ pixelhandler/vertebrae

    Slide 124

    Slide 124 text

    ぼくのかんがえた さいきょうの... 凝ったロジックと新たな複雑性の罠

    Slide 125

    Slide 125 text

    悪いこと? だれもが考える

    Slide 126

    Slide 126 text

    学習目的であれば とても良い手段 他と比較しながら、作って理解する

    Slide 127

    Slide 127 text

    Deciding good approach by yourself Become Frontend ROCKSTAR

    Slide 128

    Slide 128 text

     JavaScript Development Tools jQuery Performance Tips Testable Javascript JavaScript Architecture

    Slide 129

    Slide 129 text

    キャッチアップはつづく! Architecture / Modular Dependency / AMD Promises / FlowControl Build / Package Management Testing / Refactoring etc...

    Slide 130

    Slide 130 text

    No content

    Slide 131

    Slide 131 text

    Thank you! おしまい http://aho.mu @ahomu github.com/ahomu   ⌂

    Slide 132

    Slide 132 text

    1. Two equestrian riders, girls on horseback, in low tide reflections on serene Morro Strand State Beach http://www.flickr.com/photos/ mikebaird/2985066755 2. Energy Drinks - Monster, Red Bull and Rockstar http://www.flickr.com/ photos/aukirk/8170825503 3. - Good Friends http://www.flickr.com/photos/ngmmemuda/4166182931 4. Rhino relaxation http://www.flickr.com/photos/macinate/2810203599 5. Whale backbone http://www.flickr.com/photos/vagawi/2257918524/ 6. Sleeping 猫 http://www.flickr.com/photos/hansel5569/7687221498/ 7. Alien vs Predator http://www.flickr.com/photos/steampirate/ 1056958115/ Photo Credits...thx♡