ソースコードを読むときの3つのステップ

はじめに

はじめまして。お盆明けからMisocaでインターンをしているhmryuです。Misocaにジョインする前は、個人でサービスを作ったり、研究でプログラムを書いたりしていました。

一方で、チームで開発する経験はあまりなく、Misocaにジョインした始めの頃は慣れないことばかりでした。中でも、他人の書いたソースコードを読んで理解することが、一番大変だったかもしれません。

そこで今回は、機能追加・変更を加えるためにソースコード*1を読む上で、僕が大切だと感じた3つのステップについて書きたいと思います。

1. 機能とソースコードの対応を調べる

まず、自分が変更を加える機能がどんなもので、どこに実装されているのか理解する必要があります。実際にサービスを動かして、どんな機能なのかを確認します。その後、その機能がソースコードのどの部分に対応するのかを調べます。

例えば、メール送信について調べる場合は、実際の画面を開きformタグのaction属性を調べて、config/routes.rbと照らし合わせることで、呼ばれているアクションを特定します。

f:id:hmryu:20151001165930j:plain

# config/routes.rb
# ...
resources :mails do
  collection do
    post 'distribute'
  end
end
# ...

ここでは、MailsControllerのdistributeアクションが呼ばれていることがわかりました。

2. 処理全体の流れを追う

次に、実際にどのような処理がされているのかを把握するため、ソースコードを読んでいきます。ここでは、 メール送信の処理を読んでいくケースを考えてみます。メール送信のアクションは以下のように実装されています。

class MailsController
  def distribute
    #
    # ... logic ...
    #
    distribute = Misoca::Mail::Distribute.new
    distribute.call
    #
    # ... logic ...
    #
  end
end

読んでみると、distributeアクションの中で、Misoca::Mail::Distributeのインスタンスが生成され、callが実行されていることがわかります。ここの中でメール送信をしていそうなので、アプリ全体からMisoca::Mail::Distributeが定義されている場所を探します。

このとき、アプリ全体の構成を把握しておくと、作業が捗ります。MisocaのアーキテクチャーはThe Clean Architecture*2で構成されており、Misoca::Mail::Distributeのようなクラスはapp/misoca以下に[グループ名]/[名前].rbをという名前で保存するとルールが決まっています*3。

module Misoca
  module Mail
    class Distribute

    def call
      #
      # ... logic ...
      #
      document = find_document
      document_distributor = Misoca::Mail::DocumentDistributor.new
      document_distributor.build_to_mail(document)
      #
      # ... logic ...
      #
    end

    private
      def find_document
        #
        # ... logic ...
        #
      end
  end
end

Misoca::Mail::Distributeのcallでは、find_documentでメール送信する文書を探しています。その後、Misoca::Mail::DocumentDistributorのインスタンスが生成され、build_to_mailが実行されていることが分かります。

このような感じで、どんな処理がされているのかを調べていきます。複雑なときなどは、調べていて混乱しないように、下記のような簡単なメモを書いておいたりします。ここでは、疑問に思ったことなども簡単に書いておきます。

f:id:hmryu:20151001181405p:plain

また、上記の流れ以外にも必要に応じて、コールバックやフィルタなども気にしておくようにしています。

3. 変数やデータベースの中身を見る

ソースコードを読み進める中で、「この時点でこのオブジェクトはどんな状態になっているのか?」「これが実行された後、このモデルのレコードは増えているのか?」といった疑問が出てきます。一通り流れを把握したら、変数やデータベースの中身を調べてみます。

僕は、pryというGemを使っています。

github.com

ソースコードの任意の場所にbinding.pryと記述すると、その時点でプログラムの実行を一時停止することができます。

def call
  #
  # ... logic ...
  #
  document = find_document
  document_distributor = Misoca::Mail::DocumentDistributor.new
  binding.pry # ブレークポイントを設定
  document_distributor.build_to_mail(document)
  #
  # ... logic ...
  #
end

サーバーを起動させていたコンソールを一時停止した状態で、変数やデータベースの中身を見ることができて、とても便利です。

[1] pry(#<Misoca::Mail::Distribute>)> Mail.count
=> 1
[2] pry(#<Misoca::Mail::Distribute>)> next # 次の行を実行
[3] pry(#<Misoca::Mail::Distribute>)> Mail.count
=> 2

この例では、build_to_mailでMailのレコードが増えていることが確認できました。

まとめ

今回は、ソースコードを読むときの3つのステップについて書きました。まだ働き始めて1ヶ月くらいですが、Misocaのインターンでは、様々なことを学べています。少しでも早く成長して、学んだ知識や技術をこのブログで還元できればと思っています。

*1:MisocaがRailsで実装されているので、ここでは、Railsのソースコードを読むことを想定しています。

*2:The Clean Architecture | 8th Light

*3:Misocaでは、アプリの仕様などがesa.ioにまとめてあります。