Symfony Best Practice 訳してみた - Chapter3 -
Symfony Best Practiceの翻訳をしてます。 三日目です。
前回の記事
※多分に意訳が入っておりますので、誤訳がある場合はご指摘ください。
※読み進めていくSymfony Best Practiceは 2016/10/23時点の情報です。
※写経をする場合は、事前にPHPの実行ができる環境をご用意ください。
3行まとめ
parameters.yml/config_dev.yml/config_prod.yml の使い分けをしよう。
この先変更されない値は定数化を検討しよう。
必要ないセマンティックコンフィグレーションを避けよう。
第3章 Configuration
環境設定には、動作環境や権限付与のような異なるアプリケーションの要素、開発環境、運用環境といった環境の違いが、往々にして含まれます。 このため、Symfonyでは環境設定を3つのパートに分けることをお勧めします。
インフラ関係の設定
- インフラに関連する環境設定は、app/config/parameters.ymlに定義しましょう。
デフォルトの parameters.ymlには、インフラの設定と、データベース、メールに関する設定が記載されています。
# app/config/parameters.yml parameters: database_driver: pdo_mysql database_host: 127.0.0.1 database_port: ~ database_name: symfony database_user: root database_password: ~ mailer_transport: smtp mailer_host: 127.0.0.1 mailer_user: ~ mailer_password: ~ # ...
こうした設定がapp/config/config.ymlに記載されないのは、設定がアプリケーションの振る舞い自体になんら関係しないからです。 換言すれば、これから開発するアプリケーションは、データベースが正しく設定されていさえすれば、データベースがどこにあるか、アクセス権限があるかといったことを気にする必要がないということです。
標準的なパラメーター
- アプリケーションに関するパラメーターは全てapp/config/parameters.yml.distに定義しましょう。
Symfonyはアプリケーションに関する標準的な設定を記載したparameters.yml.distを読み込みます。 新たなパラメーターが追加されるたびに、parameters.yml.distの更新も忘れずに実施して、バージョン管理するようにしましょう。 そうすることで、開発者がアプリを更新したり、デプロイしたりするたびにSymfonyがparameters.ymlとの差分をチェックしてくれます。 差分があった場合、Symfonyは開発者に新たなパラメーターの記載を要求した上で、parameters.ymlに追加してくれます。
アプリケーションに関する設定
- アプリケーションの振る舞い関する設定はapp/config/config.ymlに定義しましょう。
config.ymlにはメール通知やfeature toggle *1のon/offといった、アプリケーションの振る舞いを制御するオプションを含みます。こうした値をparameters.ymlに書くこともできますが、サーバーごとに値を変える必要はないでしょうから、無理にレイヤーを追加してまで定義する必要はないでしょう。 config.ymlに定義されている設定は、往々にして環境によって変わります。 そのため、環境ごとに設定を上書きできるように、Symfonyではあらかじめapp/config/config_dev.ymlとapp/config/config_prod.ymlを用意しています。
定数VS設定
アプリケーションのオプションを設定する際に最も犯しがちな間違いは、ページネーションの数など、変更されることがない値をオプションとして定義してしまうことです。
- 変更されることが予想されいてない設定は定数として定義しましょう。
オプションによる設定をする方法では、以下のようにブログのページに何件記事を表示するかといった設定を読み込ませるようにしてきました。
# app/config/config.yml parameters: homepage.num_items: 10
こうした設定に身に覚えのある方ならおわかりでしょう。こうした値を変更する必要が出てくることは決してありません。 変更する予定のない設定をオプションに追加する必要はありません。 そういった値は定数としてアプリケーションの中に定義することをおすすめします。可能であれば、例えばNUM_ITEMSという定数をPostエンティティに定義するのが良いでしょう。
// src/AppBundle/Entity/Post.php namespace AppBundle\Entity; class Post { const NUM_ITEMS = 10; // ... }
定数化する最大の利点は、アプリケーションのどこからでもアクセスできるという点です。 パラメーターをつかってしまうと、Symfonyコンテナにアクセスできるところから以外は参照できなくなってしまいます。 定数なら、例えばconstant() function*2を使うことでTwigテンプレートからもアクセスできます。
<p> Displaying the {{ constant('NUM_ITEMS', post) }} most recent results. </p>
Doctrine エンティティやリポジトリからであれば、コンテナ内のパラメーターにアクセスできなくても、定数なら簡単にアクセスできます。
namespace AppBundle\Repository; use Doctrine\ORM\EntityRepository; use AppBundle\Entity\Post; class PostRepository extends EntityRepository { public function findLatest($limit = Post::NUM_ITEMS) { // ... } }
こうした設定に定数を使う欠点を1つだけ挙げるとすれば、テストコードの中から気軽に値を変更できなくなってしまうことでしょう。
セマンティックコンフィグ:やってはいけない
- バンドルにセマンティックなDIを定義してはいけません。
How to Load Service Configuration inside a Bundle*3の記事で説明した通り、Symfonyのバンドルはservices.ymlから設定を読み込む方法と、専用の*Extensionクラスを定義するセマンティックコンフィギュレーションの2通りの方法があります。 セマンティックコンフィギュレーションは強力で、設定のバリデーションといった素敵な機能を有していますが、サードパーティ製のバンドルとして扱われることがないバンドルに対してそこまで労力をつぎ込む価値はないでしょう。 (2016/11/27 追記) 「セマンティックな」というところがわからなかったので、別にまとめました。 引き続き役に関するご意見や、私の理解が違う部分があるなら教えて下さい。
Symfonyの外に取扱を注意すべきオプションを移動する
データベースの認証情報など、取扱に注意すべきオプションを扱う場合、Symfonyプロジェクトの外に持ち、環境変数から取得できるようにすることをおすすめします。詳細はHow to Set external Parameters in the Service Container*4から確認できます。
感想
この辺は写経もしたほうが理解が深められそうなので、demoアプリで確認しよう。 設定をどこに持つか(DB/configファイル/定数)用途に応じて使い分けられるようになりたい。
(2016/10/31 更新)
next
Symfony Best Practice 訳してみた - Chapter2 -
Symfony Best Practiceの翻訳をしてます。 二日目です。
前回の記事
※多分に意訳が入っておりますので、誤訳がある場合はご指摘ください。
※読み進めていくSymfony Best Practiceは 2016/10/23時点の情報です。
※写経をする場合は、事前にPHPの実行ができる環境をご用意ください。
3行まとめ
- 2.X系まではcomposerでアプリケーションを作成していたが、今はインストーラを使うのが主流。
- 開発したファイルはAppBundleに集約される。
- 「Bundle=単品でも機能する部品」と捉えるべし。変更しないで移植できないBundleや他のBundleに依存しているBundleは、Bundleとはいえない。
第2章 Creating the Project
インストール
かつて、Symfonyプロジェクトは、PHPアプリケーションの構成管理ツールであるComposer*1で始めることができました。 しかし、現状ではご自身のプロジェクトを作り始める前にインストールされている、Symfonyインストーラを使うことをお勧めします。
Symfonyインストーラの使い方はこちらから確認できます。
Blogアプリの作成
さあ、Symfonyでアプリケーションを作成する準備が整いました。ファイルの作成及び、以下のコマンドを実行できるディレクトリに移動してください。
$ cd projects/ $ symfony new blog # Windows c:¥> cd projects/ c:¥projects¥> php symfony new blog
上述のコマンドを実行することで、最新のstableバージョンのSymfonyをベースとしたプロジェクトとして、blogというディレクトリが作成されます。 インストーラは同時に、お使いのコンピュータの設定がSymfonyアプリケーションを実行するのに必要な条件を満たしているかもチェックします。 条件を満たしていない場合、修正するべき箇所の一覧が表示されます。
- セキュリティの観点から、Symfonyではリリースごとに電子署名が付されています。インストールしたSymfonyの整合性を確認したい場合は、公開されているチェックサム*3を確認するか、こちら*4の手順からご確認ください。
アプリケーションの構築
ここまでで、アプリケーションのベースが出来たので、blog/ディレクトリを確認してみましょう。以下のようなディデクトリとファイルを確認できます。
blog/ ├─ app/ │ ├─ config/ │ └─ Resources/ ├─ bin │ └─ console ├─ src/ │ └─ AppBundle/ ├─ var/ │ ├─ cache/ │ ├─ logs/ │ └─ sessions/ ├─ tests/ │ └─ AppBundle/ ├─ vendor/ └─ web/
各ファイルとディレクトリ構造は、Symfonyがお勧めするアプリケーション構築のお作法を表しています。 各ディレクトリは以下のように使い分けられることを想定されています。
- app/config/ にはすべての環境におけるあらゆる設定を配置します。
- app/Resources/ にはアプリケーションで使用する画面テンプレートファイルと、翻訳ファイルを配置します。
- src/AppBundle/ にはSymfony特有のコード(controllerやrouting)、ドメインのコード(例えばDoctrineクラス)、ビジネスロジックを配置します。
- var/cache/ にはアプリケーションが生成したキャッシュファイルを配置します。
- var/logs/ にはアプリケーションが生成したログファイルを配置します。
- var/sessions/ にはアプリケーションが生成したセッションファイルを配置します。
- tests/AppBundle/ には自動テスト(例えばUnitテスト)を配置します。
- vendor/ はComposer がインストールしたアプリケーションに依存するファイルが格納されるので、一切手を触れるべきではありません。
- web/ にはスタイルシート、JavaScript、画像ファイルなどフロントエンドの制御に必要なファイルを配置します。
アプリケーションバンドル
Symfony2.0がリリースされた時点では、ほとんどの開発者が自然と、symfony1系のお作法に則ってモジュールの分割をしていました。 これはUserBundle,ProductBundle,InvoiceBundleなどのように、多くのSymfonyアプリケーションが、バンドルを機能ごとにロジックを分割する手段として利用しながら開発していたためです。 しかし、バンドルは本来独立して再利用できるソフトウェアのパーツを意味します。仮に、UserBundleが"そのまま"他のSymfonyアプリケーションで利用できないのであれば、バンドルとして存在するべきではありません。さらに言えば、InvoiceBundleがProductbundleに依存しているのであれば、この2つをバンドルに分けるメリットが全くありません。
- アプリケーションロジックはAppBundle1箇所にまとめましょう。
AppBundle1つに実装を集約させることで、簡潔で分かりやすいコードになります。
- 共有されることがないので、AppBundleに(AcmeAppBundleのような)プレフィックスをつける必要はありません。
- 新たにバンドルを作ることがあるとすれば、(controllerのような)ベンダー*5のバンドルをオーバーライドするときでしょう。詳しくはこちら
以上のことから、次に示す構造がSymfonyアプリケーションにおけるベストプラクティスに従った典型的な構成例です。
blog/ ├─ app/ │ ├─ config/ │ └─ Resources/ ├─ bin/ │ └─ console ├─ src/ │ └─ AppBundle/ ├─ tests/ │ └─ AppBundle/ ├─ var/ │ ├─ cache/ │ ├─ logs/ │ └─ sessions/ ├─ vendor/ └─ web/ ├─ app.php └─ app_dev.php
- インストール時にAppBundleが作られませんでしたか?以下のコマンドからAppBundleを生成することができます。
$ php bin/console generate:bundle --namespace=AppBundle --dir=src --format=annotation --no-interaction
ディレクトリ構成の拡張
プロジェクトやインフラの要請により、Symfonyのデフォルトのディレクトリ構成に変更が必要になった場合、cache/, logs/, web/ のディレクトリは他のディレクトリに変更可能です。
感想
Bundleの分割やBundle内でのモジュール分割について、しっかり設計が必要。特にチームで開発している場合は、本章の内容を全員が共有していないと、思い思いのBundleが林立してしまい、アプリケーション全体の複雑性が増大する可能性があるだけでなく、似たような機能を複数箇所で実装することになり、開発効率が著しく低下してしまう。
(2016/10/30 更新)
next
*2:http://php.net/manual/ja/intro.phar.php
*3:https://github.com/sensiolabs/checksums
*4:http://fabien.potencier.org/signing-project-releases.html
*5:訳注:3rdパーティ製のバンドルをカスタマイズしたいシチュエーションを想定しているようだ。
Symfony Best Practice 訳してみた - Chapter1 -
前回予告した通り、 hanahirodev.hatenablog.com
Symfony Best Practiceの翻訳をします。
※多分に意訳が入っておりますので、誤訳がある場合はご指摘ください。
※読み進めていくSymfony Best Practiceは 2016/10/23時点の情報です。
3行まとめ
- Best Practicesの目的は、「素早く」「複雑性を排除した」「現状以上の品質」のアプリを作るためのヒント集である。
- Symfonyを使っていない人でも参考になるような内容が書かれている(少なくとも書いた人々はそこを意識している)。
- 無理にベストプラクティスを適用させようとしてはいけない。
第1章 The Symfony Framework Best Practices
- Symfony は有名な実に自由度の高いフレームワークとして知られており、小規模サイトから、数十億アクセスをさばくようなエンタープライズアプリケーション、さらには他のフレームワーク*1のベースとしても利用されている。 2011年7月のリリース以来、Symfonyコミュニティでは、 Symfonyでどんなことができるか、やりたいことをどのように実現すれば最もよいかという知見を蓄積してきた。
- こうしたコミュニティでの成果(ブログや発表資料)は同時に、Symfonyでアプリケーションを開発するための非公式なノウハウも作り出してしまった。残念なことにそういったノウハウの大部分はWebアプリケーションには必要無いし、たいていの場合、必要以上にアプリケーションの複雑性を高め、Symfonyの当初の実用的な哲学*2に沿うものではない。
本書について
- 本書はSymfonyフレームワークによるWebアプリケーション開発のベストプラクティスの説明を通して、上述のような誤りを正すことを目指している。Symfonyの生みの親であるFabien*3が明らかにしたフレームワークの哲学に沿うようにベストプラクティスは書かれている。
- ベストプラクティスとは、「最適解に近づくための手段として整理されたもの」を意味しており、本書がまさに目指すところでもある。たとえ読者の皆様が、本書の全ての内容には納得できなかったとしても、複雑さを極力排除したアプリケーションの開発に役立つものと思っている。
本書の適用対象
特に - Symfonyフレームワークで開発されたWebサイトやWebアプリケーション 以下のようなものについても、問題や要望を解決する足がかりとなるだろう。 - Symfonyコミュニティで広く使われているバンドル - 独自の標準化ルールを運用している開発者/チーム - 様々な要求から複雑性が増してしまったアプリケーション - 社内で使われているバンドル
旧習*4を打破することが難しいのは重々承知しているし、ベストプラクティスの中にはショックを受けるものもあるかもしれない。 しかし、ベストプラクティスに従うことで、素早く、複雑性を極力排除して、しかも今までと同等以上の品質を持ったアプリケーションを開発できる。 同時にベストプラクティスは、改善を続けるための指標でもあるのだ。 覚えておいて欲しいのは、ベストプラクティスはあくまでもSymfonyで開発する上での推奨であり必ず守らなければいけないというようなものではない。 これまで通りのやり方に従いたいのであれば、それでいい。Symfonyはそんなあなたの要望に応えられる程度には柔軟だし、これからも柔軟であり続ける。
対象読者(ただし、本書はチュートリアルではない)
初心者から上級者まで、Symfonyで開発をしていれば本書を読むことができる。しかし、本書はチュートリアルではないので、理解するためにはSymfonyに関する基本的な知識が必要だ。もし、全くSymfonyを触ったことがないのであれば、まずはThe Quick Tourからはじめて欲しい。 本書は意図的に、必要最小限のことだけを書くようにしている。Symfonyの他の膨大なドキュメントで書かれているようなこと(例えばfront controllerにおける依存性の注入について)を繰り返し書くということは、あえてしていない。読者の皆さんがすでに知っているであろうことを、どのように説明するかということに力点をおいている。
アプリケーション
本書に加えて、サンプルアプリケーションもベストプラクティスを意識してかかれている。 サンプルアプリケーションは「Symfony Demo Application」と呼ばれており、Symfonyインストーラーから入手できる。 まずダウンロードページからインストーラーをダウンロードして、以下のコマンドを実行してデモアプリケーションをダウンロードしてください。
$ symfony demo
デモアプリケーションは、簡単なブログになっています。これは、複雑になりがちな細かな実装にとらわれることなく、Symfonyのコンセプトと特徴に集中するためです。本書を最初から読んでも構いませんし、必要な章から読んでも構いません。
既存のアプリケーションは修正しないでください
本書を読んだ後に、既存のSymfonyアプリケーションをリファクタリングしたくなる人がいるかもしれません。 本書の内容は耳あたりがよく、スッキリしたものかもしれません。しかし、以下に挙げる理由から、ベストプラクティスに従ってリファクタリングするべきではありません。
- 既存のアプリケーションが間違っているわけではありません。ただ他のガイドラインに従って開発されているだけです。
- アプリケーション全体に及ぶ、大規模なリファクタリングは新たなエラーを発生させがちです。
- ベストプラクティス適用にかける労力より、テストの向上や新機能の追加をしたほうが、エンドユーザーへ届けられる価値の向上につながります。
感想
「Best Practiceに従って開発しなきゃダメ」というものではないということが強調されていてちょっと意外。 「エンドユーザーに届ける価値の最大化」を一番に考えるべきと、切に思う。
(2016/10/29 追記)
next
*1:訳注:LaravelやSilex
*2:訳注:「基本からしっかり学ぶSymfony2入門」第1章に詳しい。また、公式サイトにも記載あり。
*3:https://connect.sensiolabs.com/profile/fabpot
*4:訳注:悪習としての
Symfony Best Practice 訳してみた - 序 -
来月のSymfony Meetupに参加するんですが、 symfony.connpass.com
それに向けて予習がてらSymfony Best Practiceを訳しながら読んでいこうと思います。 有志の方の翻訳にもまだ掲載されてなさそうなので、お役に立てたら嬉しいです。
※読み進めていくSymfony Best Practiceは 2016/10/23時点の情報です。
動かす環境が必要になるかなーと思って環境構築もしました。
また、Symfonyの全体像を体系的に勉強したいという方はこちらがおすすめです。
- 作者: 後藤秀宣,金本貴志
- 出版社/メーカー: 技術評論社
- 発売日: 2015/12/16
- メディア: 大型本
- この商品を含むブログを見る
ブログ始めます
遅ればせながら「SOFT SKILLS ソフトウェア開発者の人生マニュアル」に触発されてブログ始めてみました。
- 作者: ジョン・ソンメズ
- 出版社/メーカー: 日経BP社
- 発売日: 2016/06/02
- メディア: Kindle版
- この商品を含むブログ (2件) を見る
勉強会のレポートや調べ物のメモから始めていきたいと思ってます。
手巻き式なので、時々巻き忘れて止まることもあると思いますが、 よろしくお願いします。