Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

JSONファイルとVueの間に中間層を設ける #3008

Conversation

hikyaru-suzuki
Copy link
Contributor

@hikyaru-suzuki hikyaru-suzuki commented Apr 8, 2020

👏 解決する issue / Resolved Issues

📝 関連する issue / Related Issues

⛏ 変更内容 / Details of Changes

メイン

  • 新たに作成したlibrariesディレクトリにビルド後参照されるTypeScriptファイルを集約(utilsディレクトリを移動)
  • JSONファイルの型や変換コードを quicktype で自動生成しlibraries/auto_generatedに配置
  • JSONファイルとVueの間に型注釈を行いデータ変換を行うRepository層を実装

その他

  • ESLintのキャッシュを有効化
  • ~/@/ に統一
  • package.jsonのdependenciesを整理
    • expressは必要ないと思われるので削除
    • ビルド後に必要のないものはdevDependenciesに移動

設計について

  • Vue -> RepositoryのInterface <- Repositoryの実装 -> JSONファイルという依存関係にすることでVue側からはRepositoryの実装変更やマスターデータの実態を意識することなくVue側の実装を行うことが可能となります
  • Repository実装のDependencyInjectionについてはlibraries/Registry.tsにて一元管理しています。このクラス内でpublic static readonlyなInterfaceの型で宣言したプロパティにインスタンス化したオブジェクトをDIしています

ポイント

  • 変更が多いのでコミット単位で見て頂けるとわかりやすいかと思います🙇
  • 一応、Vue側はRepositoryのInterfaceに依存していますが、そのInterfaceに指定するジェネリクスパラメータは自動生成された型に依存しているので完全に分離したとは言えません
  • もっと分離するならInterfaceのファイルを分けたり基底クラスやインタフェースを作らないようにするべきですが、今回はそこまで大規模ではないので扱いやすさに焦点を当てました
  • 現在のRepositoryは動的にデータが変更されることを考慮していません。インスタンス化された際にマスターデータをメモリ上にReadOnlyの形で保持しているだけなので、そのあたりを変更するならキャッシュなどの点でもう少し考慮するべきことがあるので注意が必要です

Copy link
Contributor

@nard-tech nard-tech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

気になる点,いくつかコメントしました.(コメントしていないけれどコメントした箇所と同様のところもあります)
本来はこの PR とは別に対処すべきかもしれませんので,お手すきであれば直して頂いて,そうでなければ私の方で後ほどリファクタリングします.

@hikyaru-suzuki
Copy link
Contributor Author

@nard-tech
次の理由のためインポートパスだけ修正しました!

本来はこの PR とは別に対処すべきかもしれませんので,お手すきであれば直して頂いて,そうでなければ私の方で後ほどリファクタリングします.

恐らく #3008 (comment) あたりのことだと思いますが、どのプロパティをどこで使っているか把握した上で最適化する必要があってその上数が多いので、このPRに混ぜるとややこしそうですし別PRでのリファクタリングをお願い致します!(ちゃんと書くならキャメルケースにしたほうが良いと思うのでconst { inspection_persons: inspectionPersons } = Registry.DataRepository.dataのような感じでしょうか?)
修正対象はDataRepositoryに限らずRegistryが使われている場所なので 8b36fe1 のコミットにあるファイルですかね

ただ、そのスコープ内の計算に使うだけなら分割代入をしてしまうとシャローコピーが走ってしまうので対象のプロパティを変数に格納して参照は維持したままにしたほうが良いかもしれません。dataの戻り値も新規にオブジェクトを作成しますが参照は持っている(はず。Vueがdataの戻り値をどう処理しているかによります)のでシャローコピーが走ると無駄になっちゃいます。でもシャローコピーなら重くないのでこのあたりの計算コストと可読性をどうするかはお任せ致します!

@nard-tech
Copy link
Contributor

@hikyaru-suzuki お疲れさまです.

どのプロパティをどこで使っているか把握した上で最適化する必要があってその上数が多いので、このPRに混ぜるとややこしそうですし別PRでのリファクタリングをお願い致します!

そうですね.別PRで着手することにします.

ちゃんと書くならキャメルケースにしたほうが良いと思う

スネークケースとキャメルケースが混在してしまっているのは気持ち悪いですよね.(cf. #3108)
JS のお作法としてはキャメルケースの方が望ましいはずですので,こちらも後ほど issue を立てておこうと思います.

修正対象はDataRepositoryに限らずRegistryが使われている場所なので 8b36fe1 のコミットにあるファイルですかね

8b36fe1 に限らず,components 以下のファイルは全体的に荒れている感があると思っています.

計算コストと可読性

難しいところですね.大勢が編集に参加するのであれば可読性と「美しさ」重視の方がいいのかなと思いますが,実際に修正を入れるときにバランスを考慮したいと思います.

@nard-tech
Copy link
Contributor

nard-tech commented Apr 10, 2020

@hikyaru-suzuki そして,conflict してしまっているので修正をお願いします…

(追記)#2916 の merge の後の方がいいかもしれません.

Copy link
Contributor Author

@hikyaru-suzuki hikyaru-suzuki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(追記)#2916 の merge の後の方がいいかもしれません.

承知いたしました! #2916 のマージ後にコンフリクト解決を行ってまたご連絡します!


スネークケースとキャメルケースが混在してしまっているのは気持ち悪いですよね.(cf. #3108)

こちらについてですが、quicktypeのオプションを使うことでキャメルケースへ自動変換することが出来ます。当然Vue側の修正も必要となってきますが、今回型付けによって以前よりは楽に対応できるのではないでしょうか
今回自動生成の際に入れようか迷いましたがVue側も大掛かりな変更になるので今回のPRの責務外かなと思い有効にしませんでした
こういうことを出来るのがデータ実態とアプリコードの間に一枚挟む設計の良さですよね〜

$  yarn -s run quicktype --help

Synopsis

  $ quicktype [--lang LANG] [--out FILE] FILE|URL ... 

~~中略~~

Options for TypeScript

 --[no-]just-types                                 Interfaces only (off by default)                            
 --[no-]nice-property-names                        Transform property names to be JavaScripty (off by default) 
 --[no-]explicit-unions                            Explicitly name unions (off by default)                     
 --[no-]runtime-typecheck                          Verify JSON.parse results at runtime (on by default)        
 --acronym-style original|pascal|camel|lowerCase   Acronym naming style                                        
 --converters top-level|all-objects                Which converters to generate (top-level by default)         

~~中略~~

--[no-]nice-property-names Transform property names to be JavaScripty (off by default)

このオプションを有効にすることでキャメルケースに変換されます。

Copy link
Contributor Author

@hikyaru-suzuki hikyaru-suzuki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

上記、対応するならこちらとは別PRの方が良さそうですね

#3008 (comment)

そうですね.別PRで着手することにします.

Copy link
Contributor Author

@hikyaru-suzuki hikyaru-suzuki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

実際に手元で実行してみました
libraries/auto_generated/data_converter/convertMetro.tsを例にするとこんな感じとなります

lang: 'ts',
out: path.resolve(outputPath, `convert${pascalFileName}.ts`),
topLevel: pascalFileName,
src: [path.resolve(inputPath, sourceFileName)]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

オプションを有効化すると

Suggested change
src: [path.resolve(inputPath, sourceFileName)]
src: [path.resolve(inputPath, sourceFileName)],
rendererOptions: { 'nice-property-names': 'true' }

Comment on lines +10 to +15
export interface Metro {
date: string;
datasets: Dataset[];
labels: string[];
base_period: string;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interfaceの定義がキャメルケースに変換されて

Suggested change
export interface Metro {
date: string;
datasets: Dataset[];
labels: string[];
base_period: string;
}
export interface Metro {
date: string;
datasets: Dataset[];
labels: string[];
basePeriod: string;
}

{ json: "date", js: "date", typ: "" },
{ json: "datasets", js: "datasets", typ: a(r("Dataset")) },
{ json: "labels", js: "labels", typ: a("") },
{ json: "base_period", js: "base_period", typ: "" },
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

実際に変換を行う関数にその情報が伝えられます

Suggested change
{ json: "base_period", js: "base_period", typ: "" },
{ json: "base_period", js: "basePeriod", typ: "" },

@hikyaru-suzuki
Copy link
Contributor Author

@nard-tech (メンション忘れていました)

ここで議論すべきではないと思いますが

  • Vueテンプレート内のコンポーネントの記法はケバブケース(or パスカルケース。スタイルガイドでは割とパスカルケース押しっぽい?)
  • TypeScript内は全てキャメルケース(Vueテンプレート内で使用する変数や関数も含む)
  • jsonファイルのプロパティ名の記法は何でも良い(quicktypeによる変換が入るため。現在はごちゃごちゃです)

のように統一していけたらきれいで見やすいコードになるかと!
あとESLintのルールもしっかり設定すれば事前に弾けそうですね!

@nard-tech
Copy link
Contributor

@hikyaru-suzuki 丁寧に解説頂きありがとうございます.ESLint の設定も,不慣れですがやってみようと思っています.

@nard-tech
Copy link
Contributor

@hikyaru-suzuki
#2916

@nard-tech お待たせして申し訳ありません。グラフ・表に関する大きめのPRのマージを控えていることと、都から新規グラフ・表の追加の依頼がきている現状から、こちらのPRについてはタイミングを見計っている状況です。

という状況なので,こちらもしばらく置いておいた方がよさそうですね.

@nard-tech
Copy link
Contributor

@kaizumaki こちらの close もお願いします.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

JSONファイルとVueの間に中間層を設ける
3 participants