FPにおける設計を学ぶ②: 実践から身に沁みた当たり前のこと

こんにちは
前回に引き続きまだまだFPを学んでいます
実際にClojureのアプリを設計して実践からFPの設計を学びました

行ったこと

  • 急な目的のために急いで作った grouper というグループ分けのアプリに簡易Clean ArchitectureとFP的な考えを取り入れて改善を試みました
  • 大まかに改善したこと
    • 一つのファイルにごちゃっとロジックが詰まっていた → Clean Architectureでドメインロジックの分離
    • 複雑すぎて実質ブラックボックスになっているグループ分けロジックの流れ → ユースケースドメインで抽象化することで大まかな流れを表現した
    • 汎用的でない関数ばかり → 上記の抽象化もあわせて、今回のアルゴリズムに特化した関数と汎用的なグループ分けロジックを表現する関数で分割した

身に沁みたこと

  • 関数を組み合わせて何もかも実現するFPは、シンプルである故に、正しく命名するといったような設計の基礎の基礎といったスキルが試されます
  • 結果として「FPであれOOPであれ良い設計の考え方は基本変わらないこと」という当たり前のことが一番身に沁みました
  • よって以下では具体的に学んだ当たり前のことを将来の自分に問いかける形式で書いていきたいと思います

設計をするときに自分に問いかけたいこと

処理の詳細を考える前に、インプットとアウトプットのデータの形をちゃんと考えましたか?

  • 関数のインプット(=引数)とアウトプット(=返り値)を見極めましょう
    • FPでは最初のデータの形(データA)と最終的に欲しいデータの形(データB)を見極めて、データAをデータBに変換する関数を少しずつ作ります(参考: Bottom Up vs Top Down Design in Clojure - Mark Bastian
    • よって最初と最後のデータの形は特に時間をとって考えましょう
  • TDDでテストを書き終えたら、一度手を止めてデータの形を考えましょう
    • そのドメインを表現するのはそのデータの形で良いのでしょうか?
      • リストである必要がないのにリストを使ったりしていませんか
      • シンプルな形になっていますか

誰もがその関数名から同じ理解を得られますか?

  • 「その関数で行うこと」 を 「関数名 (+引数名)」が表現していますか?
  • 「関数名 (+引数名)」 から 「その関数で行うこと」をズバリ導けますか?
  • 上記ができていないとき
    • 単一責任の原則を守っていますか?

正しく抽象化できていますか?

  • 関数を組み合わせた時など、抽象的な表現が必要な時があります
  • 図に表現したり、言葉遊びをするとふさわしい表現が見つかるかもしれません
  • ものごとの性質だけではなく、「そのコンテクスト内での意味」を考えてみましたか?
    • 意味を考えると、その「やりたいこと」にとって本質的に何が必要で不要なのかということにフォーカスして考えることができます

それは行いたいことを一番シンプルに行う手段ですか?

  • 様々な選択肢の中から一番シンプルで実現可能な手段選びましたか?
  • 「できること」に飛びついていませんか?
    • 言語のシンタックスやライブラリはあくまでツールの一つです
    • そのツールを使うことでシンプルさを得られるのかを今一度考えてみましょう