🐹

ニコニコ生放送でBCD Designを4年運用した知見(ベストプラクティス編)

2024/12/24に公開

この記事は ドワンゴ Advent Calendar 2024 24日目の記事です。

はじめに

株式会社ドワンゴのニコニコ生放送でフロントエンドを担当している misuken です。

今回は前々回の導入編、前回の基礎テクニック編に引き続き、BCD Designを4年運用した知見に基づき、BCD Designのベストプラクティスを共有し、実際に運用していく中で遭遇する、微妙な分岐点に対して、どのように対処したらうまく解決できたのかを、具体的な事例を交えて紹介していきます。

これは、システムを構成する様々な単語をどのように扱うと、意味や関係性が体系的になり、実装にピタリと連動するのかを論理的に追求するものであるため、BCD Designを使っていなかったとしても、参考になるヒントが見つかるはずです。

概要

  • ディレクトリ構成術
  • 最初に役立つ知識
  • 迷ったときに役立つ知識
  • より先進的な使い方

ディレクトリ構成術

ここではディレクトリ構成に関するベストプラクティスを紹介します。

分類ディレクトリ名の変更

BCD Designのディレクトリ名は Base Case Common Domain が標準ですが、DomainではなくFeatureを使いたい場合はディレクトリ名を変えても問題ありません。

依存関係の面から順に Base Case Common Domain の関係性にはなっていたほうがわかりやすいと思いますが、それぞれの名前をカスタマイズすることは可能です。

BCDにした理由は、わかりやすさと覚えやすさを重視しただけなので、プロジェクトによって分類ディレクトリの名前が変わっても特に問題はありません。

package by feature

どの局面においても、必要な情報が必要な場所にまとまるアプローチがあります。以下記事では、なぜうまくまとまるかの原理から丁寧に解説しているので必読です。

アンチパターンを理解して package by feature へ を参照。

派生系のまとめ方

元のコンポーネントから派生したコンポーネントが必要な場合のまとめ方。

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

関心の対象自体ごとにまとめる

コンポーネントを関心名のディレクトリでまとめる場合、先頭の単語が一致するからといって全部まとめるのは避けるべきです。

関心の対象自体を扱うものだけをまとめるようにしましょう。

domain
  program
    program-card ✅ 番組自体を対象にしたものである
    program-comment-card ❌ 番組自体を対象にしたものではない

番組コメントは番組に紐づいているものであって、番組自体の関心ではありません。programの中に入っていいのは、番組自体を表現するものか、番組の構成物であるサムネイルや番組タイトルを表現するものです。他にも番組放送者なども番組に紐づいているものなのでprogramの中に含めるべきではありません。

domain
  program
    program-card ✅ 番組自体を対象にしたものである
  program-comment
    program-comment-card ✅ 番組コメント自体を対象にしたものである

修飾語を含む関心のまとめ方

関心名をpreやspecial等で修飾しても主体が変わらない場合、新しい関心とするのは避けるべきです。pre-xxx や special-xxx でまとまってもメリットも無く、関心の千切りになるだけです。

domain
  member
    member-registration-form
  pre-foo
  pre-bar
  pre-member ❌ 会員種別が散らばってしまう
    pre-member-registration-form
  special-foo
  special-bar
  special-member ❌ 会員種別が散らばってしまう
    special-member-registration-form

プレ会員やスペシャル会員は、会員の一種であり、会員であることに変わりはありません。
会員のバリエーションに該当するため、共通部分をスマートに管理するディレクトリ構成と同じ方法が有効です。

domain
  member
    _base
      member-registration-form
    pre-member ✅ 会員種別がまとまる
      pre-member-registration-form
    special-member ✅ 会員種別がまとまる
      special-member-registration-form

これとは別に、program-comment と blog-comment のように、commentのバリエーションではなく、番組におけるコメントやブログにおけるコメントのように、関心Aで利用するBが成立する場合は、新しい関心とするべきです。

common
  comment ✅ 汎用的なコメント
domain
  blog-comment ✅ ブログにおけるコメント
  program-comment ✅ 番組におけるコメント

最初に役立つ知識

ここではBCD Designの基本的な使い方に関するベストプラクティスを紹介します。

コンポーネント名に複数形を使わない

コンポーネント名に Images のような複数形を使用すると、実装レベルで微妙に噛み合わないところがでてきますが、ImageListを使う形にすると常に安定します。

リスト系のコンポーネント名 Images と ImageList はどっちが有利かを参照。

Siteドメインの有効性

ページのヘッダやフッタはコンポーネント名が Header や Footer となりがちですが、BCD Designではそれらの名前は Base に該当します。Header や Footer だけでなく、SideBar なども様々なドメインを参照して表示する側であるため、Base に置くと依存関係の上で問題になります。

こういったコンポーネントは内容がサイトという概念に依存して構成されたものであるため、Siteドメインを作成し、その中にまとめる方法が有効です。WEBの世界にサイトマップという言葉があるように、サイトだからこそ存在(サイトの概念に依存)しているUIがあるのです。

domain
  site ✅️ サイトの概念によって生まれたものが全てまとまる
    site-header
    site-footer
    site-map-section
    site-navigation-menu
    site-side-bar

また、ニコニコ生放送では、共通ヘッダと呼ばれるニコニコサービス共通のヘッダと、ニコ生固有のヘッダの二段構えになっていますが、これらは以下のように整理されています。

ニコニコサービス共通のヘッダ

domain
  nico
    nico-common-header ✅️ nicoドメインで共通のヘッダ (実質社内ライブラリを読み込む処理)
  site
    site-header ✅️ サイトドメインのヘッダ

常に、 site-header はそのサイト独自のものになりますが、系列サイトを作ったとしても、同じコンポーネント名で運用できて便利です。

Domain名で手を抜かない

TagやCommentといった、Commonに該当する抽象的な関心名は、原則としてはDomain名を頭に付けることをおすすめします。

ニコニコ生放送では当初、番組のタグに対してTagを使用していたところ、あとから好みタグ(現名称は "好きなもの")が現れた影響で、すべてのTagをProgramTagに変更しました。さらに、番組のコメントでも、依存関係の問題で、すべてのCommentをProgramCommentに変更し、大変面倒な思いをしました。

依存関係の問題とは、ProgramTagのようにDomain所属の関心であれば、同じくDomain所属の関心への参照が可能ですが、TagのようにCommon所属の関心は、Domain所属の関心を参照できないという問題です。

何かの機能追加のタイミングで、依存関係が破綻するリスクを抱え続けることになるので、関係性があるのであれば、最初からDomain名を付けておくことが得策です。

これがYAGNI原則にあたるか?

これがYAGNI原則にあたるかに関しては、最初の実装時点で関係が明らかならば、あたらないと考えます。頭にDomain名を付けない理由が名前の短さならば、原則は付ける方針として、よほど将来に渡って影響が無いことが確実なもののみ省略を検討、というスタンスのほうがお得です。

なぜなら、ドメイン名に一単語増えるだけのコストが、あとからすべてリネームするコストを上回るとは考えにくいからです。そもそもリネームする状況に至る前には、何かしらの運用上の問題が生じ、作業コストや検討コストが発生しているはずで、思った以上にコストが掛かっています。

少しのコンパクトさより、積み上げやすさのほうが大切です。

TagやCategoryをUI名にしない

TagやCategoryはドメインとしても、UIとしても使いたくなるややこしい存在ですが、UI名には使わないほうが曖昧さの回避に繋がります。その理由は、TagやCategoryは抽象度の高い関心であり、他のコンポーネントと同様に、関心をどのUIで表現するか?という法則性に従うためです。

最近は Chip というコンポーネントが一般化されてきたようなので、TagChip として扱うと BCD Design でも上手に扱えます。

構成 コンポーネント名
(2)何を (3)どうする (4)UI タグ(を表示する)チップ TagChip
タグチップ

ニコニコ生放送では、TagCardというコンポーネントで扱っていましたが、将来的にはTagChip に統一していく予定です。

Bannerの役割を定めておく

BannerというUIは、広く一般的に使用される画像等の旗やのぼりを表現するUIと、アプリで通知などに使用するモードレスなUIの2つが存在します。

これらは名前が競合するため、プロジェクトでは予めBannerが何を指すのか、決めておく必要があります。特に、両方使用する場合、同じ名前で使用することは困難であるため、名前の使い分けが必要です。

そこで、比較的どのプロジェクトでも競合しにくく、BCD Designでも使いやすい名前を考えてみたので参考にしてみてください。

コンポーネント名 役割 備考
VisualBanner 画像だけでなく、動画やテキストの場合もある
NotificationBanner 通知 デジタル庁のデザインシステムに同等のUIが存在

通常は以下の3つの方針から選ぶことになるかと思います。

方針 通知
旗優先 Banner NotificationBanner
通知優先 VisualBanner Banner
中立 VisualBanner NotificationBanner

迷ったときに役立つ知識

ここではBCD Designで迷いがちな部分の解決策について紹介します。

動詞から始まるUIの所属先

基礎的なコンポーネントでありながら、動詞から始まるUIが存在し、BaseとCaseどちらに所属するか迷うことがありますが、動詞がUIと関心のどちらに作用するかで判別できます。

動詞の作用の対象 所属
ToggleButton
Pulldown系
Dropdown系
UI Base
SearchButton 関心 Case

ToggleButtonのToggleは微妙な存在ではあるものの、一般的にUI自体がトグル表現を持つため、Baseに所属します。

SeachButtonのSearchは何かの関心事を検索するものであり、UI自体に作用するものではないのでCaseに所属します。

ブレやすい単語リスト

末尾が以下のような単語で終わるコンポーネント名は改善できる可能性があります。こうすることで、コンポーネント名が形式に合い、説明的で、分類や並び順もキレイになり、美しく保守しやすい構成につながります。

改善前 改善後
Ad AdBanner
AdPanel
広告は抽象度の高い関心名。
❌ バナーを広告というUIで表現する
✅ 広告をバナーというUIで表現する
Badge BadgeIcon
XxxIndicator
StatusLabel
Badgeの意味によって変わってくるため、詳細はBadgeからIndicatorへのパラダイムシフトを参照
Category CategoryLabel
CategoryChip
カテゴリは抽象度の高い関心名。
表現するUI名が必要。
Footer SiteFooter 何のFooterなのかが不足しやすい。
Header SiteHeader 何のHeaderなのかが不足しやすい。
History HistoryCard
HistoryArticle等
履歴は抽象度の高い関心名。
表現するUI名が必要。
Illustration IllustrationImage
IllustImage
Illustrationは図で抽象度の高い関心名。
表現するUIは画像やiframe等があり得る。
Information InformationSection
InfoSection
InfoMessage
情報は抽象度の高い関心名。
表現するUI名が必要。
Label Label
LabelChip
単なる名称ならLabel。(LebelTextのText省略形)
タグ的な分類用途ならLabelChip。
Menu Menu
MenuPanel
MenuBar等
本当にMenu自体ならMenu。
Menu自体の周りに何か要素がある場合は、PanelやBarの中にMenuが入っている。
Navigation NavigationMenu
NavigationBar等
Navigationの意味は"道案内"なのでCase相当。
NavigationMenuはそれ自体がMenuの場合のみ。
NavigationBar SiteNavigationBar 何の道案内をするのかが不足しやすい。
Preview PreviewImage
PreviewDisplay等
Previewの意味は"試写"なのでCase相当。
必ずしも画像とは限らない点にも注意。
SideBar SiteSideBar 何のSideBarなのかが不足しやすい。
SideMenu SideMenu
SideBar
それがMenu自体ならSideMenu。SideMenu自体の周りに何か要素がある場合は、SideBarの中にSideMenuが入っている。
Tag TagLabel
TagChip
タグは抽象度の高い関心名。
表現するUI名が必要。
Thumbnail ThumbnailImage
ThumbImage
ThumbnailView等も存在するように、Thumbnail自体は"縮小した見本"という修飾語として扱ったほうが安全。
Statistics StatisticsList
StatisticsBar
StatisticsSection等
統計は抽象度の高い関心名。
表現するUI名が必要
Summary SummarySection等 概要は抽象度の高い関心名。
表現するUI名が必要。

連想しにくいUI名リスト

内容が単純、または明瞭なUIは、それが何であるか連想しやすいものの、中には様々な内容を含んでいるUIや、特殊なUIは、それが何であるか連想しにくいものがあります。

そこで、連想しにくいUIの名前を、一覧にしてみました。対象のUIが該当するかしないかの判断に使っていただけると幸いです。

UI名 用途
Controller 操作するためのUIをまとめたUI
Display 何かを展示・陳列するスペースを表すUI。映像を表示する装置とは別の役割。
Dock Launcherとほぼ同等の機能を有するUI
Footer 本体の情報に対する付加的な情報をまとめるUI
Fieldset 入力要素をグループ化するUI
Header 本体の情報に対する表題や概要をまとめるUI
Launcher 起動を補助する機能を有するUI
Pane 画面の一部を区切って表示する領域UI
Panel 画面上の部屋のようなもので、他から区別された領域を形成するUI。
区別された領域は、浮かせたり、はめ込んだりできる。
Player 媒体の再生装置を表すUI
Reader 情報を読むためのUI
Renderer 描画する装置を表すUI
Tool ある目的を達成するために必要な機能や情報を集約したUI
Toolbar Roving TabIndexの機能を有し、道具が並べられたUI
Viewer 表示、閲覧するための装置を表すUI

普段何気なく使っているMenuとPanelも、MenuはMenu、PanelはPanelのように曖昧さを排除できます。

MenuとPanelの見極め方 を参照。

条件付きのコンポーネント名

実装方針によっては、通常のコンポーネント名に少し情報を加えたコンポーネント名が必要になることがあります。その場合はコンポーネント名の後方に With For By といった前置詞を追加して追記します。

用途 コンポーネント名 意味
スタイルが適用されている場合 XxxWithStyled スタイル付きのXxx
スマホ向けの場合 XxxForSp Sp向けのXxx
ティッカーで表現する場合 XxxByTicker ティッカーによるXxx

CaseとCommonで迷ったとき

例えば、何かの情報を取得した結果を表示するようなコンポーネントがあったとしましょう。

コンポーネント名を素直に表すとFetchResultInfoMessageやFetchResultInfoSectionのようになりますが、CaseとCommonどちらに入るでしょうか?

答えとしてはCommonになります。なぜなら、FetchResultは "取得結果" という、このコンポーネントで扱われる対象を表しており、「Result を Fetch する」ものではないためです。

Caseは動詞から始まるコンポーネントを含める場所ですが、それは良いコンポーネント名の法則 (3)どうする (4)UI の3の部分の動詞であるという点に気を付けましょう。FetchResultのFetchは名詞として使われているため、Caseには入りません。

より先進的な使い方

ここではBCD Designのより先進的な使い方について紹介します。

より攻めた使い方で依存関係も完璧にスッキリさせたい方におすすめです。

Caseの扱い方

長くBCD Designを使用して洗練させていくと、意外とCase内のコンポーネント数は増えないことがわかります。特にIconの種類をsmart-svgのようなCSSで表現するものや、propsで切り替えられる場合、一部を除いて汎用的な「(動詞)ボタン」はほとんど用意する必要がありません。

また、base/dialog から case/close-button を使用したいといった、不適切な参照が発生がしやすい問題もあることから、Caseのディレクトリ自体を無くす構成が検討されてきました。(Caseの概念は残ります)

記事公開時点でのニコニコ生放送でのCaseのコンポーネント名は概ね以下の通りです。

case
  alert-dialog
  clear-button
  close-button
  confirm-dialog
  preset-form
  prompt-dialog
  search-box
  search-button
  search-form
  select-all-checkbox-control

上の構成を、派生系のまとめ方を使った以下の構成に変更することで、Caseが無くなります。

base
  button
    _base
    _variant
      primary-button
      secondary-button
    clear-button
    close-button
    search-button
  checkbox-control
    _base
    select-all-checkbox-control
  dialog
    _base
    alert-dialog
    confirm-dialog
    prompt-dialog
common
  preset-setting // 扱っているものは プリセット設定 である
    preset-setting-edit-form
  search-word // 扱っているものは 検索ワード である
    search-word-combo-box
    search-word-submit-form

これにはポイントを二つ押さえる必要があります。

  1. 汎用的な派生系の一種としてBaseに置くもの
  2. 動作だった単語を、扱っているものに捉え直して、Commonに置くもの

2は、検索がワードだけでなく、その他の条件も持つ場合はSearchConditionSubmitFormのようにできます。これにより「検索条件を提出することで、検索結果を取得するフォーム」という捉え方になり、他のCommonにあるコンポーネント名と形式が揃います。

ちなみに、ニコニコ生放送ではすでにFollowToggleFormといった形でも採用されており、Followのような関係性を表すもの(他にも購読や契約も関係性)は、フォロー関係Follow(Relationship)のように、暗黙の単語が存在すると捉えて、関係の着脱(フォロー関係の追加/解除)という概念に収束できます。

Errorの扱い方

Errorは名詞であるため、BCD DesignではCommonに分類される単語です。もしも、ErrorListのようなコンポーネントを作るのであれば、Commonが最適でしょう。自身でも以前の記事ではそのようにも書いてきました。

しかし、Error系をCommonに置くと、FieldやFormが標準でErrorListのようなものを持ちたいとき、CommonからBaseを参照してしまう問題が潜んでおり、完全にスッキリはしていませんでした。

そんな中、ErrorはStatus(状態)の一種であるという観点に着目したところ、エラーメッセージの捉え方の記事にあるように、ErrorはMessageなどの属性として扱ったほうが望ましいことがわかりました。

状態を属性にすると、errorだけでなく、warningやinfoといったものも、propsで切り替えられるため、わざわざそれぞれのコンポーネントを量産しなくて済むうえ、抽象度が一段階上がったMessageは、Baseに置くコンポーネントになるので、依存関係の問題も解消します。

つまり、ErrorListはMessageListという抽象度の高いコンポーネントで扱えば、丸く収まるということになります。

base
  message
  message-list

ちなみに、このMessageという単語を英辞郎で調べると、 "(伝えたい)意図" という使い方が最も合致するため、これは意図を表現するコンポーネントであると言えます。

英辞郎でのMessageの検索結果

改めて「Messageは、ユーザーにエラーの意図を伝えるコンポーネント」と文章にしてみると、かなり正確に明名できていることがわかります。

BadgeはUIとして使わない

Badgeは、ドメイン名とUI名で競合したり、そもそもUIとして解釈が複数存在するなど、ややこしい存在です。この問題はIndicatorという視点を持つことで、解消できます。

BadgeからIndicatorへのパラダイムシフトを参照。

まとめ

いかがだったでしょうか?

BCD Designを4年運用する中で得られた、ベストプラクティスの数々を紹介しました。

今回紹介した内容を活用すれば、誰でも迷うこと無くBCD Designの多大な恩恵を得られます。

最近は、先進的な使い方まで明らかになってきたことで、運用上の未解決課題はほぼ無いに等しいレベルまで洗練されてきました。すべての単語が過不足なく体系的に並ぶ様子には、美しささえ感じます。

また、仕組み的に流行り廃りの影響を受けないため、コンポーネント以外の分野でも応用が効きます。一度身に付ければ、様々な分野で一生役立つ、強力なスキルに繋がることでしょう。

まだまだBCD Designは一部の人だけが知る存在ですが、それではもったいないほどの魅力的な技術ですので、一人でも多くの方に知っていただき、恩恵に預かれることを願っております。

関連記事
2024-12-11公開: ニコニコ生放送でBCD Designを4年運用した知見(導入編)
2024-12-17公開: ニコニコ生放送でBCD Designを4年運用した知見(基礎テクニック編)


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

Discussion