記法における「読みやすさ」と「書きやすさ」

プログラミング言語やテンプレート言語やHTMLやPDFを吐き出す言語において、記法って大事よねってみんな思ってるけど、宗教論争になっちゃうよね。んで、今回は宗教論争をさらに熱くするための一助をしたいと思う。まとめると、記法の良さには色々あるってこと。

読みやすさ

まず「読みやすい」ってなんだろう?読み方には大きく分けて(というかこれら以外知らんが)黙読と音読があるじゃないっすか。つまり、

  • 黙読に優しい記法
  • 音読に優しい記法

があるように思う。

例えば、Rubyは黙読に優しい記法を持ってると思う。まず、RubyPerlに比べると記号が少ない。$や@や%が登場する頻度が比較的少ない。同じ理由でテンプレート言語のSlimはHamlよりも黙読に優しいと思う。人によってはこれらの記号で目がチカチカすると思う。俺なのだが。しかし、人によっては強調されてて把握しやすくて良いと思う。そして、Rubyは変数名やメソッドには慣習的にsnake_caseを用いUpperCamelやlowerCamelを使わないのでうるさくない。確か英語的な感覚では大文字は大声だったと思う。CAUTIONとかWARNINGとか強調するときに大文字を使う。そんで、俺的にはUpperCamelやlowerCamelもややうるさい。だからRubyが好きなんだな(自己解決しました)。

一方、メソッドが通常UpperCamelであるObjective-CJavaは音読に向いた記法だと思う。まぁ記法というよりは標準ライブラリがもたらす慣習と言ったほうがいいかもしれないが、これらの言語で書かれたコードが冗長なメソッド名を持つのは周知の事実かと思う。長けりゃ悪いってわけでもなくて、話すときに正確に伝えられるってことは、チーム開発とかにも良いだろうし、普通は思考を音で考えるタイプの方が多いのでいいんじゃなかろうか。

視覚に訴える記法と聴覚に訴える記法があるってわけ。五感全部あればいいのだが、残念ながら匂いがする記法や甘い記法や敏感タッチいやんな記法にはまだあったことない。小説の文章ではたまにあるけどな。第六感?HaskellOcamlは数学感というか関数脳に訴えるんじゃない?(よく知らん)

書きやすさ

書きやすさの方はすっきり腑分けできないのだが、

  • そのまま読める記法
  • 書いていて動作や結果を想像しやすい記法

があるように思う。(思考を整理するための読みやすさは上で書いたので置いておく)

例えば、Markdownは前者の配分が高めだと思う。んで、名前忘れて検索できないけど、とあるMarkdownっぽいやつは(イタリックを/Italic/などとして「あ、斜めなんだな」と分かるように書ける)後者の配分が高めだと思う。Markdownはパラグラフは良いんだけど改行がクソ(改行前に半角スペース2個打つとか、リストの前後に空白行を書かないいけないとか)なんで、小説などのepub作成にはあまり向いていない、つまり、後者の用途で差し障りがある場合もある。アセンブリは後者なんじゃないかな、多分。なんかあんま思いつかないからこれで終わるわ。

まとめ

いろんな燃え方を見たい。

f:id:babie:20140112010632j:plain

中間テーブルにidつけるとWeb APIが綺麗

なんかActiveRecordが中間テーブルにid付けるのに反対する人たまに見るんだけど、俺は付けた方がいいと思う。というのは、Web APIがすっきりするから。

例えば、followships って中間テーブルがあったとして、カラムに followee_id, follower_id って名前を付けるとしようじゃないか。(followship, followee 共に造語です。-shipsを付けて関係を表し、-ee を「される人」-er を「する人」に付けるのが個人的な趣味なのです。interviewee/interviewerの関係ね。話題が逸れるけど俺は書く!オススメはしません)

で、フォロワー作るときはいいとして、フォロワー削除するときのAPIにidナシとidアリじゃ違いが出るじゃんね。

DELETE /users/1/followships?followee_id=256&follower_id=1
_人人人人人人人人_
> かっこわるい <
 ̄Y^Y^Y^Y^Y^Y^Y ̄
DELETE /users/1/followships/4
_人人人人人人人_
> かっこいい <
 ̄Y^Y^Y^Y^Y^Y ̄

ActiveRecordってそもそもRailsで使うのが主目的じゃんすか。んで、Railsってウェブアプリケーションフレームワークじゃないっすか。なんで、Web APIが綺麗になるなら、データベースの領域とはいえ、一考に値すると思うんすよね。いかがか。

DCIが便利になるのはまだ時間がかかる

ぼんやりした随想であって、精密な議論ではありません。よくわからんけどよくわからんまま書くわ。あしからず。(一応付け足しとくけど、「DCIはエンドユーザのメンタルモデルを実装に落とし込むための設計パラダイム」だから云々とか言う気はないです。誰かがライブラリ作ってくれて実装に落としこむの楽になったら大歓迎です。)

DCIは今のプログラミングにおいては、そのメリットを生かし切れないように思う。というのは、今のプログラムはオブジェクトを使ったらGCに回収される、つまり、捨てるから。富豪!extendはいいとして、unextendする必要がない。現時点でもメンタルモデルの整理に役立ち、まぁまぁ生産性や保守性の向上は見込めるとは思うが、別に性能の向上に役立つ代物ではない。手法であって機能ではない。そもそもそんな主張は誰もしてないわけだが。

それはそれとして、手法から機能へ、つまり「物凄く便利」にまで評価が上昇する時が来ると思う。それは、MRAMなどの不揮発性メモリが普及した時。オブジェクトデータベースと共に猫も杓子もDCI使い出すのではないか。と思った。

不揮発性メモリ上のオブジェクトデータベースにはプレーンなオブジェクトを保存しておき、使うときにロールをextendし、役割を終えて何かアトリビュートの変更などがあった場合はunextendしてプレーンな状態で保存するって使い方。

どうか。どうだろな。適当。ぼんやり。

vim - Vimの自動保存で読み込み専用や名前がない場合に警告が出ないようにする設定

Qiitaに投稿しました。

http://qiita.com/babie/items/fa1154e2979c45fa77af

短いですが、今日のノルマはこれで。

次回予告

やっと新しいMacBook Proの環境が整ったので、バリバリ更新していきたいと思います。

さて、次回ですが、

  • pdfの漫画の余白を切り取る
  • はてなブログに予約投稿がないのでツラい

このあたりを何とかしたいと思っています。

Earthquakeで:plugin_install時にgithubネームに数字が含まれているときまずいのを直した(初めてのpull-request)

新しい13" MacBook Pro(Retina 2013 late)の環境構築しないといけないので軽く。

例えば

⚡ :plugin_install https://gist.github.com/no6v/946219

するとgithubネームの6の方が引っかかって https://gist.github.com/maddox/6 をインストールしそうになるってのを直しました。インストールするかどうか聞かれるファイル名がsick c0dezになるのでクラックされたのかと震えました。

https://github.com/jugyo/earthquake/pull/156

正規表現1個だけです。

始めてのpull-request

お恥ずかしながら、初めてpull-requestしました。プルリクしてたった8分後に取り込まれたので「これがSocial Coding……」と思いました。無言でしたので「アオ いいよね」「いい…」に通ずる侘び寂びがあると思いました。

それはそうとhubコマンド便利ですね。

$ git clone jugyo/earthquake
$ cd earthquake
$ git fork
$ git checkout -b fix-plugin_install-in-case-of-name-has-number
(ファイルを編集したり動作を確認したり)
$ git commit -m "fix :plugin_install in case of github name has numbers"
$ git push babie fix-plugin_install-in-case-of-name-has-number
$ git pull-request
(エディタが起ち上がるのでプルリクエストのタイトルと本文を編集して保存)

こんだけ。

次回予告

存在の耐えられない軽さのコミットでお茶を濁そうと思います。まだ梱包といてない。

upstart, pty-keeper, reptyr, socat - ターミナルアプリをリモートサーバでデーモン化する方法(Earthquakeをサーバで実行するようにした)

試行錯誤で6日かかったンゴ……普通に嵌ってしんどかった……。1 release/dayが途絶えて残念なり……。一応、毎日勤勉に取り組んでたんですけどねぇ。でも最後はかなりシンプルになって良かった。似たような方法でターミナルアプリは全て同じ方法でデーモン化して接続できるようになると思います。

例はEarthquakeです、というか、Earthquakeをデーモン化するためにいろいろ調べた。

要件

  1. Earthquakeをデーモン化したい
  2. ローカルから1コマンドで接続
  3. ssh認証したい

1は先日event_chainsave_imageってEarthquakeプラグイン作ったので、サーバに常駐させときたいなぁということです。ローカルはラップトップなので閉じてることあるから。

2は基本的には常時接続なんですが、やっぱ気が向いた時にすぐ見れなきゃまずいっしょ。

3は外から誰でも接続できると嫌なんで。危ない。

ソリューション

とりあえず、ざっくり解決法書きます。解説は後で。

リモートサーバ

reptyrとsocatをインストールします。UbuntuでやってるのでOSに合わせて適度に読み替えてください。

$ sudo apt-get install reptyr
$ sudo apt-get install socat

reptyrは別のpty(pseoudo tty)で動いてるプロセスを手元のptyで乗っ取るソフトウェアです。 socatはnetcatの高機能版みたいなもんで、ネットワーク用途に限らない色々なことができます。今回はコマンド実行して終了するんじゃなくて、リモートサーバへの接続を維持するために使ってます。

そして、拙作のpty-keeperをダウンロードします。

$ wget https://gist.github.com/babie/7297810/raw/ae3793ae39b3165e0c50f7ca4a05fb00921a9cdd/pty-keeper
$ chmod +x pty-keeper

適当な場所に置いてね。

ptyを持たせて子プロセスを起動しながら、自分から子プロセスのIOへ読み書きができなくなっても、子プロセスが生きている限りは死なない、っつーソフトウェアが見つからなかったので作りました。

要点は、PTY.spawnでpty付きでspawnするのと、SIGCHLD,SIGCLDは子プロセスが死んだ時だけじゃなくて、ptyが変更された時なんかも飛んでくるので、ホントに死んだかどうか確かめるってとこっすね。汎用的にしなければ10行です。

んで、Upstart用設定ファイル/etc/init/earthquake.confを作ります。

これでサーバ起動時に自動で立ち上がります。ユーザーやパスは環境に合わせて適度に改変してください。

HOMEはEarthquakeが設定ディレクトリを探すために、LANGはEarthquakeへ文字入力するときに日本語が化けるのを防ぐのに、COLUMNSはpty及びreadlineがデフォルト80を採用しそれ以上の入力すると強制的に行頭に戻されてつらいので、PATHはEarthquake及びpty-keeperがRubyを探すために必要です。

--no-daemonオプションを付けてるのは、upstartはプロセスIDを追跡する記述があって、expect forkはfork一回、expect daemonはfork二回という風に対応してるのですが、RubyProcess.daemonupstartが追えないプロセスIDの変わり方してるみたいなんで付けざるを得ませんでした。pty-keeper自体はconsole noneでどのtty/ptyにも接続してないので問題ありません。

プロセスの起動・終了を何に任せるかはいろんな方法がありますよね。

昔ながらのstart-stop-daemon使って/etc/init.d/earthquake書いてたんだけど、ほら、sysvinitってrespawn(プロセスを監視して自動再起動)ないじゃないっすかー。んでその後、daemon使ってやってたんすけど、--ptyオプションがうまく使えなかった。これデバッグ用でupstart(init)は元々pty持ってないからかな?んでググると、なんとUbuntuでは今upstartが普通っぽいじゃないですかー。こいつはrespawnもうまく捌いてくれるしかっこいいなということでこれ使いました。

最初は直接earthquakeを呼び出すearthquake.conf書いてたんですが、デーモン化はうまくいくんですが、文字入力がダメ。なんか行単位のバッファになってるみたいなんすよね。socatのオプションでicanon=0rawなんかを試したんですがうまくいきませんでした。

次にemptyを介したearthquake.confを書いたんですが、これはデーモン化も文字入力も問題なかったんですけど、earthquakeプロセスが2つできちゃう。デフォルトのEarthquake使うならこれでも良かったんですが、私が使ってるプラグインにタイムラインを監視してイベントに応じてアクションするってのがあるんすよね。具体的にはfavった画像つきツイートの画像を保存するって奴なんですが、画像が2個保存されて宜しくない。どうしてプロセス2つになるかというと、reptyrがpty乗っ取ったと同時に読み書きできる子プロセスがいなくなったemptyが自殺してupstartが再起動かけるって具合です。このempty、Ubuntuでのパッケージ名がempty-expectとなっているように、ptyを生成してコマンドを起動してそいつと対話するexpectなんですわ。なので子プロセス自体が生きていてもIOが読み書きできなくなったら速やかに死ぬようになってんですね。そもそもの目的がそれなんだからしょうがない、他の用途に使う俺が悪かった。

あ、この設定ファイル、密かにrbenv環境のupstart設定の書き方にもなってますね。

手動で立ち上げるときは

$ sudo start earthquake

です。この辺はinitctl辺りを調べてください。

ローカルホスト

.zshrcに以下を追記

別にaliasでもいいと思うんですけど、私はwhichですぐ見れるようにfunctionにしてます。設定再読み込みも忘れずに。

moshじゃなくてsshなのは、moshは接続を安定させるために複数のコネクションを張るので、プロセスが複数実行されて悲しいことになります。

socatは2つのブロックの引数を取り、STDINがこっちの標準入力、SYSTEMがあちらでshを実行することを意味してます。
STDINのオプション、echo=0は文字が二重に表示されるのを防ぐため、icanon=0は非カノニカルモードにして行単位ではなく文字単位で書き込みするために使ってます。詳しくはTERMIOSを読んで下さい。
SYSTEMは引数なしのコマンドを実行するならEXECでもいいんですが、今回は引数に加えてshの実行も必要だったのでこれにしました。オプションのptyはリモートサーバでpty作るかどうか、stderrはSTDERRもSTDOUTにリダイレクトしてくれるやつ、ignbrk=1はこれまたTERMIOS関連でシグナルのC(Ctrl-c)を無視するかどうかですね。どっちにしろsocat/reptyrの終了でearthquakeも再起動するんで今回はあんま意味ないんですが。

reptyrにオプション-sを付けてますが、これはプロセスにtty/ptyが接続されてない時に使うもので不要なんですが、オプションなしの既存のptyを乗っ取るより、オプションありの新しくpty作って繋ぎ変える方が速くて安定してるみたいなので付けました。

あかんかったわ。-sオプションつけると複数行や長文の入力に難あり。取り除いたら無事できました。遅延じゃろか。

これで、

$ earthquake

とすればリモートで動いているEarthquakeに接続しTwitterを楽しめます。

次回予告

はてなダイアリーに予約投稿がなくてつらいので何とかしたいと思います。んだけど、MacBook Proが届いて環境設定しないとアカンのでちょっと遅れるかも。

event_chain - Earthquakeのユーザーストリームで流れてくるイベントに応じて任意のコマンドを実行できるプラグインを作った

チョリ〜〜〜〜ッス!ブログ記事は遅れてるけど一応1日1リリース継続中。

先日のfav_machineは、①favイベントだけに反応し、②画像を保存するだけ、だったのですが、①は全てのイベントに、②は任意のコマンド(勝手プラグインコマンドも含む)に対応して、汎用性を持たせてみました。

前の記事のsave_imageと組み合わせるとfav_machine相当のことができます。

あと名前はお弁当チェーンみたいでいいかな?と思ってこれにしました。

インストール

⚡ :plugin_install https://gist.github.com/babie/7215590

設定

Earthquake.config[:event_chain] = {
  :favorite => [':retweet %{id}', ':save_image %{id}'],
  :favorited => [':update @%{him} thx 4 ur fav!', ':follow %{him}'],
}

例は、自分がfavったらついでにリツイートも実行するのと、自分がfavられたらその相手に返事をしfollowする、という意味になります。

ハッシュで設定します。keyがイベント名で、valueがイベントの際に実行するコマンドの配列になります。配列の中の順番は特に意味はないですが、内部的にはeachで順番に回してます。ので途中で例外が上がると止まる。

イベント名は、

  • block
  • unblock
  • favorite
  • favorited
  • unfavorite
  • unfavorited
  • follow
  • followed
  • unfollow

などが使えます。ストリーミングAPIのイベントを元としていて、自分がしたか・されたかによって能動態・受動態に分けました。そのままだとめっちゃややこしかったので。

コマンドは文字列で書きます。頭の:を忘れないようにしてください。例に%{him}というのが含まれてますが、よく使う変数を埋め込めます。変数には、 * me : 自分 * him : 相手 * her : himと同じ * it : himと同じ * id : ツイートエイリアス($xx) があります。コマンドに応じて埋め込んでください。
また、コマンド文字列はevalされるので、式や上記にない変数を埋め込めます。例えば':retweet #{id2var(item["id"])}'という風にも書けます。設定ファイルを読み込むときに評価されないようシングルクォート相当(%q)で囲んでください。ダブルクォート相当だと読み込み時に解釈されるので死ぬ。

使い方

一度設定したら自動です。

コード

ちょっとcallerのとこがちょっとおもろかった。コマンドにはconfirmメソッドを使ってyesかnoを問い合わせるものがありますので、このプラグインから呼ばれた時は常時trueにして手動入力なしでいけるようにしています。最初 Readline::HISTORY[-1](最後の入力履歴)を見ようかなと想ったんですが、inputに渡されるテキストをconfirmまで持ってくるのがダルいなということで、こういう風にしました。あと、prependを使ったほうがお作法的によろしいのでしょうが、Earthquakeがどのバージョンで使われるか知らないのと、元々ActiveSupportを組み込んであるのでalias_method_chainを使いました。便利。

passiviseは単語の受動態を作るメソッドです。こんな単語知らないけど適当に。ActiveSupport風にStringクラスをオープンして拡張しても良かったけどダルかった。

今後

リツイートはイベントとして流れてこないので、対応した方がいいかもなー。要望があれば。

次回予告

Earthquakeでちょっと考えてることがあって、調査していいソフトウェアがあったらその使い方、なかったら作って記事書きます。どちらにしても、Earthquakeについては次回で最後になると思います。