より良い文章作成を目指したCSスタッフがサービスを開発しました【TypeScript/Next.js/GraphQL】

# はじめに

タイトルのとおり、より良い文章作成をサポートするサービスを開発しました。
私は普段CS(カスタマーサポート)スタッフとして、お客様からのお問合せに対応する仕事をやっている者です。

本記事では、サービスと使用技術に分けて、それぞれ紹介いたします。


[サービス紹介](#サービス紹介) 
[技術紹介](#技術紹介) 

# サービス紹介
URL: https://writer-support.vercel.app
※現在はSQLのインスタンスを停止しているため、ほぼ動作しません🙇

## 使い方
主な機能は二つです。
#### 1.校正機能
- 作成した文章の文法ミスや誤字脱字を発見します。
- チェック項目は選択可になっています。
  - 意図的に弱い表現を使う場合や、長い一文を書く場合もあるからです。
- 文章作成の補助機能も作成しました。
  - 1クリックでワードをコピーできるスニペット機能
  - 対象のワードが文章中に存在していないかを調べるNGワード機能
 
![校正機能](https://user-images.githubusercontent.com/40588536/107892237-22bc1c00-6f67-11eb-9ca6-6b0010ea7eb4.gif '校正機能')

#### 2.分析機能
- 校正機能で発見した改善点を記録して分析します。
- 間違えやすい項目をランキング順に表示したり、グラフによる可視化をしたりすることで、一目で自分の癖を分かりやすくなっています。
- 日時やユーザーでの絞り込みも可能です。

![分析機能](https://user-images.githubusercontent.com/40588536/107892329-b68de800-6f67-11eb-9de6-1c0dd3a29bfe.png '分析機能')

## 制作背景etc
プログラミング以外の内容が長くなってしまったので、[外部ブログ](https://tossyisland.hatenablog.com/entry/2021/02/17/010505)に別記事を書きました。
もしよろしければ、こちらもご覧いただけますと嬉しいです。


# 技術紹介
GitHub: https://github.com/faronan/writer-support

## 技術スタック
- バックエンド: [NestJS](https://nestjs.com/) v.7.6.11
- ORM: [Prisma](https://www.prisma.io/) v.2.16.0
- API: [GraphQL](https://graphql.org/)
  - [GraphQL Code Generator](https://graphql-code-generator.com/) v.1.20.1
  - [Apollo Client](https://www.apollographql.com/docs/react/) v.3.3.7
  - [Apollo Server](https://www.apollographql.com/docs/apollo-server/) v.3.0.0-alpha.3 (alpha 版の理由は[#9](https://github.com/faronan/writer-support/pull/9)に記載)
- フロントエンド: [Next.js](https://nextjs.org/) v.10.0.4
- スタイリング: [Chakra UI](https://chakra-ui.com/) v.1.2.1 

---

- 静的解析: [ESLint](https://eslint.org/) v7.16.0 + [Prettier](https://prettier.io/) v.2.1.2
- テスト: [Jest](https://jestjs.io/ja/) v26.6.3
  - [React Testing Library](https://testing-library.com/) v11.2.3
- Monorepo(モノレポ): [Lerna](https://lerna.js.org/) v3.22

---

- ホスティング: [Vercel](https://vercel.com/)
- コンテナ管理: [Cloud Run](https://cloud.google.com/run)
  - [Docker](https://www.docker.com/)
  - [Cloud Build](https://cloud.google.com/build)
- データベース: [Cloud SQL](https://cloud.google.com/sql)
  - [Mysql 8.0](https://cloud.google.com/sql/docs/mysql)
- CI: [GitHub Actions](https://github.co.jp/features/actions)

## 構成図

![image](https://user-images.githubusercontent.com/40588536/107873126-565d5e80-6ef3-11eb-856c-291d41e2d5d4.png)

## 選定理由
使用した技術スタックについて、いくつか選定理由を説明いたします。

### NestJS + Next.js
バックエンドにNestJS、フロントエンドにNext.jsを使っています。
TypeScriptフルスタックFWとして有名なfrourioやBlitzを用いる選択肢も考えましたが、今回はいろんなパーツを触ってみたかったので、採用を見送りました。

また、バックエンドとフロントを一つのリポジトリで管理するために、Lernaを使ってモノレポの構成にしています。
片方だけテストを実行したり、まとめてアプリを起動したりすることが可能です。


(npm scriptの一部を抜粋したものです)

```package.json
  "scripts": {
    "install": "lerna exec npm install",
    "start": "lerna run start --stream",
    "start:server": "lerna run start --scope=server --stream",
    "start:front": "lerna run start --scope=front --stream",
    "lint": "eslint --ext .ts,.tsx",
    "test": "lerna run test --stream",
    "test:server": "lerna run test --scope=server --stream",
    "test:front": "lerna run test --scope=front --stream"
  }
```

### Prisma
[Front-End Study #1](https://forkwell.connpass.com/event/190313/)の発表に刺激を受けて、Prismaを使ってみました。

TypeORMとの比較としては、Prisma schemaの仕組みの利便性に惹かれました。
Prisma schemaからDBに対してマイグレーションやデータの読み書きができますし、逆にDBからPrisma schemaファイルを作成することも可能です。

PrismaはfrourioでRecommendされていたり、Blitzでも採用されていたりするのを見ると、今後Prismaはどんどん伸びて行くと思っています。

### GraphQL
GraphQLの特性やメリデメについて語れるほどの知識がなく、使ってみたかったから使ってみた程度の背景になります。
なので、今回はじめてGraphQLを使ってみた私が便利だと思った点を、簡単に紹介します。

- エンドポイントを一箇所に絞れる
- フロントとサーバーで型定義を共有できる
- Prismaと相性が良い

### Chakra UI
11~12月頃のGitHubトレンドで何度かChakra UIの名前を目にしていたのですが、決め手は[UIT meetup vol.11『フロントエンド紅白LT合戦』](https://uit.connpass.com/event/197740/)の発表に感銘を受けたことです。
デザインの知識がなくてCSSクラス設計が辛い私でも、コンポーネントをimportするだけで簡単に扱えました。
VSCodeがプロパティを補完してくれるのも、非常に使いやすかったポイントです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478011/74160193-9e60-bb67-25c4-d5ca3a998ba7.png)

### Vercel + Cloud Run
Next.jsのデプロイ先に関しては、Vercel一強に感じていてほとんど迷いませんでした。
NestJSをどこにデプロイするかは結構悩んだのですが、最終的にServerlessをやりたくて、GCPのCloud Runに落ち着きました。

他のサービスを使ったことがない身でこんなことを言うのも恐縮ですが、Vercelの開発体験には感動します。
もし、学習過程でNext.jsアプリを作られている方がいましたら、ぜひVercelでデプロイするところまで進めてみて欲しいなと思いました。

## 苦労したポイント



### 1.コンポーネント設計
今回私は、Atomic Designの指針に基づいてコンポーネント設計を進めていました。
ディレクトリ構造としては、このようになっています。

```
$tree packages/front/src/components 
packages/front/src/components
├── atoms
│   ├── AppHead.tsx
│   ├── BlueButton.tsx
│   ├── BoldText.tsx
│   ├── BorderBox.tsx
│   ├── Calender.tsx
│   (省略)
├── molecules
│   ├── AuthComponent.tsx
│   ├── CollapseText.tsx
│   ├── DataLintRuleNames.tsx
│   ├── DataTextExample.tsx
│   ├── DateFilterInputForm.tsx
│   (省略)
├── organisms
│   ├── AppFooter.tsx
│   ├── AppHeader.tsx
│   ├── DataListComponent.tsx
│   ├── ProofreadingComponent.tsx
│   └── TopPage.tsx
└── templates
    └── Layout.tsx
```
さまざまな記事で見かけましたが、このコンポーネントはどの層にあたるのかは、何度も悩まされました。
実際振り返ってみると、一度しか使わない小さなコンポーネントをatomsに作るのは、微妙だった気がしています。
本来、Atomic Designはコンポーネントを再利用しやすくするための手法です。
最初からatomに作るのではなく、重複が発生したタイミングでatomsに切り出す方が、スマートな設計になったのかと思います。

### 2. フロントエンドのテスト
フロントエンドのテストを書くのははじめてというのもありますが、実装と同じ時間をかけるくらいには、苦戦していました。
特に、GrapphQLを扱うためのApolloClientや、認証を扱うためのNextAuth周りが難しかったです。

なかなか類似の記事が見つけられなかったので、基本的にはIssueを探し回って情報を集めました。
最終的には、以下のようにモックを使いながらテストを動かしています。

```tsx

<MockedProvider mocks={mocks} addTypename={false}>
  {component}
</MockedProvider>
```

```tsx

export const auth = (email = 'test@test.com') => {
  client['useSession'] = jest
    .fn()
    .mockReturnValue([{ user: { email: email } }, false]);
};
```

### 3. Cloud Runへのデプロイ
[別記事](https://qiita.com/faronan/items/d99132950b61753050d3)でも書いたのですが、コンテナの処理に`prisma generate`を入れていなかったせいで、数日間デプロイに苦戦していました。

## 工夫したポイント

### コミットメッセージとPRの書き方
当たり前のことかもしれませんが、PRは自分以外の方が見ても分かるように書くことを心がけました。
(最後の方はちょっと雑になっていたのは反省点です。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478011/99f4c649-b383-328e-a4a9-b087cb985846.png)

またちょっとした工夫になりますが、コミットメッセージに絵文字を入れてみました。
どんなコミットか分かりやすくなるのはもちろん、見栄えが良くなるので何となく楽しくなりますよ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478011/4f0f6afe-0789-5f37-78e1-c12f0dda6e6c.png)


## 今後の課題
建てるだけ建てて後回しにしてしまったIssueがいくつも残っています。
さしあたっては、せっかくNext.jsを使っているのに全然ISRやSSGができていないところから、手をつけていこうと思います💪
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478011/6028d296-20f3-f8ca-d9c5-066820ff8f99.png)


# おわりに
やっぱりコード書くのって楽しいですね！
普段のCS業務もやりがいを感じますが、別ベクトルとして、アプリが出来上がっていく充実感やエラーを乗り越える達成感は味わい深いものです。

ここまで読んでくださり、ありがとうございました。
本記事が皆様のご参考になれば幸いです。

# 参考記事
- https://zenn.dev/mizchi/articles/c638f1b3b0cd239d3eea
- https://zenn.dev/higa/articles/d7bf3460dafb1734ef43
- https://zenn.dev/mikan3rd/articles/5b7840cdbcd2d9
- https://zenn.dev/yuyao17/articles/bcc8b87b35208b
- https://speakerdeck.com/line_developers/modest-resistance-to-tailwind-css-starting-with-chakra-ui