見出し画像

Twelve-Factor Appの考え方から、アキッパのプロダクトの課題を考える Part1

アキッパでバックエンドのリードエンジニアをしている村上です。
アキッパのプロダクトはイケてないところが多いんだと、採用やその他色んな場面で自虐する事がありますが、具体的にどこがイケてないのか!?
何か指標となるものと比べてみたいと思いまして、今回は、以下のTwelve-Factor AppというWebアプリケーション等を開発する上での12個のベストプラクティスと、アキッパの現状とを比べてみたいと思います。

いきなり脱線ですが、12っていう数字がかなり好きです。
今回のような記事を何回に分けて書こうかな…とぼんやり考えながら書き始めているのですが、12の約数は1、2、3、4、6、12という豊かなラインアップがあり、これはすなわち、1回 or 2回 or 3回 or 4回 or 6回 or 12回のどれでも分割できるわけですね!なんて柔軟な数字なんでしょう。
このシリーズは何回に分けてやろうかなと考えながら、書いていきます!
(すぐ下の目次で答えが見えてますがw)


I. コードベース

https://12factor.net/ja/codebase

コードベース は、単一のリポジトリ(Subversionのような集中バージョン管理システムの場合)またはルートコミットを共有する複数のリポジトリ(Gitのような分散バージョン管理システムの場合)である。
コードベースとアプリケーションの間には、常に1対1の関係がある。

https://12factor.net/ja/codebase

色々書いてるのですが、アプリケーションとGitリポジトリの関係は1対1が原則だよ的な事で、そんなの当たり前では?と思うのですが、以下の違反内容の記述に着目してみます。

同じコードを共有する複数のアプリケーションは、Twelve-Factorに違反している。その場合の解決策は、共通のコードをライブラリに分解し、そのライブラリを依存関係管理ツールで組み込むようにすることである。

https://12factor.net/ja/codebase

アキッパでは、ドライバーさんにお使いいただくフロントサイト、オーナーさんにお使いいただくオーナーサイト、アキッパの運用担当にお使いいただく管理サイト等、複数のWebサイトを運用しています。
リポジトリが分かれているものもあるのですが、今メインで運用しているLaravelフレームワークを採用したリポジトリでは、複数のサイトのプログラムが全て乗っている状態となってしまっています…。
早速Twelve-Factorの考えに違反しちゃっていました。
アキッパの各サイトから参照するデータベースは同じだという事でもあり、LaravelのEloquentモデルはもちろん、その他色々共通して使うプログラムもあるだろうという事で、同じリポジトリで開発をしているのですが、これがTwelve-Factor的にはアンチパターンのようです。
こういう共通処理は、ライブラリという形で切り出しておき、PHPであればComposerとかで指定したバージョンをインストールできるような状態にして共有させるというやり方がよいんですかね。

同じリポジトリにしちゃっている事でのリアルな困り事として、
現在、アキッパでは、ドライバー様向けのプロダクトを開発するチームと、オーナー様向けのプロダクトを開発するチームが分かれているのですが、リポジトリが同じなので、それぞれのリリース時期などを考慮して、メインのブランチへのマージタイミングをどうするかといった事を、チーム横断で状況を確認しながら調整する必要が生じています。
まだエンジニアが10人ぐらいだからなんとかなってる気がしますが、これ以上エンジニアが増えていくと、リポジトリが1つである事がネックでリリーススピードが鈍化していまうという事になりそうだな…という懸念があります。

II. 依存関係

https://12factor.net/ja/dependencies

ほとんどのプログラミング言語は、サポートライブラリを配布するためのパッケージ管理システムを提供している。例えば、PerlにおけるCPANやRubyにおけるRubygemsなどである。パッケージ管理システムでインストールされるライブラリは、システム全体(“site packages”と言われる)にインストールされる場合と、アプリケーションを含むディレクトリのスコープ(“vendoring”または“bundling”と言われる)にインストールされる場合がある。

Twelve-Factor Appは、システム全体にインストールされるパッケージが暗黙的に存在することに決して依存しない。 すべての依存関係を 依存関係宣言 マニフェストで完全かつ厳密に宣言する。さらに、実行時には 依存関係分離 ツールを使って、取り囲んでいるシステムから暗黙の依存関係が“漏れ出ない”ことを保証する。完全かつ明示的な依存関係の指定は、本番環境と開発環境の両方に対して同様に適用される。

https://12factor.net/ja/dependencies

何言ってるのか難しい日本語ですね。
PHPでいうと、Composerというパッケージ管理システムがあり、Laravelフレームワークを使っていれば、おのずと、必要なライブラリはcomposer.jsonに追記し、composer installでインストールし、vendorディレクトリにパッケージがダウンロードされるようになってますが、要は、こういう仕組みに則り、自分で手動でダウンロードして配置するみたいな事はしないでね!という事かと解釈しました。
これについては、一応アキッパはクリアでしょうか。
(Laravelじゃない古いフレームワークを使ってる古いリポジトリは、その限りではないですが…)
ただ、以下のような記述もありまして、これはどうなんだろう…

また、Twelve-Factor Appは、いかなるシステムツールの暗黙的な存在にも依存しない。例として、アプリケーションからImageMagickやcurlを使う場合がある。これらのツールはほとんどのシステムに存在するだろうが、アプリケーションが将来に渡って実行され得るすべてのシステムに存在するかどうか、あるいは将来のシステムでこのアプリケーションと互換性のあるバージョンが見つかるかどうかについては何の保証もない。アプリケーションがシステムツールを必要とするならば、そのツールをアプリケーションに組み込むべきである。

https://12factor.net/ja/dependencies

ImageMagic的なものは使う事あります。確かに将来的に使えない状況になる可能性はあると思いますが…
アプリケーションに組み込むってどういう事…?
ま、いっか。アキッパのプロダクトは考えないといけない事が他にたくさんあるんで、深追いするのはやめとこう笑

III. 設定

https://12factor.net/ja/config

アプリケーションの 設定 は、デプロイ(ステージング、本番、開発環境など)の間で異なり得る唯一のものである。設定には以下のものが含まれる。
・データベース、Memcached、他のバックエンドサービスなどのリソースへのハンドル
・Amazon S3やTwitterなどの外部サービスの認証情報
・デプロイされたホストの正規化されたホスト名など、デプロイごとの値

アプリケーションは時に設定を定数としてコード内に格納する。これはTwelve-Factorに違反している。Twelve-Factorは 設定をコードから厳密に分離すること を要求する。設定はデプロイごとに大きく異なるが、コードはそうではない。

https://12factor.net/ja/config

これはわかりやすい話しなので、特に解説不要でしょう。
Laravelであれば、プロジェクト直下にある.envに、環境に応じて変わる設定を記述しています。
アキッパでは、環境毎の.envの内容を特定のディレクトリに配置していて、デプロイの際に、その環境に応じたファイルをプロジェクト直下の.envにリネームして配置するといった事をしています。
これも一応アキッパはクリアしてるかと思います。

IV. バックエンドサービス

https://12factor.net/ja/backing-services

バックエンドサービス はアプリケーションが通常の動作の中でネットワーク越しに利用するすべてのサービスを言う。例としては、データストア(例:MySQLCouchDB)、メッセージキューイングシステム(例:RabbitMQBeanstalkd)、電子メールを送信するためのSMTPサービス(例:Postfix)、キャッシュシステム(例:Memcached)などがある。

従来、データストアなどのバックエンドサービスは、デプロイされたアプリケーションと同じシステム管理者によって管理されていた。このようなローカルで管理されるサービスに加えて、サードパーティによって提供、管理されるサービスを利用することもある。例としては、SMTP サービス(例:Postmark)、メトリクス収集システム(例:New RelicLoggly)、ストレージサービス(例:Amazon S3)、APIアクセス可能な消費者向けサービス(例:TwitterGoogle MapsLast.fm)などがある。

Twelve-Factor Appのコードは、ローカルサービスとサードパーティサービスを区別しない。 アプリケーションにとっては、どちらもアタッチされたリソースであり、設定に格納されたURLやその他のロケーター、認証情報でアクセスする。Twelve-Factor Appのデプロイは、アプリケーションのコードに変更を加えることなく、ローカルで管理されるMySQLデータベースをサードパーティに管理されるサービス(Amazon RDSなど)に切り替えることができるべきである。同様に、ローカルのSMTPサーバーも、コードを変更することなくサードパーティのSMTPサービス(Postmarkなど)に切り替えることができるべきである。どちらの場合も、変更が必要なのは設定の中のリソースハンドルのみである。

https://12factor.net/ja/backing-services

上記の例で言うと、データベース、キャッシュについては、エンドポイントを設定ファイルで切り替えるだけで、アプリケーションのコードを修正する必要はないようになっていますが、他はどうでしょう…。
例えば、アキッパでは、メール送信はSendGridを、ストレージではAmazon S3を主に用いていますが、これを別の手段に変えた場合には、アプリケーションの修正が必要になってくるようにはなってしまっています。
今のアキッパで採用しているLaravelのデザインパターンは以前以下でご紹介しましたが、

SendGridだとかAmazon S3だとかの技術詳細と、ビジネスロジックは切り離しているので、この技術詳細が差し替わっても、基本的にはビジネスロジック側の修正は不要になっています。
なので、一応ギリギリOKかな…という事にしておこう。

振り返り

12個あるベストプラクティスのうち、とりあえず4個を確認してみました。
ざっと振り返ると…

  • コードベース

    • 複数アプリケーションを同一リポジトリで開発しているのでNG

  • 依存関係

    • Laravel(というかComposer)を利用しているのでOK

  • 設定

    • Laravelの.envによる設定変更を利用しているのでOK

  • バックエンドサービス

    • データベース、キャッシュサーバはOK

    • メール送信、ストレージ等は、レイヤードアーキテクチャーにより許容範囲なのでOKという事にしておこう

今回見た4つのベストプラクティスと比較したら、複数アプリケーションを同一リポジトリで運用するアンチパターンを踏んでしまっているという事がわかりました。
これは、すぐに改善する事が難しい問題なので、なかなか痛い問題です…。

数年前に、Laravelでアキッパをリニューアルするぜっていうときに、このTwelve-Factor Appの考え方を知っていれば、あそこはこうしたのに…っていうのが結構あります。
これからWebサービスを構築しようとされる方は、是非ご一読を!
今回書ききれなかった他のベストプラクティスもあるんで、次回も「Twelve-Factor Appの考え方から、アキッパのプロダクトの課題を考える」シリーズを書きたいと思います。


この記事が気に入ったらサポートをしてみませんか?