SREチームの金澤です。
ランサーズのCakePHP2→3へのバージョンアップを開始しました。
これから何回かに分けてお話したいと思います。
第1回目は、バージョンアップ方針と
CakePHP新旧バージョンの共存方法についてお話したいと思います。
プロダクト規模
ランサーズのプロダクト規模は概ね以下のようになります。
この規模のソースを、普段の開発を止めずにバージョンアップする必要があります。
ディレクトリ | ファイル数 | ステップ数 |
---|---|---|
Config | 約190 | 約60000 |
Console | 約170 | 約30000 |
Controller | 約350 | 約110000 |
Lib | 約1100 | 約153000 |
Model | 約420 | 約105000 |
View | 約2800 | 約240000 |
合計 | 約5030 | 約698000 |
CakePHP1.3→2.8の段階的バージョンアップ
そのため、CakePHP1.3→2.8移行は段階的に、controller単位で、1年以上かけて行いました。
その内容について、2018年のPHPカンファレンスでも発表させていただきました。
移行中のディレクトリ構成は以下のようになっていました。
+ app(※CakePHP1.3のコード)
+ config
+ controller
+ lib
+ model
+ cake
+ ※CakePHP1.3本体
+ cake28(※CakePHP2.8のコード)
+ Config
+ Controller
+ Lib
+ Model
+ vendor
+ cakephp
+ ※CakePHP2.8本体
この方法の欠点は、
Controllerに焦点を当て、初めにModel、Libをコピーする形をとったため、
普段の開発で両バージョンのModel、Libを修正しなければならなくなったことです。
CakePHP3ではModelが大幅に変更されていることもあり、同じアプローチでは取れません。
そもそも、両バージョンに修正行う構成は避けたいところです。
CakePHPの処理の流れの概要は以下のようになります。
普段の開発で、両バージョンの修正が必要な状態にならないようにするためには、
原則、矢印の終端のコードから移行していく必要があります。
CakePHP2とCakePHP3の共存
まず、CakePHP本体の共存から開始します。
CakePHP1.3→2.8移行のときは、CakePHP1.3をcakeディレクトリに配置し、
CakePHP2.8はvendorディレクトリでcomposer管理していました。
CakePHP2とCakePHP3を共存させるために、CakePHP3をcomposer管理します。
CakePHP2をcake28/Vendor/cakephp に移動します。
CakePHP2本体そのものに手をいれることを想定し、git管理します。
+ cake28(※CakePHP2のコード)
+ Config
+ Controller
+ Lib
+ Model
+ Vendor
+ cakephp
+ ※CakePHP2本体
+ vendor
+ cakephp
+ ※CakePHP3本体
加えて、config、srcディレクトリを作成し、ここにCakePHP3のコードを書いていきます。
+ config(※CakePHP3のコード)
+ .env
+ App.php
+ src(※CakePHP3のコード)
+ Controller
+ Lib
+ Model
+ cake28(※CakePHP2のコード)
+ Config
+ Controller
+ Lib
+ Model
+ Vendor
+ cakephp
+ ※CakePHP2本体
+ vendor
+ cakephp
+ ※CakePHP3本体
旧バージョンでの開発抑止
CakePHP1.3→2.8のバージョンアップが長引いた要因の一つに、
普段の開発がCakePHP1.3で進められていたことがあります。
バージョンアップの進捗状況を壁にも書いていたのですが、途中で棚卸をした段階で、
多くの新規コントローラーがCakePHP1.3に追加されていたことが判明しました。
フレームワークのバージョンアップは長丁場になります。
その間にも普段の新規開発は行われるため、
なるべくこれらを新バージョンで開発してもらう工夫が必要になります。
CIで旧バージョンの新規開発をチェックする
バージョンアップを行うにあたり、CIで文法チェックを行っていましたが、これは非常に効果がありました。
※詳細は以前のブログに詳しく書いています。
ランサーズの開発は、CIのチェックを通らないとマージできないように設定しています。
新規開発を新バージョンで進めてもらうために、CIのチェックに
CakePHP旧バージョンでの開発を抑止するチェックを入れる予定です。
CakePHP2→4バージョンアップについて
この単位で段階的にバージョンアップするのであれば、
CakePHP2→4へのバージョンアップもできるかも知れないと思い、検討しました。
しかし、CakePHP4では、要求するPHPUnitの最低バージョンが8.3.3以上になります。
CakePHP2では、PHPUnit6以上になるとUTが正しく動作しなくなります。
$ ./cake28/Console/cake l_test cake28/Test/Case/Model/CityTest.php
Warning Error: include(PHPUnit/Autoload.php): failed to open stream: No such file or directory in [/var/www/lancers/cake28/Vendor/cakephp/cakephp/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php, line 178]
Warning Error: include(): Failed opening 'PHPUnit/Autoload.php' for inclusion (include_path='/var/www/lancers/vendor/phpunit/phpunit:/var/www/lancers/cake28/Vendor/cakephp/cakephp/lib:/var/www/lancers/cake28/Vendor/cakephp/cakephp/lib:.:/usr/share/pear:/usr/share/php') in [/var/www/lancers/cake28/Vendor/cakephp/cakephp/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php, line 178]
Error: Please install PHPUnit framework v3.7 (http://www.phpunit.de)
#0 /var/www/lancers/cake28/Vendor/cakephp/cakephp/lib/Cake/Console/ShellDispatcher.php(221): TestShell->initialize()
#1 /var/www/lancers/cake28/Vendor/cakephp/cakephp/lib/Cake/Console/ShellDispatcher.php(66): ShellDispatcher->dispatch()
#2 /var/www/lancers/cake28/Console/cake.php(56): ShellDispatcher::run(Array)
#3 {main}
$
CakePHP2のUTを利用しながらバージョンアップを行いたいので、現状はCakePHP3に留めました。
CakePHP4へのバージョンアップは、UTをCakePHP3ベースに切り替え、
PHPUnitを8.3.3以上にバージョンアップできたタイミングで検討したいと思います。
※2019/10/18追記 CakePHP3でも以下のエラーとなりました。
CakePHP3本体をPHPUnit8.3.3に対応させる必要がありますが、戻り値の型宣言が必要なのでPHP7が必須になりそう。
$ ./bin/phpunit --bootstrap config/bootstrap.php tests/TestCase/Model/Table/CitiesTableTest.php
PHP Fatal error: Declaration of Cake\TestSuite\TestCase::setUp() must be compatible with PHPUnit\Framework\TestCase::setUp(): void in /var/www/lancers/vendor/cakephp/cakephp/src/TestSuite/TestCase.php on line 35
PHP Stack trace:
PHP 1. {main}() /var/www/lancers/vendor/phpunit/phpunit/phpunit:0
PHP 2. PHPUnit\TextUI\Command::main() /var/www/lancers/vendor/phpunit/phpunit/phpunit:61
PHP 3. PHPUnit\TextUI\Command->run() /var/www/lancers/vendor/phpunit/phpunit/src/TextUI/Command.php:159
PHP 4. PHPUnit\TextUI\TestRunner->getTest() /var/www/lancers/vendor/phpunit/phpunit/src/TextUI/Command.php:177
PHP 5. PHPUnit\TextUI\TestRunner->loadSuiteClass() /var/www/lancers/vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php:101
PHP 6. PHPUnit\Runner\StandardTestSuiteLoader->load() /var/www/lancers/vendor/phpunit/phpunit/src/Runner/BaseTestRunner.php:141
PHP 7. PHPUnit\Util\FileLoader::checkAndLoad() /var/www/lancers/vendor/phpunit/phpunit/src/Runner/StandardTestSuiteLoader.php:36
PHP 8. PHPUnit\Util\FileLoader::load() /var/www/lancers/vendor/phpunit/phpunit/src/Util/FileLoader.php:47
PHP 9. include_once() /var/www/lancers/vendor/phpunit/phpunit/src/Util/FileLoader.php:59
PHP 10. spl_autoload_call() /var/www/lancers/tests/TestCase/Model/Table/CitiesTableTest.php:11
PHP 11. Composer\Autoload\ClassLoader->loadClass() /var/www/lancers/tests/TestCase/Model/Table/CitiesTableTest.php:11
PHP 12. Composer\Autoload\includeFile() /var/www/lancers/vendor/composer/ClassLoader.php:322
PHP 13. include() /var/www/lancers/vendor/composer/ClassLoader.php:444
$
今後の予定
次回は、最大の難関であるModelのバージョンアップについて書きたいと思います。
CakeFest2019に登壇します
2019/11/7 – 2019/11/10にCakeFestが東京で開催されます。
CakeFestはCakePHPの世界的なイベントで、2019年は日本で開催されることになりました。
※ランサーズは前回の2017年に続き、2019年もスポンサーになっています。
「CakePHP3への滑らかな移行を考える」というテーマが採択されました。
本記事の内容も踏まえて発表する予定です。