はじめに
クラウドワークスの初期バージョンを作ってから早6年。後任のエンジニアたちには様々なdisりを受けてきました。
システムアーキテクチャや設計(命名は除く)に関するdisりについては、何よりもビジネスを軌道に乗せることが優先されるタイミングでどこまで「ちゃんと」やるべきか、という議論の余地が常にあります(自分のスキル不足については、いったん棚に上げます)。
一方、「命名」については、サービス立ち上げ期であっても「ちゃんと」やるべきと断言できます。
なぜならば、
- システム外(例えば、非エンジニアとのコミュニケーション)にも関係してくる、ある意味ではシステムの最も基礎的な部分と言えるため、ここでしくじると影響範囲がでかい
- ネーミングをがんばったからといって、それ自体にかかる時間はたかが知れているし、その後の開発速度に悪影響を与えることもほとんどない
すなわち、命名を「ちゃんと」考えるという時間の投資はたやすく回収できるからです。
というわけで、「クラウドワークスのイケない命名 〜7つの大罪〜」、行ってみましょう。
1. サービス上の語彙と一致してない名前
例: 発注者(クライアント):受注者(クラウドワーカー)ーと、employer:employee
クラウドワークスにおいては、仕事を依頼する人を「発注者(またはクライアント)」、仕事を受ける人を「受注者(またはクラウドワーカー、ワーカー)」という語彙で呼んでいます。
ところが、システム上では、仕事を依頼する人 = employer、仕事を受ける人 = employee という語彙が用いられています。
このギャップにより、「発注者」を指すのにシステムのある所では employer という語彙が使われ、またあるところでは client という語彙が使われる、という混乱が生じます。また、
発注者の情報ってどこのテーブルに入ってるんでしたっけ?
という会話が日々繰り広げられます(やや誇張)。
辛い(。◉ᆺ◉)
なお、これは余談ですが、クラウドワークスにおいては受注者ー発注者の関係は、雇用ではなく業務委託ですので、その観点においても不一致が大きい命名となっております。
2. 紛らわしい命名
例1: closed_flag と、ステータス closed
クラウドワークスの「仕事(job_offer)」には、 closed_flag というフラグがあります。通称「スカウトフラグ」。これは、「発注者にスカウトされた人しか見られない」というフラグです。
一方で、「仕事」のステータスを示す status カラムの値として closed (募集終了、の意)という値が定義されています。
当然、 JobOffer#closed? というメソッドを見ても、
どっち?(。◉ᆺ◉)
となります。
今にして思えば、「発注者にスカウトされた人しか見られない」という語彙は、 private とでもしておくのが良かったかなーと思いつつ、それはそれで プライベートメソッド という ruby の予約語と名前が被るのでそれはそれで微妙っていう。
例2:「預り金」と「預託金」
この2つ、サービス上では全く別の概念なのですが(いちおう包含関係にはあるっちゃある)、普通に和英辞書を調べると、どちらも deposit となっています。苦肉の策で、前者は cw_deposit という奇妙な命名をしています。
後日調べたところによると、会計上の「預り金」は、 withholdings という語彙が使われるようです。 名前空間も区切って、accounting::witholdings 的な命名が正解だったような気がします。
3. 曖昧な命名
例:net_amount
クラウドワークスでは、net_amount という名前が(残念ながら)いくつかの意味を持って(しまって)います。
- システム利用料(charge)を引いたあとの金額
- 源泉徴収額(withholding_tax)を引いたあとの金額
- 銀行振り込み手数料(commission)を引いたあとの金額
- 割引(discount)適用後の金額
など。
文脈で判断できるケースもありますが、そうでないケースがやばい(。◉ᆺ◉)
現状の当社システムにおいても、net_amount という語彙を利用してもよいシーンもあるとは思うのですが、できるかぎり、amount_excluding_charge と言ったように、その意味するところが自明な語彙を用いるべきです。
4. 統一されていない命名
例:cancelled と canceled
クラウドワークスのシステムには、canceled と cancelled が混在しています。
アメリカ英語では、一般的に「canceled」が使用されます。一方、アメリカ以外の英語圏では、一般的に「cancelled」が使用されます。
補完が効かない環境では、地味にイライラが募ります。
そもそもは自分が cancelled しか知らずに使い続けていたのが原因なのですが、3人目のエンジニアこと @teriyakisan が、
cancelled ってイギリス英語ですよね? CWシステムはほかは全部アメリカ英語なのに(笑)
とツッコんできた時に、 どちらかに統一しておくべきでした。
まあ、当時既に混在していて、統一しようにもできなかったんですけどね(。◉ᆺ◉)
5. する人、される人
例:blocking_user / blocked_user
例えば、「特定のユーザーをブロックできる」という機能があった場合(というかあります)、blocking_userが、ブロックした人なのか、ブロックされた人なのか、ひと目でわかりますか?
blocking_user = ブロックした人であることはまだ分かるかもしれません。では、Userモデルの、 has_many :blockings
はどうでしょうか。
ほかにも、同じパターンは何箇所かありますが、作った自分ですら常にどっちがどっちなのか混乱します。
辛い(。◉ᆺ◉)
例えば、blocker と blockee みたいな感じにしたらまだマシな気はします。
6. _
例:_valid?
valid? というメソッドを定義したいが、ActiveRecord の model で元々定義されているメソッド名と被るため、つい出来心でやってしまいました。
ふとした機会にこのコードを見ると、未だに後悔の念にかられます。
微妙に別の話ですが、 _valid? を要するモデルには、 validated? とこれまたモヤモヤが止まらないメソッドが実装されております(。◉ᆺ◉)
7. 命名されていない命名(?)
最後に究極のやつが来ました。メタ大罪。
例: ( )
以下は、クラウドワークスでの契約〜報酬を出金できるようになるまでの流れです。
実は、わりと最近まで、上記の**「報酬が出金可能になるタイミング(あるいは、なった状態)」に名前がついていませんでした。仮払いの場合は報酬確定でよいのですが、後払いの場合には、上の図の通り報酬確定とは全くの別物**です。仮払い・後払い共通で使える名前がないと困るということは想像にかたくありません。
この命名(命名されてないけど)の罪は、説明が面倒くさい……というだけならまだしも、人は名前によって対象物を認識する生き物です。ということは、命名されていない状態は、認知されにくい、よって、考慮から漏れがちということです。やばい。
おまけ:(見た目が)紛らわしい名前
例: contact(問い合わせ) と contract(契約)
多分、この6年間で30回くらい間違ってファイルを開いた気がします。ファイル一覧でも常に隣同士にいるし。
最後に
以上、半分は社内向けの懺悔、もう半分は誰かの何かのお役に立てればと思って書いてみました。
設計の知識がどれだけ残念でも、上に書いたようなことさえちゃんとできていれば、自分がdisられる回数も半分以下で済んだんじゃないかという気がします。