Nuxtjs(Vue + Vuetify) + storybook 開発における画面設計書について考える


## はじめに
Nuxtjs は/pages フォルダにvueファイルを置けば勝手にページのルーティングをしてくれる。
Vuetify を使えばマテリアルデザインのきれいなコンポーネントがすぐに使える。
storybookを使って開発、デバッグをすれば再利用性の高いコンポーネントカタログも充実する。

実に便利な世の中になったものだなと。

そこで開発者に**「ではいい感じにあとよろ！」**と開発を依頼したところ
**「仕様が分かりません」** と言われてしまったのだが、図にまとめるとこんな状況だったと思う。

![before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/7362f7e7-cfa4-6c79-8b41-84171b3d7360.png)

…手元にいい感じの自動生成ドキュメントが手に入ったので見落としてしまったが、これは確かにわけがわからない。カイゼンしなければ。

(カイゼンの考察ポイント)

* ドキュメントで指示を出す
* 更新が面倒なドキュメントはメンテナンスされないのでできるだけ簡単に作る


## Figma / Adobe XD (却下)

プロトタイピングツール２大巨頭。
Material Design UIkit を拾ってきてポコポコ並べればだいたい完成するし、画面遷移も表現できる。これは良さそうに思えて作成してみたが、以下の理由で却下した。

- 要件がふわっとしている中、きちんとデザインをするのはコストがかかる
- 伝えたいのは機能
- 画面デザインにそこまでこだわりがない
- 最終的な実装を反映するのが面倒くさい


## 空の vue ファイル + 仕様を書いた stories ファイルを配置(採用)

実際のコンポーネント開発フォルダに、空の vue ファイルと、その時点で決まっている仕様を書いた stories ファイルを配置する。

mdx ファイルには一部プログラムが含まれるが、markdown が書ければ非プログラマでも問題なく書けると思う。

設計者は仕様変更があった場合 .mdx ファイルを更新する。gitにソースと合わせてコミットされるため、**いつの間にかエクセルの画面設計書が更新されたが開発者に伝えられず**仕様が実装に反映されないという事故を回避しやすくなると思われる。
また、stories ファイルは **画面のリグレッション試験にもそのまま使える** ハズなので全体の工数としては下がる事が期待できる。

以下にサンプルファイルを示す。

``` AppHeader.vue
<template>
  <!-- nuxt では/components フォルダ以下に配置するだけでコンポネントとして認識される。 -->
</template>

<script lang="ts">
export default Vue.extend({

})
</script>

<style>

</style>
```

``` AppHeader.stories.mdx
import { Meta, Story, Preview } from '@storybook/addon-docs/blocks'
import AppHeader from './AppHeader.vue'
import * as stories from './AppHeader.stories.js'

<Meta title="Molecules/navigation/AppHeader" component={AppHeader} />

# AppHeader

アプリケーションヘッダ。
v-app-bar で製造

## 表示項目

### 共通

- drawerToggleIcon : ハンバーガメニュー。ドロワー開閉
- title : アプリタイトル

### ログイン時

- user.id : ユーザー名
- logout button : ログアウトボタン。クリックでログアウトする。

### 非ログイン時

なし

<Preview>
  <Story story={stories.Signin} />
  <Story story={stories.Signout} />
</Preview>
```

``` AppHeader.stories.js
import { action, configureActions } from '@storybook/addon-actions';
import AppHeader from './AppHeader';

// コンポーネント名だけ変えてコピペで使う。
const Template = (args, { argTypes }) => ({
  props: Object.keys(argTypes),
  components: { AppHeader },
  template: '<AppHeader v-bind="$props" />',
});

// コンポーネント固有コード
const args = {
  title: 'SAMPLE',
  user: null,
  drawer: false,
  clipped: false
}

// ストーリー毎に定義
export const Signin = Template.bind({});
Signin.args = args
Signin.args.user = {
  id: 'test-login-user'
}

// ストーリー毎に定義
export const Signout = Template.bind({});
Signout.args = args
```

## plant UML で画面フローを定義(採用)

plant UML 以外の候補は以下。

- Excel / Powerpoint / draw.io
→ 線をつなぐのがめんどくさいので却下
- UIflow
→ 最初は爆速で書けるが「思った場所に思った画面を配置できない」ため却下
- マインドマップ
→ 爆速で書けるが書いた本人以外読めない

### plant UML での画面フロー

UMLの図には画面フローなどという図はないが、マークダウンである程度の自由度を持って図が書け、線をつなぐのが簡単なので仕様変更にも強く更新が容易と判断した。

今回採用した記述ルールは以下。

|図形   |説明   |
|---|---|
|frame |ページ定義に使う。 |
|card |ページ内に配置するcardコンポーネント定義に使う。 |
|interface |actionの終端としてapi呼び出しを行っている箇所の定義に使う。 |

ログイン画面からホーム画面への遷移を例として以下に示す。

![画面遷移図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/6a53f9ae-32b9-5f77-4b93-1652e10307ee.png)


設計側が考慮する点が増える様に見えるが、**「思ってたんとちゃう」** 実装になる可能性が減ることを期待したい。
また、力尽きて stories.mdx を書けなくてもなんとか大事なことだけ伝えられるのではないかと妄想をしている。

## おわりに

ということでカイゼンしました(?)

![after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/e01ad089-6acb-71fd-9c20-ec659049b7a1.png)

今後ますます低予算の案件が増え、小規模化かつ流動的なチームで開発をしていくことが予想されます。
色々便利なツールが無料で入手可能です。それらをうまく使いこなして、**全体の最適化**を図りつつ無理なく開発が行える様に模索を続けたいと思います。

よりよい方法があればコメント頂けますと助かります。