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

ゆるいかんじで。かたのちからぬいて。やってます。

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

先日、「保守性・管理性が劇的に上がる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()はクラス定数もチェックできる

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()の方には書いてない。

2014年

あけましておめでとうございます。もう1月5日になってしまいましたが。

新しい年を迎えたってことで
一応人並みに?何か、一年の計というか、今年はこうしよう!みたいなことを書こうか。。。

・・・と思ったのですが。
あんまりパッとしたことというか、気の利いたことが思いつかなかったので
なんとなくツラツラと思いのままに書いてみることにします。

とは言え、何もありませんってのもどうなのよ、と思うので、個人的に今年頑張りたいと思っていることは

  • アウトプットする
  • 手を動かす

この2つ。
アウトプットについては、自分はどうしてもインプットは得意なんですが
いろいろ情報漁るだけ漁って、読んで満足、みたいなところがあるので
ちゃんとアウトプットに繋げたいなと。
あと、アウトプットするためには、自分で実際に手を動かさないと、というところで。
目標というには、じゃあどこまでできたら達成と言えるのよ?という定量的な目標ではないのですが
先日出版されたトム・デマルコ先生の「ピープルウェア」第3版にも
目標も設定しないチームがもっとも生産性が高かった、みたいな調査結果もあり
(プロジェクトマネジメントと個人の目標を置き換えれるのか、という点もありますが)
あまり具体的な目標に縛られすぎると
時代の流れが変化した時に、目標を達成することが目的になってしまうようなことにもなりかねないので
敢えてメジャラブル(測定可能)なものにせず、羅針盤的なものを持つようにしようかなと。

アウトプットという意味では
今年はもう少し会社外での活動にも積極的に関われたらなと考えています。
会社人としての自分も大事だし
立場的にも、会社をアピールしていく役目が必要ってのもあるんですが
それ以上に1エンジニアとして、業界全体に少しでも貢献したいなと。
コミュ障の自覚あるので、なかなか難しいのですが、なんとか殻を破っていきたいなと。

あとは今年ついに40歳を迎えるので
自分自身今後どう身をふっていくのか、を真剣に考えないとなぁと思っています。
自分は何かにすごいエッジな才能を持っているわけではないので
いわゆるキャリアパス的なことを考えてもなかなか自分に相応なものってのが思いつかんのですが
ただ、ありがたいことに今まで仕事で関わった人からは
また一緒に働きたいと言っていただけることが多いので
・・・自分でまだそこがどうしてそう評価していただけるのか、自分自身の強みの分析がそもそもできてないのですが
自分の強みをより活かしていける道を模索したいなと思っています。

会社では、今、マネジメント的な立ち位置にいるのですが
もしかすると、そういうところよりも
アーキテクトとか、エバンジェリストとか、そういう方向性の方が向いているのかもなぁ・・・とかおぼろげには考えているのですが。

予想通り、なんかとりとめない文章で、これといったオチもないんですが
今年もどうぞよろしくお願いいたします。

MySQL Casual Talks vol.5に行ってきた

MySQL Casual Talks vol.5
http://www.zusaar.com/event/1086003

MySQL Casual Talks、日程的に今までなかなか行けなくて、今回ようやく参加できました。
Casualといいつつ、内容はなかなかDeepだったんじゃないかなと、個人的には思いつつ。
自分の実力が以下に井の中の蛙かということを思い知らされました f^^;

誤解を恐れずに全体的なところをざっくりまとめると

  • GTIDとmemcached APIは・・・今後に期待(・・・しなければいけない、現状があるということ。。。)
  • Performance Schemaは・・・まぁoffにしておいたほうがよさそうな雰囲気

でもこの3つの(現時点では)地雷を除けば、5.6の新機能、改善は良い面も多々あるので
使える環境にあるなら、積極的に使っていけばいいのではと思います。
もしバグに当たったら、bugsに上がっていないかをチェックして、すでに報告されていたら「Affect Me」ボタンを押すと。
なかったらバグ報告あげましょう、ってことですね。OSSなのだから。

最後に、ざっと拾えたところまでですが、当日発表された資料へのリンクを張っておきます。

そうそう、うちの会社のサービスのDDLも、yoku0825さんにレビューされたら
「跪け、命乞いをしろ」と言われそうだなぁ。。。(´・ω・`)


MySQL5.6でGTIDを試してそっと閉じた
http://www.slideshare.net/Yuryu/mysql56gtid

全文検索付きMySQL5.0から5.6への移行にまつわるお話をMySQL Casual Talks Vol.5にて発表しました #mysqlcasual - Y-Ken Studio http://y-ken.hatenablog.com/entry/mysql-casual-talks-vol5-mysql-migration

ストレージエンジンであそんでみた // Speaker Deck
https://speakerdeck.com/chobie/sutorezienzindeasondemita

殿堂入りのアレ~Multi-Source Replication を添えて~
http://www.slideshare.net/do_aki/ss-27565738

20131025 my sql casual talks vol.5
http://www.slideshare.net/monry84/20131025-my-sql-casual-talks-vol5

MySQL Casual Talks vol.5でLTしてきました #mysqlcasual - nekogeruge
http://onigra.github.io/blog/2013/10/25/lightning-talked-at-mysql-casual-talks-5/

僕らのMySQL5.6移行記(仮) http://www.slideshare.net/conmame/mysql56-27565355

とあるイルカのバーボンハウス
http://www.slideshare.net/yoku0825/ss-27597161

MySQL Casual Talks vol.5 - MySQL Labs - @RKajiyama http://www.slideshare.net/rkajiyama/20131025-casual-uppt

【追記】
yoku0825さんの発表の中で、スライドに記載ない(口頭でだけ言ったこと)思い出したのでメモ。

Datetime型はVer5.5では8バイトとあるが、Ver5.6からは5バイトになった。
(これは個人的見解→)データサイズ的にはそれでもTimestamp型(4バイト)の方が有利だが、たしかTimestampは今後非推奨になるとかだったはずなので、よほどサイズに厳しくなければ、Datetimeを選択したほうがいいのでは。

varbinaryについては、kamipoさんの以下発言も。

DateTimeのインスタンス達はmax(), min(), sort()できる

PHPerのみなさん、DateTimeクラス使ってますか?
意外とまだPHP4由来の関数(date()、strtotime()など)使っているケースもよくみかけるのですが
DateTimeクラス使えばいろいろスマートにプログラム書けるし、例外処理もできる*1んで
これからはこっちを使うようにしましょうよ、と思うのです*2

で、これも意外とまだ知らない人多いようなので触れておくと
PHP5.2.2以降、DateTimeクラスのインスタンス同士を、比較演算子で直接比較できるようになりました。
http://www.php.net/manual/ja/datetime.diff.php
の例2のところに記載されています。

<?php
$date1 = new DateTime("now");
$date2 = new DateTime("tomorrow");

var_dump($date1 == $date2);  //false
var_dump($date1 < $date2);     //true
var_dump($date1 > $date2);     //false

日付の比較って、Webアプリケーション書いていると大抵必要になるシチュエーションだと思うので
この書き方ができることを知ってると、読みやすくスマートにコード書けるんじゃないかなと。

で、さらにこの「DateTimeクラスのインスタンス同士は比較演算子で直接比較できる」ことの帰結として
2つのインスタンスを比較できるということは、もっと多数のインスタンスがあれば、それらも比較できる。
つまり、max(), min(), sort() といった関数にDateTimeクラスのインスタンス(の配列)を渡すこともできます。

<?php
$date1 = new DateTime;
$date2 = new DateTime('Yesterday');
$date3 = new DateTime('Tomorrow');
$dateList = array($date1, $date2, $date3);

//max()
var_dump(max($date1, $date2, $date3)); 
var_dump(max($dateList));
//min()
var_dump(min($date1, $date2, $date3));
var_dump(min($dateList));
//sort()
sort($dateList);
var_dump($dateList);

実行結果

object(DateTime)#3 (3) {
  ["date"]=>
  string(19) "2013-10-22 00:00:00"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}
 
object(DateTime)#3 (3) {
  ["date"]=>
  string(19) "2013-10-22 00:00:00"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}

object(DateTime)#2 (3) {
  ["date"]=>
  string(19) "2013-10-20 00:00:00"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}

object(DateTime)#2 (3) {
  ["date"]=>
  string(19) "2013-10-20 00:00:00"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}

array(3) {
  [0]=>
  object(DateTime)#2 (3) {
    ["date"]=>
    string(19) "2013-10-20 00:00:00"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(10) "Asia/Tokyo"
  }
  [1]=>
  object(DateTime)#1 (3) {
    ["date"]=>
    string(19) "2013-10-21 01:01:03"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(10) "Asia/Tokyo"
  }
  [2]=>
  object(DateTime)#3 (3) {
    ["date"]=>
    string(19) "2013-10-22 00:00:00"
    ["timezone_type"]=>
    int(3)
    ["timezone"]=>
    string(10) "Asia/Tokyo"
  }
}

max()、min()とかは、例えばいくつかの日時候補があって、そのうちもっとも現在日時に近いものを採用したい、というケースで使えます。
ソシャゲでいうと、レイドボスの討伐期限が普通はエンカウントして2時間後なんだけど、イベント終了やメンテナンスがある場合は
その日時と比較して、もっとも現在日時に近いものを討伐期限として採用する、みたいなことができます。

*1:例えば、strtotime('hoge')のように日付書式として正しくない引数が与えられた場合、strtotime()はfalseを返します。DateTimeのコンストラクタはExceptionをthrowします。

*2:PHP5.5からは、インスタンス生成時以外値を変更できない(代わりに新しいいインスタンスを生成して返す)DateTimeImmutableも使えます。個人的にはこちらの方がお勧めです。

「これは罠。PHPでiPhone端末にPUSH通知を送る際の落とし穴」は(一部)罠

最近、今更ながら「数学ガール」にハマっていて、ゲーデル不完全性定理の自己言及っぽい釣りタイトルにしてみました(^_^;)
大学、大学院と数学やってましたけど、
もう数学勉強しなくなってずいぶんたつしキツイかなと思ったんですが
三つ子の魂百までというか、昔取った杵柄というか、読み始めれば以外とすっと入っていけました。
もちろんこの本の構成のうまさと物語の面白さもあると思うんですけどね。おすすめの本です。

という前置きはさておき。
業務でiOS のPUSH通知を扱うことになり、いろいろと調べてていきついた記事が

これは罠。PHPiPhone端末にPUSH通知を送る際の落とし穴 | 株式会社LIG
http://liginc.co.jp/programmer/archives/2355

これだったんですが。
1年以上前のエントリーなので、もしかしたら当時とは状況違うのかも、というところも前置きしつつ。
自分がさらに色々調べた感じ、このエントリーにある

1回の通信で全パケットが5000〜7000バイトを超えるとAPNSから切断される

については、どうやらそのような制限はないのでは、という結論に至りました。

実際、この記事についているブクマコメントやTwitterをみると、少数ながら懐疑的な意見もあった模様。
ただ、それ以上に記事を鵜呑みにして拡散しているものも多く、実際google検索でも上位にヒットするので
ちゃんと真偽を確かめたほうがいいのでは、と思い、この記事を書くに至りました。

で、詳しい数値は一般公開ブログなので記載は控えますが、
ここに書かれてる数字よりかはかなり長いバイト長のパケットを送っても、
現状APNSから切断されるという事象は確認していません。

ただ、じゃあ無制限にゴンゴン送れるのかというと、それもそうでもないようで
このエントリーにも記載されているPHP実装の有名なライブラリ「ApnsPHP」GitHubのIssueにこんな書き込みが。

ApnsPHP too fast for apns · Issue #2 · duccio/ApnsPHP · GitHub
https://github.com/duccio/ApnsPHP/issues/2

要約すると、
「あまりにも速く送りすぎるとどうもエラーになるんで、
1メッセージあたり50ミリ秒くらいインターバルおいたらうまくいくみたい」
というところ。
斜め読みならぬ斜め翻訳なので間違ってたらごめんなさい。。。

で、実際、ApnsPHPの実装も、2012年10月29日の修正で、デフォルトで1メッセージ送ったあとに10ミリ秒sleep入れるようになっていました。
また、上にあげたIssueのコメントに、Apple公式ドキュメントからの引用があり、そこでは
少なくとも秒間9000メッセージは送れるよ、とあります。
この数値から逆算すると、1メッセージあたり10〜50ミリ秒おいた方がいい、てのもそうなのかなという気がする数字。
計算上は約110マイクロ秒くらいでよさそうだが、多少余裕をみているのだろうと思います。

なお、元記事のフルスクラッチのコードでは、5000バイト送るごとに一旦コネクション閉じて再度開く、みたいなことをしていますが
この部分は、PUSH通知送る件数が多いと、パフォーマンスかなり悪くなる要因になると思います。
なので、現時点は、素直にApnsPHPに任せたほうがいいかと思います。

PHPカンファレンス2013行ってきました

どこかの社長さんが「IT勉強会は意味ない」的な事を言って、一時話題になりましたが
個人的にはこういう勉強会というかカンファレンスはいろいろ刺激があって
それだけでも十分に価値あるなぁと毎年思っています。
関係者の皆様、素晴らしい機会をありがとうございました。

で、詳細はきっといろんな人がいろいろ書いているでしょうから
個人的に気になったところだけ、メモ書きレベルですが書き残しておきます。

スライド資料はすでにアップされている方も多いので、タイトルでググればでてくるんじゃないかな(手抜きですまん)

基調講演 PHPの今とこれから2013

JSONライセンスの件、知らんかった。少し前の話みたいだが、現状影響あるのだろうか・・・
PHP5.6 来年6月ごろか。現時点で確定機能は演算子オーバーロードとGMP?

Zend OPcacheの速さの秘密を探ろう

すごくわかりやすかった。
op codeキャッシュの前に最適化フェーズがあるからAPCよりも原理的に早くなりやすいのね。
やってることはgccコンパイラがやる最適化に似てる、がそれらよりはあまり機能はないらしい。
PHP5.4以降でかつAPCのKVS機能使ってないなら、こっちの方がいいかも。

安全なPHPアプリケーションの作り方2013

毎年恒例徳丸さんの発表。
今年も期待を裏切らない素晴らしい内容でした。
HTML5XSS(DOM)は、少し前に別の人の記事で見たけど
文字列連結よりも、ちゃんと真面目にDOM操作関数使って、setAttribute()なりした方がいい。

個人的にはデモで使っていたツール(Burp Suite?だったかな)が気になった。
あと、Windowsでもmacみたいにズームアップするやつ。あれも前調べた気がしたんだが、何だったか忘れた。
また後で調べておこう。

MySQL Adminが見たDevsの常識、DBAは非常識

発表を聞いていると、まだまだDevsとDBAの間の(知識的な)溝は大きそうだなぁ・・・と思いつつ。
いるいる、こういう無茶言うやつ、みたいなね。

で、発表の中で自分もちゃんと理解できてなかった部分。

EXPLAIN文は基本的には実際のSQL(後続のSQL)は実行しないが、相関サブクエリの場合は内部のSQLは実際に実行する
→EXPLAIN文が帰ってこないのはだいたいこのパターン
(昔やらかしたことあるわ、これ・・・)

クエリキャッシュはマルチコアCPUの場合並列性が悪いので使わない方がいい。Ver5.6からはデフォルトオフになった
→これは別の理由でオフのほうがいいというのは聞いたことがあったが、今後はもうオフが望ましいということなのだろう。

Vagrantで作るPHP開発環境 [実践編]

今まさにVagrant使い始めたので、とても勉強になった。電子書籍も今度買おう。
Vagrantfileはシェルで書いてもいいのね。Chef-soloといきなりまぜて使って、おいらもいろいろハマったわ^^;

.vagrant ファイルは .gitignoreに登録するのを忘れずに。

syncd_folder、そうこの機能、最初とりあえず入れた時にすごく便利で感動した。
以前VirtualBoxとかVirtualPCとか使ったことあるけど、
同じPCの中にあるのに、FTP/SFTPでファイルアップとかなんか腑に落ちない感じがしてた。
この仕組みが一番素晴らしいんじゃないかと思う。

フレームワークアップデート

LaravelとPhalconは知らなかった。
Phalconはすごい気になる。PECL拡張実装ならそりゃ早いわな。今度試してみよう。

LT

PHP5.5以上必須のフレームワークCOSMOSってのがあるらしい。こちらも気になる。