晒すつもりではありませんが、Facebook で友人のとある投稿を見かけて最初は「三単現にしないと💢」という軽い気持ちで返答したのですが、よくよく考えて見たらこれ思った以上のクソ命名でしたので、とりあえず流れのスクショを上げときます:
はい、今回の記事はマサカリです。あしからず。
見ての通り、最初は友人の後輩ちゃんが isCanUseSkill
という明らかにアレな命名をしてきたので、友人がそれを指摘をするも、まさかの allowSkill
という更にダメな名前をつけてきた件。isCanUseSkill
はまだ「なんだこいつの英語はwww」という意図はわかるから笑って済ませそうな名前ですが、allowSkill
は「これは命令なのか Yes-Or-No 質問を間違えて命令にしちゃったのか💢」という、書いた本人がもし友人じゃなかったら絶対引きずり出して小 1 時間殴りたいレベルのクソ名前です。しかも戻り値は真偽値だからマジでわからない。Yes-Or-No 質問かもしれないし、許可を出すようにしてる命令だけど成功したか失敗したかを示す戻り値の可能性も微レ存だから。
このような「Xxx できる?」系のメソッドは確かにたまに我々非英語圏のプログラマを悩ませることがあります。真偽値を返すメソッドはなんか isXxx
で統一したい気持ちもあるけど「Xxx できる?」は明らかに isXxx
に直すのはおかしいです。しかしそれをわかってもついつい isCanXxx
の名前をつけちゃう人は確かに少なくないです。でもそんな心配しなくても大丈夫、canXxx
も真偽値を返すメソッド、つまり「Xxx できる?」のメソッドの名前として使って OK なのです。みんなこうしてます。詳しくはこの記事にもたくさん書いてありますのでここでは割愛します。
ところが今日はこの「Xxx できる?」に使っている can
を、もうちょっと深く掘ってみたいと思います。
英語で「can」を使うときは、少なくとも 2 通りの意味がありますので、文脈で判断する必要があります。
まず一つ目は「能力的に Xxx ができる」という意味です。例えばよく耳にする(?)「I can fly!(私は飛べる!)」の can は、「私は飛ぶ能力があります!」という意味で使われています。
そして二つ目は「権利として Xxx をできる」という意味です。例えば「You can drive at 60 km/h on this road(あなたはこの道で時速 60 キロのスピードを出せます)」は、「あなたはこの道では 60 km/h までのスピードを出す権利があります」という意味で使われています。つまりあなたがたとえフェラーリを乗っていても、60 km/h 以上のスピードを出してしまったら取り締まる対象になってしまいます。
この二つ目の意味はまさに、友人が付け直した allow
系の意味です。
ところが、ここで一つ注意してほしい。たとえ二つ目の意味だったとしても、can
の主体はその権利を手にしたものです。この例文では「You」です。しかし allow
の主体はその権利を与えるものです。ここの例文では登場していませんが文脈で「法令」と読み取れます。つまり「The law allows you to drive at 60 km/h on this road(法律があなたにこの道で時速 60 キロを出す権利を与えています)」です。
そう、友人がつけた名前は、意味としては後輩ちゃんがつけた名前と、真逆と言わないまでも実は全く別なことを言っています。
ではどんな名前をつけるべきか。友人はゲームエンジニアですので、ここの命名もおそらくゲームプログラムの一部でしょう。そして後輩ちゃんがつけた isCanUseSkill
は文脈から察するに、ゲームキャラクターがスキルを使えるかどうか、を判定するためのメソッドになります。他の情報がないので、ここの can
は上記の二つの意味のどちらを指しているかが不明ですのでとりあえず一旦両方考えてみましょう。
まず能力的にできるかどうか、これはすでにコメントの 1 番目に返信した友人の友人が指摘した通り、isAbleToXxx
の名前が使えます。Able
は Ability
の形容詞で、つまり「Xxx の能力がある」という状態を意味します。もし「能力的に Xxx ができる」という意味でしたら、can
以上に isAbleTo
の方がふさわしいと言えるのかもしれません。
次に権利的にできるかどうか、これは友人が出した allow
の案を使いますが、もちろん直接 allowsXxx
を使うわけにはいけません。先ほど説明した通り、allow
の主体は「権利を与える方」です。ゲームにおいては主にゲームルールもしくはゲームシステムが司るでしょう。ですのでここは isAllowedToXxx
の名前を付けるべきです。英語としては Character is allowed (by the game system) to xxx もしくは Game System allows (character to) xxx です。ちなみにプログラムにおいてはその都度問い合わせる必要があるのでしたら、おそらく Delegate を通してやることになるかと思われますが、その際は delegate.characterAsksPermissionToXxx(this)
的なデリゲーションメソッドになるんじゃないかと思います。
ところが、逆にいうと can
は上記両方の意味を備え持っているからこそ、両方成立しているということも指すことができます。実際のプログラムコードでも、canXxx
は「能力的にも権利的にも Xxx ができる」を指すことがほとんど[要出典]です。ですので、今度「Xxx できる?」系のメソッドと出会ったら、このように名前の変更を検討できるかと思います:
- 能力的にできる? →
isAbleToXxx
- 権利的にできる? →
isAllowedToXxx
- 能力的にも権利的にもできる? →
canXxx { return isAbleToXxx && isAllowedToXxx }
追記
「文脈から察するに、ゲームキャラクターがスキルを使えるかどうか」と書いてましたが、ここでは暗黙的に「ゲームキャラクターのメソッド」だと考えていました。ところが逆にもしこれはゲームシステムのメソッドでしたら、確かに allowsSkill
は命名として正しいです。Game System allows (character to) xxx ですから。(それでも allow
はダメですけどね)
ですので、このメソッドがゲームシステムのものか、キャラクターのものかによって、名前が変わりますね。
さらに追記
元タイトル:「Xxx できる?」系メソッドの命名
せっかくなのでマサカリアドベントカレンダー作ったのでタイトル名変えました。みなさんもたくさんのマサカリを投げ合いましょう。
またさらに追記
おかげさまでこの記事が予想以上の反響をいただいており、たくさんの方から様々な感想をいただいており大変嬉しい極まりです。ここで一つのご感想をシェアさせていただきたいと思います:
本記事のメインテーマとしている「Xxx できる?」系の命名ではないですが、isXxx
の命名についてのご感想ですので共有させていただきました。
もちろんチームのコーディング規約などにもよると思いますが、本記事は「canXxx
でも大丈夫!」と言いました。それはつまり「is
から始まらなくても大丈夫!」ということも意味しています。
もしチームのコーディング規約にどうしても「真偽値メソッドは is
で始まらなきゃダメ!」と書いてあればそれを従う方が無難かと思いますが、ただ実際多くのフレームワークやライブラリーはそんなにこだわっておりません。例えば昔の Objective-C の時代の iOS 開発で、逆でした、Objective-C は UIView
の「不可視」を意味するプロパティーは isHidden
という名前でした。しかし現在 Swift ではそのプロパティー名は hidden
になりました。is
がなくなりました。今シェアしたツイートの通り、過去分詞なので真偽値であることは自明だからです。hidden
のプロパティーでゲッターが isHidden
で Swift もプロパティー名が isHidden
でした。頭痛しんどい😇
ですので、まとめとしては、もしチームコーディング規約があればそれに従い、なければ使っている言語やライブラリーのコーディングに従えばいいと思います。そのライブラリーに真偽値メソッドを is
で始まることを強要しなければ開発者も別に絶対 is
で始まる単語を死ぬ気で絞り出さなくてもいいと思います。なんならそのライブラリーの既存のメソッドやプロパティーの名前をリストアップしてそれっぽいものを見つけ出してそれに合わせて名前付ければいいと思います。
英語の正しさを3単元のsまで強制するのは僕は反対です。3単元のsは英語でも間違えやすいものの一つですし変化も一貫性がないので綴り間違いの危険性も増えると思います。それに引数もしくはメソッドを持っているものが配列だったら?となると動詞は受動態以外の変化形を使わないのほうがわかりやすいと思います。
まあ前ふりはこれぐらいにして本題ですが。
静的片付言語ならば返り値は見えているはずなので定義が見やすい状態なら気にする必要はないと思います。
定義と実装の分離ができない言語でメソッドに埋まってしまっているのならどこかに定義部分だけ抜き出したレファレンスを作ればいいと思います。
動的型付け言語で返り値の型がわかりにくくなっているならばシステムハンガリアンを使って型がわかるような記述にする方法があると思います。
昔は脱兎のごとく嫌われたシステムハンガリアンですが型が見えない時には有効な手段だと思います。
インスタンス化を前提としたオブジェクトの場合とモジュールの中のグローバル関数としても意味が変わりますね。
モジュール自体がそれぞれの言語でオブジェクトそのものだったり名前空間だったりいろいろありますが...、
何の言語やチーム間の命名規則などがあるので一概には言えませんが(それをいうと議論になりませんが)。
@kentaro1530
仮に綴りの間違っても、それはある意味
isCanXxx
と同じような「可愛い間違い」で意図は伝わる分マシです。仮にcan do something
の可能性チェックをbool doSomething()
で宣言したとして、戻り値で「真偽値」だとわかっているとしても、記事内で述べたとおり「それは Do Something の真偽チェックなのか Do Something の成功性チェックなのか」わからないのです。C 言語でいうとint a = 0; if (a = 1) { }
と同じくらいこれは正しいのか正しくないのか判断に迷う書き方ですこちらは申し訳ないですがどう言った意味でしたのか読み取れなかったので可能でしたら軽い例を挙げていただけると助かります
「レファレンス作ればいい」まで言われると、それこそ極端な話ネーミングなんて気にする必要がなくなります。全部「レファレンス読め」の一言で片付けちゃえますので。でもソースコード読めば一目でわかることができるようなものなのに、なぜわざわざレファレンスに飛んで仕様を読む時間を割かなくてはならないのですか。ただでさえ我々エンジニアは自分のコーディング以外にも人のコードレビューをしたりテストを書いたりしなくちゃいけないっていうのに。
綴り間違いの危険性は主に動的言語を使った時のことです、綴り間違いでメソッドがなくなってるとかを発生させてしまうことがよくあるので
静的解析ツール使えとかいう話ですが...すり抜けることも多いので
これも動的片付け言語についてですがJavaScriptで
と書いてある場合引数の長さは定義時に決まらないので単数形のみの想定でいいのか?です。逆に三人称単数形でないから複数の引数に対するメソッドであると想像させるのは無理があると思います。
レファレンスはちょっと誤解を招く表現でした。
定義宣言集ぐらいのものを想定しました、静的型付けときちんとしたネーミングルールがあれば定義宣言でだいたい何をやっているのかわかるはずなのでそれを作っておけばいいんじゃないかなぐらいの意味です。
コメントアウトで書いてもいいけどコメントアウトは読みにくいし時に雑音になりえるので別に書いてしまえばいいと思った次第です。
逆の極端に言えば逆にレファレンス作らず全部ソース読めになってしまいます。ソースファイルを読みやすくするためのネーミングルールですしある程度まではソースがレファレンスの代わりになるとは思っています。
ただ細かい実装部分まで見る必要はないと思っていますし実装部分が長くなると定義部分が見難くなるので適宜、実装と定義を分離はするべきだと思いますが詰めていくとどうしても実装が長くならざるおえない部分などが出てくるので宣言だけ抜き出しておけば便利だと思った次第です。
IDE使えば定義宣言なんかすぐ追えるかもしれませんがテキストエディタ派の人間もいるので
@kentaro1530
なるほど。まあ動的言語はそもそも罠がいろんなところに潜んであるし、メソッド名の話とは違うが PHP や Ruby みたいにそもそも変数宣言が要らず新しい単語が出てきたらそれが変数宣言だというものもありますので余計レビューしづらい部分もありますが、ただだからと言って綴りを間違うリスクを恐れて敢えて違う意味のものを使うのは、中国のことわざでいうと喉に詰まるのを怖がって食べることをやめるようなことだと思います。
なるほど。言いたいことはわかりました。が、この例はやや不適切ですね。
[value1[,value2[, ...]]]
はあくまでallow
の対象であってallow
の主体ではありません。ですので対象がいくらいようとallows
はallows
です。許可出すのは彼らvalue
ではなくsystem
です。おそらく挙げたかった例は、例えば対象の中に特定のものがあるかどうかみたいなメソッドでしょう。英語でいうと
contain
ですね。例えばcontainABC(stringA, stringB, ...)
というようなものです。JavaScript が配列に直接メソッドを拡張できるかどうかは知りませんが、ただプログラミングの慣例(少なくとも僕が読んできたいろんなライブラリーでは)としては「これらのオブジェクトをまとめて一つの主体」という認識です。ですので複数主体であっても慣例的にはそれらをまとめて一つの主体と認識して三単現を使っています。原形は「やれ」という命令風に読み取りやすいので。ちなみに JavaScript もそうですが、C# や Swift などの言語も、直接配列のメンバーメソッドで
[stringA, stringB, stringC].contains(object)
のメソッドがあります。ご覧の通り配列でも三単現です。配列であっても一つのまとまった主体という認識ですので。(まあ呼び出し元がそもそも「一つのオブジェクトだけ」ですしね)むしろまさに目指すべきゴールはこれです。英語で言えばいわゆる Self-documenting code です。内部実装やレファレンスに頼らなくても、利用部の読むだけである程度動きが想像できる作り方こそ読み手にも 3 ヵ月後の作り手にも優しい作り方です。
ところが今更ですが
過去形とかと比べれば三単現は断然間違いにくい方でしょう。基本
-s
か-es
しかないから。-es
の場合は基本決まったルールがあるのでそれ以外は全部-s
です。(唯一思い当たる「不規則変化」はhave
→has
だけですね)これについて比較的にいい例思いつきました。例えばスキルを使っていいかどうかを判断するのは複数のシステムがあるとします。そうすれば確かにこのようなメソッドになっちゃう可能性があります:
ところがこれはこれでとてもネーミングが悪いメソッドです。なぜならばこれらのシステム全員許可する必要があるのか(AND 判定)、どれか一つさえ許可すればいいのか(OR 判定)がメソッド名から読み取れないのです。ですので、下記のどっちかの名前にする必要があるでしょう
これで英文法的にも合ってますし、読めばすぐ可能性チェックしてるのをわかります(というかそもそも英文法に合ってれば読めばすぐわかるのは当然です)
isSkillAvailable
とかどうですかね@inductor 私個人の感想でしたら
isSkillAvailable
でも意図が十分伝わっている & 人によって認識の齟齬はほとんどないという意味では全然 OK だと思います。簡潔さではcanUseSkill
に負けますが簡潔さよりもやはり伝わるかどうかの方が大事だと思いますので、少なくとももし私がレビュアーでisSkillAvailable
のメソッド名が上がってきたら、「もっと簡潔にかける」という理由で却下することはないと思います。ただ厳密に考えると、
isSkillAvailable
は「スキルが利用可能」という意味で、「使っていいかどうか」とは微妙なニュアンスの違いを持つのは確かですので、最終的にisSkillAvailable
は適切かどうかはやはり実装次第かと思いますね。Codeのcontextがわからないのでそのへんは何とも言えないすね。
isCanSkillUse
という表現から、"If you can use skill under this condition"という風に受け取ったのでそう表現してみました。(If Skill is available for users under this conditionと同義)これが単純に"If you can use skill"だけであれば、
canUseSkill
でも良いと思いますが、どういうcontextであるかによって表現方法は変えるべきではないかと思います。@inductor
そうですね。それはあると思います。
例えば
isSkillAvailable
というテキスト、これも確かに「スキルが利用可能」という意味では「スキルが使える」ことを意味しますが、ゲームの場合は例えば「新しいスキルが使えるようになりました」と言ったニュアンスで「New Skill Available」を使うことが多いかと思います。その場合、どっちかというと、キャラクターがレベルアップしたりスキルポイントを利用したりすることによって「新しいスキルが解除された」というニュアンスになります。この場合はisAble
と同じような、利用者の主観的な「できる」の意味合いが大きいです。極端な話、レベルアップして新しいスキルが解除されて、例えその瞬間何かしらの客観的なルールによりそのスキルが利用不可(ホームエリアにいて敵との戦闘状態ではなかったり)であっても、ゲームの案内としては「New Skill Available」が使われたりします。じゃあ
canUseSkill
はどういう状況で使うのが一番ふさわしいかというと、経験上、例えばdoSomething
とcanDoSomething
のメソッドがあるとすれば、if (canDoSomeThing()) { doSomeThing() }
は必ず成立する、と言った状況でcan
を使うのが一番ふさわしいじゃないかと思います。ここの「成立する」とはdoSomeThing()
は必ず成功するという意味です。実行中にエラーにならないだけでなく、例えば実行中に何かしらのチェックが通らないことによる早期リターンや例外を投げることがあったらそれは成功するとは言えません。つまりdoSomething()
の結果は必ずDid Something
にならなくてはならないと思います。もしこの文が成立すれば、名前としてcan
を使うのは大丈夫だと思います。ちょっと補足になりますが、ネーミングには一貫性が必要だと思います。同じ動作なら必ず同じネーミングにすべきであり、逆に同じネーミングなら必ず同じ動作をすべきでもあります。例えばここの
can
も、場所によっては「主観的にも客観的にもできる」動作もあれば、「主観的にできることだけ保証している」動作もあるのは一貫性がないのでいいコードとは言いにくいと思います。文脈にもよりますが、私ならhaveSkillsとしたいです。
@Ted-HM せめて
hasSkills
にしましょう😇@lovee 失礼。hasSkills
@lovee @Ted-HM っていう話で行くと、Skillも安易に複数形に変えないほうが良い気が・・・。
無論、実際のコードで配列要素とかで一度に複数の値を扱うとかなら別ですが。
@lovee
これが、まさにその返答と同じことを指しています。
最近
func canAvailable(_:) -> Observable<Void>
という新種を発見しました🙈@inductor
とは…?🤔
@toshi0383
大喜利の予感🤣
isSkillAvailable
構文はよく見かけるのですが、 (単独の疑問文として使う場合には正しい語順であるものの) 直前に「主語」を置いたり if 文の中で使ったりする場合に英文法として正しい語順にならないので、個人的にはskillIsAvailable
構文を推しています。@magicant いいですねこの書き方も。更に欲を言えばもし具体的にどのスキルを示すためのスキルが引数として使うメソッドがもしあれば、ずっと前から思ってたことですが、利用するときに
if (skillIsAvailable(someSkill))
ではなく、if (skill(someSkill)isAvailable)
的な構文が書ける文法が欲しかったです。Swift(とその前身の Objective-C)は変数ラベルがあるおかげで変数の前にその役割を示す単語が書けるようになっているけど、変数の前でしか書けないので最後にisAvailable
が書けないのが辛い。遠回りの書き方になるが Swift ならなんとかギリギリここまでは持ってこれるけど:(参考:https://qiita.com/eimei4coding/items/a8b8c58f6196ce5047f4
言語によりますけど、ちょい前のJavaはis/set/getを付けてプロパティを構築するのが当たり前だったので、
日本語プロパティ派の人たちなんかはこんなのが強いられてきた時代がありました。
脱線気味ですが出身によってはis/get/setに特別な意味を感じてる人もいたりする、ということだけ。
前に別の命名系の話題でも軽く触れたことがあるんですが、世の中には
boolean型フィールドhogeへのgetterは、isHogeでなくてはならない、正常に動作しない
という言語/フレームワークがあったりします。IDEのsetter/getterメソッド自動生成機能でも、boolean型に対して実行すると無条件にisを接頭辞としてくっつけるやつも結構います、いました。
最近は少ないんだろうか……。
そしてその慣習にならされると、「booleanを返すメソッドは(getterとかでなくても)全てisから始めなくてはいけない」病に汚染されていったりしますね。
@kacchan6@github
ありましたね Java のゲッターセッター。まあそういう言語とかコミュニティーの縛りがあればそれに従った方がいいと思います
ただ Java でも、例えば文字列に特定の文字列が含まれるかどうかの真偽値チェックメソッドは
.contains("someString")
ですので、少なくとも Java においてis
にこだわる必要がなさそうに思います…🤔 Java の開発者ではないので断言はできませんが@Kilisame
それはありますね、特別なゲッターやセッターがある言語。Objective-C でも
value
のフィールドにgetValue
のゲッターが自動で生成されます。ちなみにそれは別に「変数名」がis
で始まる必要があるってわけではなくて、あくまでそれのゲッターがそうなっているだけですよね…?isとかcanとかallowとか、言いたいことはだいたいわかりますのであまりこだわらなくても良いと個人的には思います。
それよりも重要なことは、そのあとに続く、do something で、そこが的確でないと何をやってるのかわからないわけです。
また、我々日本人は文法にこだわりすぎるところがありますが、話したり聞いたりする方も大事です。
よかったらこちらの私の記事もご覧ください(笑)https://qiita.com/tfutada/items/91d727ef435c18fb8dba
Javaの場合はisにこだわるのはプロパティなので、単なる問い合わせのメソッドであれば割りとどうでもいいですね。
最近はpublicなフィールドをサポートしているフレームワークが増えたので、気持ち悪さも低減しています。
skillの例であれば、個人的にはskillsというプロパティを作って、user.skills.allows("any")みたいな感じにしますね。
「何々」の「何々」が「どうか?」というメソッドが増えるとオブジェクトが肥大化するので、
こういう命名が出てきた時点で、名前をどうするかよりも、オブジェクトの設計を先に考えるほうが実際には多いです。
this/SomeClass
のようなインスタンス/クラスを主語としてthis.is~
とするメソッドthis.isSomething~
とするメソッド、is~(something)
とする関数有名なライブラリでよく使われる
boolean
を返す関数は、(雑ですが)こういう切り分けもできると思います。もちろんcan
has
も同じで。個人的にはこれを見る限り、if
文内ではどうこうというよりもそもそも自然言語として成り立たせようとしている訳ではない気がします。あと基本的に
複数のものを主語に取れる(複数のものが主体となる)メソッド
というのは存在しないと思っているので、やはり三単現の活用は必須だし無ければ(無意識にでも)気持ち悪いと感じる人は多いんじゃないかという気がしています。同じ機能でも、言語が変われば見た目も変わる気がします。
Rubyでは、
foo.nil?
のように疑問符をメソッドの末尾に入れられるので、名詞や形容詞で表せる属性なら、finite?
とかzero?
のようにほぼ名前が決まります。あと、
File.exists?
がdeprecatedになってFile.exist?
に代替されているように、三単現のs
も省略されています。@tfutada
もちろん
do something
もとても大事ですよ!それは否定していませんしreceive100Yen
のメソッド呼び出して逆に 100 円支払わされたら絶対作った人ぶち○す(笑)ただまあ私が言いたかったのは、別に
is
にしようとかcan
にしようという絶対的な基準な話ではなく、むしろ tfutada さんと同じ「的確」なメソッド名にしようという話です。allow
の例で言うと、三単現ではないので意味合い的には「このスキルを使えるようにする、成功したらtrue
返して」と言うメソッドに読み取れてしまうのでやめましょうねと言うお話です。逆にむしろ意味が伝わるからisCanUseSkill
の方がまだ笑って済ませる分マシだと言いたかったです(笑)@kacchan6@github
プログラムの作り方にもよりますので、具体的にどのような作り方にするのがベストなのかみたいな話はちょっと難しいですね、しかも自分は Java は ROM 専で書けないので()
ただおっしゃる通りオブジェクトの設計を先に考えた方が、あとあとから名前付けるときはやりやすいと思います、多くの場合は設計通りに作れば名前も自然に決まっちゃえます
@sh0
同意です。プログラムは結局のところプログラミング言語であって自然言語ではないので自然言語として成立させるにはとても難しいです。しかもそもそも違う言語は違う言語仕様があるので、例えば Objective-C は
[actor move:view to:destination]
と書けるけど、C# ならせいぜいActor.MoveViewToDestination(View, destination)
になります。ただ自然言語にはならなくても、使う単語の形態に気をつける必要が少なからずあるかと思います。例えば同じ
validate
でも、bool result = object.validate()
とbool result = object.validated()
が読み手に与えるイメージは全く違いますので@jkr_22555
Ruby の文末に
?
を入れられるのは一般的に見てかなり特殊な仕様ですので、これによりallow?
とallow
は読み手には違うイメージを与えられるので、Ruby なら別にallowSkill?
が使えるのでそれで問題ないと思います。ただ世の中のほとんどの言語にはこの仕様がないので一般論としては「三単現を使わなくても大丈夫」ことにはやはりなりにくいかと…本文の「またさらに追記」にも書きましたが、言語それぞれ違う規約や習慣があるので、同じ動作でも最終的に違うネーミングになるのはよくあるし正しいと思います。要するに「絶対多数の使う人に伝えたいことが伝わるか」が大事です。