新規サービスの生誕一周年 ~軌跡と今後~

## はじめに

「[引越しの新サービス](https://hikkoshizamurai.jp/moving)」をリリースし、一年が経ちました。

一歳の誕生日おめでとう :tada: 
そして、幾度とない変更に耐えてくれてありがとう :bow:

今回は新規サービスをリリースして一年、その**軌跡と今後について**書いていきたいと思います。

## 謝辞

当初、Vue.jsやRailsが主体だった開発現場で、
**React**、**TypeScript**、**Go**、**GraphQL**といった技術について知見がほぼない中スタートしました。

この時、僕たちが得たかったのは、**保守性**と**開発効率**の両立でした。

- TypeScriptと相性が良いReact
- 型に厳格なGo
- Hasuraを用いたGraphQLの自動型生成による開発効率化

もちろん技術的な難易度は一気に上がりましたが、新規サービスをスタートさせるのに最適な構成だったと思っています。

- 企画者やデザイナー等のメンバー
- 毎週毎週勉強会を開いて一緒に切磋琢磨してくれた開発チームのメンバー
- 他のチームからサポートに駆けつけてくれたReactスペシャリストの方

色々な方に支えていただきました。この場を借りて、ありがとうございます。:bow:

## 軌跡

毎週のように障壁がありました。
当時、知見が足りなかったということもそうですし、先進的な構成すぎてOSS側が追いついていないという状況にも何度もぶつかりました。

その中でも大きかったトピックスをいくつかあげてみます。

### 【フロントエンド】 TypeScriptのstrictがfalseになっていた

ハマったことがある方も多いかと思いますが、Next.jsを作ったときに`strict: false`でtsconfig.jsonが生成されたりします。
これに気づかずずっと開発をしてたんですね。

開発時には、`strict: true`、CIやリリース時のみ`strict: false`に書き換えて許容する
みたいな形を取って少しずつmigrationを行なっていきました。

### 【フロントエンド】 認証情報をクライアントサイドで取り回すのが辛かった

Firebase Authenticationを用い、ユーザー認証を行なっていますが、Firebase Authentication SDKを用いると、クライアントサイドに認証情報を保持します。

サーバーサイドでのデータフェッチを行いたい場合、認証情報はhttponlyなサーバーサイドクッキーにあった方が都合がいいですし、アクセスコントロールなどの面においてもクライアントサイドに認証情報があるのは不便です。

血の滲むような努力ではありますが、Firebase Authentication SDKを剥がし、Node.js側（Next.jsのサーバーサイド）へ認証ロジックを全て移しました。

これの詳細はAteamのテックブログの方にも載せたので時間がある方は見てください。

https://techblog.a-tm.co.jp/entry/2022/11/28/104757

### 【フロントエンド】 モノレポのベストプラクティスがわからなかった

フロントエンドでは、Nxというモノレポツールを採用していましたが、ディレクトリ構成のベストプラクティスがわからず、右往左往していました。
今でも悩むことが多いですが、なんとなくの型はできてきたかなと思います。

詳しくは記事にしたのでまたお時間あるときに見てもらえると嬉しいです。

https://qiita.com/anneau/items/2322d86a74cda5c873fb#%E3%81%93%E3%82%93%E3%81%AA%E6%A7%8B%E6%88%90%E3%81%AB%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B%E3%81%A8%E8%89%AF%E3%81%95%E3%81%9D%E3%81%86

### 【フロントエンド】 GraphQLのGlobal Object Identification形式に合わせるのが至難の技だった

GraphQLでは、[Global Object Identification](https://graphql.org/learn/global-object-identification/)というスキーマのベストプラクティスがあります。

GraphQLはエンドポイントが一つしかないですし、POSTで全てが表現されるため、RESTのようにエンドポイントごとキャッシュするみたいなことができません。
なので、全てのクエリに対し、NodeIDという全テーブルでユニークなIDを返し、サーバーサイドでNodeIDをキーにしてキャッシュを行う。というものです。

```graphql
interface Node {
  id: ID!
}

type User implements Node {
  id: ID!
  name: String!
}
```

Hasuraでは、このエンドポイントを自動生成してくれるRelayモードというものがβ版で提供されています。
私たちのサービスではこのβ機能を使い開発を行なっておりましたが、Hasura本来の機能がこのRelayモードを使っていると使用できないと言うシーンがあり地獄を見ました。

最終的にはGlobal Object Identificationを諦め、シンプルなスキーマを使うように書き換えを行いました。

### 【バックエンド】 Hasuraが自動生成してくれるクエリでは解決できないことが増えた

HasuraはGraphQLのクエリを自動生成してくれます。
プロジェクト初期にはこの機能はとても有用でした。

しかし、自動生成のスキーマでは、データ構造をそのままフェッチすることしかできないため、フロントエンドの責務がどんどん増えてしまいます。
これを解消しようとすると、HasuraのActionという機能を用い、外部のREST API（僕たちの場合はGo）を呼び出す必要がありますが、結果、多くのロジックでバックエンドを介さないといけないという形になってしまいました。

これに関してはまだ解消できていない状況が続いています。

### 【バックエンド】 Goで採用したクリーンアーキテクチャにおいて、DIしすぎた

僕はフロントエンドに入ることがほとんどでしたが、バックエンドで採用したGo×クリーンアーキテクチャという構成。
クリーンに作ろうという意識が強すぎた結果、レイヤー数も多く、ほとんどの層でDIを行なった結果、メンテナンスが難しい状態になってしまいました。

詳しくは、チームメンバーの@lostfindが書いてくれた記事を見てください。

https://qiita.com/lostfind/items/ba108f48b9f2a1ecc4a9#%E5%85%A8%E3%81%A6%E3%81%AE%E3%83%AC%E3%82%A4%E3%83%A4%E3%83%BC%E3%81%A7di1%E3%82%92%E3%81%97%E3%81%A6%E3%81%84%E3%81%9F

## 今後

毎週のように改善を続け、なんとか形になってきましたが、まだまだやりたいことがあります。
構想なので変わる可能性も大いにありますが、以下のようなことを考えてます。

### HasuraをApollo Serverへ書き換える

上に書いたように、DB構造からスキーマを自動生成してくれるHasuraはプロジェクト初期にはとても活躍してくれましたが、
自動生成では、できないことが増えたり、バックエンドの責務をフロントエンドがになってしまったりしています。

柔軟なスキーマ定義やBFF層的な役割をApollo Serverに持たせたいなと思っています。

### バックエンドのレイヤーを見直す

詳しくは先ほども紹介した@lostfindの記事を見てください。

https://qiita.com/lostfind/items/ba108f48b9f2a1ecc4a9#%E3%81%9D%E3%81%97%E3%81%A6%E3%81%9D%E3%81%AE%E5%85%88%E3%81%B8

### モノレポの構成を見直す

現在、僕たちのフロントエンドモノレポでは、

- ユーザー画面
- 提携業社管理画面
- 社内管理画面

が同居しており、一つのNxで管理されています。
構造上、問題はないのですが、Nxは一つのアプリケーションをマイクロサービスのように分割し、キャッシュを有効活用するというのが良いのに対し、`libs`がsharedロジック以外置かないという構造になっておりキャッシュがあまり有効活用できていない状況にあります。

Nx自体を3つに分割し、yarn workspaceでsharedロジックを読み込む

という形式に変化させれればと思っています。

## まとめ

今回は触れませんでしたが、このサービスは1年間ずっと作っては壊しという検証フェーズにありました。
数多くのリファクタをmigrationしながら、新規機能を開発したり、削除したりと慌ただしい一年を耐え続けてくれたプロジェクトになります。

改めて、この改善に耐え続けてくれたプロジェクトとプロジェクトメンバーに感謝を :bow: