「現場で役立つシステム設計の原則」読書会レポート vol.7

株式会社リゾーム システム企画・開発部 第4グループの尾古(@patorash)です。

読書会の第7回目のレポートです。

前回のレポートはこちらです。

tech.rhizome-e.com

7回目レポート

それぞれの感想

画面にロジックを書いてしまうこと
  • 画面に表示するロジックと業務ロジックが混在してしまう
    • 1章で言われていた、ちょっとした条件分岐を追加したら複雑になってしまう件が頻発する
    • ビューにif文が入ると見辛くなる
      • 特に、slim*1で書いていると、閉じタグがないため、インデントが重要になるが、if文が入るとかなり見辛い
    • 複数画面にコードが重複してしまう
  • 表示のロジックと業務ロジックを分ける意味では、Railsでいえばビューヘルパーを使ったり、デコレーターを使っていくのがいいとは思う。ビューヘルパーのメソッドはオブジェクトをレシーバにできないのであまり好みではないけれど、契約による設計を重視した形にすれば、あまり散らからないのではないか?
論理的なビューと物理的なビュー
  • どこに画面用ロジックを集めるか問題
  • 論理的なビューに関してはドメインオブジェクトでいい、というのはわかるのだが、結局苦しんでいるところは物理的なビューだったりする。
  • Railsだとデコレーター層でやりがちだが、ビュー専用オブジェクトは極力作るべきではない
  • 画面に依存したドメインモデルもアンチパターン
  • class属性をドメインオブジェクトが持つべきという話
    • オブジェクトの状態によってclassを書き分けるif文がView上に出るたびに薄々感じていた
タスクベースのインターフェース
  • 関心事毎に画面を分割する発想はあまりなかった
  • ユーザーの入力負担軽減につながるので良さそう
  • 画面をタスクベースにできなくても、設計をタスクベースにしたり、画面の方も4原則を使って整えたらかなり見やすくなるのではないかと思う
  • 画面デザインの考え方をドメインオブジェクトのコードに当てはめるのは面白いと思った
  • 要件定義をする際に、お客様側は画面ありきで要件を考えるため、それがそのまま設計に繋がってしまうことがあった。
  • 今作っているサービスだとなんでも入力画面になっている。後で入力すればいいものまで、必須にする必要はないので、ドメインオブジェクトで整理していきたい。
  • 画面とオブジェクトを一致させることが、次第に画面に依存したオブジェクトを生み出すことに変わってしまいそうなのが一番懸念される
    • つまりレビュワーはこの点を特に注意深くレビューする必要がある
  • 画面もドメインオブジェクトで管理したいとなると、MVVMを使うようになってくるのは必然。しかし、この辺りをよくわかっていない人がやっているコードを見ると、「画面を値が連動していて便利」止まりになっている気がする。
利用者向けの情報もソフトウェアと整合させる
  • そうあるべきだが、これが難しい…
  • 開発者とプレスリリース/リリースノート/利用者ガイドを作成する人が異なるので…。
  • ドキュメント系のメンテナンスのためにはもうちょい開発者増やしたい。

意見交換

出た意見として、「全てのアンチパターンはモノに注目するが故に起きる。コトに注目することで細分化できたり解決するように見える」というのがありました。今まで読んできた中で、ドメインオブジェクトを作るにしても、テーブル設計をするにしても、コトに注目して整理することで、随分良くなるように感じています。

また、論理ビューと物理ビューをどうするべきか?について、時間をかけて話し合いました。最終的には、「物理ビューに依存したドメインオブジェクトにするべきではない」ということになりました。 最初は私は「論理ビュー用のロジックはドメインオブジェクトに持たせて、デコレーターには責務を割り切って物理ビューを担わせてしまえばいいのではないか?」という意見を展開していたのですが、ビュー専用オブジェクトになるし物理ビューと密結合になるのでよくないのでは?という意見もあり、考えを改めました。

Railsで論理ビューと物理ビューをどう管理するか?

読書会の後、ビューヘルパーに物理ビューを出力するメソッドを定義し、その引数に論理ビューを渡すという方式が一番しっくりくるのではないか?と考えました。

例えば、順番なしリストを作る場合は以下のような形になります。

まず、unordered_listヘルパーメソッドを定義します。

module ListHelper

  # ulタグのリストを表示する
  # @param [Array<String>] items リスト表示したい文字列の配列
  def unordered_list(items)
    render 'shared/ul' do
      render partial: 'shared/li', collection: items, as: :item
    end
  end

end

次に、上記のメソッドでレンダリングするViewを書いていきます。 views/shared/_ul.html.erbをこのようにします。

<ul>
<%= yield %>
</ul>

そして、views/shared/_li.html.erbをこのようにします。

<li><%= item %></li>

利用する場合は、例えば記事にタグがある場合はこのようにできます。

<h3>タグ一覧</h3>
<%= unorderd_list(@article.tags) %>

この形であれば、

  • ドメインオブジェクトは論理ビューに徹する
  • ヘルパーメソッドは論理ビューと物理ビューの繋ぎに徹する(ロジック含む)
  • 部分テンプレートは物理ビューに徹する(ロジック含まない)
  • 物理ビューにループ等のロジックを書かないで済む
  • 再利用性が高い
  • メソッドなのでIDEで補完が効く

と、良いこと尽しな気がしています。

まとめ

本章を通じて、普段から業務用ロジックと画面用ロジックのところで悩んでいたため、活発な議論ができたのではないかと思います。私自身もメンバーとの議論を通じて、考えを改めたほうがいいなと思えましたし、その中でより良い解決策を見出せたと感じています。

やはり本を読むだけでなく、意見交換を行える場があるほうがいいなと感じました。