BLOG.QuelLENcode

by Moza USANE (a.k.a. Mozamimy)


(photo credit: Mark J P via photopin cc)

ひよコード

醜悪なコード、いわゆる「クソ」なコードを「ひよコード」と呼ぶことで、そのコードを書いたプログラマを傷つけないようにしている、という趣旨の発言を目にした。

この慣習に対して、何かムズムズとした思いを抱くのはわたしだけだろうか?

引用の主張では、コード中のクソな部分を指して「ピヨピヨしている」と言うことでプログラマを傷つけないそうだが、それは単に、「この部分がクソだ」ということを曲げて言い換えているだけにすぎない。

それともう一つ、「コードがピヨピヨしている」と言っているが、実際にコードがピヨピヨしているわけではない。そのコードを書いたプログラマが「ピヨピヨ」しているのである。ピヨピヨしていると言い放った人は、相手のプログラマに向かって、遠回しに「お前は未熟者だ」と言っているわけである。引用の主張の最後の一文を見ればそれは明らかだ。

「このコードはクソだ」と直接的に言及する場合は、あくまで「コードがクソ」なのであって、だからといって「このコードを書いたプログラマがクソだ」と言っているわけではない。

さて、どちらがクソコードを書いたプログラマの人格に踏み込むような発言だろうか?

「そのコードはクソだ」と言われ、その理由も明らかなのであれば、わたしは自分の未熟さを恥じて、そして「そのコードはクソだ」と断じてくれた彼に感謝して、もっと質の良いコードを書く気になるだろう。だって、クソなものはクソなのだから。

「そのコードはピヨピヨしている」と言われたら、間違いなくわたしは反感を感じる。趣味や仕事でそれなりに経験は積んでいるつもりだし、茶化したような言い方が鼻について、人格を攻撃されているような気になってしまうだろう。

わたしの感覚がおかしいのだろうか。
一般的なプログラマは、「ピヨピヨしてる」と言ってもらったほうが嬉しいのだろうか。

わたしには理解できない世界である。

Rubyにおける文字列リテラル

Rubyには、文字列を表現するための方法が3種類ある。
本題に入る前に、その3種の方法をおさらいしよう。

ダブルクォーテーションを使うやりかた

str = "Alice" # => "Alice"

サンプルコードでは、strというオブジェクトにAliceという文字列を格納している。
ダブルクォーテーションを使う場合は、式展開できたり、エスケープ文字を扱うことができる。

name = "Alice"
str = "I am #{name}!\n" # => I am Alice!\n

#{}の中括弧の中はRubyのコードとして実行され、返り値のオブジェクトのto_sメソッドを呼び出した結果に置換される(式展開)。
また、改行文字(\n)やタブ文字(\t)なども含めることができる。

シングルクォーテーションを使うやりかた

str = 'Alice'

同じく、strにAliceという文字列を格納する例である。
シングルクォーテーションを使う場合は式展開されないし、エスケープ文字で特殊な文字を表現することはできない。

name = "Alice"
str = 'I am #{name}!\n' # => I'm #{name}!\\n

%記法を使うやりかた

alice = %!Alice! # => "Alice"
cheshire_cat = %Q[Cheshire Cat] # => "Cheshire Cat"
white_rabbit = %q[White Rabbit] # => "White Rabbit"

%!!記法と%Q記法は、ダブルクォーテーションと同様の性質を持つ。つまり、式展開が可能でエスケープ文字が使える。
一方%q記法は、シングルクォーテーションと同様の性質を持っている。

ちなみに、%Qおよび%q記法では、[]に限らず任意の文字を使うことができる。
したがって以下のコードは正しい。

queen_of_hearts = %Q*Queen of Hearts* # => "Queen of Hearts"

String#sub(String#gsub)と正規表現を使って置換する場合

String#subString#gsubと正規表現を使って文字列を置換する場合、\N(Nは正の整数)を使うと、正規表現中のN番目のカッコにマッチした部分を再利用できる。

"Alice found a bottle".gsub(/^(.+) found/, '\1 picked up')
    # => "Alice picked up a bottle"

ダブルクォーテーションを使う場合、バックスラッシュがエスケープ文字の一部として認識されるため、以下のように書く必要がある。

"Alice found a bottle".gsub(/^(.+) found/, "\\1 picked up")
    # => "Alice picked up a bottle"

結局どれを使えばいいの?

本題である。
紹介したように、Rubyには3種類の文字列リテラルの表現がある。
わたしの知る限り、どれを使うのかは、Rubyプログラマの間でのコンセンサスのようなものはない。

わたしは、原則としてダブルクォーテーションを使い、例外的にシングルクォーテーションを使う。%Qや%qは使わない。理由としては、

  • 今式展開が不要だと思っていても、後から必要になることがある。いちいち書き換えるのが面倒。
  • 感覚的に、ダブルクォーテーションの方が「文字列らしい」。
    Cの影響を受けた言語の多くでは、シングルクォーテーションは文字リテラルを表現するために使われる。
  • %Qや%q記法を積極的に使っているコードは、経験上希少である。
    わざわざ普及していない記法をメインにしてもメリットがない。

などが挙げられる。

ただし、正規表現を使って置換する場合など、明らかにシングルクォーテーションの方が可読性が上がる場合は、シングルクォーテーションを使う。

%Qや%qの使いドコロ

以上の議論から、%Qおよび%qは使いどころがないように思える。
現実、%Qや%qをモリモリ使っているコードは見たことがない。

ただし、以下のような場合には有用かもしれない。

  • 何か特別な種類の文字列を表現する場合には%Qや%qを使う、というルールを決めて可読性を上げる場合
  • DSLを設計するときに、内部的には文字列として扱いたいが、DSL上の表面的な意味としては普通の文字列と区別したい場合

もし、他に有用な使い方をご存知であれば、ぜひ教えてほしい。

風変わりなメソッド、Object#tap

RubyのObjectクラスには、コードを簡潔にできる可能性を秘めたメソッドが豊富にある。Object#tapはその中の一つだ。

作用

以下のコードを見てほしい。

#!/usr/bin/env ruby
# encoding: utf-8
# example01.rb

returned = Object.new.tap do |obj|
  puts obj.inspect
end

puts returned.inspect
#<Object:0x00000101226008>
#<Object:0x00000101226008>

このコードから分かる通り、ブロック引数にtapのレシーバ自身が入り、返り値はtapを実行するオブジェクト自身である。
つまり、ブロック中のobjreturnedは同じオブジェクトを指しているわけだ。

どういう風に使えばいい?

経験上、最もよく使われると感じるのは、メソッドチェインの間で値を覗き見たいときである。

#!/usr/bin/env ruby
# encoding: utf-8
# example02.rb

output = ->(str) { puts str }

"Alice".downcase.tap(&output)
       .upcase.tap(&output)
       .swapcase.tap(&output)
       .capitalize.tap(&output)
alice
ALICE
alice
Alice

DRYにするために、ラムダ式を使ってoutputにブロックを格納し、それをObject#tapの引数として使っている。
このようにすることで、メソッドチェインを繋げつつ、途中の過程を覗き見ることができる。

ちょっとトリッキーな使い方も見てみよう。

#!/usr/bin/env ruby
# encoding: utf-8
# example03.rb

class String
  def to_a
    Array.new.tap do |array|
      self.chars { |ch| array << ch }
    end
  end
end

p "Alice".to_a
["A", "l", "i", "c", "e"]

これは、文字列を1文字ずつ配列にしたものを返すString#to_aというメソッドをStringクラスのインスタンスに付け加える例だ。
もしObject#tapを使わなかったら、このような感じで書くハメになるだろう。

#!/usr/bin/env ruby
# encoding: utf-8
# example04.rb

class String
  def to_a
    array = []
    self.chars { |ch| array << ch }
    array
  end
end

p "Alice".to_a

うーん、なかなか香ばしい。

ちなみに、RailsでFactoryGirlを使ってseedを用意するときにも役に立つ。
以下の例では、Girlというモデル(一)と、Perfume、Rouge、Manicureというモデル(多)に一対多のリレーションがあると仮定している。

#!/usr/bin/env ruby
# encoding: utf-8
# example05.rb

3.times do
  FactoryGirl.create(:girl).tap do |girl|
    FactoryGirl.create(:perfume, user_id: girl.id)
    FactoryGirl.create(:rouge, user_id: girl.id)
    FactoryGirl.create(:manicure, user_id: girl.id)
  end
end

Girlを生成しつつ、それに関連するPerfume、Rouge、Manicureを見通しよく生成することができる。
seedに直接リレーションが見えるように書きたいときにObject#tapが大活躍する。

工夫すれば、もっといろいろな利用法が見つかると思う。
もし面白い使い方を発見したら、ぜひ教えてほしい。

あなたのベスト・オブ・プログラマージョークは?

みんな大好き、stackoverflowに面白いQuestionがある。
5年前に投稿されたもので、クスリとさせられるジョークが目白押しだ。

language agnostic - What is your best programmer joke? - Stack Overflow

このような言葉遊びも、ハッカー文化の華だ。
せっかくなので、いくつか気に入ったものをまとめておく。

SQLクエリ

A SQL query goes into a bar, walks up to two tables and asks, “Can I join you?”

SQLクエリがバーに行った時のこと、2つのテーブルに近寄って、こう尋ねた。「君たちをjoinしてもいいかな?」

再帰

To understand what recursion is, you must first understand recursion.

再帰とは何かを理解するためには、まず再帰を理解する必要があるね。

ロシアンルーレット

Command line Russian roulette

[ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo *Click*

ロシアンルーレットのようなコマンド。

nptdの脆弱性を悪用した大規模攻撃

nptdの脆弱性に起因する大規模攻撃が流行しているようだ。
monitor機能を無効にしているか、ntpdをpublicに公開していなければ影響を受けないとのこと。

NTP増幅攻撃で“史上最大規模”を上回るDDoS攻撃発生 - @IT

ちなみに、openSUSE 13.1のntpdのバージョンは4.2.6p5なので、この脆弱性の影響を受ける。
うちのサーバではmonitor機能が有効になっていたが、ファイアウォールによって適切にパケットをフィルタしているので事なきを得た。

初心者とVPS

Webページを巡回していると、初心者向けの「VPSを使ってサーバ管理の勉強を始めよう!」といった記事を頻繁に見かける。思うに、これは非常に危険だ。
言うならば、銃の撃ち方を知らない一般市民が、テロリストが立て籠もっている建物に突撃するようなものだ。
なお悪いことにVPSでは、脆弱なサーバが攻撃されると、ネットワーク的に近いサーバも危険にさらされやすい。その影響は、脆弱なサーバだけにとどまらないのである。

近年は、計算機の性能向上、QEMUやVirutalBoxなどの発展によって、仮想環境によるサンドボックスを構築することが容易になった。
初心者はVPSを使って海原を泳ぐ前に、仮想環境という安全な小さなプールで泳ぐ練習をすべきだ。

どこからどこまでが初心者、といった線引きをするのは難しい。
だが、少なくともLinuxコマンドのリの字も知らないぐらいの人間に、VPSを積極的に勧めるのはやめてほしいと思う今日このごろである。

昨日、さくらのVPSにインストールしてあったopenSUSE 13.1をアップデートし、再起動すると起動しなくなってしまった。
なお悪いことに、シリアルコンソールに何も表示されない状態に陥ってしまった。
アップデートの内容にカーネルの更新が含まれていたので、おそらくこれが原因だろう。カーネルのバグを踏んだか、それともQEMUのバグを踏んだか、詳細な原因は不明だ。

何とか原因の究明と復旧を試みたものの、シリアルコンソールがうんともすんとも言わない以上、どうする手立てもない。
用途としては、mumbleのサーバ・nginx・自分用のgitサーバ・ファイルのバックアップ先程度だったので、データを失う痛みはなかったものの、また一から構築しないといけないので面倒だ。

確かにVPSは便利だ。しかし、この一件で、実機が遠い場所にあるということは、それだけでリスクを抱えていることを痛感した。

さくらのVPSに、ディスクイメージのスナップショットをとるような機能があればいいのだが。
そのような機能があれば、システムが元気に跳ねまわっていた頃のディスクイメージにロールバックすることができる。
もっとも、月々900円程度の価格では、そのような機能を提供するのは不可能だと思うが。

大学関係のプロジェクトで、iOSアプリ(ターゲットはiPad mini)の開発をすることになった。

しかしながら、ここで大きな問題が立ちはだかっている。

  • Objective-Cの経験がゼロ
  • デッドラインが近い
    具体的には、今月末くらいにはひと通り完成している必要がある

時間さえ許せば、ゆっくりとObjective-Cの新しい世界を探訪するのもよいのだが、なにせデッドラインが近い。そんな余裕はないのである。

調べているうちに、どうやらPhoneGapTitaniumを使えば、普段親しんでいるHTML+CSS+JavaScriptでアプリの開発ができるらしい。
本当はRubyMotionを使うのがベストであるように思えるのだが、プロプライエタリなので躊躇する。

要件としては、ジェスチャに反応してレスポンスを返す程度のものでよい(現時点では)ため、Web技術をベースにしたプラットフォームを使えば、デッドラインに間に合わせられるのではないかと考えている。

Ruby・Ruby on Rails使いが「間に合わせで」iOSアプリの開発をしたい場合、どのような選択肢がベストなのだろうか?
識者の意見を聞きたいところである。

set :gatewayが使えない

capistranoのメジャーバージョンが3になってから、多段sshのためのset :gatewayが使えなくなってしまった(version 3.0.1現在)。

2の頃は、以下のようにすれば踏み台の設定ができた。
(踏み台サーバのIPアドレスをfumidai.example.comとする)

set :gateway, "fumidai.example.com"

sshのconfigファイルを使う

多段sshで目的のサーバにログインする必要がある場合、sshのconfigファイルを使うのが常套手段だ。
fumidai.example.comを踏み台にして、踏み台と同じローカルネットワークに所属する172.16.0.1に接続する場合、~/.ssh/configに以下のように書く。

Host fumidai
  Hostname     fumidai.example.com
  User         alice
  
Host production
  Hostname     172.16.0.1
  User         alice
  ProxyCommand ssh fumidai nc %h %p

すると、以下のコマンドでssh接続できるようになる。

ssh production

capistranoで使われているNet::SSH~/.ssh/configを見てくれるので、sshのconfigが適切に設定されていれば、deploy.rbに以下のように書けばよいだろう。

server 'production', user: 'alice', roles: %w[app web db],
  ssh_options: {
    keys: [File.expand_path('~/.ssh/id_rsa')],
    forward_agent: true,
    auth_methods: %w(publickey)
  }

多段sshでサーバにログインする場合、sshのconfigを用意するのが普通なので、この方法がベターだと思う。

capistrano 3.Xで多段ssh

SSH gateway support in v3 - Issue #725・capistrano/capistrano

上述のディスカッションによると、以下のように書けば多段sshできるとのこと。

require 'net/ssh/proxy/command'

server '172.16.0.1', user: 'alice', roles: %w[app web db],
  ssh_options: {
    keys: [File.expand_path('~/.ssh/id_rsa')],
    forward_agent: true,
    auth_methods: %w(publickey),
    proxy: Net::SSH::Proxy::Command::new('ssh alice@fumidai.example.com -W %h:%p')
  }

見ての通り、あまりにも醜くなるので、素直にsshのconfigを使うほうが良いと思う。

共感覚という言葉がある。
1つの感覚刺激から、複数の知覚がもたらされる現象のことを言うらしい。

共感覚というほど大それたものではないが、わたしは、プログラミング言語に色のイメージを持っている。
人によってイメージは全く違うと思われるので、コメント欄などで是非意見を聞きたいものである。

Ruby

Rubyは赤だ。
Rubyという名前自体が宝石のルビーを想起させるし、公式ページも赤をイメージさせる配色になっている。
Rubyに関しては、皆同じようなイメージを持っているのではないだろうか。

Python

Pythonは緑だ。
その名前から、緑色のニシキヘビを連想する。

ただし、今しがた調べてみたところ、ニシキヘビは緑ではないようだし、公式ページも緑を連想させるパーツは見当たらない。
でもわたしの中では、Pythonは緑だ。

C/C++

CとC++を一緒くたにすると怖い人たちからお叱りを受けそうだが、色のイメージとしては、どちらも鮮やかな黄色を連想する。
黄色いイメージのルーツを辿っていくと、独習Cに行き当たった。

今思えば、中学生だった当時に、よくもまあ、よりによってこんな入門書を選んだものだ。
翻訳された本なので、ヤード・ポンドの換算など、日本人になじみのない例があまりにも多すぎるのである。
もっとも、内容は申し分ないということは付け加えておく。

Haskell

最近わたしの中でアツいHaskellは、明るい灰色だ。
ちなみにこの色、茶鼠(ちゃねず)という色らしい。

公式ページのHaskellのロゴには、右側のラムダに灰色があしらわれており、わたしの中でのイメージもこれに由来しているのだと思われる。

C#

近頃はRubyのような動的型付け言語が好みであるが、静的型付け言語で一番好きなのは、やはりC#である。
わたしのプログラミング人生の中でもC#の占める割合は大きい。

そんなC#は黄緑だ。
近頃のVisual Studioがどうなっているのかは全く知らないが、C#を示すアイコンに黄緑色が使われていたのだ。

Java

Javaは紫だ。
これは、おそらくEclipseのイメージカラーが紫であるからだと思う。
OracleのJREの配布サイトは赤基調になっているが、やっぱりわたしの中では紫だ。

sh (Bourne Shell)

シェルスクリプトは.. 色というよりは、上の見出しのようなイメージだ。
そもそも黒地に黄緑というこの配色、はるか昔のコンソールに使われていて、古き良き時代の象徴となっている。

Tcl

Tclには褐色のイメージがある。
普段Tclを使うことはないが、Synopsys社の回路設計ツール群がTclをサポートしていて、論理回路の研究をしていたころにちょっと触った経験がある。

JavaScript(ECMAScript)

JavaScriptは深緑だ。
このイメージのルーツを辿ると、以下の書籍に行き着く。

HTMLとJavaScriptは、初めてプログラミングに触れたあの頃に、HSPと同時に勉強していた記憶がある。
今は仕事上JavaScriptを日常的に触っているが、あの頃とは何もかも違うなあとため息が出る。

CoffeeScript

JavaScriptが出たので、CoffeeScriptにも触れておかねばなるまい。

CoffeeScriptは比較的新しいプログラミング言語である。
プロトタイプベースのJavaScriptのややこしい部分を取り除き、今風のオブジェクト指向で書けるカッコイイ言語である。
CoffeeScriptのコンパイラは、CoffeeScriptを解釈してブラウザで実行できるJavaScriptに変換する。
モダンなRailsでは、生のJavaScriptではなくCoffeeScriptがデフォルトになっている。

似たようなコンセプトの言語に、Microsoftの主導するTypeScriptというものもあるらしい。

TeX

TeXは黒である。カラーコードで言うと、#000000である。
まさかと思ったのだが、なんとまあ、TeXはチューリング完全なれっきとしたプログラミング言語だそうだ。

VHDL

昔、論理回路の研究をしていたこともあったので、VHDLについても語っておこう。

VHDLは浅葱色のイメージがある。
このイメージのルーツは以下の本だ。

この本によってハードウェア設計のいろはを学んだ記憶がある。
巻末にはVHDLのサンプルが掲載されており、わたしの心のなかに「VHDLは浅葱色」というイメージを植え付けることに貢献している。

HSP

最後に、わたしが初めて触れたプログラミング言語であるHSPは、コーンスープの色である。
Hot Soup Processorという名前に由来するイメージである。

久しぶりに公式ページを見てみると、着実にバージョンアップされているようで、最新版は3.3だそうだ。
わたしがバリバリとHSPを楽しんでいた頃は、2.Xだったと記憶している。

ああ、すべてが懐かしい。

openSUSE 13.1におけるmumbleサーバ

Mumbleというボイスチャットをするためのフリーソフトウェアがある。
TeamSpeakという競合もありmumbleと人気を二分しているが、こちらはプロプライエタリなのであまりイケてない。

さくらのVPSで動かしているサーバのOSをopenSUSE 13.1に上げたときに、なぜかmumbleの起動スクリプトが無くなってしまった。
mumbleの本家リポジトリにあるスクリプトはopenSUSE 13.1で動かないので、このリポジトリをフォークして、それを参考にスクリプトを作った。
以下からダウンロードできる。

mumble/scripts/murmur.init.opensuse at master・mozamimy/mumble

#! /bin/sh
#
# Mumble server init script
# Copyright (C) 2004 Moza USANE / quellencode.org
# mozamimy@quellencode.org
#
# When you use this script, do following instructions.
#
# 1. Make the directory named /var/run/mumble-server to store PID file.
# $ sudo mkdir /var/run/mumble-server
#
# 2. Change the owner of the directory to mumble-server:mumble-server
# $ sudo chown mumble-server:mumble-server /var/run/mumble-server
#
# 3. Enable pid configration in mumble-server.ini
# $ sudo vi /etc/mumble-server.ini
# And add "pidfile=/var/run/mumble-server/mumble-server.pid"
#
#
### BEGIN INIT INFO
# Provides: murmurd
# Required-Start: $network $local_fs $remote_fs dbus
# Required-Stop:        $network $local_fs $remote_fs dbus
# Should-Start:                $mysql
# Should-Stop:                $mysql
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Mumble VoIP Server
### END INIT INFO

INIFILE=/etc/mumble-server.ini
MURMURD_BIN=/usr/bin/murmurd
MURMURD_PID=/var/run/mumble-server/mumble-server.pid
NAME=murmurd

. /etc/rc.status
rc_reset

case "$1" in
  start)
    /sbin/startproc -p $MURMURD_PID $MURMURD_BIN -ini $INIFILE
    rc_status -v
    ;;
  stop)
    /sbin/killproc -p $MURMURD_PID -TERM $MURMURD_BIN
    rc_status -v
    ;;
  status)
    /sbin/checkproc -p $MURMURD_PID $MURMURD_BIN
    rc_status -v
    ;;
  restart)
    $0 stop
    $0 start
    rc_status
    ;;
  *)
    N=/etc/init.d/$NAME
    echo "Usage: $N {start|stop|status|restart}" >&2
    exit 3
    ;;
esac

exit 0

以上のスクリプトを/etc/init.d/murmurdに配置し、

sudo chmod +x /etc/init.d/murmurd
sudo chkconfig murmurd on

でOS起動時にmumbleのサーバも自動で起動するようになる。