OSSコードリーディングのすゝめ

# はじめに
### OSSとは
簡単に言うと、誰でも無料で読んだり使ったりすることができるソースコードです。

オープンソースという言葉が生まれた1998年に、定義が定められました。
[オープンソースの定義(v1.9)注釈付](https://opensource.jp/osd/osd19/)

まとめると、
**・再配布自由**
**・ソースコードの公開**
**・派生物の許容**
**・差別の禁止**
**・追加ライセンスの禁止**

これらの条件を守っているものがオープンソースと呼ばれるようです。
### ChatGPTの出現
ChatGPTや各Pluginの活用方法がメジャーになったことで、コードリーディングに関しても今までとは比べ物にならない程、効率的に行うことができるようになりました。
# 何のために読むのか
OSSコードリーディングは、他人のコードを読むことで技術力を向上させる方法として知られています。
実際にどのような良いことがあるのかをまとめました。
### 業務のため
自社のシステムに組み込まれているOSSのコードを理解し, システムの安定性を保つために行います。
OSSのコードまで理解しておくと、開発やシステムの保守、デバッグも**本質的な理解**をした上で行えるようになります。
### 発生している障害を解決するため
自分の作っている、または既に存在しているシステムにおいて障害が発生した時、**OSSの内部構造を理解していないと解決できない場合**があります。
ライブラリのソースコードまで踏み込むのは一見遠回りなようですが、**本質的な解決**をすることでエンジニアとしての経験値を得ることができます。
### 機能実装のため
ソースコードにおける既存の機能を学習することで、自身のプロジェクトに実装する際の参考にします。
例えば、Reactによる先人のソースコードを読むことで、フロントエンド開発に関して自分の中のベストプラクティスを定めることができるでしょう。
### 技術のキャッチアップのため
技術トレンドをキャッチアップするために、先進的なプロジェクトのコードを読むことがあります。
例えばEthereumのソースコードを読み、ブロックチェーン技術について理解を深める、などです。
### プログラミング言語学習のため
学習したいプログラミング言語の理解を深める際に有効です。
ある程度文法が理解できている言語であれば、**実際にソフトウェアでどのように使われているか**を学習することができます。
# 何を読めばいいのか
業務上読むべきものが決まっている場合はそれを読むとよいでしょう。
そうでない場合は、

**・ある程度習熟している言語**
**・実際に使っていたり、仕様を把握しているもの**
**・新しい技術で、知的好奇心がくすぐられているもの**

など先ほど例に挙げたような目的別に、自分なりに選定しましょう。
もし馴染みのないOSSの場合は、一度自分で動かしてみたり使ってみることをおすすめします。

ここで、githubで自分の読みたい言語を指定して検索する方法を紹介します。
![Repository search results · GitHub - Google Chrome 2023_09_16 14_42_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740560/780967b4-6cc9-e645-4d72-d50de4509f7d.png)
とは言っても、検索バーで`language:<言語>`と入力するだけです。
他にも、
`filename:`でファイル名を指定したり、
`path:`でパスを指定することもできます。
# 気を付けるべきこと
### 全体を読もうとしない。
OSSコードリーディングにおける初見殺しと呼べる行動が、
**巨大なソースコードを一から読もうとすること**です。

Linuxなど超有名どころのソースコードは、
自力でコードを一から読み始めても一生全体を理解することはできないでしょう。

途中で挫折して、自分がどの部分を理解したのかさえ分からないというのがオチです。

小規模なソフトウェアの全容を把握したいときはいいかもしれませんが、
どのみちいきなりコードを読み始めるのではなく、**自分が全体の中のどの部分を読もうとしているのか**を把握しましょう。
### 目的を見失わない
とにかく自分が何のためにコードを理解したいのかを忘れないようにしましょう。
OSSコードリーディングに限ったことではありませんが、
**忍耐力が必要な作業には目的意識が必要**です。

読んだ先に何があるのか、何を得ることができるのかを明確にし、
**飽きてきたとしても作業を続けることができる動機を作る**ことが重要です。

せっかくであれば後から振り返って意味のない行動にならないようにしたいですね。
# OSSコードリーディングの手法
### コードリーディングのための環境
github上で読んでいくのが手軽かつ構造的に見ることができるのでいいでしょう。

ただ開発や保守で必要な場合など、本格的に細部の挙動まで把握しておくべき場合は普段自分が使っているエディタを用いるのがよいと思います。

検索やコードジャンプ機能がある、VScodeなどが便利です。

### 目的を決める
先ほども述べたように何のためにコードリーディングを始めるのか、どのような状態になりたいのかは明確にしておきましょう。
### ドキュメントを読む
ドキュメントが充実している場合、目的によってはそもそもソースコードを読む必要もないかもしれません。
関数の説明や、コンポーネントごとの役割の説明などをしてくれている場合が多いのでまずは目を通してみることをおすすめします。
### QAサイトを確認する
コミュニティサイトやチャットで、開発者が質問に対して答えている場合があります。
自分の気になっている部分が既存の疑問の場合、それを読むことで解決できる場合があります。
githubやslack, google groupなどが使われることが多いようです。
### 全体像を把握する
アーキテクチャや主要なコンポーネントを把握しておくと、調べたい機能がどのあたりに属するのか見当がつきやすいです。
ここに関してはいくつか方法があります。
・ドキュメントを読んで把握する。
・ChatGPTに聞いてみる。
・自らの経験と勘で、フォルダ構成から把握する。
自分のレベルごとに全体像を把握するための方法を考えましょう。

以下はPyTorchのソースコードに関して、ChatGPTに質問した例です。
![torch全体像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740560/9b1dde8b-f098-9e94-7a31-7856687b2056.png)
PyTorchに関してあまり知らない人でも、`torch/nn`らへんを見ればニューラルネットワークモジュールとその周辺が記述されているんだなということが分かりそうですね。

### 重点的に読む部分を決める
先ほども注意点としてあげたように、いきなり全体を読もうとするのは危険です。
全体像を把握した上で、自分の目的と持っている時間的なリソースとの兼ね合いで何を重点的に読むのかを明確にしましょう。

ここまで来たら、あとは自信をもってどんどん読み進めるのみです！
### コミットログ・プルリクエストを見てみる
余裕があれば、コミットログやプルリクエストを見てみると勉強になります。
どのような経緯で実装したのか、なぜ変更が必要だったのか、を考えることでエンジニアとしての経験を自分のものにすることができます。
### 読んでも分からない時は実際に動かす
OSSに限らず、最も自分の身になる勉強法は自分で動かすことです。
ソースコードの一部分を自分のエディタ上で動かせるような環境を整え、積極的に実行するとよいでしょう。
### アウトプットする
言わずもがなですが、アウトプットすることで理解度・定着度が圧倒的に高くなります。
・個人ブログ
・社内wiki
・スライド+登壇
など手軽なものでもアウトプットすることで自分のレベルをどんどん上げていくことが可能です。
# OSSコードリーディングの実践
今回紹介した流れを基に、OSSコードリーディングを実践してみました。
Lightningのソースコードについて読んでいきたいと思います。

Lightningとは、PyTorchのコードを簡略化して書くことができるようになるライブラリです。
研究者がエンジニアリングに力を入れなくても機械学習を用いられるようにすることを目的としています。

以下が公式ドキュメントです。

https://lightning.ai/pytorch-lightning/

目的としては、`pytorch_lightning.LightningModule`の仕組みをある程度理解することとします。
`pytorch_lightning`モジュールに含まれる、`LightningModule`のソースコードを探し出し、理解していきたいと思います。

まずはドキュメントやQAサイトを読んでみます。機能の説明はしてくれていますが、実際のソースコードについては触れられていないため、ソースコードを読んでいくことにします。

![Welcome to ⚡ PyTorch Lightning — PyTorch Lightning 2.0.9 documentation - Google Chrome 2023_09_19 18_26_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740560/39fa9356-ac64-299d-d9f6-e508fa1bebe4.png)


ドキュメント内にソースコードが記述されているgithubリポジトリへのリンクがあったのでそこへ飛びます。

https://github.com/Lightning-AI/lightning/tree/bc85c5fd14005965faae4010db428820e422e2d3

![github.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740560/b63a9008-04df-f94a-4768-c9d1a9fdca19.png)

全体像を把握するために、一通り各フォルダの中身を眺めてみました。
以下の`src/lightning/pytorch`ディレクトリにpytorch lightningについて記述されているようでした。

https://github.com/Lightning-AI/lightning/tree/80f131c668f83d21779b0120957466a23b24a5af/src/lightning/pytorch

またChatGPTにも、各フォルダがどのような役割をしているのかを簡単に聞いてみました。

![lightningフォルダ構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740560/a825a9f7-54b8-fdde-07d4-0195925f4b5c.png)

出力にもある通りChatGPTの内容は2022年1月時点の内容であるためディレクトリの構成は若干違いますが、各フォルダの役割に関してある程度全体像を掴むことができました。

ある程度全体像を掴むことができたので、`LigtningModule`について読んでいきます。

一旦「LightningModule」でリポジトリ内を検索してみます。
早速、`LightningModule`について記述されていそうな場所を見つけました。

![Code search results - Google Chrome 2023_09_20 15_47_31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740560/6f0ce397-b9a2-2c50-7b6a-af2cc3bd84a3.png)

この`LightningModule`の仕組みを把握するために、中身を読んでいきます。

まずは全体をざっと眺めます。
親となるクラスが複数存在し、関数やクラスメソッド、オーバーロードが多く記述されています。

github上では、クラス内にどのような関数や変数が記述されているのかを構造的に書いてくれています。
![5github_func.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740560/61074f2d-73b1-87a0-9c60-0479cfcc2dd6.png)
これは全体像を把握する上では大変便利です。

次に、自分が仕組みを把握するために重点的に読む部分を決めました。
具体的には、

・元となるクラスの構造
・自分も使う、主要な関数の仕組み
・気になる関数の役割

を読みました。
深く読もうと思えばもっと深く読むこともできますが、ここは自分の持つ時間と目的との兼ね合いで考えましょう。

まずは元となるクラスの構造とその役割を見ていきました。
元となるクラスは5つあることが分かります。
それぞれについてリポジトリ上で検索をして、記述されている場所を探しました。

以下は１つめの親クラスに関しての記述です。
![hyper.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740560/210dc4a7-8f06-5a05-0fa8-2a105fa0ac4b.png)

この時、親クラスの呼び出し順について復習するために、自分でコードを書いて実行をするなどをしました。
```python:myclass.py
class BaseClass:
    def __init__(self):
        super().__init__()
        print("BaseClass init")
        super().__init__()

class SecondClass:
    def __init__(self):
        print("Second init")
        super().__init__()

class ThirdClass:
    def __init__(self):
        print("Third init")

class MyClass(BaseClass, SecondClass, ThirdClass):
    def __init__(self):
        super().__init__()
        print("MyClass init")

myclass = MyClass()
```
```
Second init
Third init
BaseClass init
Second init
Third init
MyClass init
```
`super().__init__`によって次に記述されている親クラスのコンストラクタが呼び出されることが確認できました。

次の親クラスである`ModelHooks`, `DataHooks`, `CheckpointHooks`は同じファイル内に記述してありました。
こちらもそれぞれ読んである程度の役割を把握しました。

残るはModuleクラスです。Moduleクラスに関しては、
```python:module.py
from torch.nn import Module
```
でインポートされているため、lightningではなくpytorchに記述されているクラスのようです。
今回の目的とは少し逸れますが、この`Module`クラスの場所も探したいと思います。

pytorchのリポジトリ

https://github.com/pytorch/pytorch

を眺め、それぞれのフォルダの中身を見てみましたがどこに記述されていそうか見当がつきませんでした。
リポジトリ内を検索をしても様々なmoduleという単語がヒットしてしまい見つかりそうにありません。
そこで、今回はChatGPTに聞いてみることにしました。
![moduleの場所.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2740560/d3e88b16-4e7d-3d34-5091-f0630d9f5d7a.png)
今回の場合は一発でそのファイルへのリンクを出力してくれました。
以下がそのリンクです。

https://github.com/pytorch/pytorch/blob/main/torch/nn/modules/module.py

Moduleクラスが記述されていることが分かります。
Moduleクラスに関しては今回の目的に対して重要ではないので、眺める程度にとどめました。

# まとめ
今回はOSSを題材に、コードリーディングのに関する進め方、気を付けた方がよいことをまとめました。
これらを意識するだけで効率の良いキャッチアップを行うことができると思いますので、ぜひご活用ください！


::: note
弊社Nucoでは、他にも様々なお役立ち記事を公開しています。よかったら、Organizationのページも覗いてみてください。
また、Nucoでは一緒に働く仲間も募集しています！興味をお持ちいただける方は、[こちら](https://www.recruit.nuco.co.jp/?qiita_item_id=5c37eea3663068d6fd65)まで。
:::
https://www.recruit.nuco.co.jp/?qiita_item_id=5c37eea3663068d6fd65