メソッド名/関数名には戻り値が予想できるような名前をつける

概要

名前付けって難しい。
自分は名前付けがとくに苦手で、以前飼っていた金魚の名前は「金魚ちゃん」だった。
ペットの名前付けが難しいように、メソッドの名前付けも難しいのだ ()

今回は、名前付けがまだまだな駆け出し時代の例を振り返ってみよう。

まえおき

ここに登場するコードは以下で実装されたものを前提としている。

例やコードは、サンプル向けにアレンジしたもののため、違和感はご愛嬌。

やりたかったこと

書籍idを引数で受け取って、合致する書籍があれば書籍オブジェクトを返し、合致しなければ例外を送出するメソッドをつくりたかった。
以下のようなコードである。


class Book:
  ...
  def has_book(book_id: int) -> Book:
      """book_idに合致する書籍が存在するかを判定する

      :param book_id: 検索対象の書籍id
      :return: book_idに合致した書籍
      :raises BookNotFoundError: book_idに合致する書籍が存在しない場合に送出
      """

      try:
        book = Book.objects.get(id=book_id)
      except Book.DoesNotExist:
          raise BookNotFoundError

      return book

このコードの問題点

上記のコードは、以下の点でイマイチである。


  • has で始まるメソッド名なので bool を返すのかと思いきや、Book オブジェクトを返している
  • docstringには、書籍の存在有無を判定するという内容の説明が書かれているので、これまた bool が返りそうだがそうではない

総じて、メソッド名と docstring の説明が処理内容と合っていない!!

なぜこうなった?

  • 「◯◯が ある かどうか」を調べるためのメソッドなので、has でヨシ!と思った
  • bool を返すメソッド名/関数名には、一般的に hasis のような名前が使われるという前提知識がなかった

どうするとよさそうか?

  • とりあえず、リーダブルコードは駆け出しのうちから読んでおこうな
  • 今回の場合は、Book クラスの中に定義されたメソッドであり、Book オブジェクトを1件返すメソッドなので、return_by_id() という名前でよさそう (book は省略)
  • Book.objects.get() を使っているので、get_by_id() でもよいかもしれない
  • Django の場合は .get().filter() のような ORM メソッドを使うので、get や filter の単語をメソッド名に使うことがある
    • が、単に「取得する」の意味合いで get や filter の単語を使う場合は要注意
    • 外部サービスからデータを取得するなら fetch が適しているだろうし、ファイルの内容を取得するなら load のような名前が適しているだろう

おわり

駆け出しの頃はコードを書くのに精一杯で、名前を考えることに時間を使うのはもったいないと思っていた (むしろ時間をかけてはイケナイと思っていた)。
が、シニアエンジニアでも「名前付けは難しい」「名前は大事」と言っているのを聞いたり、メソッド名や変数名に対するレビュー指摘をもらうことがちょこちょこあったり、他のメンバーも指摘を受けているのを見たりしたので、「やっぱり名前付けって難しいんだ。名前を考えることに時間を使うのはイケナイことではないんだ」と知って安心したことを思い出した。

名前付けに困っている場合は、下記のような状態になっていることもありえるので、やはり名前付けは大事なんだなぁと思った。

逆にふさわしい名前がつけられないということは、その機能が果たすべき役割を設計者自身も十分理解できていないということ プログラマが知るべき97のこと > 107.名前重要 Matz

以前までは codic や翻訳機能を使ったり、他の人が書いたコードを読んだりして参考になる名前を探していたが、今はAIでいろんなサンプルを提示してもらえるので、そのようなサービスも積極的に活用していきたい。

参考