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

いまさら聞けない「コードの英語」超入門

広告事業部の鈴木達矢です。コーディングをしてると変数やメソッド名の付け方に悩むことって多々ありますよね。逆にコードを読んでいると単語の選択がこれでいいのかなという時や、動詞の活用形が間違っていてよく意味がわからない、時に潔く日本語の変数名になっていることも見かけます。でもプログラミング言語の単語が英語をベースにしていますし、Railsを使っている場合は日本語が規約(Convention)に合わなかったりします(複数形が無いなど)。それから動詞の活用形が違っていると主語(動作の主体)が変わってしまい、意味が変わってしまいます。その結果コードの可読性が落ち混乱を招きやすくなります。

いくつかの基本的な法則だけおさえておけばコーディング中に可読性の高い単語の選択ができるようになります。今回はそれを目的に、英語の扱いに都度時間を費やしてしまうような方に向けていくつかの法則をご紹介します。*1

変数やメソッド名の選定

単語の意味の範囲

辞書を引いて見つかった単語をそのまま使っているケースをよく見かけます。日本語の単語の意味の範囲と辞書で見つかった英単語の意味の範囲が異なる場合があるので注意が必要です。

例. 広告のキャンペーン企画の案件終了日時の終了日に使う変数として以下の名前をつける例

  • 日本語:案件終了日時
  • 変数名:issue_end_datetime

案件終了日時という単語は一つの単語としては英語辞書にはありません。ですので、それぞれの単語をばらばらに辞書で引いた結果、案件_終了_日時という変数名が出来上がったのではないかと思われるケースです。正解は無いですが私の場合はcampaign_ends_atと命名すると思います。*2

ここで浮かび上がるのが案件に対してissueという単語が適当なのかという疑問です。辞書を引く際に前提として注意すべきなのが、「日本語と英語では単語の意味の範囲が違う」ということです。

f:id:szkmp:20150831141900p:plain

上の図は案件issueをそれぞれ類語辞典で引いた結果です。争点、出来事、問題、論点といった意味では意味の範囲が重なっています。そのためissueという単語が選ばれたのですが、今回のキャンペーン企画プロジェクトという意味では意味の範囲が重なっていません。issueという単語をその意味の案件として使うのには無理がありそうです。

ある単語の意味の範囲をどこに据えるか、言い換えるとどのシーンを言い表すのに適当な単語を使用するのかというのはまさに集合知で、それが決まるまで判断には文化的背景が深く関わります。それから日本語には曖昧な単語を広い場面で使用する癖があるというのも知っておくと良いと思います。*3

つまり、そういったことを前提により正確に表したいものをまずは再定義するとより良い訳に近づけると思います。さらに英語の類語辞典を使ってより意味が重なる範囲が多い単語を選ぶと良い結果に近づけます。この場合は企画計画という意味に近いcampaignという単語を選びました。

日本語変数名

日本語変数名はそれが表すものが固有名詞の場合は使っても良いと思います。例えばクックパッドにはあるレシピに対してつくったよをレポートするつくれぽという機能がありますが、これは説明すると長い概念ですからひとまとめの固有名詞としてtsukurepoと呼ぶのは良いと思います。

それ以外の場合は、先にもあげたようにRailsの場合規約に合わなかったり、アルファベット表記の日本語がいっぱいあると可読性が落ちたりするので基本的には英語に寄せるのが良いでしょう。

原形・現在分詞(-ing)・過去分詞(-ed)?

時々見かけるのが動詞の活用形が間違っているケースです。間違えると意味が変わってしまうので注意が必要です。以下に最も推薦できる形をリストしました。

コミットコメント

コミットタイトル(最初の行)は基本的に動詞の原形で始めます。本文は普通の文章で説明的に書いて大丈夫です。

Summarize changes in around 50 characters or less

More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.

引用元

コード中のコメント

対象のメソッドやラインを主語として動詞の原形、もしくは三人称単数形で書かれることが多いようです。プロジェクト中でそのどちらかに統一されていれば良いと思います。

# Converts the object into textual markup given a specific format.
#
# @param format [Symbol] the format type, `:text` or `:html`
# @return [String] the object converted into the expected format.
def to_format(format = :html)
  # format the object
end

引用元

メソッド名

各言語によって慣習が異なると思いますが基本的にはメソッドが所属するクラスを主語とした時の動詞の活用形に合わせます。

class Car
  # A car runs
  # 主語: Car
  def run
  end

  # A car is running?
  # 主語: Car
  def running?
  end

  # A car has navigation system?
  # 主語: Car
  def has_navigation_system?
  end

  # A car is permitted to be shipped?
  # 主語: Car
  def shipping_permitted?
  end

  # Someone commands to ship a car to a country.
  # 主語: 誰か(業務ロジック中の主体)
  def ship_to(country)
  end
end
  • has_navigation_system?

Railsの慣習では疑問系に三人称単数を使います。自然言語としての英語の疑問系はDoes the car have navigation system?もしくはThe car has navigation system?ですが、おそらく変数から呼び出すときのcar.has_navigation_system?がより自然に響くので後者の疑問形の例の形になっているのだと思います。

  • shipping_permitted?

自然言語ではA car is permitted to be shipped?が自然に響くのでpermitted_to_be_shippedでも良いですが、長いのでpermitとshipを一つの形容詞的な感覚にしてshipping_permitted?としています。(この辺は賛否あると思います。)

  • ship_to(country)

蛇足ですが、最後のship_to(country)はshipが他動詞なので(shipは自動詞にもなりうりますが、この場合Carが何かを出荷しするわけではない)ほかに主語がありそうに感じます。だから、(実際にはCar classにあるような場合もよく見かけますが)主語がCarと異なるのでなんとなく別の場所に実装があるべき匂いがします。

RSpecの英語

RSpecの英語は特殊です。英語の短縮形に似ていますが、もっと独特な書き方をします。よく気になるところを挙げてみました。*4

whenの後の過去分詞

describe Car
  describe "#" do
    context "when it is permitted to be shipped" do
    end

    # 主語とbe動詞を省略して良い
    context "when permitted to be shipped" do
    end
  end
end

describeされている主語(Car)を形容する感覚でpermittedを使うことができます。permitするのはCarではなく、Carpermitされるので過去分詞です。

このような感覚で主語を省略し、よりcontextを短くすることができます。長い小説的な文章によるcontextは可読性が落ちますのでなるべくこの形をとるのが望ましいです。

前置詞の後は現在分詞

そんなの当たり前だと思われる方もいるでしょうが前置詞の後に動詞の原形があるのをよく見かけます。forやaboutなどの前置詞のあとは名詞的に現在分詞を使用します。 it "consumes a litre of petrol for completing a round trip"*5

日本語の癖

動詞を名詞的に使う

日本語はすごく便利で熟語的に単語をつなげることで名詞を形容的に使い事物を表すことができます。しかし、同じことを英語で行うと別の意味になることがしばしばあります。例えばよく見かける例としては単語をなんでも名詞的につなげて変数名とするケースです。

class Car
  def fuel
    complete_round_trip = true/falseを返す処理
    ...
    if complete_round_trip
      ...
  end
end

このような一時変数名を見かけた場合はまっさきに往復行程を完了せよという意味のメソッドだと思ってしまいます。completeが動詞として脳に飛び込んでくるからです。おそらく最初に熟語的に日本語でコンプもしくはコンプリートするのコンプリートを名詞的に羅列し、その結果を直訳した結果ではないでしょうか。しかし、英語のシンタックスが分詞と語順に支配されていますので原形の動詞が先頭に来るとまずは命令形である往復行程を完了せよという意味を思い浮かべてしまいます。Carround tripを完了したという形容的な意味で過去分詞を使用してround_trip_completedとした方が良いです。

日本語はコンテキスト依存の高い省略の多い言語

これは日本語に限ったことではないのですが、日本語はよりコンテキストへの依存が高く正確でならないといけない場面で思わぬ間違いを引き起こすことがあるので注意が必要です。

  • 現にあったopenという名前による勘違い

これは実際に最近あったケースです。かなり過去にコンテスト開催中という意味でContest.openというメソッドが定義されていて、ページビューの集計にそのメソッドを使おうとしたところ集計期間が足りなさそうということが発覚したということがありました。実際にはコンテストには公開中に募集期間審査期間発表期間という三つの期間の概念がありましたが、openがカバーしていたのは募集期間のみで、それに対して集計処理は全ての期間を集計対象としていました。

募集期間に対してopenという単語が選択されていたわけですががopenだったのか翻訳の過程で失われてしまっていました。募集がopenだったのか案件の公開状態がopenとも取れるので、さらに具体的に意味を狭めるopen_entryなどをここでは名前として使用すべきでしょう。コンテスト開催中とはユーザさんにとっては募集期間中であり、公開期間中を通じた訪問者数を知りたいキャンペーン主の立場からすると先述の3つ全ての期間なのでした。このように日本語はコンテキストによって意味が変わりやすいので単語の選定の際には注意が必要です。

便利なサイト

意味をキーに類語がグループ化されているので自分が欲しい類語を探しやすいです。

類語(synonyms)だけでなく上位語(hypernyms、より広義の単語)、同じコンテキストで登場する単語(same context)、今調べている単語を意味の解説に持つ語(reverse dictionary)など様々なアルゴリズムの関連語を提示してくれます

Stackexchangeの英語サイトでword-choiceのタグが付いている質問の回答がよく解説してあったりして便利です。時間があってとことん突き詰めたいときはこちらで質問すると便利です。

まとめ

  • それぞれの言語にそれぞれの単語の範囲があることを意識してより狭義の意味で短い単語を選定しよう
  • 主語がだれなのかを意識して動詞の活用形を決めよう
  • 日本語の癖(ハイコンテキスト、名詞を形容詞的に使う)が単語の選定に影響しないように意識しよう

このように、いくつかの基本的な法則を頭に入れればあまり迷うことなくコーディング中に英語を選定することができます。また、後々に間違いを引き起こし、事後処理に時間を使うというような間違いを引き起こすというのがワーストケースですので、より正確な意味を考えるのに時間を費やすのはそれなりに価値があることです。あなたの現場の英語も見直してみてはいかがでしょうか?

*1:なお本記事に関してネイティブスピーカーのレビューをしていただいています。

*2:タイムテーブルのように時間が定まっている場合はends(第一人称単数)を使用し、日時を表す時はそれに続くatを使用します。

*3:参考

*4:なお、Better specs(http://betterspecs.org/)がとても参考になりますのでチェックしてみてください。

*5:round tripは往復(行程)という意味です

/* */ @import "/css/theme/report/report.css"; /* */ /* */ body{ background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527163350.png'); background-repeat: repeat-x; background-color:transparent; background-attachment: scroll; background-position: left top;} /* */ body{ border-top: 3px solid orange; color: #3c3c3c; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; line-height: 1.8; font-size: 16px; } a { text-decoration: underline; color: #693e1c; } a:hover { color: #80400e; text-decoration: underline; } .entry-title a{ color: rgb(176, 108, 28); cursor: auto; display: inline; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; font-size: 30px; font-weight: bold; height: auto; line-height: 40.5px; text-decoration: underline solid rgb(176, 108, 28); width: auto; line-height: 1.35; } .date a { color: #9b8b6c; font-size: 14px; text-decoration: none; font-weight: normal; } .urllist-title-link { font-size: 14px; } /* Recent Entries */ .recent-entries a{ color: #693e1c; } .recent-entries a:visited { color: #4d2200; text-decoration: none; } .hatena-module-recent-entries li { padding-bottom: 8px; border-bottom-width: 0px; } /*Widget*/ .hatena-module-body li { list-style-type: circle; } .hatena-module-body a{ text-decoration: none; } .hatena-module-body a:hover{ text-decoration: underline; } /* Widget name */ .hatena-module-title, .hatena-module-title a{ color: #b06c1c; margin-top: 20px; margin-bottom: 7px; } /* work frame*/ #container { width: 970px; text-align: center; margin: 0 auto; background: transparent; padding: 0 30px; } #wrapper { float: left; overflow: hidden; width: 660px; } #box2 { width: 240px; float: right; font-size: 14px; word-wrap: break-word; } /*#blog-title-inner{*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-position: left 0px;*/ /*}*/ /*.header-image-only #blog-title-inner {*/ /*background-repeat: no-repeat;*/ /*position: relative;*/ /*height: 200px;*/ /*display: none;*/ /*}*/ /*#blog-title {*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527172848.png');*/ /*background-repeat: no-repeat;*/ /*background-position: left 0px;*/ /*}*/