古いPHPアプリケーションの移行について考えてみる
エンジニアのアカイです。
レガシーマイグレーションなどと聞くと、基幹システムで大規模なリプレースを行って、 プロジェクトが炎上…というようなものを想像してしまいますが、 Webアプリケーションにおいても同様の問題が多く発生する時期なのではないかと思います。 実際、ここ数年私もそういうシステムばかり触っているような気がします。
モデルケース
- 大きな分類での機能(フロント機能/管理機能など)がすべて一か所に集中している
- ドキュメントがなく、詳細仕様はコードを解析しなければならない
- データベースの構成変更は管理されていない状態
- 運用中のシステムであるため、長期のメンテナンスは実施できない
- 新しい機能のリリース頻度が高い
このような状況では、開発者はシステム全体を新しいものに入れ替えることを考えますが、 上記のような項目が足かせになり、実現は困難になります。
コードレベルでの移行(クラス/メソッドのリライトなど)が、 実際に多く行われている方法だと思います。 これは、大きな変更を行わずともすぐに実施できるからですが、 根本的な問題の解決には至らないことが多いです。
従って、今回は上記の「大きな機能分類」を別のシステムで再構築する、 という観点から移行を考えてみたいと思います。
移行時の問題
最も大きな問題としてあるのが、既存システムが変更になった際、 新しい方も別途対応が必要になる、というものがあります。
新システムを別の言語で開発するような場合は、この問題は深刻なこともあるので、 この時点で入れ替えを断念することも多いのではないかと思います。
このような問題に対処するには、やはり既存システムを事前に変更して、 移行実施自体を現実的にする措置も必要でしょう。
移行前の準備
仕様の理解と定義
ドキュメントがない分、コードから仕様を理解し定義することは必ず必要になる作業です。 これは、当然ですが最も重要な部分です。
このような状況では、仕様書もテストも存在せず、 新たにテストコードを記述するのも困難な場合が多いので、 少なくとも移行対象部分に関しては、現状の仕様を定義する必要があります。
色々な理由を挙げて実施しない事が多いと思いますが、 これなしでは移行自体も困難ですし、実施すべきでないでしょう。
設定ファイル
システム全体で共有している設定ファイル等の設定情報は、 たいていのアプリケーションであれば存在すると思います 新旧両方で共有できる可能性がある場合は、多少の労力を伴ってでも、 対処したほうが良いでしょう。
- ファイルの形式を汎用的なものに変更する
- 制御部分はそれぞれ別の設定項目/別の設定ファイルとして設定する
- 複数の設定ファイルを一つにまとめる
1.については、開発言語のファイルに設定を記述している場合の対処です。 (config.php 等)
INIやYAML等になっていれば、たいていの言語で利用できます。
設定ファイルの内容に応じて、ファイルフォーマットを選択するのがよさそうです。
2.は1.のようなタイプのファイルに制御文を記述しているような場合です。
環境によって動作を変更する必要がある場合は(開発用/テスト用/本番用など)、 最近のフレームワークが使用しているような方法を積極的に採用して、 環境別の設定ファイルを使用部分だけ制御すればよいでしょう。
環境依存ではなく、実行時の状況に依存するものは、設定値として別のものを定義すべきでしょう。 この点で、場合によっては対処が難しくなると思います。
3.は設定ファイルが細分化されているケースです。
これについてはそのままの対処をすればよいと思います。
設定ファイルを細分化することのメリットはほとんどないと思いますが、 なぜかこうなっているシステムは多いような気がします。
※当たり前ですが、設定値を使用している部分の改修も必要です。
具体的な対処内容
今回は以下のものを取り上げてみようと思います。
管理機能部分を別のシステムへ移行する => 移行部分の開発を行う
移行の方法として、前面にproxyサーバを設置して、 リクエストはそこで直接処理するよう変更します
- 管理機能部分へのアクセスは新システムへ遷移
- その他の場合は既存システムへ遷移
という設定を行います。
データベースの状態を変更管理する => データベース構造をコード化する
SQL文をgitで管理するだけでも全く違うと思いますが、 今回はデータベース構造をコード化して管理する方法を試してみます。
事前準備
*** nginxをインストール
$ sudo yum -y install nginx
※CentOS7系です
proxy設定
nginxを使用して、入れ替えるパスへのアクセスをproxy_passで 新システムへ渡すのがよさそうです。
以下、設定例です
サイトURL: http://example.com/
移行パス: /admin
事前に以下のようなサーバの変更が必要です。
旧システム: apacheのポートを80から8080に変更 新システム: localhost:3000 で起動
/etc/nginx/conf.d/new.conf
server { listen 80; server_name example.com; location /admin { proxy_pass http://localhost:3000; } location / { proxy_pass http://localhost:8080; } }
※SSLの設定は省略しています
-Listen 80 +#Listen 80 +Listen 8080
データベースの対応
今回の対処では、データベースの移行はしないことを前提に書いていますので、 データはそのまま使用します。
新しいシステムで既存DBの情報を読み取るには、以下のような方法が良いと思います。
ActiveRecord(rails)の場合
$ bundle exec rake db:schema:dump
http://qiita.com/tetsuya/items/f21170a9667d7e465da8
※PostgreSQLでtimestampのdefaultを'now()'等にしている場合、ここで作成したコードの実行に失敗します
同じ設定を反映するには、ALTER文を追加してDEFAULTを設定する必要があります
Sequelの場合
$ bundle exec sequel -d "dsn文字列" > 出力ファイルパス
http://qiita.com/futoase/items/9c76b2a50ba31f866f16
実際のところは、こうした対処を実施するのはそれほど簡単なことではありませんので、 ほとんどが机上の空論です。
実施内容自体が適用できないケースもあると思いますが、 それ以上にシステム自体とは直接関係のない部分の問題が… というのが現実なのでしょうね。