【Laravelから】脱PHPプロジェクト【ASP.NET Coreへ】

こんにちは。

テックリードのTerukiです。

Oh my teethのTechチームでは現在旧システムから新システムへの移行作業を絶賛行っているのですが、その中でどうやって移行していっているのかを今日は書いてみようと思います。


# TL;DR
- PHPのレガシーコードが負債になっていて困っている
- ASP.NET Coreのコードベースに移行中
- 移行時は可能な限り新旧二重管理にならないよう立ち回ると良さそう

# なぜ移行しようとしているのか

Oh my teethは今年で6期目のスタートアップなのですが、かれこれ4,5年以上稼働しているシステムもあり全体的に技術的な負債が散見されます。

長い事やっていれば、ビジネスサイドからの依頼で仕様が変更になったりなどで負債が溜まっていくのはある程度はしかたないことではありますが、いよいよ無視できないレベルになってきました。

Oh my teethでは昔に開発したシステムは基本的にPHP ＆ Laravelで実装されていて、最近新規開発したものはC# & ASP.NET Coreで実装されています。

以前からPHPの言語仕様の緩さ故に他の静的型付け言語ならコンパイル時に気づけるようなミスも本番投入してから気づくような事案も発生しており、脱PHPの機運が高まっていました。

(╯°□°)╯︵ ┻━┻

# なぜC#なのか

この手のシステム移行で候補となる言語やフレームワークはいろいろとあると思いますが、Oh my teethのTechチームではC#とASP.NET Coreを採用しています。

理由はいくつかありますが、シンプルにチームメンバーのスキルセットと親和性があるのと、Microsoftの後ろ盾があるのに一定の魅力を感じています。

他の言語やフレームワークではサードパーティのライブラリを入れないと実現できないようなことがだいたいMicrosoft製のファーストパーティライブラリで実現できることが多く、これやりたいけどライブラリがない・・・といったことになりにくいです。

例えば、LaravelでJWTを扱いたいとなった場合、「[jwt-auth](https://github.com/tymondesigns/jwt-auth)」などを使って実装するかと思います。

NodeJSでJWTを扱う場合はauth0の「[jsonwebtoken](https://www.npmjs.com/package/jsonwebtoken)」を使うかと思います。（直近更新が止まっており心配。。）

ASP.NET CoreではNuGetから「[Microsoft.AspNetCore.Authentication.JwtBearer](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer)」をインストールするだけです。
Microsoft製なので、.NETがバージョンアップした際も同時に新しいバージョンが出ますし、リリース版の安定感は非常に良きです。

┬─┬ノ( º _ ºノ)

# 移行が大変

PHPでできたシステムは3つほどありますが、そこそこ行数があり大変です。

ちょっとでもモチベーション高く取り組めるようLooker Studioで下記のようなダッシュボードを作成して毎日Slackに投下されるようにしてみました。

コードが減ると前日比が表示されるのでちょっとモチベが上がりますね。（私だけかもしれない）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192685/9c2b5ae6-bee2-39f7-320d-06e30a7ffc62.png)

やってることはめちゃくちゃシンプルで、GitHub Actionsで毎日0時に各リポジトリの行数をカウントしてZapier経由でスプレッドシートに記録しているだけです。

```yaml
name: LoC Counter

on:
  schedule:
    - cron: '0 15 * * *'

jobs:
  loc:

    runs-on: ubuntu-latest

    defaults:
      run:
        working-directory: ./

    steps:
      - uses: actions/checkout@v2
      - name: Count Lines of Code and Post to Zapier
        run: |
          total_lines=$(git ls-files | xargs wc -l | grep total | awk '{sum += $1} END {print sum}')
          curl -X POST -F "total_lines=$total_lines" -F "system=xxx" ZapierのURL
```

（脱PHPとはいえこのスクリプトはフロントエンドのコードもカウントしてしまうので厳密には脱PHPだけではないのですが、フロントエンドも移行しないといけないので細かいことは気にしません。）

# 移行方法

PHP製のシステムはだいたい下記のような内訳です。

- 定時起動のバッチ
- LINEなどのWebhookを受け取るエンドポイント
- ジョブ
- 社内向けWebシステム
- その他細かいもの

|処理|構成|移行方法|
|-|-|-|
|定時起動のバッチ|AWS EventBridge+ Lambda|C#版をリリースした後にPHP版を無効化|
|LINEなどのWebhook|ECS FargateのマルチAZ構成|一回で切り替えるにはコードベースが大きすぎるので、切り出せる部分を先にC#移行、PHPからHTTPリクエストをC#側に投げて後続処理をさせる|
|ジョブ|AWS SQS+Lambda|C#版をリリース後にSQS経由で呼び出すように変更|
|社内向けWebシステム|ECS FargateのマルチAZ構成|社内調整が必要なので気合でC#版を作りきって切り替えてもらうパワープレイ💪🏻|
|その他|略|一回で切り替えられるものは一回で、厳しそうな部分は切り出せる範囲で少しずつ|

移行作業を行う上で、極力PHP版とC#版の二重管理が起きないように心掛けています。

大きな処理を一回で切り替えるにはそれなりに時間がかかりますが、移行作業中に移行元に変更が入ることなんてザラにあるのでなるべく小さい単位で移行していきたいものです。

実際二重管理をせざるを得ない箇所があり、切り替え後に先祖返りしてしまった処理などもありました:sob:

移行計画を立てる上では、この点を重視すると良いんじゃないかなと個人的に感じます。

# おわりに

この脱PHPプロジェクトはまだ途中ですが、今年中に終わらせる目標を立てて進めています。

長い間PHPに触れていましたが、いよいよ今年でおさらばできるので嬉しい反面今まで会社を支えてきたシステムでもあるので、レガシーコードたちにも敬意を払いながら来年はPHPのない世界を迎えたいなと思います。

ありがとう、PHPとLaravel。

# Oh my teethについて
Oh my teethでは未来の歯科体験を創るために日々活動しています。

Techチームではより良いユーザー体験を提供するべく、Webフロントエンドからバックエンド、スマホアプリに機械学習モデルなど、さまざまなプロダクトを開発しています。

一緒に未来の歯科体験を創りませんか？興味がある方は是非こちらを確認してください。

https://oh.careers/

カジュアル面談も可能なので気軽に応募してみてください！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192685/0138b492-e02b-852e-61fa-fc065b53d285.png" width="450" />