OpenAPI(Swagger)でいい感じに自動テストさせるためのベンダー拡張を考えてみた。
定義するのは下記の二つ
- Path Item Object の x-create-operation
- Parameter Object の x-found-in
x-create-operationはそのリソースを作成するための操作のoperationIdを指定する
x-found-inはパラメーターを取得するためのoperationとパラメーターがレスポンスのどこにあるかを示すオブジェクトあるいは同オブジェクトを共通定義した#/x-found-ins/以下へのReference Objectをしていする。
パラメーターの所在は指定はParameter Objectと同じように行えばいい。
APIによる生成・参照が不可能なやつはこれらの値を設定しない。
これによって、依存するオペレーションが明示されるので、
(再帰参照になっていない限り)いい感じにテストができるはず。
続フレームワークの責務とセキュリティ
先日のエントリに対してさまざまな反応を戴きました。ありがとうございます。
今回はその中からいくつかを取り上げていきたいと思います。
今回の件に関してはまず前提としてBasic認証の実装です。他の認証についてはおっしゃるようにフレームワークでは何ら規制も規定するという訳ではありません。また、平文パスワード保存については積極的に提供しないというだけであり、必要な状況に応じて実装することをフレームワークで禁止するということでもありません。
平文パスワード保存をフレームワークで安易に提供してしまうと、その危険性を理解していない開発者が利用用途が適切でない場面で乱用してしまう可能性が高まるため、十分な注意喚起を最低限としてできれば提供を避ける(=障壁を設ける)べきだということです。
PRでも僕は下記のように言及しています。
拡張・変更が容易なようにDIやAOPを導入しているのでエッジケースには対応しないというのであれば、
むしろ、プレーンテキストでパスワードをソースコードに記述しなければいけないような危険な要件はエッジケースとして扱って実装対象から外すべきだと僕は思います。
その他、koriymさんを殴る殴らないというコメントもありましたが、たった1度の意見の対立で暴力に訴えるとかどんな世紀末ですか。
ちなみに今夜はローストビーフを仕込んでいます。
フレームワークの責務とセキュリティ
お久しぶりです。 夜中にモツ煮込み作りながら書いてます。
さて、今回はフレームワークの責務とセキュリティについて思うところがあって久しぶりにエントリを書くことにしました。
背景
まず、背景としてBEAR.Sundayの一部であるBEAR.PackageにサンプルとしてBasic認証の実装を追加するPullRequest#90でのやり取りがあります。このPRはzukimochiさんが作ったものに僕が修正を加えて出した物です。この中では、Basic認証用のパスワードをハッシュとして扱うように実装されています。
多くの人が斜め読みしているのは背景説明が長すぎるからだと思ったので削除しました。詳しく知りたい方はPRをご覧ください。
本題
いよいよ本題です。 PRの最後にkoriymさんが発言している次の言葉はフレームワーク開発に於いてとても重要です。
より関心のある問題に集中するために、特に専門としていない問題に注力しすぎないようにするために役立てているのです。
言い換えれば、「余計な機能作ってる暇あったらよりいいフレームワーク作ろうぜ!」といったところでしょうか。この考えをもとに開発することによってフレームワークは肉を削ぎ落して、骨格だけをもつ枠組みとしてより洗練されていきます。
そこで重要になってくるのが、削ぎ落すべきものと削ぎ落してはならないものの線引きです。先のPRでの問答は「生パスワードのセキリティリスク」がその線の内か外かあるいは内側の場合どう対処するのかの議論になります。ちなみに、本エントリのタイトル「フレームワークの責務とセキュリティ」の責務とは境界線の内側のことです。
では、この実装がフレームワークの実装として取り込まれるという前提で話を進めましょう。
ここで、生パスワード保存機能を削ぎ落さずにリリースした場合に想定しうるセキュリティリスクを考えてみると、こんなシナリオが浮かびます。
- 開発者が生パスワードを設定ファイルに書く形で管理画面のアクセス制御を行うアプリケーションを作成
- アプリケーション利用者AがSNSでも利用しているパスワードを設定ファイルに書きインストール
- アプリケーションのバグ(ディレクトリトラバーサル脆弱性)を利用し攻撃者がパスワード設定ファイルを取得
- 攻撃者がアプリケーション利用者AのSNSアカウントを乗っ取る
より具体的にしました
これは、PRで挙げた問題点の具体例ですね。
では、このセキュリティリスクに対する責務はフレームワークにあるのでしょうか? それとも、フレームワークの本質ではないと切り捨てるべきでしょうか?
僕はフレームワークの責務であると考えます。 提供する機能がセキリティリスクを抱えているのであれば当然です。フレームワークに余分な複雑さを持ち込みたくないのは分りますし、一般にはそうあるべきですが、セキュリティリスクが絡む場合はリスク回避もフレームワークの責務です。
ならばどうすればいいのか、選択肢は3つほどあります。
1つ目は、問題の機能自体を切り捨てることです。 もしフレームワークの本質を損なわないのなら切り捨ててしまえば簡単です。フレームワークが十分な拡張性を持っているならば、第三者による実装に期待することができます。
2つ目は、セキュリティリスクを抱えていることをフレームワークの利用者(=アプリケーション開発者)に対して周知徹底することです。 マニュアルやソースコード中のコメントにわかり安く注意事項を表示します。先のシナリオでは開発者が広く一般に使われるアプリケーションを生パスワードを利用する形で実装しなければ、リスクは回避できたわけです。消極的な対策であり、マニュアルをきちんと読まない開発者を想定するとまだリスクは残りますが、責務を果たしていると言えるでしょう。
3つ目は、リスク排除した実装を提供することです。今回で言えば、生パスワード保存を提供せず、適切なハッシュ化などを用いたパスワード保存のみを提供します。 こちらも、生パスワード保存機能を自分で開発して利用してしまう開発者というリスクはまだあるわけですが、それを言い出したらさすがにきりがないですし、水が低い方に流れるように、開発者も楽に実装できる方に流れるのできっとハッシュ化されたパスワード保存を利用してくれるでしょう。(これがPRでの僕の主張です)
最終的にどれを選択するかはリードコミッターやプロダクトオーナーの采配によることになりますが、何も対策しないというのはあり得ません。オープンソースでタダで開発していても、その倫理的責任から逃れることはできません。
また、3つ目の積極的な解決方法を容易にとることができるのであれば、2つ目を採用するのではなく3つ目で対策を行うべきでしょう。責任の範囲内ではベストエフォートをなすべきです。
今あるJSONベースのHypermediaフォーマット仕様まとめ
RESTful Web APIs: Services for a Changing World (English Edition)をよんだりなんだりして、JSONベースのHypermediaフォーマットに興味が出たので調べてみました。
ここで紹介するフォーマットは2013年10月6日現在どれも策定段階です。
リスト化するに当たりググってもパッとしなかったので、IANAに登録されているmedia-typeのうち"+json"を接尾辞に持っているものからそれっぽいモノを選びました。
Collection+JSON
その名の通り、コレクション(を含む)リソースのための仕様です。
この仕様ではコレクションの参照だけではなく、コレクションに対する追加・更新・削除操作に言及しています。
Collection.next+JSON
上記Collection+JSONの拡張し、より複雑な定義をできるようにしています。
追加されている主な機能は下記になります。
- フォームへの選択肢の提示
- HTTP 202 Acceptedとともに返されるレスポンスで利用するstatus表現
- ハイパーリンク、テンプレート定義における型(type)指定
Siren: a hypermedia specification for representing entities
サブタイトルの示す通り、エンティティ(リソース)を表現するための仕様です。
Collection+JSON系と異なり、エンティティの表現方法についても言及しています。またフォーム表現も充実しており、柔軟に追加・更新を行えます。
株式会社VOYAGE GROUPを退職し、ウェブニウム株式会社を設立しました。
お久しぶりです。アドベントカレンダー以来の投稿となりますね。
さて、この度、3月31日付でVOYAGE GROUPを退職しました。
PHPカンファレンス2011の翌日の2011年9月12日に株式会社ECナビに入社し、翌10月に株式会社VOYAGE GROUPに社名変更、その後MBOを行いIPOを目指すと宣言する、という激動の時期に内部で関わることができました。
私の入社した頃はVOYAGE GROUP内のエンジニア陣が強化される時期でもあり、元々いた優秀なエンジニアに加えて様々な分野からの中途組と一緒に仕事をしたり、部署の違う方とは社内勉強会などを通じて刺激を受けることができました。 また、それまで経験してこなかった、専任のインフラチームが居る環境で働くことを通じても多くのことを学ぶことができました。
VOYAGE GROUPという会社は、コーポ―レートカルチャーの推進に専任担当者を設けていて、半期に1度の総会やVOYAGE CUPという運動会、クリスマスなどの年中行事などの刺激と楽しみに満ちたとても良い職場でした。
また、福利厚生として四半期ごとに加入できるサークル活動を通じて1年前からボルダリングを始めました。 本当に楽しい活動で、この活動を通じてCTOの小賀さんとも親しくなることができました。 今後もボルダリングサークルの活動にご一緒したいと思っています。
自分の中の予定では、もっともっと、VOYAGE GROUPの一員として働き続けるつもりでした。本心からそう思っていました。 それくらい働き甲斐のある会社でした。
けれど、漢には夢があります。
僕の夢は、いつか、信頼できる人とともに会社を興し、日本にそして世界に誇れるサービスを創りたいというものです。 僕はトップになれる性格ではないので、社長にはなれそうもないのでパートナーが必要なのです。
そして、ついに、信頼できるパートナーにめぐり合うことができ、2013年4月1日にウェブニウム株式会社を設立いたしました。
これからは、一従業員という立場を卒業し、取締役CTOとして精進していきます。 改めて、よろしくお願いします。
PHPerのMVCの一体どこが間違っていたのか
メリークリスマス! PHP Advent Calendarもいよいよ24日目に突入です。
昨日はxhprofについてでしたね。僕もパフォーマンスチューニングの際に使っています。手軽に利用できるのでお勧めです。
さて、このエントリーでは表題の通りMVCについて書かせていただきます。これは、PHPカンファレンス2012&WordCamp Tokyo2012合同LT大会で発表した「やはりお前らのMVCは間違っている」で煽るだけだったこの問題をきちんと解説するものです。
この発表資料を公開するとPHPの枠を超えて広く閲覧いただき*1、また多くの方から突っ込みを戴きました。「LTだから」と言って逃げていた回答をして、気持ち新たに新年を迎えようと思います。
MVCとはなんなのか
間違いを指摘する前にMVCがそもそもどういうアーキテクチャであるのかを確認しなければいけません。
MVCは1970年代にパロアルト研究所(Xerox Parc)で発明され、1980年代にSmalltalk-80のドキュメント*2に登場します。このMVCのコンセプトはGUIアプリケーションにおいてオブジェクトを3つに分類しました。
- Model
- ドメイン領域のデータと振る舞い
- View
- ユーザーに対する視覚表現
- Controller
- ユーザーの操作を受け取りModelやViewに命令を送る
また、これを実現するため下図に示したオブザーバーパターンによる連携を用いました。
これこそがMVCの原点です。
@koichikさんからの指摘に基づき上図を変更しました。後に下図のような連携も出てきますが、原点で示すべきは上図でした。訂正してお詫びします。
Webへの対応
WebへのMVCの導入はJAVA界隈で行われました。この時、HTTPがステートレスであることに対応してMVCに変更を加えMVC2としました*3 *4。すなわち、MV間、VC間のオブザーバーパターンによる通知を排除し下図のような構成にしました。
このようにMVC2でもそれぞれの役割分担がはっきりしており、またデータの流れも均一です。
ではStrutsの実装を見てみましょう。StrutsのMVC実装は下図で示したものとなります。ViewがJSP(テンプレート)でActionとActionForm BeanがModel領域とフレームワークとの間に立つアダプターパターンを採用しています。ViewがJSPになった背景にはデザイナーの範囲を分離する意図があったようです。*5
PHPでもMVC2実装がなされ、Mojaviとして公開されました。Strutsやその後に登場した多くのWebApplicationFramework(WAF)でViewをテンプレートのみで構成ているのに対して、MojaviではViewをテンプレートとViewクラスの2つで構成しているのが特徴です。これにより、複雑なプレゼンテーションロジックをテンプレートから排除しながら、コントローラの肥大化を避けています。(裏を返せば、Viewをテンプレートのみで構成するとプレゼンテーションロジックが行き場を失います。)
Ruby on Railsの登場
Ruby on RailsがWAFに与えたインパクトは絶大でした。 フルスタックであり、自動コード生成機能、テスト機能そしてActiveRecordなど、その思想は後続の多くのWAFに影響を与えています。
RailsにおいてModelを生成するには次のコマンドをたたくだけでした。
rails generate model profile
たったこれだけでプロフィールクラスのひな形が出来上がります。そして出来上がったひな形はActiveRecordを継承しています。これがMVC初心者に誤解を与えることになりました。
RoRのコマンドで生成されるモデルはドメインモデルで言うところのエンティティに当たるものです。これはMVCのモデルの部分集合にすぎません。しかし、"モデル生成コマンド"で生成されるものだけがモデルであると人々に誤解を与えるのに十分でした。*6
その結果、本来モデルに実装されるべきビジネスロジックが行き場を失いコントローラへ集まってしまいました。こうして憎むべきファットコントローラが量産されるようになります。
この波はPHPにもCakePHPとして訪れます。CakePHPはまさしくRoRのクローンであり、自動コード生成によりActiveRecordなモデルを生成しました。しかも、そのクラスの基底クラスはAppModelという名前でした。結果として多くのPHPerがMVCを誤認識することになりました。
PHPerの認識しているMVC
さて、このようにして多くのPHPerが認識するMVCが誕生しました。この特徴を一度整理してみましょう。*7
- Model
- 自動生成されたアクティブレコードのモデル
- View
- テンプレートファイル。ロジックは排除。モデルへのアクセスは厳禁。
- Controller
- Model,View以外のすべてをコントロール
何が間違っているのか
ここまでの説明でPHPerの認識するMVCとSmalltalk MVCの違いを理解いただけたかと思います。
件のLT発表において私が「間違っている」と断言したのは、この違いにより冒頭で紹介したMVCのコンセプトから外れてしまっているからにほかなりません。コンセプトがズレているのにそれをMVCと呼び続けることは厚顔無恥と言わざるをえません。
しかし、MVCから外れることそのものは悪ではありません。MVCとて完璧なアーキテクチャではないですし、そもそもがGUIアプリケーション用のアーキテクチャなのでWebアプリケーションには適さない(あるいはオーバースペックな)部分もあります。
そして、もしMVCに確固たる意志をもってコンセプトから外れるような手を加えてるのであれば、そのアーキテクチャに新しい名前をつけるのが良いかと思います。
結論
PHPerの認識するMVCがどのように出来上がったのかを振り返りました。MVCのコンセプトからのずれが生じた背景には何らかの問題を解決する意思があったのだと思います。しかし、そのずれは次第に周りに影響を与え結果として多くの人が全く別物をMVCとして認識するに至りました。時には立ち止まり、振り返ることが大切なんだと痛感させられます。
2012年もあと少しです。私たちも今年を振り返って小さな間違いのうちに改めていきましょう。
PHP Advent Calendar、明日はいよいよ25日目、ジェネレータが実装されるPHP5.5に備えてforeachについてのお話です。
*1:まさかの3万views越え!
*2:ネット上には原典は見つかりませんでしたので後継ドキュメントを示します "Applications Programming in Smalltalk-80(TM):How to use Model-View-Controller (MVC)" by Steve Burbeck, Ph.D. http://st-www.cs.illinois.edu/users/smarch/st-docs/mvc.html
*3:MVC2という用語はJSFのMVC対応Type2を指すものがあれこれした結果であるとかないとか?要出典
*4:こちらの"Model2" architectureが元のようです http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-eedocs-419425.html#7036-design_ent_app-2.0-oth-JPR
*5:参考: http://struts.apache.org/1.x/index.html
*6:参考: Life is beautiful: Ruby on Railsの「えせMVC」の弊害
*7:あえて、一番ダメな例を出します
VOYAGE GROUPで新卒エンジニアを生暖かく見守ったお話 #vgadvent2012
※この記事はVOYAGE GROUP エンジニアブログ : Advent Calendar 2012の13日目の記事として書かれています。
ご無沙汰しております、あるいははじめまして。 ここ1年強、VOYAGE GROUPでPHPerのトレンドを社内に伝える仕事をしています。ついでにシステムも作っています。
さて、VOYAGE GROUPエンジニアブログ Advent Calendar 2012、13日目がやってまいりました。いよいよ後半戦です。このエントリでは空気を読まずに真面目な話を適当に書きたいと思います。
2012年4月に弊社VOYAGE GROUPには多くの新卒が入ってきました。入社すると彼らは1か月の基礎研修を受けることになります。エンジニアとして入社した新卒たちはさらに技術研修を受け、その後ようやく各部署に配属となります。配属された後もOJT担当がつけられて実地での研修となります。
そんな彼らと研修の教官でもOJT担当でもない私がこの1年どのように関わって来たかご紹介したいと思います。
同じ部署の新卒との関わり
部署内の新卒とは自然と関わりが多くなります。OJT担当であるかは関係なく出来る限りの指導を行いました。
社内でコードレビューを行う風潮が根付いて居いたため、新卒の指導の機会として利用することができました。通常のレビューでは問題点を指摘するだけですが、新卒相手の場合には詳しい説明をしたり、逆にわざとヒントだけ与えるということもしました。
また、一人では解決が難しそうだと判断した場合にはペアプロを行うことも何度かありました。ペアプロでは主に新卒のこにドライバーを任せていました。自由に書かせて詰まっているときや明らかに間違っているときヒントを与える形です。考える力を付けるにはドライバーの方が向いていますから。
ところで、同じ部署に配属された新卒について弊社CTOの小賀と話をする機会がありました。ボルダリングサークルの後だったかと思います。
その時の話の中で2つの言葉が印象に残っています。
1つ目は「失敗させた方が良い」という趣旨の言葉です。失敗することによってはじめて学べることがあるので(取り返せる範囲で)失敗を経験させるべきだということでした。失敗するとわかっているのをあえて何も言わずに見守るのはとても労力を使うことです。本当に苦労しました。
2つ目は「叱る人が必要だ」という言葉です。この話が有ってから、新卒のRくんに対してあえて厳しく当たるようにしました。しばらくすると脅えられる様になりましたが、その分気持ちを引き締めて仕事をしてもらえたのではないかと思います。
そんな指導のおかげか、彼自身の努力のたまものか、Rくんが最近他部署のエンジニアに褒められているとの噂を耳にしました。とてもうれしかったです。
他部署の新卒との関わり
彼らとは社内勉強会でのかかわりが主になります。社内勉強会で何度か登壇した時には意欲的に話を聞いてくれました。
勉強会後に社内バーのAJITOで話すとこともありました。もう少し関われたらよかったなと思わなくもないです。