ソースコードを楽しんで読むためにコミットログを漁る

SF小説を読まずにSF作家になった人はいない。それと同じく、ソースコードを読まずして優秀なエンジニアになった人はいないと僕は思います。
Smalltalkの青木先生も以下のようにおっしゃられてます。

http://www.cc.kyoto-su.ac.jp/~atsushi/Links/bcn/BCN_ShiTen_20090316.html

この記事に感化されてソースコードを読むのですが、いくら読んでも意味がわからないということはよくある話。ということで、僕が考え出した手が、

#githubのhistoryを読む！

という手です。ということで、githubのhistoryを読むのですが、これが結構面白い！

例えば以下のコミットログですが、

https://github.com/django/django/commit/d6ea4898c44f75a25bc0b7a60b54fd6dddc69eb5

Fixed decoding of non-UTF-8 bytes objects in response.json().

つまり、response.json()でUTF-8じゃないバイトオブジェクトが返された時の振る舞いを直してます。

```
response._json = json.loads(response.content.decode(), **extra)
```
というソースコードを、以下のように直してます。

```
response._json = json.loads(response.content.decode(response.charset), **extra)
```

ただ単に、response.charsetを引数として加えてるだけですね。これを加えるだけで、UTF-8じゃないバイトオブジェクトがきた時に対応しているようです。

テストケースもちゃんと同時に記述してます。

```python
def test_json_charset(self): 
    response = self.client.get('/json_response_latin1/') 
    self.assertEqual(response.charset, 'latin1') 
    self.assertEqual(response.json(), {'a': 'Å'}) 
```

で、ここで疑問が湧いてくるのが、'Å'は別にUTF-8であるよねと思う。で、以下のサイトを見てみる。

https://charbase.com/00c5-unicode-latin-capital-letter-a-with-ring-above

JavaScript Escapeだと、'\xc5'という文字になる。で、コミットログを見てみると、。

```
def return_json_response_latin1(request):
    return HttpResponse(b'{"a":"\xc5"}', content_type='application/json; charset=latin1')
```

これはテストケースの一部なんだけど、つまるところ、JavaScriptのクロスサイトスクリプティング防止機能で、'Å'がエスケープされた時、いろいろ問題が発生したんじゃないかという推測ができる。

もう一つ見繕ってみる。

https://github.com/django/django/commit/7feddd878cd0d4ad6cc98f0da2b597d603a211a7#diff-97160f50594424a40f2621d5a3c581cc

Added support for the test client to return 500 responses.

レスポンスコード５００はInternal Server Error（HTTP500エラー）ですね。
このコミットはテストクライアントに、５００レスポンスをサポートさせた形になる。

以下はテストケースのクライアント側のコード。リクエストの例外を含むかどうかを設定する引数を加えている。

```python
    def __init__(self, enforce_csrf_checks=False, raise_request_exception=True, **defaults):
        super().__init__(**defaults)
        self.handler = ClientHandler(enforce_csrf_checks)
        self.raise_request_exception = raise_request_exception
        self.exc_info = None
```

self.handler = ClientHandler(enforce_csrf_checks)で、CSRFのチェックを強制してるのかな？

変更点はもう一つ

```python
raise exc_value
```

変更前は正直に例外値をraiseする
変更後は以下の通り

```python
if self.raise_request_exception:
    raise exc_value
```
もしもself.raise_request_exceptionがTrueだった場合のみ、例外値をraiseする。

以下のようなテストコードも追加されてます。

```python
    def test_exc_info(self):
        client = Client(raise_request_exception=False)
        response = client.get("/broken_view/")
        self.assertEqual(response.status_code, 500)
        exc_type, exc_value, exc_traceback = response.exc_info
        self.assertIs(exc_type, KeyError)
        self.assertIsInstance(exc_value, KeyError)
        self.assertEqual(str(exc_value), "'Oops! Looks like you wrote some bad code.'")
        self.assertIsNotNone(exc_traceback)

    def test_exc_info_none(self):
        response = self.client.get("/get_view/")
        self.assertIsNone(response.exc_info)
```
リクエスト例外の設定をFalseにした状態で、壊れたビューにアクセスする。そうなるとサーバー側のエラーなので、５００が帰ってくる。exc_typeとexc_valueは返さない。ただし、exc_tracebackはNoneにして欲しくないみたい。
セキュリティ上の理由から、exc_typeとexc_valueをサーバに生成して欲しくない場合が存在する。その場合の状況をクライアントにテストしてもらうためにはこうするみたい。

exc_typeとexc_valueのそれぞれの意味は以下の通り

- *type*: The type of the exception. （例外のタイプ）
- *value*: The exception instance. （例外のインスタンス）
- - *traceback*: A traceback object which encapsulates the call stack at 
           the point where the exception originally occurred. 

test_exc_info_none()テストケースでは、普通の存在するビューにアクセスした時に、response.exc_infoを返して欲しくないみたい。

ちょっと奥歯に何かが挟まったような感じになりました。

#まとめ
結構こういう、ソースコードを読みたい時にコミットログを読む方法って有効に思えるんだよね。ただ単にソースコードを読んでいくよりも。
Linuxカーネルとかもgithubにコミットログ付きでホストされてるので、悪くない方法かなと思う。