読者です 読者をやめる 読者になる 読者になる

ありがとう。また会おう。

まぁゆるりとやっていきますよと。

「足し算の順序」アナタは大丈夫?

MySQL

この記事は MySQL Casual Advent Calendar 2015 の20日目です。

1ヶ月ほど前ですが、こんな記事がネット上で話題になりましたね。
r25.yahoo.co.jp
togetter.com

個人的には、算数(数学)と国語の授業を取り違えてるんじゃないかな・・・と思ってもやもやします。
数学は抽象化して扱うから、様々な定理・公式が使えるというのに
小学生どあたまの教育でこんな風に教えるんじゃ、ますます算数・数学嫌いを増やすんじゃないかと危惧したりするのですが・・・


ところで。
MySQL(に限った話ではないのですが)では、この「足し算の順序」が重要になる場合があります。

AWS上のMySQLであるRDSでは、タイムゾーンの設定がデフォルトでUTCなので、NOW() 関数を使うと 日本の標準時間(JST)とは9時間ずれた日時が出力されます

※サーバシステム時刻を確認

$ date
Sun Dec 20 12:01:54 JST 2015

※RDSに接続し、NOW()関数を出力

$ mysql -u norii -p -h norii-db.************.ap-northeast-1.rds.amazonaws.com
mysql> SELECT NOW();
+---------------------+
| NOW()               |
+---------------------+
| 2015-12-20 03:02:19 |
+---------------------+
1 row in set (0.01 sec)

なので、これを補正するには、9時間ずらす必要があります*1

mysql> SELECT NOW() + INTERVAL 9 HOUR;
+-------------------------+
| NOW() + INTERVAL 9 HOUR |
+-------------------------+
| 2015-12-20 12:02:29     |
+-------------------------+
1 row in set (0.00 sec)

時に、DBにあるデータに対し、「1ヶ月前」の日時が必要になることがあります。
素朴に現在日時に対する「1ヶ月前」を、上記の要領で求めると

mysql> SELECT NOW() + INTERVAL 9 HOUR - INTERVAL 1 MONTH;
+--------------------------------------------+
| NOW() + INTERVAL 9 HOUR - INTERVAL 1 MONTH |
+--------------------------------------------+
| 2015-11-20 12:02:41                        |
+--------------------------------------------+
1 row in set (0.00 sec)

となります。ここで、「+ INTERVAL 9 HOUR」と「- INTERVAL 1 MONTH」の順序を入れ替えてみます。

mysql> SELECT NOW() - INTERVAL 1 MONTH + INTERVAL 9 HOUR;
+--------------------------------------------+
| NOW() - INTERVAL 1 MONTH + INTERVAL 9 HOUR |
+--------------------------------------------+
| 2015-11-20 12:02:48                        |
+--------------------------------------------+
1 row in set (0.00 sec)

NOW() 関数通してるので秒は実行のタイムラグの分ずれてますが、基本的には同じ日時を指し示しています。

ですが、この計算式は、実行する日時によっては、等値になりません。

たとえば、このSQLを 日本時間の 12月1日 1:00 (UTC では 11月30日 16:00)に実行したとしましょう。
(以下ではNOW()関数ではなく、日時をリテラルで渡しています)

mysql> SELECT '2015-11-30 16:00:00' + INTERVAL 9 HOUR - INTERVAL 1 MONTH;
+------------------------------------------------------------+
| '2015-11-30 16:00:00' + INTERVAL 9 HOUR - INTERVAL 1 MONTH |
+------------------------------------------------------------+
| 2015-11-01 01:00:00                                        |
+------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT '2015-11-30 16:00:00' - INTERVAL 1 MONTH + INTERVAL 9 HOUR;
+------------------------------------------------------------+
| '2015-11-30 16:00:00' - INTERVAL 1 MONTH + INTERVAL 9 HOUR |
+------------------------------------------------------------+
| 2015-10-31 01:00:00                                        |
+------------------------------------------------------------+
1 row in set (0.00 sec)

と、なんと1日ずれてしまいました。

まぁ考えてみれば当たり前の話で
1ヶ月の日数は、月によって異なるので
上記のSQLで、先に9時間足すと、日付またいで12月1日なるので、その1ヶ月前で11月1日になる
先に1ヶ月減算すると、10月30日になって、そこに9時間足すことになりますが、10月はもう1日ありますから、10月31日になると。

Webアプリケーションで集計組む場合は、プログラム側から日時を渡せばいいですが
ストアドプロシージャでこのような日付周りを扱う場合は、地味にハマるかもしれません。

・・・というか、地味にハマったんでこのエントリ書いたんですけどね(´・ω・`)
なんで素直な順番で書けばなんにも問題ないのにわざわざ順番変えちゃったんだろう。。。

*1:Webアプリケーションから扱う場合は、MySQLのNOW()関数などは使わず、アプリケーション側で日時リテラルを組み立てて渡すべきです

12/13 Symfony Meetup #7 & 「Symfony2入門」読了

もうひとつ12月に参加したイベント。Symfony Meetup #7

symfony.doorkeeper.jp

久々にあまり知り合いのいないイベント参加で若干緊張しました。
そういえば久しぶりの六本木ヒルズでした。昔は毎日通ってたってのが信じられないw(通勤距離的な意味で)

発表資料や当日の様子はきっと誰かがもう書いていたり
Twitterハッシュタグ #symfony_meetup をみればわかると思うので省略して。

Symfonyは今業務でバリバリ使っているのですが
体系だてて勉強したわけではなく、必要に迫られて必要なところを調べる、みたいな形で知識をつけてしまったので
今ひとつちゃんと使いこなせてないんですよね。
(しかも、自分が設計したシステムではなく、今のプロジェクトに途中からジョインしたので)

で、ここで聞いた話や、後述しますが、「Symfony2 入門」を読んでいて
ほんとまだまだ全然便利な機能使いこなせていないなぁ、というのを痛感しています。

@hidenorigoto の発表だったか質疑応答のときだったか
ちょっと記憶が曖昧なのですが
フレームワークの選定の話で
それなりに大きなシステムを組もうとすると
きちんと設計できるのはSymfonyかZendくらい、と言っていたのが印象的で。
というのも、自分もそれなりに今までいろんなフレームワーク触ってきたのですが
CakePHPやCodeIgniter、FuelPHP は、そのあたり難しいってのは同意で。
もちろんそれに向いたシステムってのもあるので、どちらが優れているか劣っているかという話ではなく
そのビジネスで解決したい課題に適した道具を使いましょう、ということではあるのですが。

で、SymfonyやZendが大きなシステムに向いているってのは、ひとえにDB関連がActiveRecordではなく
Data Mapper 使っているところだと。
(Doctrineも1の頃はActiveRecordでしたけど、2はData Mapperになったので)
Data MapperはActiveRecordの手軽さはないですが
その代わりビジネスに要求されるような複雑な要件を、適切にモデリングして扱う上では
やはりこちらの方式のほうが素直に組めるんですよね。
ActiveRecordだとどうしても無理しなきゃいけないところが出てきてしまう。

このあたりは、PofEAAの知識があると腹落ちしやすいと思うんですが
ちょっと初学者には敷居が高いってところが、学習コストなのかなとか思っていたりします。

で、ちょっと時間に余裕があればLTできるかなとおもって、現場で仕込んでみたのですが時間切れだったのでスライドだけ上げました。

www.slideshare.net

これ、実際業務に使ってるんですが
最初その問題を解決するのに、Twigのドキュメント見て、この関数使えそうじゃん!って思い
Google先生を引いてみたんですけど、びっくりするほど情報無いんですよね。公式ドキュメント以外。
かといって、使うとヤバイ的な話もないし。
単にあまり光があたってないのかな、と思ったので話題にしてみました。

発表できずに終わるのも悲しいので
なんか別の機会があれば、これともう少し話を肉付けして、どこかでしゃべろうと思います。


で、もうひとつの話題の「Symfony2 入門」

基本からしっかり学ぶ Symfony2入門

基本からしっかり学ぶ Symfony2入門

Symfony2は今まで専門書籍、という意味ではあまりなかったんですよね。
効率的なWebアプリケーションの作り方 ~PHPによるモダン開発入門 には触れてる部分あることはあるんですが
体系的に学べる、という意味では初の書籍かと。

で、端的に言って、今業務でSymfony扱っている人は必携の本ではないかなと思います。
理論の部分と実践の部分がうまく融合されていて、
とてもわかりやすくまとまっています。
特にSymfonyは今まで初学者には敷居が高い、学習コストかかるという印象があったと思うのですが
この本1冊読み進めていけば、きちんと基礎力つくと思います。

自分もこの本を読んでいていろいろ発見があって。


あと、7章のAPI Docの生成とかもいいなぁと。今あるプロジェクトでも隙をみていれたいな、と思ったり。

SymfonyはWebのリソースが豊富なので
今までは事実上それがドキュメントだったわけですが
体系的に学べる本が出版されたというのは本当に大きいと思います。

自分のエンジニア魂に火がつくような、素晴らしいイベント&書籍でした。

12月7日 GLT(Genesis Lightning Talks) Vol.49 で話してきた

最近は年末の風物詩?となった、「GLT Vol.49」にてLTしてきました。スライドは以下。

www.slideshare.net

GLTはここ最近、年1開催だったので
どうしても同窓会ノリで近況報告になってしまいがちで、これもまぁそうなんですが。

ネタの発端としては、昨年のGLT Vol.48 にて、懇親会の時に彼女の話になって
こっちの話のほうがLTのネタになるじゃん、みたいなことを言われていたので
じゃあ1年越しにそれをネタにしようかと。
・・・というのがネタフリで、いかにも喋るような体にしておきながら
実際は弊社絶賛エンジニア募集中だよ!って言いたいのを延々喋って、ちょうど5分時間切れになる、という
最近ではこの手の落ちも使い古しではありますが、「時間切れ狙い」というオチでした。
(最後のほうのスライドで、スーパーマリオの絵があるのは、以前のGLTは1分前にマリオのhurry up音
 時間になると、1 down音が流れる仕様だったので、それにあわせてのネタ)

で、スライドの本題の方は、ここでわざわざしゃべるつもり無いのですが(笑)
(それこそどこかの懇親会でツッコんでください)
エンジニア募集の方は、ほんとに真面目に募集しています。

事業ドメインとしてはなかなか手堅いところを抑えていて
まだまだ事業拡大中という状況で、
その一方、エンジニアは今超売り手市場なので、なかなかいい人材と巡り合うのが難しいんですよね。
ましてや弊社も特にエンジニア界隈では全然無名な方だと思うので
(あまり外の勉強会に積極的にでることもなかったので)
そこは自分がある程度スポークスマンになって、動こうかなと思っており。

技術的には、超最先端を常に追っていきたいとか、一発勝負出て大儲けしたい、という人には向かないですが
堅実に末永く腰据えてエンジニアリングに取り組みたい方
特に、音楽系、最近はスポーツ系も取り組み始めているので、そのあたりに興味ある方であれば
とても向いてると思っています。

なので、このブログで改めてという感じで
こういったビジネスのシステム開発・運用に興味あるなぁという方は
TwitterでもFacebookでも構いませんので、お気軽にお声がけください。

そうそう、GLTもいよいよ次回で50回!なんですね。
このイベント自体が発足した当時を知るものとしてはなかなか感慨深い。
もう、あの当時あの会社にいた人もすでに別の場所で活躍してる人も多くなりましたが(というか、残ってる人がいない・・・か?)
これだけ継続している事自体、コミュニティの力はすごいなと思います。
GLTがなければ出会うこともなかった人もほんと多いですし。

会場提供いただいたドワンゴ様、運営担当の皆様、ありがとうございました。

レコードがなかったらINSERTして返すみたいなのをもっと確実にやる

元ネタ

レコードがなかったらINSERTして返すみたいなのを確実にやる | おそらくはそれさえも平凡な日々
http://www.songmu.jp/riji/entry/2014-03-02-find-or-create-surely.html

このソースコードの処理だと

# エラーが発生していて重複エラーだったら取り直す

# ロックかけたいときは取り直す

の処理の間に、該当レコードがDELETEされてしまうと
空行にFOR UPDATEしてしまい、ギャップロックの悪夢再び、になってしまうかと。

どうしても確実にやりたい、でも、ON DUPLICATE KEY UPDATEも
INSERT IGNOREも、(元ネタには言及ないけど)REPLACE INTOも嫌!ってことなら
「ロック専用テーブル」を作るのがいいのではないかなと。

処理をかけたいテーブルと同じPKを持つテーブルを作る。(複合キーなら同じく複合で)
このロック専用テーブルには他のカラムは要らない。

で、トランザクションの最初に、
ロック専用テーブルにこれから処理しようとしているデータのPKをINSERT。

本来やりたい処理(レコードがなかったらINSERT)を行う

ロック専用テーブルにINSERTしたデータを削除してからコミット

こうすれば、いけるんじゃないかしら。
並行スレッドは、処理をしようとしても、最初のロック専用テーブルのINSERTに失敗するから
処理できないはず。
一方、ロック専用テーブルにはPKを直接指定してINSERTしてるので
このケースの時はネクストキーロックはかからないんじゃなかったかな。。。ちょっと記憶が曖昧。
実際動作確認したわけじゃないので
嘘書いてたらごめん。

まぁ、このためだけに、一見何も入ってないテーブル
トランザクション開始時にINSERTして、コミット直前にDELETEしちゃうから)
を作らなきゃいけないってのがうざいので
許容できる状況なら ON DUPLICATE KEY UPDATEがおすすめかな。

退職のご挨拶

2014年8月末で、現職の株式会社トライフォートを退職することになりました。
本日(8月25日)が最終出社のため少し早いですが、退職エントリーを書きます。

トライフォートでは最終的にはサーバサイドエンジニアを束ねる部門
インフラエンジニア束ねる部門、2つの部門長という肩書で活動をしておりました。
身に余る光栄であるとともに、短期間で会社を去る決断をしたことについては
関係各位にはご迷惑おかけすることをお詫び申し上げます。

トライフォートに入社したのが、2013年の9月で、ちょうど在籍は1年ということになります。
終わってみれば、たった1年だったのですが
1年だったのか!?と自分でも思ってしまうくらい
この1年はとても勉強することも多く、実りも多く
自分の職歴では最短の在籍期間となったものの、得たものは本当にたくさんあった
充実した1年間であったと思っています。

サーバおよびインフラ部門の長として
マネジメントとして心がけていたことが2つあります。

1つは、書籍「Team Geek」に取り上げられている「HRT」です。
Humility(謙虚)
Respect(尊敬)
Trust(信頼)
現場のメンバーと謙虚に向き合い、尊敬し、信頼する。
言葉で言うのは簡単ですが、実践するのはなかなか難しい。
時には「これ自分がやった方が早えし」とか「ちょwおまw」と思ってしまうこともあるんですが
できるだけそこは堪えて、
皆の心(Heart)に届くマネジメントをしてきたつもりです。

もう1つは、「情報の共有、アウトプット」です。
トライフォートのエンジニアは、技術レベル高い人が揃っていると
贔屓目にみても思ってはいるのですが
ただ、情報を共有する場があまりなかったり、アウトプットを積極的にする文化がまだ足りないと感じていて
そこは力を入れて仕組み、仕掛けをいろいろしてきました。
「社内Lightning Talks」なんてのも始めて
普段は人前で発表しない人にも、強制的に発表する場を仕掛けたりもしました。
正直最初は反発もあるかな…と危惧していたのですが
初めて見ると、意外とみんなそれぞれにアイデアをだして良いネタを披露してくれて
この人はこういうところに興味が向いてるんだなという発見もあったりで
始めた当初の想像以上に、良い効果が出てるんじゃないかなと自負しています。

ただ、アウトプットに関して言うと、やりきれなかった部分として
社内にとどまらず、社外に発表できるレベルまで引き上げたかったな...というところが心残りです。
というか、内容的には社外に発表しても問題ないものも多いのですが
恐らく文化的な部分で、社内向けだからということで
ちょっと詰めの甘い部分があったり
あとは社内PJに関する情報が多くて、公表できないだけ、というのもあり
それはもうちょっとエッセンスを抽出すれば、公表して、
それもまた一つ会社のバリューにも、そのエンジニアのバリューにもなると思うのですが
そこまで組織力を持ちあげられなかったのが、自分の力不足を痛感している次第です。

ほんとはもう少し有休残ってたので
のんびりできたらという気持ちもあったのですが
諸々事情があって、休暇も取れず、この時期になってしまったのですが
8月25日に最終出社というのは、ちょっと思うところもありまして。
25日なので、給料日なんですよね。
事情あって、退職公表から最終出社まであまり時間がなかったので
せめて、最後の給与明細くらいは、部門長としてきちんと手渡したいなという気持ちもありました。
(何人かは夏休み中で叶わなかったのですが)
きょうび、給料明細なんて、単なる記録でしかないので
特別な思い入れなんか無い人が多いのかもしれないですが
やはり現場のみんなが尽力してくれた上でのお給料ですので
今までの感謝の気持ちを込めて最後の明細をお渡ししたかった
・・・そんな思いもありました。

退職理由については、退職エントリとしてはもはや常套句ですが
「音楽性の違い」とだけ記載しておきます。
(それにしても便利な言葉だw これ最初に退職エントリで言ったの誰だろう... 起源を知りたい)

次の職場でも、相変わらずサーバサイドのエンジニアはしています。
ただ、ここ半年くらいはほぼマネジメント寄りだったので
手を動かすってことに対してちょいと鈍っているので、勘を取り戻せるかが若干不安だったりもしますが...
まぁ、なんとかなるでしょう(笑)

株式会社トライフォートの皆様、および業務にて関わった皆様、本当にありがとうございました。

のりぃ流、保守性・可読性の高いコードの書き方

先日、「保守性・管理性が劇的に上がるPHPのスマートなコードの書き方」という某社のブログエントリが話題になってましたが
それについては、もういろんな方がいろんな言及をしているので
改めて僕が言及することも無いと思うので。

で、じゃあ自分ってそういう「人に読まれること」を前提にしたコード書く時
(仕事上のプログラムは99%そうだと思うのですが)
どんなことに気をつけてるか、ブログ書いてみようかなぁ…とFacebookにぽつと書いたら
意外と需要ありそうだったので、つらつらと書いてみた。

といっても、そんな特別なことはしてない・・・と思ってます。
あと、プログラム設計上こうすべき、とか、もあることはあるんですが
それよりも、もっと「これだけは心がければ」という根本的なポイントだけ。
実際、僕がいろいろなソースコード見てて、読みやすいな、メンテしやすいなと思うのも
このポイント抑えてあるものが多いので。

英単語を省略しない

昔ながらの慣習で、返り値用の変数を「ret」「rtn」とか、
msgとかstrとかはまだ可愛いと思うのですが
例えば、「カテゴリ」を「Ctg」みたいな、母音を抜いて省略する表記を多用されると辛いなと。
で、これがスコープ範囲狭いローカル変数ならいいんですが
クラス名とかでこういう省略をされると結構厳しい。

一昔前の、iアプリ出始めの頃のプログラミングならそういう省略も必要だったでしょうが
もうきょうびそういうのはいいんじゃないかなと。*1

英語のスペルミスをしない

英単語を省略しない、てのとも近いのですが、地味に気になるのがこれ。
率いる人の意味の「リーダー」を「reader」と平然としてあったり。
ガラケー全盛期によくあったのは、携帯キャリアの「Carrier」を「Career」(こっちは経歴の意)とか。
アバター」も「Avater」って頻出間違いパターン。(正しくは「Avatar」)

複数形変化の間違いも多いっすね。「Abilitys」とか。(正しくは「Abilities」)

こういうのが積もり積もると、地味に読みにくい。ストレスになる。

例えば、コーディングしている環境が、セキュリティの都合上、インターネットに繋がりません
ってのであればしょうがないですが
きょうび、英語のスペルなんて、Web辞書で1分もあれば調べられるじゃないですか。
さらに言えば、今どきのIMEカタカナ語辞典ってのがあって、
「いんたーねっと」って打てば「Internet」が候補にでてくるでしょ。
スペルチェック機能があるようなエディタやIDEもあるでしょうし。

で、ここが大事なところで、一番言いたいところなんですが
そういう細かいところに行き届かない人が書いたコードって
実際のプログラムも、動作的に行き届いてない、残念なものが多いような傾向があるように思います。

あと、いい加減、IT業界最頻誤用英語「regist」*2も撲滅したいなぁ。。。
(registという英単語はありません。正しくはregister)

同じ概念を示すものは言葉を統一する

例えば、課金を扱う処理を書いていて
あるところでは「Payment」って単語が使われているんだけど
別のところでは「Purchase」が使われているとか。そういうこと。

ソシャゲ業界あるあるとしては、「ガチャ」が「Gacha」だったり「Gatya」だったり。
そういう表記ゆれを許さない。統一する。

以前の仕事で、自分が某ソシャゲを設計した時は
最初に「用語集と使用英単語」の表を作ってました。
「風」は「wind」を使いましょう(airではなく)とか。

ここまで3つは、プログラムとは全然関係ない
どちらかというと、英語力というか、それ以前の(日本語で文章書く時だって同じ問題あるし)
表記ゆれをさけるとか、そんなことばっかですね。
人によっては、そんなの下らねえよ、って思う人もいるかもですが
こういったところにきちんと行き届いているソースコードって
ほんと読みやすいし、メンテしやすいですよ。


これだけでも充分かと思うのですが、一応プログラムに関したことも2つほど。

ネストをできるだけ抑える。elseもできるだけ避ける

有名な「オブジェクト指向エクササイズ」というやつにもでてきますが
できるだけネストを避ける。
できれば1段階まで。
許容できたとしても3段かな。
その3段全体が、エディタ1画面で収まるボリュームという前提で。
それ以上になるようなら、そもそも設計がおかしいです。

elseもできるだけ避けたいですね。
returnで早返しするテクニック使えば、結構elseは削減できるはず。

関数・メソッドの引数の数をできるだけ抑える

これも、個人的な理想値は2つまで。
座標系を扱うコンストラクタだと、3つ4ついっちゃうけど、それは例外かな。
これも、引数が5個も6個もいるような関数・メソッド
そもそも設計がおかしいことが大半だと思ってます。

まとめ

もちろんもっと細かいルールとか、先人の知恵を踏襲すべきところは
たくさんあるとは思うのですが
そういうのは「リーダブルコード」とか「リファクタリング」とか
「Clean Code」読んでね、ということにして。

ネストの話と引数の話は、やや付け足し感あるのですが
その前の、命名に関する部分はほんとすごく大事だと思ってます。
ソースコードは書くことよりも読むことのほうが圧倒的に多いので
それこそ、ブログ文章を校正するのと同じように(校正しない人も多そうだけど)
ソースコードもそういう意識で書いていくと
それだけでも、だいぶ読みやすいコードになるよ、と思っております。

おまけ

最初に触れない、と言っておきながら、やっぱ事の発端になったブログの件。
超カンタンにだけ触れると。

  1. カッコの省略 原則ダメ。*3
  2. 三項演算子 あれは例が悪い。ネストはダメ、節度もって使うならあり。
  3. switch文 ポリモーフィズム使え…という人もいて、そうした方がいい時ももちろんあるけど、そこまで複雑性持ち込まなくて良い場合はswitchでもいいかと。
  4. for文 これも例が悪い。でも他の人も指摘してるけど、そもそもPHPだとforeach使うほうが圧倒的に多いのでは?
  5. 配列への要素追加 array_push()そういやそんな関数あったねw
  6. 引数のデフォルト値 例が悪すぎる
  7. global宣言 これは全力でダウト。ダメ、絶対。
  8. 条件式での代入 これ、今どきならIDEが警告するっしょ。これも原則ダメ。
  9. 文字列への変数挿入 僕ならsprintf()使う。
  10. empty() PHPの暗黙の型変換という闇の世界に誘われるよw 原則、イコール3つの厳密比較使うべき
  11. 再帰処理 再帰自体はもちろんいいんだが、この他の11個の並びと比べると、この中に再帰がでてくるのは違和感ある
  12. 結合代入演算子 これも例が悪くて、変数の使い回し自体が問題かな。あと、ピリオドって見落としやすいからそもそも可読性悪くない? なのでsprintf()派。

*1:自分はサーバサイドのプログラマなんで、ネイティブ側だとまた事情違うかな。パフォーマンス最重要ってケースもあるでしょうから

*2:あと「エンカウント」もありますね。encountって英単語はない。encounterが正解

*3:単にreturn、break、continueするだけの時はついやっちゃいますが

defined()はクラス定数もチェックできる

PHP

define()で定義する(グローバルな)定数が、定義されているか否かをチェックするdefined()関数
http://php.net/manual/ja/function.defined.php
ですが、この関数、実はクラス定数に対しても使えます。
(Version 5.4.17にて確認)

<?php
class Hoge
{
    const FUGA = 1;
}

var_dump('Hoge::FUGA'); // 出力bool(true)
var_dump('Hoge::BAR'); // 出力bool(false)

定数の値を返す constant()関数
http://www.php.net/manual/ja/function.constant.php
には、

この関数は クラス定数に対しても動作します。

って明記されてるんですけどね。
なぜがdefined()の方には書いてない。