MacのCheatSheetが素晴らしかった

http://cheatsheetapp.com/CheatSheet/

これ起動しておくと、commandキーを押して「あれ? あのショートカットキーなんだっけ?」って思ってると、こんなのが出てくれます。

これ、Mac OS 標準のアプリケーションだけでなく、ショートカットの登録状況を見て、どんなアプリでもショートカットの一覧を出してくれるんですね。ツールバーボタンは少なくて初心者に優しいけど、上級者には全部ショートカットを覚えろとなかなか厳しい、そんな感じのMacの習慣に慣れない人にはすごくオススメ。

「はじめてのフレームワークとしてのFuelPHP」書評

ご無沙汰しております。ものっそ久しぶりに書きます。

著者様から献本頂いて、達人出版会発行の「はじめてのフレームワークとしてのFuelPHP」読みました。EPUBをダウンロードするやつです。

http://tatsu-zine.com/images/books/37/cover_s.jpg

http://tatsu-zine.com/books/fuelphp1st

ただのFuelPHPのテクニック本だと思ったら大間違い、FuelPHPはむしろPHPフレームワークのわかりやすい一例として取り上げましたという印象で、この本の本質は、今どきPHPで開発するってのは、これぐらいの基準ラインに乗ってるよ、というのが一気にわかる本でした。

  • 自分のローカルホストにきっちり開発環境作る
  • OSSコミュニティへのURLリンクをしっかり持つ
  • 自分が使っているOSのコマンドラインを押さえよう
  • どれぐらいWeb開発用語の知識を持つべきか体で知ろう
  • フレームワークと呼ばれるものがおよそどんな機能を持つのか
  • Webアプリケーションのセキュリティは初心者向けでも案外レベル高いぞ
  • 自動テスト自動テスト自動テスト、ロジックは徹底して自動テスト
  • そしてフレームワークを盲信しないこと(^^;

ざっくりこんな内容です。えと、FuelPHPはどこに? いや大丈夫、表向きはFuelPHPとEclipseのチュートリアル形式で学びながらなので、つかみはOK、あとは日本語ドキュメントがあるからもう大丈夫でしょって感じにはなりますよ。

不必要に長い説明はなく、これやる、これやる、これやる、と、淡々と進みます。長ったらしい説明を読んでいちいち良し悪しを考えたりしないで、まず言われたとおりに受け取る、というふうに読めるので、用語ですごく詰まる人でないかぎり、サクサクいけます。本だけでは説明不足に感じるところがあっても、実はキーワードだけはしっかり登場してるので、それマークしておいて、あとで検索する学び方もいいですね。Web時代ですね。電子書籍っぽいですね。

本書の流れの中でとくに好感を持てたのが「モデル」の扱いです。機能を試している間はアプリケーションのモデルが存在しないので、びっくりするぐらいコントローラに実装が書かれます。うーん、MVCって最初に言ってたのに大丈夫かなと思っていると、後半、アプリケーションに目的ができてきた瞬間から、機能的なサービスをモデル層に移して単体テスト、という怒涛の流れに入っていき、データベースの便利CRUDもORマッピング(というかかなりActiveRecordっぽいけど)の使い方も、最後の章でようやく登場します。

はいこれ、なんてすばらしいんでしょう。

WebアプリケーションフレームワークRails以降、ActiveRecordCRUDが目立ちすぎました。それで何が起こったかというと、データベースに保存できるActiveRecordを最初に「モデル」と呼び、まずその操作をマスターするような学習フローが流行ったんですよね。最初にそこ叩き込まれるから、初学者が「モデル」=「DBの行」って思っちゃう。それで、「いろんな処理」=「ロジック」=「コントローラ」って印象になってしまう。モデルがひとつの行を表さないといけないから、複数のオブジェクトが対等に処理されるべきロジックを特定のモデルクラスに所属させたくない→コントローラ? 違いますよね。

モデルはアプリケーションの目的を実装した本質です。コントローラは本質とそれ以外の関連付けです。この「はじめてのフレームワークとしてのFuelPHP」では、最初、無目的に機能を遊んでいるうちはずっと、コントローラの中でやります。で、だいたいこのフレームワークがどういうものかわかったら、実用を意識した実験をして、その次にようやく「ではこういうアプリケーションを作りましょう」と決めて、やっとモデルになるクラスを作り始める。しかもそれは、最初はメールを送るという、ストレージを持たないサービスときたもんだ。そう、モデルはDBの行じゃなくて、アプリケーションの機能の親玉。まずそういうMVCの意味を理解するのが最初にあって、ORMなんかはもっと後にこういうのもあるよって話になる。

うん、正しいですね。とにかく最初にDBのCRUDから入るタイプのフレームワークを題材にしちゃうと、なかなかこういう学習プロセスは提供しにくいでしょう。プレーンPHPCMSのカスタマイズよりは技術的に高度で、かといって、いきなり一発楽ちんが出来上がっちゃってるフレームワークじゃないもの、という意味で、このFuelPHPはいい題材だと思いました。題材がこうだから本の展開がこうなったのか、本の展開が先にあったところに題材がハマったのか...は、わかりませんが、まあたぶん両方なんだろうなと思います。

それと、いちいち単体テストが徹底しているのもいいですね。もしかして、MakeGoodをこんなに詳しく紹介した出版物って、初ではないでしょうか。Eclipse+PDTの人はぜひMakeGoodを。MakeGoodに清き一票を。

そうそう、あと、前述してますが、この本ところどころに、「FuelPHPはこういうのがまだ不十分」という説明が入ってきます。これ実はいい感じです。フレームワークは完璧なブラックボックスだと思って信じてると、裏切られることもあるんですよね。中を見れば、たまに自分の期待とは違う意図で書かれたコードもあるし、TODOしか書かれてないことだってあるし、もう未完成な設計や見落としケースはしょっちゅう修正されてて、だからこそ、進化するために何度もリリースするんですよね。そのへん包み隠さないことで、フレームワークのバージョンとの付き合い方を意識するメッセージにもなってる気がします。魔改造で置き換えるより本家の修正リリースのほうが有利だとかそのへん。

まあ、FuelPHP 1.2代は、機能はいろいろあるけどOOP的に微妙な設計に感じるところもあるし、いろいろ名前が短いのはいいけどPSR-0準拠じゃなくて一貫性がなかったり、PHPUnitはいいけどコアのテストが一部メソッド空っぽ(!?)だったり ...と、人によってはまだ満足できるものじゃないと言われるかもしれません。が、より正しい道順を追って学ぶための足場として、プレーンPHPでもなく、いきなり高度なところから始まるフレームワークでもなく、ちょうどいいところにあるものなんだなと、改めてCodeIgniter系の作りの価値を再認識しました。

繰り返しますよ。この本は「フレームワークを使った今どきのWebアプリ開発のスキル標準」を「たとえばFuelPHPを使ったら」で教えてくれるものですよ。なのでこの本の思想は、他のフレームワークでもきっと役に立ちますよ。Fuelであるということに気を取られすぎなければ、これからWebアプリ開発本気出すと思ってる人なら、誰が読んでも楽しめます。もしまだ自分のホームになるフレームワークがない人がいたら、この本読んだんなら、そこを足がかりにまずはFuelPHPをゴリゴリに学んでから視野を広げていくのが、スキルアップの最短コースじゃないかなと思います。

とりあえず、本で学べる機能は吸収してと...さて僕は2.0から本気出すか(違!?

ところで二番目のフレームワークとしてのYii... だれか

P.S.
僕が最初にFuelPHPで作ったプログラムです:

https://p.twimg.com/AxDJTaHCMAICDYJ.png
https://twitter.com/tanakahisateru/status/220897717000482816

※注: アニメーションはありません。

PHPのarrayをリストとして使うときはunsetしちゃダメという話

タイトルそのまんまです。

PHPのarrayは順序付き辞書なんだけど、リストに見えちゃうのでついついやってしまうのが $a[count($a)-1] こういうの。善良なプログラマほどこの罠にかかるから、こういうときはunsetじゃなくてarray_spliceを使おうね。

PHPのinterfaceなめんな

はいタイトルは釣りです。

OOPのインターフェースはただの実装漏れチェック機能じゃないし、ましてや継承は差分プログラミングツールじゃないぞ。というのはわりと一般的な話だけど、Ruby(respond_to?でホントにいいの)とJava(インターフェースが自然すぎてユーザが意識しないのよ)が、PHPに対してOOPどうこうで偉そうに言うのはどうかなと思ったもので。まあそれと同時に、PHPの人自身がその意義を発見してるのかなという疑問もあったりしたんですけどね。

Rubyというのは「オブジェクト指向ってのはつまりメソッドに応答できるアヒルはみんなアヒルとみなせるよね」というレベルのダックタイピングで割り切った言語だと、個人的に認識しています。継承とミックスインにはis_aが応答するけど本質はrespond_to?のほうで、インターフェースを宣言してなくてもメッセージ送れたらいいあの感じ。

そんなRubyでオブジェクトが特定の機能の「セット」を実装しているかを調べて、アヒルかどうかを分岐するコードはこんなふうになります。

めんどくさいですね。おっと、ここで継承かミックスインで解決してis_aを使えばいいというのはナシです。単一継承の言語における継承はそうそう安易にできるものではないですね。OOPで設計してる人なら、本質的に意味の違うものを同じ継承ツリーの枝に入れないといけないとき、辛い思いをしたことは何度となくあるはず。

ミックスインなら同じ継承ツリーじゃない、ってことでミックスインをマーカーに使おうとするとこんな感じ。

機能的にはだいぶいいけどちょっとだけ残念。でも「ミックスインは機能の混ぜ込み」だという本来のコンセプトに反した使い方なので、人にわかってもらえにくい気がします。

いっぽう、Javaではインターフェースとメソッド実装のコピペ自動生成を分けてやることで、オブジェクトに複数の顔をもたせられます。まあその代わり、メソッドに渡す型の制約が強すぎて、アヒルを扱うにはいろいろめんどくさい子です。でもたまに型がRubyお得意のダックタイピングに勝ることもあります。

いまこれRubyのダックタイピングの例と同じ意味のことをやってるんですが、そうは見えませんね。ここちゃんとやり始めると、MLとかそっちの「型」の本質の話になってしまって、PHPをdisる人よりもっと恐い人が来るのでやめときます。分岐をコンパイル時ではなく実行時に持ってくると、こうなります。

だいぶLLっぽくなりました。インターフェースがくっついているかどうかを分岐の根拠にしたりするテクニックはマーカーインターフェースと呼ばれ、マイナーですがあります。ああでもやっぱ、型のある言語の本質は前のやつが何も意識しなくてもできることなんですよねホント... いいなぁ。

さてさて、PHPだとどうなるか。Javaのコードは手抜きしちゃいましたが、ここが本題なのでというわけで:

PHPさん意外にも超スッキリ!

PHPみたいに変数に型がない(値に型があるのとは違う意味ね)言語におけるインターフェースというのは、Javaの教科書に書いてある、「実装の制約」と「入出力型のコンパイラチェック」用ではなくて、むしろJavaでは応用的なほうだと思われてる、マーカーの意味合いが強いと思うのです。PHP で instanceof があのグローバル関数のカオスに紛れていないファーストクラスの演算子だというのは、そういう意味なんじゃないでしょうか。たしかにアノテーションの記述性が高ければそっちでも良かったぐらいのものなんだけど、それに十分な表現力を持たせようとすると、必然的にJavaのinterfaceみたいになるので、偶然にもPHPの選択は正解だったとようやく最近思っています。

たしかに、Javaみたいにコンパイル時に型の分岐が済んでいるのはありがたいのですが、オブジェクト指向以外に型理論まで意識しないといけないのは、楽しい楽しいプログラミングの本質を遠ざけてしまうと思います。これはずっと最初からRubyが教えてくれたコンセプトだと思うし、だからこそLAMPブームが起こったわけで、なので、安直に型に支配されるほうが良いとはあまり言いたくないです。(OCamlScalaの人がなんか言いそうですが、型推論は記述量を減らせても型の本質的高度さから逃れることはできないと思うのでちょっと...)

PHPのコードでもっとも大事なのは、

  • 抽象クラス => インターフェース + 実装差分
  • インターフェース + 実装差分 => 抽象クラス

というセオリーが成り立ってるということです。だだ綺麗なのが目的じゃなくて、意図が明確でトリッキーじゃないというのが大事。

僕は抽象クラスの継承がインターフェースと実装差分に分けて考えられないのは、ちょっと不健全な気がするんです。そういうのって、結局継承システムがその本質である「概念の抽象レベルの階層化」に使われず、ただの実装差分としてしか意識されなくなって、ロジックさえ全部書いてあればいいんじゃないかという錯覚に陥る危険性もあるんじゃ...という危惧があります。
やはり、継承とミックスインだけあってインターフェースがないとか、継承とインターフェースだけあってミックスインがないというのは、ちぐはぐな感じがするんですね。普通に生産的で使いやすいオブジェクト指向言語というのは、差分プログラミングするかどうかと、APIインターフェースの設計をどうするかという問題とは、直交しているべきだと思います。

たしかにPHPも、5.3まではJavaのようにちぐはぐでした(おっと5.3未満のことは言うな)が、5.4でトレイトが入ってくるので、やっとこれで役者が揃ったように思います。(クロージャという名のRunnableの無名インナークラスはすでに5.3で入ってますしね)


しかしarrayとリファレンスと文法パーザの作りはそれ以前の問題だ、という声が聞こえなくもないですが、たとえば何の取り柄もない幼馴染みがごくまれに上手にお菓子とか作ったらかわいいじゃないですか。

jEdit4.5.0の日本語リソースできました

jEditの4.5があっという間にfinalになってリリースされました。4.4preは何だったのかという...
まあ、早い段階でちょっと便利な機能が増えて安定版になってくれるのはありがたいことです。

さてそんなわけで4.5.0対応の日本語ファイル作りました。
https://github.com/tanakahisateru/jedit_gui-ja/downloads

前のからちょっと用語を変えました。禁則処理はワードラップに統一、文字を入力する文脈でカーソルと呼んでいたのはキャレットに変更してわかりやすく、という具合です。他にもいろいろと整合性がなかったり元の表現が変わったりしてたのを訂正しました。

ちなみに4.5はMac対応もけっこういい具合になってます。このバージョンから、Macで使うとショートカット用の修飾キーがあのMacのキーボードの絵になってくれてます。これはオシャレ。

で、せっかく本家がMacを意識してるので、こっちもやっとこうというわけで、Mac用の翻訳ファイルは別にしました。Macのメニューって、Windowsみたいな日本語でのキーボードニーモニックの代替手段が通じなくて「新規作成(N)(C+N)」の(N)のところがただの邪魔な文字になってしまうんですね。そこで、Mac用のファイルはニーモニック全部消しました。

CakePHP2のTwitterBootstrapプラグインがかっこいい

CSSフレームワークのような、Webアプリのフロント用ツールキットのような、TwitterのBootstrapがいい感じです。フォームのmargin/paddingの具合やプリセットの表現がほんとスマートで、やりすぎないのにすごく丁寧。

http://twitter.github.com/bootstrap/

そのBootstrapのかっこいいフォームのスタイリングなんかをCakePHPでさくっと使えるようにしたプラグインがこちらにあります。

https://github.com/slywalker/TwitterBootstrap

  1. このGitHubプロジェクトをまるごとCake2の app/Plugin/TwitterBootstrap に入れる。
  2. app/Plugin/TwitterBootstrap/webroot に bootstrap の js, css, img をぶちまけ。
  3. プラグインの中にある View/Layout/bootstrap.ctp と View/Element/alert.ctp を app/View の下の各所にコピーしてくる。

これであとは、app/Console/cake bake するとき増える適当なbakeテンプレートを選べばOK。コントローラとビューにそれぞれ、プラグインからbakeテンプレートが提供されます。

以下、ほんとに bake しただけのビューの周りをちょっとだけカスタマイズしただけのものです。

やったのはパンくずウィジェットを入れたぐらいで、アプリケーションロジックっぽいことはいっさいやってませんが、なんだか頑張った感があってかっこいいですね。もっとがんばったら、というか、あまりがんばらなくても、Bootstrapのプリセットのスタイルやアイコンを引っ張り出して来るだけで、もっとオシャレな感じにもなると思います。

エラーまで勝手にかっこよくなりました。

余談: あとで app/Config/bootstrap.php を開いてHTMLをデザインしようとしてああってなりました。ファイル名が似てるけど間違えないように注意しましょうオレ。

GitHubでプルリクエスト用ブランチを保守するメモ

GitHubにリポジトリを置いてる人はみんなプルリクエストを待っています。けどプルリクエスト用にフォークした自分のリポジトリを保守する方法が途中でわからなくなって...という人が案外多いんじゃないかなと思ったり。なので、ちょっとメモ置いときます。って、人のためみたいな言い方ですが、まあ自分用のメモです。

まずこうしたほうがいいという原則。masterブランチはフォーク元から変更せず、かならず自分用のブランチを作る。これは、masterを作業の同期用に置いておくためです。

自分のブランチでコミットしたあと、フォーク元のmasterが進んでないかのチェックは必ずすること。
もし進んでいたら自分のmasterに元作者のコミットを取り込んで自分のGitHubでのフォークが最新と同期してる状態にしましょう。で、元作者のコミットログを確認して何が起こったのかを理解しましょう。

$ git checkout master
Switched to branch 'master'
...

$ git remote add upstream git://github.com/original-developer/repository.git

$ git pull upstream master
From git://github.com/original-developer/repository
 * branch            master     -> FETCH_HEAD
Updating ...
Fast-forward
...

$ git push origin master
Counting objects: ....

$ git log

pull のまえに remote add している upstream という名前は、オリジナル版の名前です。originが自分用なので、オリジナルのほうを指す名前を o で始まる名前にしないほうがいいということで、習慣的によくこの名前が使われます。

で、もし元作者の作業がmasterで進んだのに、自分の作業ブランチが遅れたmasterを元にしてるというのはダメです。なので作業の基点をやり直すためにrebaseをしておきましょう。

$ git checkout mytopic
Switched to branch 'mytopic'
...

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: ...

ここで自分の最後のコミットとフォーク元のmasterの進化の間で競合があると、rebaseプロセスが保留されてこんなメッセージで止まります。これ初めて目にすると「あわわどうしたら」ってなりますね。でも落ち着いて。

CONFLICT (content): Merge conflict in ...
Failed to merge in the changes.
Patch failed at ...

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".

このときソースコード的には競合をマージしないといけない感じになっています。

<<<<<<< HEAD:...
自分が作業してる間に元の作者がやったこと
=======
次分が古いコードをもとに行ってしまった変更
>>>>>>> mine

とにかくこの競合を解決して両方の意図が反映されたコードにすること。それができるまで他のことしちゃダメ。というのも、このときローカルリポジトリは処理保留中の状態なので、下手するとせっかくの自分の作業を紛失しちゃったりするかもしれません。あわてないあわてない。

統合できたら保留されていたrebaseの処理を再開するように指示します。

$ git rebase --continue
Applying: ...

これで競合がなくなれば、ローカルリポジトリでの同期は完了。
あとはGitHubに自分の作業ブランチをpushします。

$ git push origin mytopic

と、ここでもし過去にrebaseされていない作業ブランチをpushしていると ![rejected] とか fast-forwards とかいう例のメッセージが出てうまくいきません。これ、いちどGitHubにpushしたはいいけどやっぱりまだプルリクエストする勇気がないからってそのままにしてたけど、っていうようなブランチでよく起こります。

そんなときは、リモートの自分のコミットをいちど巻き戻します。そこに、rebaseしてマージしたその上に自分のコミットを積んだものをpushします。

$ git push -f origin HEAD~1:mytopic
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:myname/repository.git
...

$ git push origin mytopic
Counting objects: ...
...
To git@github.com:myname/repository.git
   4400314..070e6f3  mytopic -> mytopic

...というここまでの操作を繰り返して、よし送るぞという決意が固まったらGitHubのフォームから熱い思いを綴ったメッセージとともにプルリクエストを。元の作者さんだって、コミットログが少々雑でもないよりあったほうがだんぜん嬉しいのがプルリクエストです。

以上、プルリクエストの作法、というよりは、勇気が出るまで自分のブランチをメンテナンスし続けるうえで、パニックにならないための自分なりの操作手順メモです。より良い作法なんかはもっと詳しい人の情報を参考にしてください。