コネヒトに入社したことでCakePHPをはじめて触ってみたんですが、その感想を述べてみます。
このエントリは、 コネヒト Advent Calendar 2019 の6日目のエントリです。
はじめに
今年7月にコネヒトに入社しまして、5ヶ月ほど経過しました @takoba です。
コネヒトではサーバーサイドの主要言語としてPHPを採用しており、その上で採用しているアプリケーションフレームワークは CakePHP です。一方でぼくは、PHPの経験こそあれど入社するまでCakePHPを触ったことがありませんでした。
このエントリでは、そんなぼくがはじめてCakePHPを触ってみた結果について書き殴ってみます。
前提
@takoba がいままで触れてきたアプリケーションフレームワーク
主要なものは、ざっとこんなかんじです。
- Zend Framework(PHP5, v1)
- CodeIgniter(PHP5, v1)
- Laravel(PHP7, v5)
- Ruby on Rails(Ruby2.1, v3-4)
「なんでコネヒトはCakePHPを採用しているの?」
詳しくは以下のエントリをお読みください!
抜粋すると、以下のように「CakePHPの"制約"が、開発スピードの向上に寄与する」点が大きいようです。
いまでも採用をしているのは、CakePHPの「設定より規約」を重視しているところが個人的にはチーム開発において効果的だと考えているからです。チーム開発は、どうしても個々人によってコードのブレが出てくることもある。だから、フレームワークレベルである程度「縛り」を入れることで同じような設計やコードになり、それが開発スピードの速さ、品質の担保につながり、全体的に開発スピードが速まります。
「コネヒトにあるCakePHP製アプリケーションってどんなのがあるの?」
ママ向けコミュニティサービス「ママリ」のiOSアプリやAndroidアプリで利用されているAPIアプリケーションはCakePHP3が採用されています。その他、社内に提供している管理画面のサーバーサイドもCakePHP3を採用しています。
また、弊社CTOのいとしょさんが最近つくった社内ツールでは、お試しする気持ちを込めてCakePHP4(4.0.0 bate1)が採用されています。
感想
というわけで、ようやく本題です。
「率直にどうなん?」
「(全く触ったことないと)慣れるまでが大変ですが、慣れてからは便利だな〜〜」という気持ちです!
CakePHPは前述しているように「設定より規約」を重視したフレームワークです。そのため、触り始めはその"規約"を理解することに時間を使うことが多かった印象です。
幸い、理解するための材料はたくさんありました。既に本番環境でバリバリ動いているアプリケーションが目の前にあるので、「どのように実装してるんだ...?」とアプリケーションのコードを眺めたりlocalで動かしたりしながらフレームワークの挙動も把握していきました。また、実際にコードを書いてみて作成したPull Requestをレビューしてもらう中でも同僚から教わったりしていました。
そうやって徐々に慣れると「えーっとこの処理はどのクラスに書けばよいんだ...?」的なことは大抵のことは迷わなくて済むサクサク書けて便利だな〜〜ってなってます。
「設定より規約」が生む"共通認識"が、日々のコミュニケーションを加速させる
例えば、APIアプリケーションでユーザー情報の登録エンドポイントを追加するとします。エンドポイントがリクエストされた際に渡されるパラメータに関するバリデーション処理は、どのように表現したらよいでしょう。APIなのでView側でバリデーションすることは難しい*1ので、Controllerに書くか?Modelに書くか?という議論になりそうです。
この場合、CakePHP3で書くと「入力された値のバリデーションは、入力された値をEntityクラスに格納するとTableクラスに書いてあるバリデーションルールに沿って処理してくれるので、その結果を見ればよいな〜〜」というかんじになるので、CakePHP3を書いたことがあれば設計はそれなりに一意に定まるんですよね。*2*3
<?php // 中略 class UsersController extends AppController { public function initialize() { parent::initialize(); // `/user/add.json` のようにリクエストするとextに合わせてJsonViewを適用してくれる // 従来は `AppController::initialize()` で定義しとくとよい $this->loadComponent('RequestHandler'); $this->loadModel('Users'); } public function add() { $user = $this->Users->newEntity($this->request->getData()); $errors = $user->getErrors(); if ($errors) { $this->set(compact('errors')); return; } $this->Users->save($user); $this->set(compact('user')); } }
<?php // 中略 class UsersTable extends Table { public function validationDefault(Validator $validator) { $validator ->requirePresence('name', 'create') ->allowEmptyString('name', false) ->maxLength('name', 100); $validator ->allowEmptyString('description') ->maxLength('email', 255); return $validator; } }
Ruby on Railsでもまさにそうですが、フレームワークの規約に乗ることで書き方が一意に定まるとその部分の設計を擦り合わせるコミュニケーションコストが確かに減るよな〜〜って実感しています。日々実装したりコードレビューしたりすることで、そのコストが軽くなっていき開発スピードが上がる!ということは確かに起きそうです。
また、コネヒトでは複数のアプリケーションでCakePHPを採用していますが、ドメイン知識の違いこそアプリケーションごとにあれど、アプリケーション自体に触れることへのハードルはだいぶ下がっていると感じています。開発環境のセットアップはどれかひとつのアプリケーションで覚えれば大体同じですし、見様見真似でソースコードを追っていくまでに時間はさほどかかりません。アプリケーション固有のレイアウトになってることはまず無いので、そんなに触ったことのないアプリケーションでもすぐに本質的な作業にアクセスできるのは非常によいです。
「複雑なことができない」制約による産物
一方で、こういった制約があることで「自由度が少ない!」「ちょっとレールを外れると非常に苦労する」という声も大いにあると思います。現にCakePHPとLaravelを対比する記事を読むとそんな声が大半です🙉
とはいえ、昨今のMicroservicesが流行していることも踏まえると、多くの責務をひとつのアプリケーションに委ねないことも必要だよな〜〜と感じています。
複数のアプリケーションをキューイングサービス*4などで繋いでパイプラインを組み、処理を完遂させるようなアーキテクチャは既に主流になっていますし、アプリケーション単位ではなくマクロな視点でシステム構成を設計していくことで持続可能なアーキテクチャを実現することに繋がるはずだ、と思います。別にこういったことが他のフレームワークじゃできない!ってことではないのですが、"CakePHPが持つ思想"を開発チームに装着することで理想的なアーキテクチャを実現していくための一助になるかもな?なんて思ったりしました。
おわりに
というわけで、CakePHPにはじめて触れた感想を書いてきました。特にCakePHPに関してはひよっこなので、いろいろ間違えてたらすみません><
今回は割とよくある話を改めて説いた感はあるので恐縮なのですが、とっても雑な感想としては、過去を振り返ると割とレガシーなアプリケーションを触ることが多かったので、例えば cakephp/orm のような表現力の高いORMがあるだけでも割とテンションが上がりました😇
そろそろCakePHP4がリリースされる日も近づいてきて、まだまだCakePHPは盛り上がっていくと思います。というわけで、ぼくも修練を重ねてCakePHPを使いこなし、" サービスの成長を第一に費用対効果を最大化させるコード "を書いていけるようにやっていくぞ!!!💪
*
[PR] エンジニア絶賛募集中です!!!
柔軟な働き方を求める、サービス開発好きなPHPエンジニアWanted!
*
[PR] 弊社で採用している開発環境を参考に書かれたCakePHP本もよろしくな!!!
*1:入力がURLに含まれるクエリストリングだったり、POSTリクエスト時のリクエストボディだったりするので、View的な機能が介入されない場合が大半となるため。
*2:細かい話をすると、APIエンドポイントの振る舞いを考えたときに必ずしもEntityが担うバリデーション処理とエンドポイント側でのバリデーションが一致しない場合はあると思います。Laravelだとその辺りを柔軟に書けるよね!って話が多いのですが、単体テストを用いて動作保証をすることを考えると、CakePHP3でもEntityが担うバリデーションとエンドポイントが担うバリデーションを分けて書くことで、責務の分離をしつつ柔軟な振る舞いが実装できそうです。
*3:(2019/12/06 14:30追記)ブコメを見ると、LaravelだとFormRequest機能があって、それを用いるとController側でのバリデーション責務を分離できるようですね。これは便利そうだし、一定の責務分離はできそうですね。教えていただきありがとうございます!🙇♂️