2010年12月28日火曜日

仕事で使う言語の条件(1)

似たようなエントリは何度か書いてますが。

出稼ぎでの実装やら、今までの後始末経験を踏まえて、
「仕事」での理想の言語を考えます。

  • 未定義変数をいきなり参照する(代入式の右辺で使う)とエラー(例外)が出なければならない。
    • 極めて当たり前の話の筈が、PHPではNotice
  • 関数の内側から、グローバル変数を使うには、特殊な宣言がなければならない。
    • 勝手に外部スコープを参照しちゃうのは読みにくい。
    • 非オブジェクト指向での実装を助長している気がします。「カプセル化」に逆行する挙動。
  • クラス関数(メソッド)内部で、クラス変数(プロパティ)を使うには、this経由でなければならない。
    • 勝手に外部スコープを参照しちゃうのは読みにくい。
    • グローバル変数への参照と区別が付きにくい。「判るに決まってるだろ!」とか言わないように。
  • mixinのための多重継承。http://ja.wikipedia.org/wiki/Mixin
  • 動的型付け。
  • 関数が第1級オブジェクトでなければならない。http://ja.wikipedia.org/wiki/%E7%AC%AC%E4%B8%80%E7%B4%9A%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 
    • create_functionとかあり得ない。
  • 関数の可変長の引数の受け渡しを、自然な構文で運用できなければならない。
    • func_get_argsとかva_argsとか駄目だと思うわけですよ。
  • 必要であれば、バイトコードの保存/利用も可能であること。
  • 例外処理のサポート。
  • Unicodeサポート。
    • 機能が使える、だけじゃ無意味。プログラマが意識せずとも、任意バイト文字をそれぞれ同じように扱えないと困る。
      • PHPでは変数の中身をプログラマが区別して運用しなければならない、シングルバイト文字はstrlenで、マルチバイトはmb_strlenで、エンコーディングはmb_languageでとか、テンでバラバラ)
    • 比較的理想に近いのはpythonのstr及びunicodeオブジェクト。両者、同じ操作メソッドを持つし、相互変換も容易。
ハイ、聡明な皆さんならもう判りましたね。pythonの宣伝です。

pythonは所謂スクリプトなので、というわけではないのでしょうが、protected/privateとかが有りません。これらは「カプセル化」って奴で、「オブジェクト指向」で重要ってことになってるファクタです。ただし小生はカプセル化を重要視してません。

2010年12月26日日曜日

mercurialのススメ(2)

筆者は5年ほど前から
バージョン管理はmercurialで統一しました。
http://mercurial.selenic.com/
利用当初は0.6だったと思いますが、今や1.7.2。
あのGoogle Codeですら採用しています。

subversionを使ってる方々は、今すぐgit/mercurialに移行しましょう。

もちろん筆者としてはmercurialを勧める訳ですが

デメリットを先に言っておきましょう。
多分それだけです。
subversionの問題点の殆どが解消します。それがメリット。

  • 「サーバ」が要らない。ってサーバ機能を内包してる。windowsの人はtortoiseHG(http://tortoisehg.bitbucket.org/)で一発インストール。
  • リポジトリ通信が高速。同規模のプロジェクトで、subversionの数倍。
  • リポジトリ同期のプロトコルが豊富。しかも内蔵。httpd, ssh, 
  • ブランチ&マージは半自動的。場合によってはほとんど人手を介さない。
  • 事実上、コンフリクトは起こらない。(マルチプルヘッド扱いになるので先送りできる)
オフィシャルサイトの情報もよくできてますが、
http://mercurial.selenic.com/wiki/JapaneseMercurial
日本語チートシート(アンチョコ)を作ってくれてる人が居たので、これを傍らにおけば、運用は容易でしょう。http://www.textdrop.net/doc/mercurial-cheat-sheet-ja/

bazaarが入ってないのは?
http://bazaar.canonical.com/en/
リポジトリ間同期をするときに、必ずマージをさせるのは
筆者的にはsubversionの反省点ですので。
あと、実際に色々試してみると、激遅い。なんなのコレ。

故に、比較的シンプルなmercurialをお勧めしています。

Goldendance AUDIO BONE AQUA

骨導式ヘッドフォンです。筆者は、3年ほどまえから愛用してます。

興味をもつひとは結構多いみたいですが、不適切な使い方をして文句を言ってる人も多いので、製品を擁護しておきます。

これは本質的に「音楽に没入しないためのヘッドフォン」です。

音質云々を言うのは間違ってるのですよ。

  • 通勤中に音楽を聞いてる人、多いですよね。
  • 電車の中、歩行中。
  • さらには自転車に乗りながら。これは心底危ないです。
  • もしくは何かしらの作業中。
  • 自宅で勉強しながら、
  • 比較的「自由な」職場では仕事をしながら。

これ以外のシチュエーションでの運用は除外した方が良いでしょう。

最後の、「自由な職場」は「自由」とはいえ、同僚に呼ばれても気づかないんじゃ迷惑を掛けます。

そこで骨導式です。鼓膜が暇なので、回りの音が鮮明に聞こえます。

聴くときのコツは、「骨に当てること」。これ判ってない人多いです。
コメカミに当てる、って人居ましたが、大間違いです。
いやいや、その骨はもっと下まで続いてますよね。

具体的には、頬骨の頂点からそのまま耳たぶまで、で、骨が終わる直前あたり。
モミアゲを伸ばしている人にはちょっとアレな箇所です。

ちゃんと使ってる人も居るじゃありませんか。
http://ameblo.jp/noporin/entry-10157279503.html

装着者には、かなり斬新な聞こえ型をしているので
音漏れを心配する声は多いですが、
http://bbs.kakaku.com/bbs/20462211092/#6983837
基本的にはほとんど漏れないと思って良いです。

嘘だと思ったら、再生中に外して、耳から遠ざけてみればいい。

漏れるとしたら、接触箇所のモミアゲの毛で共鳴してのことです。

問題の製品、AUDIO BONE AQUAは、骨導式では安価な部類ですが、
アンプを内蔵してないが故ではあります。
ポータブルオーディオのイヤホン端子では電力不足でしょう。

基本的には、ボリュームMAX付近で使うものだと思ってください。
世間一般の「イヤフォン」の3倍ぐらいの音量出力が必要です。

とは言え、至近距離で怒鳴るモノ(カナル式)が無いので、
長時間聴いても全く疲れません。

鼓膜ってのは多分、
大音量で音楽を聞くには感度が良すぎるのでは無いでしょうか。
だって、本来、微弱な空気振動をキャッチするための装置ですよ?

ヘッドフォンステレオの聴き過ぎで、難聴になる、なんてアホな話もあるらしい。
http://health.goo.ne.jp/column/healthy/h003/0084.html
いやアホでしょソレ。

2010年12月5日日曜日

PHPの本当にあった怖い話(1)

筆者はPHPを仕事で使うようになって5年経ちますが、それは自慢になりません。
何故なら、未だに裏切られます。

結論から言いましょう。


$aaa = range("0","9");
$bbb = range("a","z");
$ccc = array_merge( $aaa, $bbb );
$ddd = array_search( "a", $ccc );


この$dddには何が入るのか?10が入って欲しいですよね?
0です。

この理由がいきなり説明できる人は、PHPの仙人もしくは関係者でしょう。
師匠もしくは、インサイダーと呼ばせてください。

実は最初のrangeが曲者です。
これは"0"と"9"を指定したにも関わらず、intの配列を作ります。
結果、$cccの中身にはintとstringが混在していることになります。

まだ前フリです。

そしてarray_searchで何が起こるのか?

"a"を探せ、って言ってるのに、intval("a")==0 で0番目が一致しちゃってるのです。

ありえなくね?

結論として、前述の例では、rangeとarray_searchの挙動の共犯です。

PHPは、こういった「暗黙の型変換」が大量にあり、warningすら出ません。
http://www.php.net/manual/en/types.comparisons.php

sortについては、これを反映して、「比較「型」の強制」があります。
http://www.php.net/manual/en/function.sort.php

しかし、array_searchには無いわけです。

初心者のうちは助けられることが多いと思いますし、
それを意図しての型変換でしょう。
しかし、中級になったとたん裏切られるのです。

これを期待通りに可動させるには、rangeの結果にstrvalを通す必要があります。


$aaa = array_map( "strval", range("0","9") );
$bbb = range("a","z");
$ccc = array_merge( $aaa, $bbb );
$ddd = array_search( "a", $ccc );


ありえなくね?

2010年12月3日金曜日

ifを書いたら負け

筆者の持論というか、
最近の見解で「条件分岐を書いたら負け」というものがあります。

具体的にはif,for,while,switchです。

プログラムと条件分岐は、切っても切れません。
しかも要件定義者は、プログラムに都合の悪い仕様を考えてくれるので、
馬鹿正直に実装すると、条件分岐で大変な事になります。

何が大変って、デバッグがです。
極論すれば、条件分岐を一つ書くと、バグの可能性が一つ増えることになります。

20年前には、ソースプログラム上のif文の数等を数えて、バグ件数を見積もって、
それに満たなければ「枯れてない」と判断する。そんな昔話もあるらしいです。

面倒な仕様は、実は仕方有りません。
面倒な仕事を面倒なままやるなら、誰にでも出来ます。

困難な問題は分割せよ、と昔の偉い人も言ったらしい。

もう少し具体的な話を書きます。
例えば、非連続値が関わってるタイプの条件分岐は、工夫次第で条件分岐を省けます。

簡単な話では、「「入力値」を幾つかの範囲にグルーピングするもの」。集計ではよくありますね。

perlではフツーに書くと、こんな感じになると思われます。

my @threshold = ( 20,60,100,150,200,500);
sub islevel{
my($value)=@_;
my $level = 0;
foreach my $ii (@threshold){
last if( $ii > $value ) ;
$level = $ii;
}
return $level;
}


#一応デバッグしたから正しい筈

  • 各範囲の閾値のうち、
  • 入力値より大きいもの
  • 直前が、範囲値

直前の値、が曲者で、地味に面倒な処理です。

この手の実装をするときには、大きい方から回した方が、
条件文はスムーズだったかな。

結論からいいましょう。
perlらしく書くとこうです。

my @threshold = ( 20,60,100,150,200,500);
sub islevel{
my $value = shift;
my @levels = grep { $_ <= $value } @threshold; return $levels[$#levels]; }


後者の考え方は実にシンプルです。

  • 各範囲の閾値のうち、
  • 入力値以下のもの全てを、
  • のうち、もっとも大きいものが、範囲値

余り変わってない?そうですね。「直前の値」の解釈を変えただけです。

本稿で論じたいことの肝は、
処理は多めにやっちゃったほうがプログラムはシンプルになる。
というところです。

ループと条件分岐は、grep に任せています。
第2引数に配列、第1引数に条件式を指定すると、
それにマッチした要素を全て抜き出してくれるという便利関数です。
関数型プログラミングの発想らしい?

これがサンプルをperlで書いている理由だったりしますが、
似たような考え方は他の言語でも出来ます。

grepで回せるように、要件を意訳した。と言った方が正しいでしょう。
性能についての議論はややこしくなるから割愛します。

って言うか、grep に相当する機能が無かったら
自分で作るぐらいが本当でしょう。
毎回、前者のループをコピペしまくるんじゃ頭悪すぎます。