Shibuya.rb に初参加してきた。
なんかもう救えないくらい使えない俺ですが、勇気を出して勉強会*1に飛び込んできました。*2
おじゃましたのは、渋谷.rb[:20130320](拡大版)。
会場はVOYAGE GROUPさん、祝日開催ということで14時からでした。
当日の形式
全体の構成は
- セッション1
- セッション2
- LT大会
- 懇親会
という形式でした。
俺はセッション1で「テストの書き方」、セッション2で「gemの作り方」に参加しました。
セッション1:テストの書き方
RSpec Bookは一通り読んで単体テストくらいなら書けるものの、TDDな感じで開発できないので参加。
具体的な書き方等の話はあまりなかったが、「Rails4からはminitestだよー」とか「RailsのControllerテスト書いてる人は実は少ない」とか「Cucumberの代わりにTurnipとかあるよー」とか知れて良かった。
セッション2:gemの作り方
セッション1の時間に漏れ聞こえてきた内容(「kaminariのコードを読むべき!」とか)が面白そうだったので参加しましたが、セッション1の時とは参加者が一変していたため、もくもくgemを作るという内容になって、そこはちょっと残念だった。
しかし、「え? 1時間でgem作るの??」ってなって、テキトーなgem書いてみたところ、思っていたより使えそうなものが出来たので「少しでも再利用しそうなコードはもっと積極的にgemで書いていってもいいのかもしれない」と思えた。*4
これは地味に大きい収穫かも。
ちなみに、kaminariは近々自力で読んでみる予定。
個人的にもお世話になっているし。
LT大会
2回のセッション後、LT大会がありました。
東京Ruby会議10のときも思ったんですが、みなさん、しゃべるのが上手い。*5
自分もLTできるようになりたいというのもひとつのモチベーションかなー、と。
懇親会
実は、一番勇気を出したのがココ。
隅のほうでずっと縮こまってるんじゃないかと危惧してたんですが、いろんな方が声をかけて下さったので、非常に楽しかったです。*6
他の地域.rbの話を聞いたり、まどマギ観たり*7、楽しくも有意義な時間でした。
その他雑感
- 東京Ruby会議10もそうだったが、9割以上Macユーザー。
- 今度からは電源タップを持って行こう。
- VOYAGE GROUPさんのオフィス素敵すぎ。
まとめ
俺のようなしょぼい人間にとっての勉強会のメリットは大きく2つあると思います。
知らない技術を知ることができる
普段は主にGoogle先生にいろいろ教えてもらってるわけですが、Google先生はpull型の教え方をしてくれる先生なので、自分が調べようとも思わないことは基本的には教えてくれない。
一方、勉強会に参加すると、「turnipっていうのがあって〜」とかpush型の教え方をしてくれるので、「知らないこと」を教えてくれます。
時間の都合もあるので詳細な解説などはされないことが多いですが、詳細はGoogle先生に教えてもらえるので、キーワードを拾っておくだけでも勉強になります。
モチベーションが上がる
俺のような人間が勉強会に出ると「俺しょぼすぎる!」ってなります。
そして、同時に「あの人すげー!」ってなります。
「俺しょぼすぎる」+「あの人すごい」=「あの人みたいになりたい」
上手く言語化できないのですが、このモチベーション向上は非常に大きい。
ある意味、これはしょぼい人間の特権な気がします。
自分のレベルが低いからこそ上に引っ張ってもらえる、みたいな。
ネトゲで高レベルパーティに混ぜてもらう、みたいな。*8
俺のようなチキンにとって、未知のコミュニティに飛び込んでいくのはかなり怖いことです。
しかし、本当に怖いのは何もしないまま、何も出来ない人間になることだと思います。
人間賛歌は「勇気」の賛歌ッ!!
人間のすばらしさは勇気のすばらしさ!!
――ウィル・A・ツェペリ
恐れていては何もできん。あらゆる局面において重要となるのは、不安定な勝算に賭け、不確定な未来へと自らを投げ込める自己への信頼・一足の内面的跳躍、つまり「わずかな勇気」だ。
――エヴァンジェリン・A・K・マクダウェル
もし、俺のように二の足を踏んでいる人がいたら、とりあえず行ってみればいいと思います。
技術力がないからといってdisられたりしません。*9
長々と書きましたが、3行でまとめるとこんな感じです。
- 勇気を出して飛び込んでみるべき。
- モチベーションの向上が非常に大きなメリット。
- 懇親会にこそ出席するべき。
ホント、ぐだぐだでごめんなさい。*10
EmacsをRuby/Rails/RSpec向けに設定してみる
動機
RailsでRSpecを使っていて、「アプリケーションコードとspecファイルを行き来するのめんどくせー!」ってなった。*1
そこで、調べてみたところ、emacsにはrspec-modeなるものがあり、上記の不満を解決してくれそうだったので設定してみることにした。
はじめに
ユーザーごとのEmacsの設定ファイルは~/.emacsにあります。*3
また、拡張機能*4のインストール先はどこでもいいのですが、今回は~/.emacs.d/elispを使うことにし、Emacsからのload-pathを通しておきます。
$ mkdir ~/.emacs.d/elisp
;; ~/.emacs (setq load-path (cons "~/.emacs.d/elisp" load-path))
ELPA
EmacsにはELPA(Emacs Lisp Package Archive)が存在します。*5
Emacsのカスタマイズを簡単に行うために、まずはELPAを入れていきます。*6
参考
auto-installのインストール
ELPAがauto-installという拡張機能に依存しているので、まずはauto-installを入れます。*7
$ cd ~/.emacs.d/elisp $ curl -O http://www.emacswiki.org/emacs/download/auto-install.el
次に、今入れたauto-install関連の設定をします。
ところどころ、シングルクォートが閉じられてなくて気持ち悪いですが、動きます。*8
;; ~/.emacs ;;auto-installの設定 (when(require 'auto-install nil t) ;;インストールディレクトリを設定する (setq auto-install-directory "~/.emacs.d/elisp/") ;;EmacsWikiに登録されているelispの名前を取得する (auto-install-update-emacswiki-package-name t) ;;install-elispの関数を利用可能にする (auto-install-compatibility-setup) )
ここまででauto-installのインストール及び設定ができたはずです。
ELPAのインストール
それでは、ELPAを入れていきます。
Emacsを起動して、
M-x install-elisp RET http://bit.ly/pkg-el23 RET
すると、冒頭に
;;; package.el --- Simple package system for Emacs ;; Copyright (C) 2007-2011 Free Software Foundation, Inc.
とか書かれた長いElispファイルが表示されるので、C-c C-cで保存します。
さっきと同じように設定します。
;; ~/.emacs ;;package.elの設定 (when (require 'package nil t) ;;パッケージリポジトリを追加 (add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/")) (add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t) (add-to-list 'package-archives '("ELPA" . "http://tromey.com/elpa/")) ;;インストールするディレクトリを指定 (setq package-user-dir(concat user-emacs-directory "elpa")) ;;インストールしたパッケージにロードパスを通して読み込む (package-initialize) )
以上でELPAのインストールが完了します。
拡張機能のインストール
便利な拡張機能たち
カッコ内はmode-lineに表示されるmode名。
ruby-mode(ruby)
ruby-modeはデフォルトで入っていますが、Rakefileにruby-modeが適用されないのでそれを修正。
;; ~/.emacs (add-to-list 'auto-mode-alist '("Rakefile$" . ruby-mode))
ruby-electric(REl)
do endや{}などのブロックを閉じる要素を保管してくれます。
課題
Rails4について自分が気になったところをまとめてみた。
今月のWebDBでRails4の特集があったので、個人的に気になるところをまとめてみる。
Rails4についての超まとめ
Rails4について一言でまとめると、こうです。
DHH「ぼくが かんがえた さいきょうの れいるず」
これから、
- 追加されたもの
- 変更されたもの
- 削除されたもの
の3つの観点から特に気になったことをまとめてみます。
追加されたもの
concernsディレクトリ
複数のモデルやコントローラにまたがった処理を記述する場所として、app/models/concerns, app/controllers/concernsというディレクトリが新設されました。
このディレクトリに置かれたファイルはautoloadの対象となるため、requireなしでincludeできます。
定義されているroutesがブラウザから見れるように
rake routesの出力と同じものがhttp://localhost:3000/rails/info/routesで確認できるようになりました。
whereメソッドにnotメソッドをチェーンできるように
今まで
users = name.nil? ? User.where("name IS NOT NULL") : User.where("name <> ?", name)
と書かなければいけなかったところを、notメソッドにより
users = User.where.not(name: name)
と書けるようになりました。
これはかなりcool。
変更されたもの
自作スクリプトの置き場所がscriptからbinへ
Bundler1.3ではbinstubsという機能が提供されました。
binstubsとはgemから提供されるコマンドをBundler環境下で実行するためのものであり、そのためのwrapperをbinディレクトリに配置する必要があります。*2
このbinstubs対応のため、scriptディレクトリがbinディレクトリへと変更されました。
今後は自前のスクリプトもこのディレクトリに置くことになります。
testディレクトリ以下の構造変更
testディレクトリ以下のディレクトリ構造がmodels, controllersなどのテスト対象のディレクトリ名に変更されました。*3
開発者向けエラーページがリッチに
開発時にお世話になるエラーページが「今風に、きれいに見やすく」なったそうです。
これに関してはスクリーンショットなどが掲載されていなかったので、実際に試してみたいところ。
allメソッドがRelationを返すように
モデルのallメソッドはこれまでは配列を返していました。
しかし、ActiveRecord4におけるallメソッドは今までのscopedメソッドと同じ動きをします。*4
個人的にこれは嬉しい変更。kaminariとかに繋げるときにキレイに書ける気がする。
# 今まで users = User.scoped.page(params[:page]).per(20)
としていた*5ところを
# これから users = User.all.page(params[:page]).per(20)
と書けるはず。
名前付きスコープがlambda記法のみに
今まで
scope :administrators, where(admin: true)
と書いていたものを
scope :administrators, lambda{ where(admin: true) } # lambda記法 scope :administrators, -> { where(admin: true) } # 矢印lambda
と書かなければならないように。
なくなったもの
Ruby1.8以前のサポート
Rails4ではRuby1.8のサポートが打ち切られました。*8
Rails4を利用するためには、最低でも1.9.3以降を使用する必要があります。
ダイナミックファインダ
ダイナミックファインダとは、
user = User.find_all_by_name("Bob")
のようなメソッドのことですが、このダイナミックファインダがfind_by_xxx, find_by_xxx!を除いて全て廃止されました。
今後はクエリメソッド(whereメソッド)を用いて書く必要があります。
ActiveRecord::Observer
モデルにObserverパターンを簡単に実装するActiveRecord::Observerが「記法・APIがイマイチ」という理由により廃止されました。
*9
コントローラのrespond_toブロック
scaffoldで生成されるコントローラからrespond_toブロックが消えました。
jsonのリクエストに対してJbuilderを用いたテンプレートを使用します。*10
このテンプレートを用いたjsonのレスポンスを得るためには、http://example.com/users/1.jsonのようなURLを叩きます。
最後に
ここに書いたこと以外にも重要かつ様々な変更点*11が記事では取り扱われています。
また、リリースノートには記事に書いてあること以外にも多くのことが書かれているはずですので、興味がある方はそっちもあたってみると良いかと思います。
*1:とはいえ、ターミナルからrake routesで見てしまう気はします。
*2:binディレクトリにwrapperを置いておけば、bundle execと書かなくてもbundle execしたのと同様の効果が得られる
*4:scopedメソッドは廃止されました。
*5:実はscopedメソッドを知らなかったので、where "name like %"という最強にイケてない感じで書いてました。死にたい。
*6:記事には明記されていませんでしたが、当然after_filterも同じだと思います。
*7:ただ、新しいbefore_actionフックはフィルタ機能として使われることが多いと思うので、before_actionへのエイリアスという形でbefore_filterを残しても良かった気もします。
*8:個人的には1.9系を使ってるので何ら困らないのですが。
*9:近いうちに使ってみようと思っていただけに残念です。キレイに書けるようになって帰ってくると嬉しい。
超約『エリック・エヴァンスのドメイン駆動設計』(前編)
『エリック・エヴァンスのドメイン駆動設計』を読んだのでまとめてみます。
第1部 ドメインモデルを機能させる
第1章 知識を噛み砕く
我々プログラマはシステム開発のプロだが、顧客自身の業務領域(ドメイン)に関しては何も知らない。
一方、顧客は自身の業務領域については熟知しているが、それを上手くシステム化する方法を知らない。
したがって、顧客が持つ「何をするのか、なぜするのか」とプログラマが持つ「どうやってやるのか」をすり合わせる作業が必要。
方法を知る者が職を得て、彼の働く理由を知るものが雇い主になる。
――クラフト・ロレンス(行商人)
昔の人はよく言ったものです。
第2章 コミュニケーションと言語の使い方
一言で言うと、「名前重要」。*3
本書の中ではどこでも使える言語ということで「ユビキタス言語」と言っている。
プログラマが使う言葉と顧客が使う言葉に乖離があってはならない。
技術的に詳細な部分まで顧客に理解してもらう必要はないが、クラス名やインスタンスが持つ属性名は顧客と共有できるものでなければならない。
実装上、クラス名などは英語でつけると思うので、このあたり英語圏の人間は得だなと思う。
第3章 モデルと実装を結びつける
プロジェクト参加者の共通語彙(ユビキタス言語)を設定し、ドメインを表せるモデルを考えたら、それを実装に生かす。
ただし、困難なことは常に実装をする際に現れる。
実装上の困難が生じた場合、モデルを考えなおす。
このとき、実装上の困難を解決するために、ドメインモデルと実装が乖離してはならない。
また、ドメインモデルと実装を解離させないがために、貧弱な機能になってはならない。
ドメインモデルと実装を一致させるためには、モデリングと実装の間でコミュニケートし、フィードバックを伴ったイテレーションによってすり合わせを行う必要がある。
そのためには、モデルに携わる人がコードに触れ、コードを書く人がモデルを理解・表現しなければならない。
第2部 モデル駆動設計の構成要素
第4章 ドメインを隔離する
他の一般的な設計のように、ドメイン駆動設計においてもレイヤ化アーキテクチャを用いて複雑な処理をシンプルな要素に分解する。
本書では、
の4層に分けられている。
このうち、アプリケーション層は「何をするべきか」のみ知っているべきであり、「どうやるか」はドメイン層がその責任を負う。
ドメイン駆動設計では、ドメインモデルを表したドメイン層によってソフトウェアが構成される。
ドメイン層の要素を他の無関係な要素から分離し、設計と実装を一致させることがドメイン駆動設計の必須条件となる。
第5章 ソフトウェアで表現されたモデル
ドメイン駆動設計では、モデルを表現する要素を3パターンに分ける。
エンティティ
仮に「人オブジェクト」なるものがあったとして、ある2つのインスタンスの氏名が一致したとしても、それは同姓同名の人というだけであって、同一人物ではない。
こういった、同一性によって定義されるオブジェクトをエンティティと呼び、エンティティは連続性を維持しなければならない。
値オブジェクト
あるモデル要素が物事の特徴を記述するものであり、その属性しか関心の対象にならないのであれば、それを値オブジェクトという。
値オブジェクトにおいては同一性は重視されない。
値オブジェクトはその性質上、複数のインスタンスから参照されるので、不変(immutable)でなければならない。
また、住所と郵便番号など、類似の概念バラバラに定義するのではなく、統一体を形成すべきである。*7
サービス
設計を進めていくと、概念的にどのオブジェクトにも属さないような操作が含まれることがある。
この操作をどこかのオブジェクトに無理やり押し付けるのではなく、独立したサービスとして設計する。
エンティティや値オブジェクトが本質的に名詞になるのに対し、サービスは「何かをする」ものであるため、動詞にちなんで命名される傾向がある。また、この操作名はユビキタス言語と共通の語彙でなければならない。
さらに、サービスは何かを受け取って何かを返すためだけに使用し、サービスに状態を持たせてはならない。
第6章 ドメインオブジェクトのライフサイクル
オブジェクトは生まれてから破棄されるまでの間に様々な状態を経る。
このオブジェクトの生涯にわたって整合性を維持し、かつ、ライフサイクル管理によってモデルが複雑になることを防ぐ必要がある。
そのために3つのパターンを用いる。
集約
ファクトリ
第7章 言語を使用する:応用例
Gemfileについて調べてみた
Gemfileについてよくわかってなかったので調べてみた。
そもそもGemfileって?
Bundler用の設定ファイル。
BundlerはGemfileの記述にしたがって、gemの依存関係を示したGemfile.lockを生成する。
じゃあ、Bundlerって何さ?
アプリケーションで使用するgemのバージョン管理を行うプログラム。
「お前が書いたコード動かないんだけど?」
「ハァ? 俺の環境では動いてるし。バージョン違うんじゃねーの? 死ねよ」
ってならないためのツール。
Railsをはじめ、SinatraやRubyMotionでも使われている。*1
ちなみに、Bundlerの公式サイトにはこう書いてある。
The best way to manage your application's dependencies
ベストらしいので使わない手はない。
source
gemが置いてある場所を指定する。
Bundlerはこのsourceにgemのコードを取りに行く。
普段、Railsを使っていると自動挿入されるのであまり意識しないが、Gemfileには最低1つのsourceが指定されていないといけない。
ちなみに、RailsデフォルトのGemfileだとこう。
source 'https://rubygems.org'
さらに、これはURL文字列以外にもシンボルで書くことができる。*2
String | Symbol |
---|---|
http://rubygems.org | :rubygems |
http://gems.rubyforge.org | :rubyforge |
http://gemcutter.org | :gemcutter |
ruby
アプリケーションを実行するRubyのバージョンを指定できる。
ruby '1.9.3'
ハッシュの{key: value}記法を使っている場合などは指定しておいたほうがいいかもしれない。
ちなみに、引数にハッシュを渡すことによって、Ruby処理系を指定することができる。
ruby '1.9.3', engine: "jruby", engine_version: "1.6.7"
gem
gemコマンド*3で使用するgemを指定する。
例えば、アプリケーションでnokogiriを使いたい場合、次のように書く。*4
gem 'nokogirl'
バージョン管理
Bundlerはただのgemインストーラではなくバージョン管理ツール*5なので、このgemコマンドは第2引数にバージョンを取れる。
gem "nokogiri" # 最新版を入れる gem "rails", "3.0.0.beta3" # 3.0.0.beta3で固定 gem "rack", ">=1.0" # 1.0以降のバージョンに制限 gem "thin", "~>1.1" # 1.1以降2.0以前のバージョンに制限
他のオプション
gemコマンドは他にもいろいろなオプションをハッシュで渡せます。
ソースの取得先を指定
gem "nokogiri", git: "git://github.com/tenderlove/nokogiri.git", branch: "1.4" gem "nokogiri", path: "~/sw/gems/nokogiri"
自動的に読み込むファイルを指定
gem "nokogiri", require: "nokogiri" # default gem "redis", require: ["redis/connection/giredis", "redis"] gem "wirble", require: false # autorequireしない
group
groupコマンドではgemをインストールする環境を指定できる。
group :development, :test do gem "rspec-rails" gem "cucumber" end
のように設定した上で本番環境で
$ bundle install --without development test
とすると、developmentグループ及びtestグループのgemを除いてインストールを行うことができる。
こうなると、
$ bundle install --only test
とかが欲しいところだが、そういったオプションは用意されていない模様。
その他Bundlerのオプション
よく使うのはこんな感じ。
bundle install --path dir_name
$ bundle install --path vendor/bundle
Bundlerによってインストールするgemをデフォルト($BUNDLE_PATHまたは$GEM_HOME)のディレクトリ以外にする。一度指定するとBundlerがそのディレクトリを覚えてくれるため、次回以降は指定不要。
bundle install --system
$ bundle install --system
上記の--pathの逆。システムのデフォルトディレクトリにgemをインストールする。
*1:Bundler公式サイトには書いてなかったけどPadrinoでも使ってるっぽい。
*2:ただし、引数が:rubygems, :rubyforge, :gemcutterのいずれかの場合、どれを指定してもhttp://rubygems.orgを参照する。
*3:コマンドと書いたが、実際にはBundler::Dslクラスのインスタンスメソッド。sourceコマンドなども同じ。
*4:nokogiriはnokogirlでも入ります。俺のためにHTMLをパースしてくれるnokogirlたん萌え。
*5:こう書くとGitとかと紛らわしい。なんと呼べばいいんですかね?
*6:ステキすぎて鼻血でそう。
*7:シンボルで書くと、エラーを吐かれます。
*8:グループごとにまとめる場合はgroupコマンドのブロックの中に書いたほうがキレイ
*9:「rakeのバージョンがおかしい」とか言われたときに使うと高確率で幸せになれる。
*10:足りないアタマを使ってGitHubのコードも読んでみた。
*11:Bundlerのサンプルコードには:ciとかあった。