とりゅふの森

GCPデータエンジニアとして生きる

【リーダブルコード】新人ITエンジニアが抑えておきたい、コーディング3つの基礎

プログラミング言語をなにか一つ、学ぶ時、
はじめはHello Worldの出力から、
その後演算子、条件分岐、ループ、メソッド、クラスと、基礎を学んでいき、
最終的になにか一つ簡単なアプリケーションを作ってみる、
といった流れが一般的だと思います。企業のITエンジニア向けの新人研修でも同じ感じですね。
f:id:true-fly:20201205230845p:plain

そして、実際の開発現場の配属になると、研修で学んだこと以上の難しさが現場にはあって、みんな挫折するわけです。
(僕の場合はプログラムを書くことなく、いきなりオンプレからクラウドへのシステム移行をやらされ、C#を二度と書くことはなかったのですが。)

ちょうど今、新人研修を終えて現場に配属となった後輩のOJTを担当して、同じチームで開発をしているのですが、
やはり実際の開発現場に入ると、研修では学んでいないことのほうが多いと新人本人も感じているみたいです。
プログラムの変数名の付け方1つとっても、独学や研修で学んだ人と、何年も現場で働いている人とで考え方が異なってくるみたいなんですよね。
f:id:true-fly:20201205230859p:plain


今回は、そんな新人たちのような、プログラミングの基礎を一通り学んだ人が次に学ぶべきことについてお話したいと思います。

自分の書くコードに魂を込めろ

まずはこの本を読みましょう。『リーダブルコード』です。
260P程度で、翻訳本ですが実際のコードの例も併せて読みやすい本です。
2006年代にアニメオタクになった人が『涼宮ハルヒの憂鬱』を見てきたように(新刊発売おめでとう)、
コードを書くITエンジニアたちも皆、これを読んでいます。

この本、一言でいうと、

チーム内でプログラムを書く上で考えないといけないことを完結にまとめた本

です。

自分でプログラミングの基礎を身に着けたと思ったら、その次に考えなきゃいけないのは、

他人に自分の書いたコードを読んでもらう。

これに尽きます。自分一人でできたとしても、他人のレビューが入り、
リリースしたとしても、いつか他人がそのコードを変更するときがくるのです。

僕の手元の版の『リーダブルコード』の12章のタイトルは、
コードに思いを込める
でした。これをもじったのか、僕の友人が後輩を指導する時に、
「コードに魂を込めろ」
と言ったみたいです。
言い回しはどうであれ、自分の書いたコードに責任を持って書けるようになろうということですね。

では、この本を読んだ人も読んでない人も、具体的に、プログラムを書く時にどのようなことを考慮していけばいいか、考えていきましょう。
『リーダブルコード』に書いてある内容をベースに、
僕が最低限これだけは抑えておいてほしいと思う、コーディング3つの基礎をまとめました。

名前の付け方を考えよう

短いサンプルコードを見ながら少し極端な例でお話します。
例えば以下のようなコードがあったとしましょう。

def get_user_list():
    """ 外部システムからユーザ情報のリストを取得する

    Returns:
        list: ユーザ名のリスト
    """
    # 中略
    return user_list

def user_check(user):
    """ ユーザがユーザ一覧リストに存在するかを確認する
    
    Args:
        user_name: (str): ユーザ名
    
    Returns:
        boolean: ユーザ一覧リストに存在すればTrue
    """
    values = get_user_list()

    error_flg= True
    if user in values:
        error_flg= False
    return error_flg

user_checkメソッドを使って、ユーザが存在するかどうかを確認するだけの処理です。
このコード、とりあえず動くと思いますが、なにがいけないかを考えてみましょう。

変数名はパッと見て何を表現しているのかわかるようにする

サンプルコードの19行目の

values = get_user_list()

valuesという変数にユーザ一覧リストの情報を代入しています。
今回の場合、変数のスコープが小さい(=valuesを使っている箇所がメソッド内のみでかつ行数が少ない)ので、大きな問題にはなりませんが、このvaluesという変数が100行先、200行先にも繰り返し現れるとしたらどうなるでしょう?
「あれ?このvaluesにはなにが入っているんだっけ?型は?」
となるはずです。
変数名は、それだけを見て何が入っているのか、どんな型なのかがわかるように命名するべきです。
今回の場合、ユーザ一覧リストなので、user_listという名前にすればよいかと思います。
これだけでユーザのリストが入っているんだなとわかるし、listで終わっているからきっとlist型なのだろうと推測ができるようになります。

何だ当たり前じゃんと思う方もいるかもしれませんが、意外とこういうケースよく見かけます。
独学で学んできた人に指摘してみると、
「変数名の意味なんて考えたこともありませんでした」
と言われてしまいました。
まずは変数名に意味を持たせることから考えましょう。

○○フラグという変数名には注意

サンプルコード21行目のこの変数、

error_flg = True

これややこしくないですか?
普通に考えると、ユーザが存在するならTrue、ユーザが存在しないFalseですよね。
でもサンプルコード、逆になってます。ユーザが存在するならエラーではないからFalse、という考え方ですね。

よく変数名に、○○_flagとか、〇〇_flgのような命名を見かけますが、避けるべきだと思います。
フラグだと、どちらがTrueで、どちらがFalseなのかがわかりにくいからです。
真偽値の場合は、以下のような、「動詞 * 名詞・目的語・過去分詞など」の形で表現することが多いです。

変数名の例 意味 使い所
exists_user ユーザが存在する。 データベースにユーザが存在するかどうかを確認する時など
valid_user ユーザが有効である 入力された内容が適切であるか確認するときなど
is_failed 失敗している 前の処理が成功したかどうかを判定する時など

他にもcanやhasなどで始まるパターンもあります。真偽値の変数名が個人的には一番考えるのが大変だと思ってます。
今回の場合は存在チェックなので、exists_userが適切ですね。

メソッド名は動詞+αにしよう

サンプルコード10行目のメソッド、ユーザが存在するかチェックするメソッドですね。

def user_check(user):

これまず英文法的におかしいです。これだと「ユーザがチェックする」ですね。ユーザはチェックされる方なので、
順番を入れ替えて、check_userのほうが文法的にはベターです。
メソッドはプログラムの動作を担うものなので、動詞+αの形で命名するのが一般的です。

更にもっと言うと、「何をチェックするのか?」と突っ込まれます。
今回の場合は真偽値を返すメソッドなので、真偽値の変数名の時のように、どういう場合に真となるのかがわかるようになっていなければなりません。
なのでexists_user()というメソッド名が良いと思います。

メソッドは1つの機能にしよう

今度は機能もりもりのサンプルコードを書いてみました。

def check_validate_create_user_create_user_file(user_name)
    """ ユーザの存在チェックと
    名前の整合性チェックをし、
    ユーザを作成し、
    ユーザ情報をファイルに作成し、
    そのファイルパスを返す
    """
    # ユーザリストを取得
    user_list = get_user_list()
    
    # ユーザの存在チェック(本来は同姓同名の人もいるのでこんな判定はしないけど)
    exists_user = False
    if user_name in user_list:
        exists_user= True
        # すでに存在していたらなにもしない
        return

    # 名前の整合性チェック
    if user_name is None or len(user_name) > 50:
        raise UserNameException('ユーザ名が不正')

    # ユーザが存在しなければDBにレコードを新規作成する
    user_id = create_user(user_name)
    
    # ユーザ情報をファイル出力する
    file_path = 'path/{}.txt'.format(user_name)
    with open(file_path, 'w') as f:
        f.write('ID:' + user_id)
        f.write('\n')
        f.write('名前:' + user_name)
    return file_path

まずこんなこと書く人ありえないのですが、やりたいことが多すぎてもはやどうなっているのかわからない状態です。
全体の処理の流れがこうなるのはよいのですが、メソッドを適切な形に分解できないと、このようにメソッド名がわけわからないことになります。
メソッド名は動詞+αというルールに従うのであれば、メソッド名は原則1つのことを処理するべきです。

今回やりたいことを、

  • ユーザが存在するかどうか確認する
  • 名前の整合性を確認する
  • DBにレコードを新規作成する
  • ユーザ情報をファイル出力する

といったように、
「○○する」のように動作を書き出してみましょう。
そしてこれら1つずつがメソッドだとした時、きっと名前がつけられるようになるはずです。
メソッドが適切な形、1メソッド1処理の形に分解できてはじめて、メソッドに対して適切な名前がつけられるようになります。

コメントを書きまくれ

よく処理だけを書いて、コメントを全く書かない人がいます。短いコードを書く競技プログラミングでもかない限り、なるべく多くのコメントを書くべきです。
わかりきった不要なコメントは書くべきでないという意見もありますが、僕はパッと見て見にくくなければコメントは多い方が良いと考えてます。
メソッドやクラスにはdocStringといったコメントの書き方があります。メソッドの処理概要、引数、返り値、例外などを、指定のフォーマットで記述すると、それがメソッドのドキュメントとなります。このメソッドを外部から呼び出す時に、docStringをちゃんと書いていれば、その仕様を把握することができます。

僕の場合、処理を書くよりも先にコメントから書くケースも少なくないです。自分の中で書きたいことを整理できるのと、あとから見返した時にわかりやすいのでそうしてます。たかがコメント、されどコメント。特に英語圏ではなく、日本語で詳細を書くことに大きな意味を持つ日本の開発現場では、コメントの充実したコードを書いていくべきかなと思っています。

def exists_user(user):
    """ ユーザがユーザ一覧リストに存在するかを確認する
    
    Args:
        user_name: (str): ユーザ名
    
    Returns:
        boolean: ユーザ一覧リストに存在すればTrue
    """
    # データベースからユーザ一覧を取得する
    user_list = get_user_list()

    #ユーザ一覧リストに存在するか確認
    exists= False
    if user in values:
        exists= True
    return exists

まとめ

以上、新人エンジニアがプログラムを書くことにある程度なれてきた時に、
僕が最低限これだけは抑えておいてほしいと思うコーディング3つの基礎を紹介しました。
どれも簡単なことかと思いきや、ベテランエンジニアでも意外と意識できなかったり悩んだりする、
プログラムを書く人だったら永遠のテーマだったりするのかもしれません。

今回紹介したこと以外にも、この『リーダブルコード』にはコードを読みやすくするテクニック、
美しいコードを書くテクニックがたくさん書かれています。
全ITエンジニア必読の書だと思うので、少しでも良いコードを書きたい方はぜひお手にとってみてください。