pragmatic patterns of ruby on rails - ruby kaigi2009

Post on 19-Jan-2015

10.771 Views

Category:

Documents

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

RubyKaigi2009

株式会社万葉

Pragmatic Patternsof Ruby on Rails

2009.7.17Yasuko OHBA(大場寧子)

現場で役立つ Ruby on Rails パターン

RubyKaigi2009

株式会社万葉

自己紹介what I do

• developer of Rails applicationsRailsアプリケーションを開発

•Akasaka.rb• Everyleaf Corporation株式会社万葉

提供

株式会社万葉Everyleaf Corp.

RubyKaigi2009

株式会社万葉

スポンサーブースsponsor booth

• first time to be a sponsorはじめてのスポンサー

• we serve candies飴あります

• you can play ‘Romantic Ruby’ !ギャルゲーあります

RubyKaigi2009

株式会社万葉

作ってるものmy products

• home accounting web serviceWeb家計簿「小槌」http://www.kozuchi.net

• http://github.com/everyleaf/kozuchi/tree

株式会社万葉

RubyKaigi2009

iCarta

株式会社万葉

RubyKaigi2009

Ruby on Rails逆引きクイックリファレンス

株式会社万葉

RubyKaigi2009

伝えたいこと

personal message

株式会社万葉

RubyKaigi2009

中学生くらいからプログラミング

I started programming when I

was 14 years old

株式会社万葉

RubyKaigi2009

女子校

school for girls

株式会社万葉

RubyKaigi2009

孤独なプログラマ

I was alone

株式会社万葉

RubyKaigi2009

就職

got the job

株式会社万葉

RubyKaigi2009

似た人々と出会う

find similar people

株式会社万葉

RubyKaigi2009

でも

however

株式会社万葉

RubyKaigi2009

エンタープライズ

‘enterprise’

株式会社万葉

RubyKaigi2009

社外に出ない

only activitiesinside the company

株式会社万葉

RubyKaigi2009

見積もりマネージメントアウトソージング

other things mount up

株式会社万葉

RubyKaigi2009

どうしたらいいのか

I was lost

株式会社万葉

RubyKaigi2009

実装がしたい

want to write codes

株式会社万葉

RubyKaigi2009

そんな時that’s when..

株式会社万葉

RubyKaigi2009

Rubyに出会った

Ruby was given

株式会社万葉

RubyKaigi2009

人生変わった(^o^)/

life becomes happier

株式会社万葉

RubyKaigi2009

Rubyでエンタープライズ

Ruby for enterprises

株式会社万葉

RubyKaigi2009

実装してて幸せになる道

the way to live happily writing codes

株式会社万葉

RubyKaigi2009

そして

And...

株式会社万葉

RubyKaigi2009

素晴らしいコミュニティ

great communities

株式会社万葉

RubyKaigi2009

仲間ができた

many friends

株式会社万葉

RubyKaigi2009

ありがとう!thank you !!

株式会社万葉

RubyKaigi2009

本題

today’s presentation

株式会社万葉

RubyKaigi2009

実装パターン

coding patternswith

Ruby on Rails

RubyKaigi2009

株式会社万葉

ターゲットthe target

• large & complicated applications複雑で大きなアプリ

•teamチームでの開発

RubyKaigi2009

株式会社万葉

大きなアプリの課題

problems of large applications

•different coding styles書き方がバラバラ

•nasty parts made品質が揃っていない

株式会社万葉

RubyKaigi2009

メンテナンスしにくくなる

becomes harderto maintenance

株式会社万葉

RubyKaigi2009

コードをいい状態に保つ

keep your codes nice

RubyKaigi2009

株式会社万葉

いいコードとは?• good designいい設計

• easy to understand読みやすい、わかりやすい

• easy to find something wrong 間違いにすぐ気づく

what is the ‘nice code’?

RubyKaigi2009

株式会社万葉

そこで、パターン

• make and share coding patterns共通パターンを作る

• add some DSL (not too much)DSLを作る(控えめに)

coding patterns work fine

株式会社万葉

RubyKaigi2009

もちろん効率も上がる

efficient, of course

RubyKaigi2009

株式会社万葉

このプレゼンで触れないことwhat I won’t say

• how to get the best performance極限のパフォーマンスの追求

• ActiveRecord’s alternativesAR以外のDB層の選択肢

株式会社万葉

RubyKaigi2009

O/R Mapper

ActiveRecord

株式会社万葉

RubyKaigi2009

て言うか、

frankly speaking,

株式会社万葉

RubyKaigi2009

ActiveRecord大好き

I love ActiveRecord

株式会社万葉

RubyKaigi2009

なぜなら

because

株式会社万葉

RubyKaigi2009

オブジェクト指向で書ける

OOP

株式会社万葉

RubyKaigi2009

複雑さに耐えられる

still able to maintenancewhen it gets complicated

株式会社万葉

RubyKaigi2009

実用的

pragmatic

株式会社万葉

RubyKaigi2009

Railsの中核

the heart of RoR

株式会社万葉

RubyKaigi2009

ActiveRecordを中心に話します

many AR features in this presentation

株式会社万葉

RubyKaigi2009

実例紹介

examples

株式会社万葉

RubyKaigi2009

権限のあるデータの表示

show permitted data

要件 ①

株式会社万葉

RubyKaigi2009

ARオブジェクトから始める検索

find starts froman AR object

パターン ①

株式会社万葉

RubyKaigi2009

IDでNoteを検索find a note by id

/note/3

def show @note = Note.find(params[:id])end

株式会社万葉

RubyKaigi2009

ログインユーザーのNoteを検索

find a note of the current user

@note = Note.find_by_id_and_user_id( params[:id], current_user.id)raise ActiveRecord::RecordNotFound unless @note

/note/3

株式会社万葉

RubyKaigi2009

restful_authentication

current_user?

株式会社万葉

RubyKaigi2009

named scope?

@note = Note.written_by( curret_user.id).find(params[:id])

/note/3

株式会社万葉

RubyKaigi2009

条件を忘れても気づきにくい

hard to notice the luck of condition!

@note = Note.find(params[:id])@note = Note.find_by_id_and_user_id( params[:id], current_user.id)@note = Note.written_by( current_user).find(params[:id])

株式会社万葉

RubyKaigi2009

そこで

so,

株式会社万葉

RubyKaigi2009

ARオブジェクトから始める検索

find starts froman AR object

pattern ①

株式会社万葉

RubyKaigi2009

オブジェクト起点で検索

starts from an object

def show @note = current_user.notes.find( params[:id])end

株式会社万葉

RubyKaigi2009

関連を使う

use the association

def show @note = current_user.notes.find( params[:id])end

株式会社万葉

RubyKaigi2009

関連

association

class User < ActiveRecord::Base has_many :notesend

株式会社万葉

RubyKaigi2009

問題に気づきやすい

easy to notice problems

@note = current_user.notes.find( params[:id])

@note = Note.find(params[:id])

株式会社万葉

RubyKaigi2009

データの権利者が一目でわかる

easy to see who can access

株式会社万葉

RubyKaigi2009

データの権利者

who can access

@note = current_user.notes.find( params[:id])

株式会社万葉

RubyKaigi2009

ARオブジェクトを得るFilter

filters to find the starting AR object

pattern ②

株式会社万葉

RubyKaigi2009

さっきのパターンで書くと

with the previouspattern

株式会社万葉

RubyKaigi2009

コントローラのアクションの多くの

起点が揃う

most actions willuse the AR object

株式会社万葉

RubyKaigi2009

例)グループのノートのCRUD

example;CRUD of the specified

group’s notes

RubyKaigi2009

株式会社万葉

URL

•ノートの帰属するグループがURL

の前に付く• /groups/15/notes• /groups/15/notes/3

RubyKaigi2009

株式会社万葉

class Note < ActiveRecord::Base belongs_to :groupend

Model• Note has group_idNoteが group_id を持つ

class Group < ActiveRecord::Base has_many :notesend

株式会社万葉

RubyKaigi2009

Controllerdef index @group = Group.find(params[:group_id]) @notes = @group.notes.paginate(:page => params[:page])enddef show @group = Group.find(params[:group_id]) @note = @group.notes.find(params[:id])end

株式会社万葉

RubyKaigi2009

重複したコード

the duplicated line

@group = Group.find(params[:group_id])

株式会社万葉

RubyKaigi2009

Filterで記述する

write that linein a filter

RubyKaigi2009

株式会社万葉

Filterとは?what’s the filter?

• the separated logic which would be called around actionアクションの前後に行いたい処理をアクションとは別に記述

• declarative宣言的

株式会社万葉

RubyKaigi2009

class GroupNotesController < ApplicationController

before_filter :find_group .......actions ...... private def find_group @group = Group.find(params[:group_id]) endend

Filterで@groupを得るfind the group in a filter

株式会社万葉

RubyKaigi2009

重複を避けられるDRY

before_filter :find_groupdef index @notes = @group.notes.paginate(:page => params[:page])enddef show @note = @group.notes.find(params[:id])end

株式会社万葉

RubyKaigi2009

アクセス制限を変えるのも楽

easy to changeaccess control

株式会社万葉

RubyKaigi2009

例) メンバーしか見られないようにする

example; change to allow access to members only

def find_group @group = current_user.groups.find( params[:group_id]end

株式会社万葉

RubyKaigi2009

それだけじゃない

other merits

株式会社万葉

RubyKaigi2009

securegroupでの

絞り込みを確実に

株式会社万葉

RubyKaigi2009

@groupで始まれば安心safe if it starts from @group

def index @notes = @group.notes.paginate(:page => params[:page])enddef show @note = @group.notes.find(params[:id])end

株式会社万葉

RubyKaigi2009

filter urges developersto use @group

Filterがあれば自然な強制力が

働く

株式会社万葉

RubyKaigi2009

and

さらに

株式会社万葉

RubyKaigi2009

読みやすい

readable

株式会社万葉

RubyKaigi2009

コントローラ名とFilterで

概要が分かる

you can understandthe controller’s summary

from name and filters

株式会社万葉

RubyKaigi2009

さっと把握できる

understand the summaryquickly

class GroupNotesController < ApplicationController before_filter :find_group

RubyKaigi2009

株式会社万葉

大事なことthe points

•a good controller name良いコントローラ名

•readable filters読みやすいフィルター

株式会社万葉

RubyKaigi2009

複雑なビジネスロジック

complicatedbusiness logics

要件 ②

株式会社万葉

RubyKaigi2009

ビジネスロジックはモデルに書きたい

want to writebusiness logics

in models

株式会社万葉

RubyKaigi2009

なぜなら

because

RubyKaigi2009

株式会社万葉

モデルに集めると嬉しい点

merits of writing business logics in models

• easy to testテストしやすい

• easy to reuse再利用しやすい

• readable, easy to find the target codesコードが分散せず、読みやすい

株式会社万葉

RubyKaigi2009

しかし

however

株式会社万葉

RubyKaigi2009

集め方が問題

‘how’ matters a lot

株式会社万葉

RubyKaigi2009

悪い例a bad example

class MyModel < ActiveRecord::Base def do_create(params) .... def do_destroy(params) ...end

RubyKaigi2009

株式会社万葉

どこが悪いか?why is it bad ?

• it breaks MVCMVCを壊している

• hard to reuse再利用性が低い

株式会社万葉

RubyKaigi2009

そこでnow

株式会社万葉

RubyKaigi2009

コントローラからモデルへ

うまくコードを移してみましょう

let’s move codesfrom controller to model

in good way

株式会社万葉

RubyKaigi2009

パラメータによる分岐ロジックの

移動

move the logicbranching on parameters

from C to M

pattern ③

株式会社万葉

RubyKaigi2009

パラメータによる処理の分岐branching on parameters

def update @note.attributes = params[:note] @tags = params[:auto_tagging] == '1' ? generate_tags(@note) : []

# do saving and tagging ...end

株式会社万葉

RubyKaigi2009

コントローラに書きがち

often written in controller

株式会社万葉

RubyKaigi2009

モデルに持っていくには

to move to model

株式会社万葉

RubyKaigi2009

制御条件をモデルの属性に

add an attribute for branching to the model

株式会社万葉

RubyKaigi2009

分岐条件

the condition

params[:auto_tagging] == '1'

株式会社万葉

RubyKaigi2009

モデルの属性にas an attribute of the model

class Note < ActiveRecord::Base attr_accessor :auto_tagging

end

株式会社万葉

RubyKaigi2009

パラメータ構造を変える

change parameters structure

{ :note => {.....}, :auto_tagging => '1' }

{ :note => { ....., :auto_tagging => '1' }}

株式会社万葉

RubyKaigi2009

そのためにビューでフィールド名を変更

change the view for it

<%= check_box_tag :auto_tagging %>

<% form_for :note, ... do |f |%> <%= f.check_box :auto_tagging %><% end %>

株式会社万葉

RubyKaigi2009

params[:note]で渡せるnow it’s in params[:note]

def update @note.attributes = params[:note] if params[:auto_tagging] == '1' generate_tags(@note) end .....

株式会社万葉

RubyKaigi2009

モデルで分岐できる

can branch in the model

class Note < ActiveRecord::Base .... if auto_tagging ... endend

株式会社万葉

RubyKaigi2009

分岐は移動できた

finished to movebranching

株式会社万葉

RubyKaigi2009

残るはgenerate_tagsロジックの移動

move generate_tags next

株式会社万葉

RubyKaigi2009

付随する他モデルへの処理

の移動

move the logic processing other models

from C to M

pattern ④

株式会社万葉

RubyKaigi2009

付随する他モデルへの処理def update generate_tags(@note)endprivatedef generate_tags(note) tags = Tag.extract(note.body) note.tag_list = tags.join(',')end

the logic processing other models

株式会社万葉

RubyKaigi2009

これもコントローラに

書きがち

also often written in controller

株式会社万葉

RubyKaigi2009

モデルのコールバックへput it into model’s callback

class Note < ActiveRecord::Base before_save :generate_taggings

private def generate_taggings return unless auto_tagging tags = Tag.extract(body) self.tag_list = tags.join(',') endend

RubyKaigi2009

株式会社万葉

モデルのコールバックとは?

what’s the model’s callback?

• methods called before/after save or destroysaveやdestroyなどの前後に呼び出される処理

RubyKaigi2009

株式会社万葉

Rails Model You

normal method call普通のメソッド呼び出し

savesave(validation)

before_save

after_save

do saving

株式会社万葉

RubyKaigi2009

自律的なモデル

self-directive models

RubyKaigi2009

株式会社万葉

目標を達成!now we’ve done it !

• easy to testテストしやすい

• easy to reuse再利用しやすい

• readable, easy to find the target codesコードが分散せず、読みやすい

RubyKaigi2009

株式会社万葉

話せなかったことother patterns

• multi levels for validation多レベルの検証

• design & coding policy for STISTIの原則

• use owner object’s attributes in association関連オブジェクトに属性情報を伝える

• how to make routes.rb a little readableroutes.rb の整理

株式会社万葉

RubyKaigi2009

最後に

the last topic

株式会社万葉

RubyKaigi2009

Rails実装パターンの見い出し方

how to findcoding patterns

株式会社万葉

RubyKaigi2009

私の場合

in my case

株式会社万葉

RubyKaigi2009

Railsの中で自然に感じる書き方の追究

try to choosethe most natural style

for RoR

株式会社万葉

RubyKaigi2009

Railsにおいて何が自然か

what is the most natural way

in Ruby on Rails?

株式会社万葉

RubyKaigi2009

1. オブジェクト指向

1. OOP

株式会社万葉

RubyKaigi2009

ビジネスロジックをモデルとして表現

express business logics as models

株式会社万葉

RubyKaigi2009

誰のすべき仕事かにこだわる

always think who should do that job

株式会社万葉

RubyKaigi2009

Note or User ?

@note = Note.find_by_id_and_user_id( params[:id], current_user.id)

@note = current_user.notes.find( params[:id])

株式会社万葉

RubyKaigi2009

必ずしもテーブルで決めない

you can’t always decide it from tables

株式会社万葉

RubyKaigi2009

オブジェクトの世界の中で決める

decide it in objects world

株式会社万葉

RubyKaigi2009

2. 原則に従う

2. follow the principles of RoR

RubyKaigi2009

株式会社万葉

Railsの原則principles of RoR

•DRY•CoC•RESTful

株式会社万葉

RubyKaigi2009

RESTful

株式会社万葉

RubyKaigi2009

RailsではRESTfulから逃げない方がいい

accept RESTfulin Ruby on Rails

株式会社万葉

RubyKaigi2009

コントローラをどう分けるか?

how to designcontrollers ?

株式会社万葉

RubyKaigi2009

“RESTful”

株式会社万葉

RubyKaigi2009

対象リソース1種類に

1つのコントローラ

one controller fora type of resources

株式会社万葉

RubyKaigi2009

リソースって何だ?

what’s the resources?

株式会社万葉

RubyKaigi2009

URLで示される

you can find it in URL

/companies/everyleaf/notes/3

株式会社万葉

RubyKaigi2009

コントローラの設計は

design of controllers

株式会社万葉

RubyKaigi2009

URL設計から始める

starts from design of URLs

株式会社万葉

RubyKaigi2009

ざっくり

roughly speaking,

株式会社万葉

RubyKaigi2009

Resourceリソース

Model Classモデルクラス

1

1..*

株式会社万葉

RubyKaigi2009

重要なのは

the point is...

株式会社万葉

RubyKaigi2009

複数リソースのCRUDはまずい

one controller shouldprovide one resource

type’s CRUD

株式会社万葉

RubyKaigi2009

こういうのはまずいmight have been derailed

class BlogsController < ApplicationController

def create_comment end def comments end def destroy_comment ...

株式会社万葉

RubyKaigi2009

もうひとつ

one more

株式会社万葉

RubyKaigi2009

モデルの基本的な流れに乗せる

write codes in model’s standard flows

RubyKaigi2009

株式会社万葉

standard flows

•find•new → save (create)•find → save (update)•find → destroy

標準的な流れの種類

株式会社万葉

RubyKaigi2009

流れの中身

inside of a flow

株式会社万葉

RubyKaigi2009

例) createnewbuild

attribute =属性代入

before_validation

validation検証

after_validation

before_save

creation作成処理 after_save

株式会社万葉

RubyKaigi2009

適切な場所に書く

write codes inappropriate place

株式会社万葉

RubyKaigi2009

newbuild

attribute =属性代入

before_validation

validation検証

after_validation

before_save

creation作成処理 after_save

where, what

株式会社万葉

RubyKaigi2009

Railsの中で自然に感じる書き方の追究

try to choosethe most natural style

for RoR

株式会社万葉

RubyKaigi2009

基本的な書き方から大きく離れない

don’t go too farfrom the basic styles

株式会社万葉

RubyKaigi2009

そうすれば

because

株式会社万葉

RubyKaigi2009

Railsプログラマにとって標準的

it’s normal to Rails programmers

株式会社万葉

RubyKaigi2009

誰でも読める

easy to readfor everyone

株式会社万葉

RubyKaigi2009

そのためには

for that purpose

株式会社万葉

RubyKaigi2009

Rubyの柔軟性を活用する

use Ruby’s flexibility

株式会社万葉

RubyKaigi2009

まとめ

summary

株式会社万葉

RubyKaigi2009

複雑で大きなアプリでは

in developinglarge & complicated

application

株式会社万葉

RubyKaigi2009

コードをいい状態に保つのが大事

it’s importantto keep codes nice

株式会社万葉

RubyKaigi2009

そのために

for that purpose

株式会社万葉

RubyKaigi2009

実装パターンを意識して共有しよう

be aware of coding patterns,

and share them

株式会社万葉

RubyKaigi2009

Railsでの自然な書き方を

目指せば

coding patternsfitting Ruby on Rails

株式会社万葉

RubyKaigi2009

読める人の多いコードができる

make source codes easy to read for

general developers

株式会社万葉

RubyKaigi2009

メンテナンスできる

it meanseasy to maintain

株式会社万葉

RubyKaigi2009

ご静聴ありがとうございました

thank you !

top related