酒と泪とRubyとRailsと

Ruby on Rails と Objective-C は酒の肴です!

ソースコード・リーディングしよう![GemJam][ActiveSupport]

@h5y1m141さんに誘って頂いて、 @hitomi_twさんや shiro615さんと一緒に、RubyGemsのソースコードリーディング勉強会『GemJam』を行いました。

今回は最近仕事でソースコードを読む時間が増えてきて、苦労していたのでソースコード・リーディングのモチベーションアップやコツを調べつつ、いつもRailsでお世話になっていた『ActiveSupport』 のソースコードリーディングに挑戦してみました。

(12/28 12:10) 勉強会のアウトプットを更新しました。全員アウトプットしたのは素晴らしいです


Included file ‘custom/google_ads_yoko_naga.html’ not found in _includes directory

プログラムのモチベーション

これは経験談からくる話なので、これが正解ということでないッス。どちらかと言うと、今までエンジニアとして経験してきた中で、僕個人はこう思っていますという観点で書きました!

プログラミングは継続する事が一番大切

プログラミング経験ゼロだが180日で180個のウェブサイトを作るプロジェクトがゴールまであとわずかに

プログラミング経験0のデザイナさんが、毎日1つサイトを作っていったお話です。最初はテキストとリンクが並ぶだけのサイトでしたが、少しずつゲームやチャットなどが作れるようになっていきます。

今知っている知識だけで、作れるWebサイトを作っていく。そして、自分の知っている2つの知識を組み合わせたり、1つずつやりたいコトをGoogleに教えてもらうくらいが、挫折せずに続けられると思っています。

個人的に学生さんらにプログラムを教えた事がありますが、プログラムが出来るようになるために一番大切なことは『継続』することだと常々実感させられます。

じゃあ、なぜソースコードを読むのか?

僕は1人の力には限界があると思います。たった一人で本当に価値のあるソフトウェアを作るのは本当に難しいことだと思います。だから、価値のあるソフトウェアを作っていくためには、他のエンジニアと一緒にプログラムを作り込む必要があると考えています。

そのためには、他の人のソースコードの意味を理解し、他の人にわかりやすいプログラムを書く必要があります。言い換えるとソースコードを読むこと、読みやすいソースコードを知ることが重要だと思います。

オススメのドキュメント

まつもとゆきひろのハッカーズライフ:第10回 ソースを読もう - ITmedia エンタープライズ

Rubyの製作者、まつもとゆきひろさんが2007年に書かれていた記事を見つけました。まつもとさんのソースコードを読む際の動機を垣間見える面白い記事でしたので、良ければぜひご覧になってみてください。

ソースコードの読み方

今回『ActiveSupport』 のソースコード・リーディングをしてみたので、その時の僕の手順を紹介します。(もしもっといい方法をご存知の方がいれば是非コメントお願いします)

(1) コードを効率よく読むためのツールを準備する

まず、オススメのエディタは『RubyMine(などのJetBrains製のエディタ)』です。理由はメソッドのドリルダウンがデフォルトの設定で簡単に行えるからです。1ヶ月無料なのでよかったら是非試してみてください!

次にプロジェクトフォルダ直下で、Gemfile作成して以下の様に追加。

1
2
3
4
5
6
7
8
9
10
source 'https://rubygems.org'

# debug用
gem 'pry'

# stackを表示
gem 'pry-stack_explorer'

# 各種便利ユーティリティ
gem 'activesupport'

以下のコマンドを実行して、Gemをインストール。

1
2
3
4
5
# Gemを追加するためのディレクトリを作成
mkdir vendor

# Gemをディレクトリに保存
bundle install --path vendor/bundle --jobs=4

(2) 実際に動かしてみる

例えば、sample.rbを作成して以下のようにコードを記入。

1
2
3
4
5
require 'pry'
require 'pry-byebug'
require 'active_support/all'

puts 2.days.ago

これを実行するとactive supportの機能である2日前の日付を取得する事ができます。

1
2
bunlde exec ruby sample.rb
#=> 2014-12-25 14:09:42 +0900

(3) デバッガの準備

次に今回はデバッカを書いて実際に2.daysのメソッドにどんな風に動いているのかを見れるようにします。

まずは、vendor/bundle/ruby/2.1.0/gems/activesupport-4.2.0/lib/active_support/core_ext/numeric/time.rb を開いて、daysメソッドに以下を追加。

1
2
3
4
  def days
    binding.pry # <= この行を追加
    ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
  end

そしてもう一度以下のコマンドを実行すると今度は、binding.pryを書いた地点で停止します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
bunlde exec ruby sample.rb

# デバッカが表示
#=> From:
#=>/active_support_reading/vendor/bundle/ruby/2.1.0/gems/activesupport-4.2.0/lib/active_support/core_ext/numeric/time.rb @ line 50 Numeric#days:
#=>
#=>     49: def days
#=>  => 50:   binding.pry
#=>     51:   ActiveSupport::Duration.new(self * 24.hours, [[:days, self]])
#=>     52: end

# 呼び出しの関係を取得
2.1.4 (2):0 > show-stack
#=> Showing all accessible frames in stack (2 in total):
#=> --
#=> => #0  days <Numeric#days()>
#=>    #1 [main]    <main>

2.1.4 (main):0 > show-source Benchmark.ms
#=>
#=> From:
#=>/active_support_reading/vendor/bundle/ruby/2.1.0/gems/activesupport-4.2.0/lib/active_support/core_ext/benchmark.rb @ line 11:
#=> Owner: #<Class:Benchmark>
#=> Visibility: public
#=> Number of lines: 3
#=>
#=> def ms
#=>   1000 * realtime { yield }
#=> end

# ここでstepを実行すると処理の中身に移動、nextで次の処理を見ることができる

あとはちょっと変更して見て動かしたりしてみてください。

どんなふうにソースコードを読み進むべき?

手始めにどんなふうにソースコードを読んでみたらいいかをいくつかのサイトを調べながら考えてみました。 アイデアレベルですが、よかったらぜひソースコード・リーディング試してみてください!

* 普段関わっていたり、仕事に役立つコードを読んだり、コメントを書く
* 興味のある分野や機能を持ったソースコードを読む
  * 全体を読む必要はない。面白そうなところをつまみ食いして、先人の知恵を学べばいい
* ちょっと変更して動作させてみる
* バグがないか探してみる

Included file ‘custom/google_ads_yoko_naga.html’ not found in _includes directory

ActiveSupportの面白い機能

ActiveSupport』の 便利機能を調べつつ、その部分のソースコードを読んでみました。今回知らなくって、後で使えそうだった機能を中心に紹介します!

Benchmark.ms

Benchmark.msはブロックを渡すとブロックを評価して実行時間を計測します。
(Benchmark.realtimeのラッパーです)

1
2
3
require 'active_support/all'

puts Benchmark.ms {  sleep 1 } # => 1000.234

cattr_accessor

attr_accessorはインスタンス変数へのアクセッサを提供するメソッド。
cattr_accessorは、クラス変数へのアクセッサを提供するメソッド。

1
2
3
4
5
6
7
8
require 'active_support/all'

class Sample
  cattr_accessor :hoge
end

Sample.hoge = 1
puts Sample.hoge

descendants

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require 'active_support/all'

class Parent
end
class Child < Parent
end
class GrandChild < Child
end

# 継承してくれている先を出す
puts Parent.descendants.to_s #=> [Child, GrandChild]

# 継承元を出すメソッド
puts GrandChild.ancestors.to_s
#=> [GrandChild, Child, Parent, Object, JSON::Ext::Generator::GeneratorMethods::Object, PP::ObjectMixin, Kernel, BasicObject]

Hash.except

1
2
3
4
5
require 'active_support/all'

# ハッシュから特定のキーを削除
hash = { hoge: 1, huga: 2 }
puts hash.except(:hoge).to_s # => {:huga => 2}

Time#change

1
2
3
4
require 'active_support/all'

# その日の4時0分0秒を取得
Time.now.change(hour: 4, minute: 0, second: 0) #=> 2014-12-27 04:00:00 +0900

ここの記事が大変参考になりました!

RailsDoc - 広島Ruby勉強 #032 - Rails のソースコード読んだので面白そうなところを紹介する – ActiveSupport CoreExt編 その1

pry詳解

今回ソースコードを読んでいて、改めてpryの素晴らしさに感動しました。ということでpryに関する記事を見つけたので紹介です。

pryの使い方解説

pryの動作原理の解説

GemJam勉強会アウトプット

GemJamという勉強会を行いました

@h5y1m141さんが、GemJamを作った背景や、今回調べたことについてブログにまとめて頂けました。4人位のコードリーディングや読書会的な勉強会って結構面白いと実感しました。あと、みんなが終了後1-2日でちゃんとアウトプットしているのはほんとうに素晴らしいです!

GemJamという勉強会を行いました - TitaniumMobile勉強記

GitHubでMergeされたらBacklogもRailsで自動更新する

@hitomi_twさんがActiveSupportのconcernを使いつつ、Backlog APIへのアクセスメソッドを調べて発表してくれました。その際のソースコードをQiitaに公開して頂けたので紹介です!

GitHubでMergeされたらBacklogもRailsで自動更新する - Qiita

配列からハッシュを作成/ActiveSupportでHashの一部だけ取り出す

まだ、プログラムの実務経験はないそうですが、短い時間でアウトプットや発表なんかをしっかりしてくれて、自分の初心者の頃と比べると雲泥の差で素晴らしいと感じました。ぜひプログラムを楽しんでください^^

shiro615 - Qiita

Included file ‘custom/google_ads_yoko_naga.html’ not found in _includes directory

Special Thanks

変更来歴

(12/28 12:10) 勉強会のアウトプットを更新

おすすめの書籍