Understanding Computation (1) Part1 プログラムと機械
「Computation」とは何か?
ということを定義してる。
- プログラムを読み
- プログラムを実行し
- 入力を取り
- なにかしら出力する
Computationとは「コンピュータが何をするか」ということ。
Computationの3つの基本的な材料が
- コンピュータが何を計算出来るか
- 機械が理解できることばを書くための言語
- ↑の言葉で書かれたプログラム、機械に何をさせるか書き下したもの
Part1の章について
- 2章でプログラミング言語を作る
- 同じ言語をいくつかの手法で作るっぽい
- 3章で基礎となるマシンを作って
- 4章でなんか洗練されたやつが出来る
- 5章では汎用的な計算機作る
雑感
Part2ではなんかもっとヤバいことする方法を学び最終的に(作り方を知ってる範囲で)最強マシンを作るよう。楽しみだ。
Understanding Computation (0)
Understanding Computationを購入しました。
O'Reilly Coupon Codesに掲載されている「DSUG2」コードを入れて、O'Reilly版を半額で購入いたしました。Kindle版よりも安いです。
正式な価格だとKindle版の方がO'Reilly版よりも安いのですが、Kindle(DRMのかかった不自由な電子書籍)版は、AmazonのKindle以外では読むことができません。
O'Reilly版はPDF/ePub/Mobiなど、だいたいどこでも読めるフォーマットが用意されていて、DRMも掛かっていないので、お勧めです。
適当に読んでブログ書いていこうと思います。
オブジェクト指向Rails - よりよいコントローラーを書く
Ruby 5で紹介されていたObject Oriented Rails - Writing better controllers - Pivotal Labsの訳です。(翻訳の質はうんこかもしれません、元記事読みましょう)
私は最近、Objective-Cを使ってiOS、Javaを使ってAndroid、たくさんのモバイル開発をしている。
私はRuby開発者でもあるので、それらの言語やフレームワークから学んだことを可能な限りRubyでも試し、適用してみようとするのは当然のことだろう。
今日はRailsアプリでよりよいコントローラを書くため、僕のベストを尽くそうと思う。
私はAndroidやiOS向けのアプリを書くとき、スタブやモックを使わないよう、自分自身に強制している。それは、オブジェクトの設計を向上させ、DI(依存性の注入)を使ってテストを書くことを意図している。
では、コードの例を見てみよう。
class User validates_uniqueness_of :username end class RegistrationController < ApplicationController def create user = User.where(username: params[:username]).first user ||= User.new.tap do |new_user| new_user.username = params[:username] new_user.save! end render json: user end end
ここで我々が必要としているのは、ユーザーを登録するためのユーザー名だ。 あと、もしもユーザーが既に登録していた際は、単にユーザーの情報を返すだけだ。
すっごくシンプルだね。
だけど、そのロジックはControllerに属していない。
それだと、うんこみたいなスタブやモックを使わずに、データベースに接続せずにコントローラーをテストすることは不可能だ。
any_instance
をテストで使うのは、「あなたは間違ったことをしている」ことを示す良い目印だ。
まず最初のカイゼンは次のようになるだろう
class User validates_uniqueness_of :username def self.register(username) user = User.where(username: username).first user ||= User.new.tap do |new_user| new_user.username = username new_user.save! end end end class RegistrationController < ApplicationController def create user = User.register(params[:username]) render json: user end end
これは既に元よりもはるかに優れたコードだ、君はコントローラーをテストするためにUser.register
をスタブすればいい。それでうまく行く。
もしも君がそこで足をとめ、君のアプリが大きく成長しすぎなければ、それでうまいこと出来るだろう。
だけど、もし君のアプリが成長しはじめたら、User
モデルはもっと大きく大きく育っていって、君はより多くの責務を与えていくだろう、
君はUser
モデルにもっと責務を与えていくだろう。そして、君が知っていることを超えたあたりで「僕はただしいのかな?」と自分自身に問いかけるんだ。
コードをよりよく切り分ける道、実際にスタブを取り除く最終的なコードがこれだ:
class User validate_uniqueness_of :username end class RegistrationService def register(username) user = User.where(username: username).first user ||= User.new.tap do |new_user| new_user.username = username new_user.save! end end end class RegistrationController < ApplicationController before_filter :load_registration_service def create user = @registration_service.register(params[:username]) render json: user end def load_registration_service(service = RegistrationService.new) @registration_service ||= service end end
RegistrationService
は、データベースに関連する登録に関してのみ、責務をおう。
このサービス自体はデータベースにアクセスを行わずに、HTTPサービスを使うような別のものに取り替えることが可能なことに注意して欲しい。
その上、あなたは今テストから完全にスタブを取り除くことが出来るようになった。 次のような感じだ
describe RegistrationController do before do @fake_registration_service = controller. load_registration_service(FakeRegistrationService.new) end describe "POST #create" do it "delegates to the registration service and renders the returned user" do expected_user = User.new.tap {|u| u.username = "damien"} @fake_registration_service.registered_user = expected_user post :create, username: "damien" expect(response.status).to eq(200) expect(response.body).to eq(expected_user.to_json) expect(@fake_registration_service.username_registered).to eq("damien") end end end class FakeRegistrationService attr_accessor :registered_user attr_reader :username_registered def register(username) @username_registered = username registered_user end end
哀しいことに、我々はRailsがどうやってControllerをインスタンス化するのかコントロールしていない。
だから我々はbefore_filter
の中でこんな感じのトリックを使って、サービスのデフォルト値を使うようにしなくちゃならない。
PORO(Plain Old Ruby Object、素のRuby)でこれをやるならコンストラクターを作って似たようなことをやればい。
AndroidやiOSのアプリでテストを走らせるとき、依存性の注入を使うのは非常に一般的だ。 私は個人的にはこれらのプラットフォーム上でモックを使わないことを好む。
そして、私はRuby on Railsのアプリケーションでもこのテクニックをもっと試してみたい。 それはあなたによりよいオブジェクト設計について考えること、より特定の目的を持ったオブジェクトを持つこと、値オブジェクト上にロジックを持つことを制限(モデルとプレゼンターのように)することを強制するだろう。
あなたがこの記事について考えていることを、ぜひ教えて下さい! :)
Ruby5 - Episode #383 - July 2, 2013
Ruby関連の情報はもっぱらRuby Weekly(週一で届く無料のRubyニュースメルマガ)に頼ってます。
Ruby5も聞いてみようと思いましたが、日本語じゃない(`;ω;´)
日本語記事を探してみたら
すごく良いブログなんだけど更新止まってるみたい。 せっかくなので僕もやってみたいな〜。と思って聞いてみました。
- 一旦英語で聴きとって書きだす
- 意訳
の順番で行こうと思ったがそんなに甘くなかった。普通に知らない単語出てくるし、聞き取れない。 なので
- 聞き取れた範囲で意訳
のみで頑張ろうと思います。TopRubyJobsは翻訳しない方向で。
Ruby5 - Episode #383 - July 2, 2013
ワンライナーウェブサーバー、コントローラーへの提案、きちっとしたモック、モッキングライブラリを作る、Rails4への用意、オープンソースプロジェクトの地図
ワンライナーウェブサーバー
nobu (Nobuyoshi Nakada)さん(Rubyコントリビュータ)による、Rubyだけを使って、ワーキングディレクトリでウェブサーバーを立ち上げる美しくてシンプルな方法。
ruby -run -e httpd . -p 5000
を呼ぶだけ。Rubyの標準ライブラリのWEBRickを使ったサーバーがhttp://localhost:5000/で立ち上がる。(index.htmlがあればそれが表示される) 静的なファイル配信のに特化してるすごい技w
- Twitter / n0kada: @tenderlove you can run without ...
- Feature #8586: Add a simple file server to WEBrick - CommonRuby - Ruby Issue Tracking System(※訳注: 僕が付け足しました)
よいコントローラを書く
週末にPivotal Labsのダミアンレベゴッド(※訳注: 発音難しいのでカタカナでちゃんと書けてない可能性高いです)が書いた興味深いブログについて。
コントローラをテストするときモックとスタブを使わず、オブジェクト指向な設計を育てよう。
コントローラをテストするよりもインテグレーションテストをする方にみんな興味持ってそうなのに、Controllerのテストの話。
any_instance
を使ってオブジェクトのメソッドをスタブするのは、コードの臭いぷんぷん。
まずクラスメソッドに切り出して、それをサービスクラスに切り出す。 (※このあとの部分聞き取りづらかった。ブログ記事のコメント欄の方も盛り上がっていて面白い)
verified_double
rspec-fire
と似てるモック用のライブラリらしい。
違うのは、そのモックがスタブしたメソッドが正しい値を返すかテストで保証出来ること。
スタブが返す値をテストしていない場合warningがでるらしい。
モッキングライブラリを作る
7/23にあったAncient City RubyでのAndy Lindemanさんのモックライブラリを作るついての話。YouTubeで配信中。(今まで見た中で一番のライブコーディングらしい) モックが出来ること、レッド・グリーン・リファクタのサイクルを高速に回して、どれほどパワフルなことが出来るか理解出来るよう。(※ぼくもあとでみる)
Rails4 Ready?
Francesco RodríguezさんとFlorent Guilleuxが作ったready4rails4.netの話。 gemがRails 4に対応してるかしてないかが調べられる。
オープンソース地図
世界オープンソースコントリビュータ地図。 David FischerがGitHub's Date Challengeに投稿した超ヤバいツール。 GitHubで最も活発な200のオープンソースリポジトリのコントリビューターが、世界のどこにいるのか地図にプロットした。
サイト
Rails 4.0.0を入れた後でRails 3.2.13を入れ直したいとき
当方rbenvを使っています。
gem install railsしてうっかり4.0.0を入れてしまったあと、3.2.13を入れなおしたのですが、rails -v
、rails --version
しても4.0.0のままで困っていました。
状況
gem install rails # 4.0.0が入る gem uninstall rails # 3.2.13が使いたいので、4.0.0を消す gem install rails -v '3.2.13' # 3.2.13を指定して入れる rails -v # 3.2.13だと思った?? ざーんねんっww4.0.0でしたっwww
解決策
railtiesを消そう
gem uninstall railties -v '4.0.0'
なんで?
rails
コマンドはrails
gemじゃなくてrailties
gemのコマンドだからです。
https://github.com/rails/rails/blob/master/railties/bin/rails