かきあげせいろはラーメンがたべたい

技術プログラミングいろいろ記録メモ備忘にゃーん!

設計Night2018@自分用理解メモ

builderscon2018で(@shinpei0213)さんによる発表「開発現場で役立たせるための設計原則とパターン」を聞きました。 https://nekogata.hatenablog.com/entry/2018/09/10/163206

現場において暗黙知となっている部分、例えばコードレビュー時にどのコードが良い悪いなどを議論する際に、その現場で技術的に優れている人(もしくは年数が長い人とか)だけが把握している"良い悪い"を、設計原則(単一責任原則や開放閉鎖原則)などを"良い悪い"の基軸として据えることで、議論のテーブルに持っていくことができるのではないか。

という問題提起から、

「問題に対して、その設計原則が最適である」というのはどのように判断するのか?

「結局はケースバイケース」という答えのようで答えになっていない結論とするしかないのか?

というさらなる問題に対して、

デザインパターンなどを利用し、構造やコードを作成する」⇄「設計原則を利用し問題に対して良い構造になっているか見直す」

というサイクルを繰り返すことで、最適な状態を削り出していくのが良いのではないか。

という発表でした。

私はまだまだ経験の少ないプログラマーで、入門書の次のレベルとはどういうことなのだろうか?そもそも良いコードとはどういうことなのだろうか?デザインパターンや設計原則を少し学んだけど、現場で活かせているような気がしない。という疑問でしばらく悩んでいました。

この発表は、上記の疑問に一定の答えを示してくれていると感じ、大変感動しました。

その発表の続編(上記だけでは解決できていない問題がテーマ)に当たる勉強会に参加してきました。

設計Night2018 powered by Classi

https://connpass.com/event/104821/

論点1:パフォーマンスについて

@moznion ‏)さんの発表

https://twitter.com/moznion/status/1060494440832233474

プログラムは解決したい問題をそのままプログラムに書き換えるだけ(ピュアなドメイン)ではない場合が多いです。

パフォーマンスはその代表で、例えば重い処理は溜め込んでバッチでまとめて処理をしたり、一つの処理を高速で処理するために並列処理をしたりです。

これらは解決したい問題をそのままプログラムにしたときに発生する問題に対しての対策と言えます。

しかし、パフォーマンスを意識したプログラムはピュアなドメインから離れていくこともあるため、"ピュアなドメインの設計"の設計が歪められます(コードが読みにくい・挙動をイメージしにくい・修正コストが高くなる・メンテナンスコストも高くなる)

そのため、ドメインに対するしっかりした理解を持った上で、パフォーマンスを考える必要があります。

上記を踏まえて、どのように設計すべきなのか?

まずは素直にドメインモデリングする。

  • 多くの場合は実用に耐える

困ったらシンプルにしておく

  • シンプルな方が後から手を入れやすい

最初の設計

上記の通り、パフォーマンスはコンピュータの都合(非機能要件に近い?)ので、最適化の余地を残して、ドメインをシンプルにモデリングする「最適化の余地のある設計」を第一の設計とするのを目指せば良いのではないか

感想

まずはシンプルに設計し、問題がある部分を最適化する。という方針自体がシンプルでわかりやすくて嬉しいです。どれだけ詳細に設計しても、実際にプログラムを書くときはいろいろなことに頭を使っているので、同時に考えることがとりあえず減る方針はミスや余計な工数を発生させないように思います。

(あと、パフォーマンス自体についてあまりにも無知なので勉強しなければいけない・・・)

論点2:問題をいかに捉えるのかについて

@magnolia_k_)さんの発表

https://twitter.com/magnolia_k_/status/1061472093210955779

(@shinpei0213)さんによる発表「開発現場で役立たせるための設計原則とパターン」で、暗黙知ボトルネックが"どうやって設計原則を使うか"から"問題そのものの捉え方"に移動したので、問題そのものとどう向き合うか?について。

そもそも問題を捉えるとは

  1. 問題を理解すること

  2. 未知のもの、データ、条件は何か?

  3. 条件は十分か、矛盾していないか
  4. 条件は書き表すことができるか

既に存在しているプログラムには、問題そのものは記載されていない。

上記URLに出てくる、年齢計算の法律は閏年について特別に記載されているわけではないが、シンプルな記載で閏年への対応ができている。

閏年への対応ができている」という事実を後世の人に示すべき。そのためにどうするか。

  • テストをちゃんと書く(この場合、閏年を引数にするなど)
  • もしくはロジックにあえて入れておく(2月29日の場合のifや、コメントに閏年もそのロジックで対応できていることを書く

問題は潜んでいる可能性がある

ドメインの知識にも暗黙知がある("プロダクトをよく知っている人"の存在)。

潜んでそうなところを考える。

事実

  • 手順書に書いてない手順とか
  • 実施する人が意識していない作業・確認観点
  • ログのない変更履歴
  • 設計根拠のわからない機能

関係

  • ピュアなドメインと、プログラムの関係
  • グローバル変数が多用されたモジュール構造(もしかしてグローバル変数自体が関係を表す?)
  • 参照のための条件が多いテーブル定義(取り消しは除く、再掲、初期値だけ特別、など。。。)

関係は事実だけを並べていても出てこない

言葉だけで表現しにくい

何が必要な関係かあらかじめわからない

原則

規則は明文化されていることが多いが、原則は明文化されにくい。

  • 一貫性が重要
  • 規則や原則によって、一貫性が担保されるのではないか
  • パターンを網羅するのは難しい(例外まで考えられない)
  • 意識するのが難しい

暗黙知形式知にしていく

どうすれば

  • 事実を形式知

    • 5W1H
      • When(いつ)
      • Where(どこで)
      • Who(誰が)
      • What(何を)
      • Why(なぜ)
      • How(どうやって)
    • コードはHow(どうやって)になっている
    • テストコードにはWhat(なにを(引数))
    • コミットログにはWhy(なぜ)
    • コードのコメントにはWhy Not(なぜ〜〜じゃないの)
  • 関係を形式知

    • 図とか表(これらには問題の視点がある)
  • 原則を形式知

    方法論がない?

    「緩やかな一貫性」とする

    上記2つを出す中で、原則が導出されてくる?

問題を継続的に捉えるために

  • 形式知が多いと、形式知の読み取り方が暗黙知になっちゃう(形式知を完全にするのも現実的ではない)
  • 後輩にdisられない駆動開発

  • 変更されそうな場所

感想

  • 暗黙知ボトルネックが"どうやって設計原則を使うか"から"問題そのものの捉え方"に移動」という考え方を聞いた時、目が醒める思いでした。現状の問題をすべて解決した時、上位のレイヤーに問題が移動しているという考え方はいろいろなものに応用が効きそうと感じます。夢物語ですが、すべてを形式知にすることができ、メンバー全員がそれを把握できるようになった時、問題は更に上位に移動するのでしょうか。
  • 設計原則を議論のテーブルに乗せる時と同じように、形式知にしてみて、上記の発表の内容を満たしているか?を確認する作業を相互に繰り返し、「問題を捉えられているか」を削り出していく必要があるように感じます。

(この発表自体が「問題をいかに捉えるのか」の設計原則みたいな?)

論点3:MicroServicesという視点

@qsona)さんの発表

https://twitter.com/qsona/status/1060494570205589506

マイクロサービスとは「協調して動作する小規模で自律的なサービス」のこと

以下の特徴を持っています。

  • 技術異質性
    • サービスに適した言語、ライブラリ、データストアを利用できる)
    • 負債を他のサービスに引きずりにくい
  • 回復性
    • サービスに障害が起きても全体に影響がない
  • デプロイの独立
  • 小さく自立・独立した組織
    • 意思決定を素早く

マイクロサービスにおける設計ポイント

サービスの境界を定める

境界内で失敗する分には後から取り戻すことができる

  • 負債管理しやすい
  • サービスを小さくしているメリットでもある

ただし、DBの正規化はしっかりやっておくほうがいい

サービスの統合

  • 複数のサービスの連携方法
    • API
    • 非同期メッセージキュー

どんな技術を利用するか、その粒度はどうするかなど・・・

横断的な問題

サービスが増えると似たような課題が複数サービスで発生する。それを個々に対処するのは効率が悪い。

これらの問題を設計原則を武器に立ち向かってみる

  • サービスの境界
    • サービスは1つだとしても、想定ユーザに種類が存在する場合、種類毎のビジネスが1つのサービスに存在
      • 単一責任原則に合わないのでは?
        • プレゼンテーションビジネスとドメインビジネスの二種が存在するのでは?
        • この二種の境界はあやふやでは?
      • DRYが適用できる同じ処理がサービス間でまたがっているのでは?
        • 「昔々あるところに〜〜」を共通ライブラリ化することは良いのだろうか?
          • よくない。なのでコードのDRYではなく、作業のDRYをすべきではないか。

まとめ

設計原則はやはり万能ではない。常に考えることが必要。→結局ケースバイケース?

設計原則に捉われすぎるのもよくないので、成長のための軸として利用するのが良いのではないか?

感想

マイクロサービスを適用したプロダクトや知識経験がないのでなんとも言えないですが、そのようなプロダクトでも@shinpei0213さんが掲げた

デザインパターンなどを利用し、構造やコードを作成する」⇄「設計原則を利用し問題に対して良い構造になっているか見直す」

を常に実施できる環境そのものを作ることがプロダクトの品質を高く保ち続ける秘訣なのではないかと感じます。

また、成長の軸として利用する。というのは激しく同感です。いいコードとは、いいプロダクトとはに明確な答えを定めることは危険な気がしますし、どうしても納期やマネタイズの問題によって、プロダクトの品質に影響が発生することは避けられません。その意味である程度ふわふわしたものが軸になるというのは、応用がききやすいバランスではないでしょうか。