Schematics で Layered Architectureを実現させるライブラリを作って公開してみた話

この記事 [Angular Advent Calendar 2019](https://qiita.com/advent-calendar/2019/angular) 9日目の記事です。

[Schematics](https://angular.io/guide/schematics)でライブラリを作成してみました。
今回は作ったライブラリの説明と、作成を通して学んだことを共有させていただきたいと思います。

# 作ったもの
https://www.npmjs.com/package/ng-layer-generator です。
![ng-layer-gen.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178093/7e746505-6e92-7014-63e3-92f2076c9abb.gif)


```
$ yarn add ng-layer-generator -D
```

して、

```
$ yarn ng-lg --name=task --type=usecase
```
とコマンドを叩くと、
`task.usecase.spec.ts`と`task.usecase.ts`が作成されます。
作成されたファイルの中身は`ng g service task`で生成されたものとほぼ同じで、class名が`TaskService`ではなく`TaskUsecase`となっているということだけが異なります。

要は、**serviceと同じ中身だけど、sercviceって名前がつかないファイルを作るためのライブラリ**です。

`--name`オプションと、`--type`オプションの他に、ファイルを作成するパスを指定できる`--path`オプションと、multiple projects用にどのプロジェクトに作成するかを指定する`--project`オプションがあります。

### きっかけ
現在私が所属しているチームでは、Layered ArchitectureでAngularアプリケーションを開発しています。
<img width="1046" alt="スクリーンショット 2019-12-09 0.01.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178093/b387ec0b-f651-9ecc-45b3-f25e15db5d92.png"> 
引用元: https://speakerdeck.com/kasaharu/classi-angular-night-number-4?slide=26

このアーキテクチャではビジネスロジックを~Serviceに詰め込むのでもなく、NgRxを使ってeffectsに集中させるのでもなく、

**usecase**
- コンポーネントのイベントから呼ばれて、そのイベントに応じた処理をする

**query**
- storeから必要な情報を取得しコンポーネントに渡す

**repository**
- バックエンドのAPIやブラウザストレージなどアプリケーション外との橋渡しになる

といった具合に、各レイヤーがそれぞれ責務を持つ形になっています。

詳しくは @kasaharu さんのスライド https://speakerdeck.com/kasaharu/classi-angular-night-number-4 をご覧ください。

### `ng g service` or `ng g class`
このアーキテクチャで開発している時に、私的に面倒くさいなと感じたのは、ファイルの生成方法です。
UsecaseやQueryなどの各classは、コンポーネントや他のclassからDIされるので、@Injectableデコレーターをつける必要があります。

@Injectabeデコレーターが付いているclassは、お馴染みの`ng generate service`コマンドで作成できますが、`~UsecaseService`という名前になるのも変だし、class名とファイル名を変更するのも面倒です。
`ng generate class`コマンドも使えますが、DIのためにclassに@Injectableデコレーターを書き足したり、テストコードを変更するのもまた面倒です。
それなら、**`~Service`という名前ではないけど、ファイルの中身はserviceと一緒のものを作ってくれるツールを作っちゃえばいいじゃん！！**と思ったのが、今回のきっかけです

# schematics とは
schematicsとは、angular-devkitとして提供されているコード生成ライブラリです。
使い方はすでに、

https://qiita.com/hand-dot/items/db780a51915e2dc85221
https://qiita.com/puku0x/items/462a038133e7233dfaed

でとても分かりやすくまとめられているので、そちらをご覧ください。
今回のライブラリ作成に参考にさせていただきました。ありがとうございます:bow:

schematicsを使ってみた所感ですが、テストが簡単で最高でした。

```ts
it('specify name, type, path, and  project', () => {
  const runner = new SchematicTestRunner('schematics', collectionPath);
  const options = {
    name: 'sample',
    type: 'usecase',
    path: 'usecases',
    project: 'app1'
  };
  const tree = runner.runSchematic('ng-layer-generator', options, Tree.empty());
  const expectedOutput = [
    '/projects/app1/src/app/usecases/sample.usecase.spec.ts',
    '/projects/app1/src/app/usecases/sample.usecase.ts'
  ];

  expect(tree.files).toEqual(expectedOutput);
});
```
こんな感じで、このoptionを渡してコマンドを実行すると、どんな名前のファイルが生成されたかテストすることができます。

# ライブラリ作って学んだこと
ライブラリ開発中に、実際にローカルで開発しているAngularのアプリケーションで使ってみて挙動を確かめることが多々ありました。
しかし、ローカルで開発中のライブラリを別リポジトリで使ういい方法が思いつかなかった私は、ログを仕込んで確認するためだけにその都度バージョンを上げてnpmにpublishしていました。

↓ 無駄にバージョンが上がって行く様子
<img width="767" alt="スクリーンショット 2019-12-09 4.20.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178093/f61fcfd1-1267-2c9e-8afa-c5a14774bb9a.png">

そんな時に便利なのが`npm link`です。
開発しているライブラリのディレクトリで、

```
$ npm link
```

ライブラリを使用したいアプリケーションのディレクトリで、

```
$ npm link <ライブラリ名>
```

とすれば、アプリケーションからライブラリを使うことができます。

yarnを使ってる場合は、`yarn link`と`yarn link <ライブラリ名>` で大丈夫です。

今まで、OSSのライブラリを手元でどう動かして確認するか全く想像がつきませんでしたが、npm linkで手元で確認できそうです。

# まとめ
まだこのライブラリは完成??したばかりでチームではまだ使ってないので、メンバーに使ってもらってブラッシュアップしていきたいです。
また、個人的にnpm linkを知ったのが大きくて、これからいろんなOSSをcloneして手元で動かしていきたいなと思ってます。

明日は@MasanobuAkibaさんです。

# 参考資料
https://speakerdeck.com/kasaharu/classi-angular-night-number-4
https://qiita.com/hand-dot/items/db780a51915e2dc85221
https://qiita.com/puku0x/items/462a038133e7233dfaed