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


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

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

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


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

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

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

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

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

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

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

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

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

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

オススメのドキュメント

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

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

🗻 ソースコードの読み方

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

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

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

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

source 'https://rubygems.org'
# debug用
gem 'pry'
# stackを表示
gem 'pry-stack_explorer'
# 各種便利ユーティリティ
gem 'activesupport'

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

# Gemを追加するためのディレクトリを作成
mkdir vendor
# Gemをディレクトリに保存
bundle install --path vendor/bundle --jobs=4

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

たとえば、sample.rbを作成して次のようにコードを記入。

require 'pry'
require 'pry-byebug'
require 'active_support/all'
puts 2.days.ago

これを実行するとactive supportの機能である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メソッドに以下を追加。

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

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

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で次の処理を見ることができる

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

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

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

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

🚕 Active Supportのおもしろい機能

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

Benchmark.ms

Benchmark.msはブロックを渡すとブロックを評価して実行時間を計測します。

(Benchmark.realtimeのラッパです)

require 'active_support/all'
puts Benchmark.ms { sleep 1 } # => 1000.234

cattr_accessor

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

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

require 'active_support/all'
class Sample
cattr_accessor :hoge
end
Sample.hoge = 1
puts Sample.hoge

descendants

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]

🗽 ハッシュ。except

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

😼 Time#change

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さんがActive Supportのconcernを使5つ、Backlog APIへのアクセスメソッドを調べて発表してくれました。その際のソースコードをQiitaに公開していただけたので紹介です!

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

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

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

shiro615 - Qiita

🐞 参考リンク

🎃 変更来歴

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

📚 おすすめの書籍

🖥 サーバについて

このブログでは「Cloud Garage」さんのDev Assist Program(開発者向けインスタンス無償提供制度)でお借りしたサーバで技術検証しています。 Dev Assist Programは、開発者や開発コミュニティ、スタートアップ企業の方が1GBメモリのインスタンス3台を1年間無料で借りれる心強い制度です!(有償でも1,480円/月と格安)