JavaScript
CleanArchitecture
0

JavaScriptでクリーンアーキテクチャはどうすればいいのか(前編)

JavaScriptでクリーンアーキテクチャはどうすればいいのか(前編)

by Gatz
1 / 7

クリーンアーキテクチャとは

まず以下の記事を推す。

持続可能な開発を目指す ~ ドメイン・ユースケース駆動(クリーンアーキテクチャ) + 単方向に制限した処理 + FRP

私なりの要点は次の通り
* 内側から、DomainModel/Usecase/Interface Adapter/External Adapter
* Interface Adapterが内と外を変換する単一方向のパイプのようなもの
* 外から内への入力がController、内から外への出力がPresenter、入出力を分離する必要がない場合はGateway
* Usecaseに業務手順を書き下す。業務手順の明示的なテストができるって凄い
* Usecase中では、Contolerからの入力で、DB−Gatewayからデータを得て、Presenterに出力し反映など。パイプを繋ぎ直しているようなイメージ
* 出力パイプであるPresenterは他のUsecaseの入力になったりはしない(ようにすべき)
* 出力先が別れる時はUsecase中で分ける。パイプはステートレスだから完全に個別にテストできる。素晴らしい


実装で理解したい場合

クリーンアーキテクチャの右下の図

  • インタフェースがうんたらは置いておいて、いかに単一方向のパイプであるかイメージできた
  • 生成する順番は、outportつまり外側から、interactor=Usecase、その次にcontroller。以下が秀逸
static void Main(string[] args)
{
    var outputPort = CreateOutputPort();
    var interactor = CreateInputPort(outputPort);
    var controller = new Controller(interactor);
    controller.Execute(new[] {"source", "data", "foo", "bar"});
}
  • JavaScriptでは、最近、DOMContentLoadedをよく目にします。

原典

クリーンアーキテクチャ(The Clean Architecture翻訳)


JavaScriptで実践

勤務実績一覧

  • 人を選んだら過去勤務実績を年度/毎月(概要あり)のタブ区切りで表示する
    • 毎月、何時間働いたか、その内訳は何か
  • 選択ユースケース
    1. 選択した所属部門に属する人だけ絞込可能
      • 選択可能な従業員の勤務形態も同時変更
    2. さらに選択した勤務形態(社員/パート)でも絞込可能
      • この場合は所属部門は絞り込まれない
    3. 同様に、勤務した個別月から絞込可能

UIイメージ

 選択UI


早速困ったこと

  • Usecaseの粒度
    • ひとまず、class Usecaseで一つ
    • FilterUsecase#changeDepartment(i, department)
    • FilterUsecase#changeLabortype(i, labortype)
    • FilterUsecase#changeMember(i, member)
  • UIセレクトボックス中の選択状態は?どこに?
    • filterUC.cond = {department: ?, labortype: ?, member: ?}
    • ひとまずUsecaseに?持たせる(いいの?)
class FilterUsecase {
  changeDepartment(i, department){//まずは部門で絞込
    this.cond = {department : (i < 1) ? null : department}
    const 勤務実績表 = this.repository.q("勤務実績", this.cond);
    this.oport["memberfilter"].update(勤務実績表, this)
  }
  // this.outport["memberfilter"]の実態は、Presenterとする
}
class Presenter
  constructor(id){
    this.node = document.getElementById(id)
  }
  update(table, usecase){
    //勤務実績repositotyから得られたtableを変換してUIに反映する
    //1. Table -> Arrayへ変換 -> domへの中間表現 vdomに変換
    const arr  = this.selectMember(table)
    const vdom = this.toSelectBox(arr)
    //2. vdomの内容を、DOMに反映
    this.node.appendChild(toDom(vdom).addEventLister("change", (evt)=>{
     const i = this.selectedIndex;
     const member = this.options[i].text
     usecase.changeMember(i, member)
    }))
  }
  • Table->Arrayへの変換はPresenterの役割?Usecaseの役割?
  • Array->vdomへの変換はPresenterの役割?Usecaseの役割?
  • vdom->DOMへの反映時に
    • 部門セレクトボックスの選択で、氏名セレクトボックスが更新される
    • さらに、氏名セレクトボックスはonchangeイベントハンドラを持つ必要がある
    • onchangeイベントによって最終的に特定一名を指定する
    • 従って、changeDepartment()がFilterUsecaseにある以上、usecaseレシーバが引数で与えられる必要がある
    • 部門を毎回選択する度に、appendChildするNodeListを消して付け加えるのは冗長では?
    • optionタグ分だけを入れ替えれば良いはず
  • ...

Usecase編へ続く