🐹

コンポーネント名を明名するときに考えたこと

2024/01/18に公開

ニコニコ生放送でフロントエンドを担当している misuken です。

今回はコンポーネント名を並べたときに感じた小さな気付きから視野を広げ、最終的に周辺領域も含めて詳細に明らかにするまでの様子を書きます。

この記事で行われているのは、一般的な 命名 ではなく BCD Design における 明名 (名前は決めるものではなく決まるもの)の工程になると言えます。

コンポーネント名を明らかにするためにどのように捉え、どのように考えていくのかのヒントになれば幸いです。

前提

この記事は BCD Design を基礎とし、以下の記事で紹介した理論を踏まえた内容となっています。

わからない点があったら BCD Design 及び上記二つの記事を参考に読み進めてみてください。

FieldInputField の違い

以前の記事 共通部分をスマートに管理するディレクトリ構成Field というコンポーネントを例に挙げましたが、記事を書いている初期段階では Field という名前ではなく InputField としていました。

理由は "入力フィールド" は "入力" の単語に対応する Input が必要になるためです。

しかし、他のコンポーネントと一緒に並べたとき、InputField とすると若干異物感があります。

Button
Form
Icon
Input
InputField 🤔
Dialog
Label
Link

以下であればとても自然に並んでいると言えます。

Button
Field ✅
Form
Icon
Input
Dialog
Label
Link

これはほんの些細な違いに思えるかもしれませんが、大規模なシステムの場合、小さな歪みが次の歪みを生み、連鎖的に歪みが大きくなるので、基礎に近い部分の歪みを解消することは意外と重要です。

そのため日頃からこのような小さな歪みは何が原因で生まれているのか?歪みを無くして成立する形にするにはどうすれば良いのか?といったことを意識しています。

これまでの知見を踏まえると、上記の部分だけでも以下のことが言えます。

  • InputFieldField の派生である
  • InputField だと Input 側にまとまって関心の千切りになってしまう
  • UI層では後方一致のUI名でまとめたほうが望ましい

これはアンチパターンを理解して package by feature への記事を読むとしっかり理解できます。

BCD Design において InputField は Base Case どっち?

InputField は入力する状況に依存した Input という単語から始まっているので Case ではないかと思うかもしれません。

しかし、ここで扱っている InputTextBox 等の総称としての単語であり、 Input という抽象的なUIを表しているため Base に該当します。

CheckBox SelectBox PulldownMenu などもUI自体を表す名前であるため、 Base に該当するのと同じ原理です。

ここからは Field とその派生について分析し、それらの関係性を深掘りすることで、最終的な結論に達するまでの流れを書いていきます。

Field とその派生について分析する

なぜ InputField を検討するかと言うと、最初にも述べたように入力UIと連携するものだからです。

また、なぜ人が「入力フィールド」や「入力欄」と言うかといえば、それは入力以外の "フィールド" や "欄" が存在していて、無意識に識別していることを示唆しています。

入力系以外のUIと連携するフィールドがあれば XxxField となるはずで、 InputField とは違う系統になります。

そこで、AIに「入力以外のフィールドはありますか?」と尋ねると、代表的なものとして "表示フィールド" DisplayField というものを挙げてきます。

入力目的ではなく、情報を表示することを目的としたフィールドです。

この時点で InputFieldDisplayField の中立的な抽象が Field であるべきで、 Field 自体が "入力" に依存したり "入力" に寄った存在になっていると、対称性や依存関係などの観点から整合性が取れなくなることが想像できます。

DisplayField を分析する

新たに現れた DisplayField を分析してみましょう。

DisplayField は何らかの情報等を表示するコンポーネントと考えられるため、何らかの入力UIと連携する InputField と似ていると言えます。

しかし、InputField とは違いがあります。

InputField の場合は TextBox と連携して TextBoxField を作るなど、具体的な入力方法を固めることに意味があるため、UIのみの世界でも具体的なコンポーネントを定義できましたが、 DisplayField の場合そうはいきません。

LabelField LinkField など UI + UI でコンポーネントを定義しようとしても、利用価値のあるものにはならないのです。

DisplayField は何を表示するかを表そうとすると、ほとんどの場合 BCD Design における Case Common Domain のいずれかに属する単語と連携することになり、UIのみの世界で具象コンポーネントを定義する意味がありません。

つまり、BCD Design の Base に DisplayField を具体化したコンポーネントはほぼ現れないということを意味します。

DisplayField の責務を分析する

次に DisplayField というコンポーネントがどのような責務を持つべきかを分析してみましょう。

DisplayFieldField が持つ基本構成に加え、メインの表示部分で children が渡せるコンポーネントになるはずです。

ここで改めて考えてみるとコンポーネントという存在は常に何かを表示するための存在なので、DisplayFieldDisplay に意味はあるのか?という疑問が生まれてきます。

すると DisplayFieldField コンポーネントに統合できる可能性が浮上してきます。

例えば DisplayField に入力系コンポーネントを表示したらそれは InputField の具象になるのではないかということです。

DisplayFieldField なのか?

もしも DisplayFieldField 自体であると仮定した場合、どのようになるか分析してみます。

DisplayField = Field ということは、ディレクトリで言うと base/Field/_base = base/Field/DisplayField ということになります。 (ディレクトリ構成の意味は 共通部分をスマートに管理するディレクトリ構成 を参照)

base
  Field
    _base          // DisplayFieldと同じ
    DisplayField   // _baseと同じ

base/Field/_basechildrenTextBox を連携させたら base/Field/TextBoxField になります。

base
  Field
    _base          // DisplayFieldと同じ
    DisplayField   // _baseと同じ
    TextBoxField   // TextBox + _base

説明を表示する領域として、説明フィールド DescriptionField というコンポーネントが必要になったとします。

この場合の "説明" はデータ(処理される対象)なので、Common に所属します。"検索" などと違い、それが "説明" という処理自体を行うものではないので Case にならないという解釈になります。(詳細は Case と Common の使い分け を参照)

base/Field/_basechildren に説明に関する依存を連携したら common/DescriptionField になります。

base
  Field
    _base          // DisplayFieldと同じ
    DisplayField   // _baseと同じ
    TextBoxField   // TextBox + _base
common
  DescriptionField // 共通の関心 + base/Field/_base

具体的な説明内容(データ)はより具体的な使用箇所で決まることになりますが、説明フィールド特有のスタイルは DescriptionField で一元管理できます。

結果、 base/Field/_base があれば表示フィールドを具体化した説明フィールドを作れることがわかります。

分析の結果

分析の結果はこうなります。

  • DisplayField の具象が Base 内に現れることは考えにくい
  • DisplayField に入力系UIを組み合わせたら InputField の具象になり得る
  • DisplayField という概念は存在するものの、それは事実上 Field のことである

この結果を踏まえると以下のように Field 内で InputFieldDisplayField など複数系統のフィールドを分類する必要が無いことがわかります。

Field
  _abstract
  DisplayField
  InputField
    _abstract
    CheckboxBoxField
    TextBoxField
    SelectBoxField

従って DisplayFieldInputField というディレクトリは不要で、 Field の直下に TextBoxField を展開しても特に問題は生じません。

概念的には Field/InputField/TextBoxField のほうが正しいかもしれませんが、Base の中に表示系フィールドの具象が現れることは考えにくく、上記の理由を理解した上で利便性を優先して Field/TextBoxField で運用することは、実運用上問題にならないでしょう。

Field
  _base
  CheckboxBoxField
  TextBoxField
  SelectBoxField

FieldInputField の関係を深掘りする

ここまでの正確性を検証するため FieldInputField の関係を深掘りしてみましょう。

もし InputField を作る必要が出てくるとしたら、決定打になるのは InputField における Field 部分に入力系特有の依存が含まれるかどうかになります。

依存は主に3つ。

  • 実装(定数やロジック)としての依存
  • スタイルとしての依存 (入力UI部分は除く)
  • DOMとしての依存 (入力UI自体は除く)

実装(定数やロジック)としての依存

入力フィールド系共通で使用する定数があれば Field/InputField/InputField.definition.tshooks 等のロジックがあれば、 Field/InputField/InputField.hooks.tsx 内に定義するとうまく整理できるはずです。

スタイルとしての依存

入力フィールドと、表示系フィールドで 、内容を除いたフィールド自体が構成する部分のスタイルに違いがあれば入力フィールドに依存したスタイルがあるということになるので Field/InputField/InputField.module.css が必要になるでしょう。

DOMとしての依存

ここは非常に奥が深いので長くなりますが、重要なのでしっかり説明します。

DOMとしての依存とは、表示系のフィールドには概念上不要で、入力フィールドのみに存在するDOMがあるかどうかです。

  • 共通で良さそうなもの
    • ラベル
  • 入力フィールドのみに依存しそうなもの
    • エラーメッセージの表示
    • 必須表現

ラベル以外はフィールドのメタ情報で、表示系フィールドと入力フィールドで共通ではないように思えます。

しかし、捉え方を変えるとパラダイムシフトが起こります。

エラーメッセージの捉え方

エラーメッセージとは、エラーのメッセージであり、メッセージの一種です。

他にどのようなメッセージがあるかを思い浮かべると以下が挙げられます。

  • 警告を伝えるためのメッセージ
  • 補足等の情報を伝えるためのメッセージ

エラーのメッセージと他のメッセージの違いは何があるでしょうか?一般的に考えられるのは以下です。

  • 色が違う
  • アイコンが違う

つまりこうなります。

メッセージを表示したフィールドの例

DOM的にはアクセシビリティ的な部分でaria属性が違ってきますが、それ以外は構造的に共通で問題ないはずです。

構造的には同一で毛色が違うパターンは以下のように変換できることを意味します。

「エラーとはメッセージにおける属性の一種である」

エラーにはもう一つ面白い関連性があります。

エラーというのはログレベルでもよく使用されますが、そこには一般的に info warning error があるように、メッセージに意味を持たせる上での良いモデル(事実上メッセージという概念の型)になります。 これらはまさにログの属性です。

このモデルの親和性をさらに説明できる良いものがあります。

JavaScript でも console.log に属性を付けられる以下の関数があり、色 アイコンだけに留まらず、メッセージという部分まで完全にリンクしていることがわかります。(これは人に情報を伝えるという根底で意味が繋がっている根拠になります)

関数(レベル) color アイコン MDNの説明
console.info i console.info() メソッドは、ウェブコンソールに情報メッセージを出力します。
console.warn console.warn() メソッドは、ウェブコンソールに警告メッセージを出力します。
console.error x console.error() メソッドは、エラーメッセージをウェブコンソールに出力します。

※ ブラウザやバージョンによって info が青やアイコンを使わなくなっている場合もあります

これにより、エラーは属性の種類の一つであり、コンポーネントとしては Message で表現できることがわかりました。

これを踏まえた上で、表示系フィールドにおける Message の役割を考えてみましょう。

例えば、設定状態を確認できるページがあるとします。

そこには設定としては有効であるものの、何かしらの注意を促したい項目があるとします。

このようなとき、表示系のフィールドとして、設定内容と共に警告レベルのメッセージを表示できると便利です。

他にも、ある設定がオーバースペックな設定な設定となっており「改善が可能です」という情報を提供したい項目があれば情報メッセージを表示できると、きめ細やかなサービスを実現できます。

設定状態を確認するときのフィールドの例

必須表現の捉え方

次に必須表現です。

入力フィールドでは必要不可欠な必須表現も、表示系フィールドにおいて利用価値があるものとして捉えられます。

例えば、何かのイベント参加に関する注意書きがあるとします。

その注意書きには当日持参が必要なもののリストが項目(フィールド)として表示されていて、説明とともに、あるものは必須で、あるものは必要に応じてと表現されています。

表示フィールドの例

このように、入力欄がなかったとしても必須表現を使う可能性はありえます。

これはまさに説明フィールドに該当する使用例です。

捉え方のまとめ

一見 "入力" に依存しているように見えたエラーメッセージや必須情報も、"表示" の観点から捉えたときに何に該当するのか、意味や役割、世の中に存在するモデルや利用シーンと照らし合わせることで適切な抽象化の着地点が見えてきます。

"入力内容に対するエラーメッセージ" という考え方から、 "フィールドの内容に対するメッセージ" のように適切に抽象度をコントロールし、エラーはメッセージの属性として存在するものと捉えることで、 基底の Field が持つべき真のスペックが明確になりました。

このように考えてみると、入力フィールドの入力に依存していると思われていた要素のほとんど or 全ては表示系のフィールドでも意味のある存在であることを理解でき、より凝集度が高く情報表現豊かな設計が可能になります。

また、DOMとしても同じものを使用できることから、実装や保守面で見ても効率アップに繋がりますし、HTML表現やCSS表現としてもスマートになるので、一石二鳥以上の効果が期待できます。

これらを踏まえると、DOM的な依存によって InputField が必要になることはあまりないのではないかと思われます。

結論

ほとんどの構成物は基底の Field に持つべきで、Field を事実上表示フィールドとして使用できることから、 DisplayField は不要であることがわかりました。

InputField は依存するものの有無によって以下の2パターンに分けられます。

InputField に依存するものがない場合

入力フィールドは Field/_base をそのまま使用して入力UIと連携すればよく、 InputField というディレクトリは必要ありません。

また、表示系フィールドで Field の基底コンポーネントを利用できるよう、 Field/_abstract ではなく Field/_base としています。

Field
  _base
    Label
    MessageList
    ...
    index.ts
  CheckBoxField
  TextBoxField
  SelectBoxField
  index.ts

InputField に依存するものがある場合

Field の外部から見ると、 InputField のディレクトリは隠蔽されていて存在を感じることはありませんが、入力フィールドに依存したものを InputField/_abstract に置けるので Field 内は整理された状態になります。

Field
  _base
    Label
    MessageList
    ...
    index.ts
  InputField
    _abstract
    CheckBoxField
    TextBoxField
    SelectBoxField
    index.ts
  index.ts

Fieldexport するものは index.ts で管理されているため、途中で InputField の有無を変更しても外部への影響が無いところも、責務を正しく閉じられていることを表しています。

まとめ

FieldInputField という名前の違いから分析を開始し、さらに深掘りを経ることで、 Field 周辺におけるディレクトリ構成だけでなく、それぞれの責務や関係性、エラーメッセージや必須表現のあり方までも詳細に明らかにすることができました。

これらは主観的に決めたものはなく単語の意味やUIの本質を正確に表現した結果であるため、意味と合致する部分で自然と整合性がとれ、納得感や理解のし易さにも繋がっていくものと考えられます。それはつまりプロジェクトやチームに依存しない永続的に利用可能な基礎になります。

このような世界観に魅力を感じた方は BCD Design の思想を参考に、単語一つ一つの意味を改めて見つめ直して見てはいかがでしょうか?

実践的な ニコニコ生放送のBCD Design導入事例 も公開しています。

命名から明名へと切り替えれば、きっと色々な気付きや発見に繋がり、将来への有益な投資になることでしょう。

参考

株式会社ドワンゴでは、様々なサービス、コンテンツを一緒につくるメンバーを募集しています。 ドワンゴに興味がある。または応募しようか迷っている方がいれば、気軽に応募してみてください。

Discussion