修行の場

知人が言っていました。これは修行だと。

設計の本質とあるべき姿

設計の本質

Code Complete ch.5に設計の本質についてまとまっていました。

せっけいは本質的に困難で、その理由があげられています。

  • 設計は完全にはならない。正しいか終わったかの確信も得られない。ただ、後々の大きなミスを防ぐ可能性を秘めている。
  • 設計はwicked problemである。
    • 解いてみないと正しい解がわからない。例えば、橋を作って壊れるまで、橋設計に流体力学が必要なことはわからなかった。
    • 設計しても、実装上の理由でその設計が無効であることもある。
  • 設計はsloppyである。
    • 間違ったやり方とか失敗をしながらきちんとしたものが完成する。(ただ、設計時に失敗して修正するのはコーディングで失敗して修正するよりもコストが低い。)
    • だめなやり方と正しいやり方は近いことが多い
    • 終わりがいつかわからない。
  • 設計はトレードオフと優先度に関するものである
    • 開発時間とシステムのレスポンス時間どちらを優先するか?によって設計が変わってくる。
  • 設計は制限をもたらす
    • 制限をかし、可能性を作ることでシンプルな解放がデてくる
  • 設計は決定的ではない
    • 3人が設計すれば3通りの良い設計ができる。
  • 設計はヒューリスティックである
    • なので、ある問題の解決で役立ったものが他でも同様に使えるとは限らない
  • 設計はEmergentである
    • 設計はレビューや議論やコードの記述や修正によって変わる。進化する。

essential complexityとaccidential complexity

とある文献では、複雑さには二種類があり、accidential complexityとessential complexityの二種類に分類されています。 関数化せずに同じ処理がコピペされているのは、accidential complexityでessential complexityとは異なります。 コードが読みにくい場合には2つの原因があり、

  • もともと複雑な問題を取り扱っていたり、要件が複雑といった理由で、essential complexityが高い。
  • 良いPracticesでコードが書かれておらず、accidential complexityが高い。

後者の場合、コード規約を作ってレビューで直したりすることで対処されていると思います。 前者の問題は要件や解く問題の問題で解く問題をいかに単純化するかという問題や設計の問題であるため、個別の対応になると思います。エンジニアレベルでは、議論をするか、時間がなければバックログに積んで対処していくということになるでしょう。

設計の望むべき性質

  • Minimize Complexity
    • シンプルな解法を選ぶ
      • ある部分を見ているときに他の大部分を無視できなければ設計は仕事してない
    • 複雑性を排除すべき理由
      • ソフトウェアは使う部分は完璧に正確じゃないと動かない
      • 多くの部分を気にしてある部分を治すのは難しい
  • Easy of maintenance
    • 保守・運用エンジニアがしそうな質問をいつも頭に思い浮かべる
    • 将来の自分がコードを読むときを思い浮かべる
      • 戻り値ははタプル?一個目はなんだっけ?
    • 自己説明するシステムを作る
  • システムを部分的に利用する
    • Extensibility
      • 既存システムを壊したり変更せずに修正できる
    • Reusability
      • システムのパーツを再利用できる
    • Portability
      • 他の環境下でも少ない工数で動かせる
      • 例:scrapyはストレージとして、AWS上でもクローラ実行環境上でも使える。様々な条件で使える。
  • エンティティの入出力
    • High Fanin
      • 多くのものから使ってもらえるものは良い
    • Low Fanout
      • できるだけ少ないものに依存するモジュールであるべき
        • なぜなのかは不明だが、多くのものに依存=責務が大きすぎると捉えられるのではないか?
        • 書き手が覚えることが多くなるのが問題?
  • Leanness
    • 最低限の設計に。不要なものが設計時点であると、実装、検証、改修すべてのフェーズに影響を及ぼすし、後方互換性の確保もし続けなければならない。
  • Stratification
    • あるレイヤだけ見て設計が理解できるようにする。
  • Standard

実験的な機械学習プロジェクト

例えば、1,2ヶ月ごとに機械学習アルゴリズムを変更していき、それらのアルゴリズムで使う共通の処理を作っていくようなプロジェクトでは、どのようにcomplexityを管理していけば良いでしょうか?

共通処理のcomplexityはできる限り低く抑えるべきだと思います。 また、機械学習アルゴリズムWebサービスなどで使うことを想定します。そうすると、機械学習アルゴリズム側もできる限りComplexityを下げるべきです。

データパイプラインなど共通の部分は、Leanness, minimize complexity, ease of maintenanceを満たした上で、portabilityを様々なPC、AWS上で動かせる程度に満たし、Extensibilityを満たすべきです。 また、テストもそれなりに書く必要があり、そういう点では、モジュールがloosely coupleになっている必要があります。

機械学習アルゴリズムもほぼ同様ですが、 機械学習アルゴリズムブラックボックス的にテストできる場合は、外部的な性能評価にとどめ、loosely coupleやextensibility, ease of maintenanceを犠牲にするという手もあると思います。性能を評価する部分はテストをきちんと書いて作るべきだと思います。

また、データ収集処理などの共通部分は寿命が年単位であるため、設計ドキュメントを詳細に書いたほうが良いと思います。 機械学習アルゴリズム部分はアルゴリズム設計に関してドキュメントにするべきだと思います。