読者です 読者をやめる 読者になる 読者になる

methaneのブログ

このブログに乗せているサンプルコードはすべてNYSLです。

言語とリーダビリティ

この記事は 勝手に添削: PHP初心者向けのコード最適化 の続編です。リーダビリティの定義は前と同じく、「そのコードが何をしたいかを把握する時間+そのコードをレビューして正しいと自信を持てるまでの時間」の短さです。

よく「php よりも Python の方がリーダビリティが高い」という主張に対して、「Pythonでも糞コードはかける」「言語よりも人の問題だ」といった反論をする人がいます。

この反論をする人は「同じ程度のスキルの人が同じ程度の丁寧さでコードを書く」という暗黙の前提が伝わっていなくて、「リーダビリティは言語に依存して人には依存しない(あるいは人よりも言語に強く依存する)」という主張だと誤解しています。(この主張にかぎらず、大抵「◯◯でも悪い△△は存在する」という類の反論は、暗黙の前提を理解していないか、あるいはわざと無視しているケースが多いです)

言語設計が(書き手のスキルほどでないにしろ)リーダビリティに影響を与える例を、先ほどの前の記事のコードを例に説明します。

<?php
//...
        $nameIds = array();
        foreach ($sampleList as $sample) {
            $nameIds[] = $sample['name_id'];
        }
//...
        $nameMap = array();
        foreach ($nameList as $name) {
            $nameMap[$name['name_id']] = $name['name'];
        }

この部分は、 Python の内包表記を使うと次のように書けます。

    name_ids = [s['name_id'] for s in samples]
#...
    name_map = {n['name_id']: n['name'] for n in names]
    # Python 2.6 の場合は
    name_map = dict((n['name_id'], n['name']) for n in names)

配列や連想配列に追加していく、というループが、要素を列挙するという書き方になることで簡潔になり、コードレビューをする場合に注意しないといけない点が減っています。(余談ですが、存在しないキーへのアクセスで例外が起こるので、警告メッセージを出すだけで処理を継続してしまうphpよりも安全ですし、 php プロジェクトでよくある警告メッセージをちゃんと確認しないメンバーリスクも Python には存在しません)

一方で、内包表記は、特に数学の内包表記に馴染みがない人にはそれなりの学習コストがかかります。これは構文にかぎらず、リーダビリティをあげることを目的としたあらゆる便利関数などにも当てはまります。

リーダビリティの単位は「時間」なので、学習コストと天秤にかけることができます。その構文なり便利関数を追加することで下げられる時間が学習にかかる時間を上回るという確信があれば、それを利用するべきです。その構文なり便利関数の利用機会が少なかったり、ほとんどリーダビリティを上げていないのであれば、追加するべきではありません。

内包表記に関して言えば、こんな簡単なサンプルで2回も出てくるほど利用機会が多いので、例えば1週間以上かかる規模のプロジェクトなら元が取れるでしょう。一方、まだ内包表記を知らなくて、読まれる機会が少ない書き捨てのスクリプトを書くなら、使う必要はありません。

さて、前回のサンプルを Flask + SQLAlchemy 風に書き直してみます。

前回の php のコード と見比べてください。 これは、同一人物が、同じような丁寧さで書いたコードです。

今回のサンプルではでてきませんが、内包表記以外にも、プロパティや、ソート順の指定方法など、頻出してリーダビリティを大幅にあげる機能があり、感覚値ですが行数やレビューにかかる時間が1/2~3/4程度になります。

Web アプリ開発を主な仕事として2年以上続けるのであれば、現在 PHP を書いているプログラマーが Python を新しく覚える価値は十分にあると思います。 (おまけで、スレッドや、使いやすいインタラクティブシェルや、Web以外の分野のライブラリも付いてきます)

リーダビリティを上げて節約した時間で、さらにリファクタリングやテストをして品質を上げたり、恋人や子供やペットと過ごしましょう。