Software Design連載記事を掲載します。

株式会社技術評論社の許可を得て掲載しています。
草稿なので細かい部分は実際の記事とは異なることがあります。

他の記事は左下にある「■雑誌連載中(全文公開)」から見られます。

Emacsは小宇宙

 ども、るびきちです。
ここ3ヶ月は基本に立ち帰り、標準コマンドに光を当ててみました。
やはりさすがEmacsは奥が深く、標準コマンドにちょっと触れるだけでも3ヶ月かかってしまいました。
これまで当たり前に思ってきた標準コマンドの機能性を再発見できれば幸いです。

 でも、標準コマンドで終わるEmacsではありません。
Emacsユーザは当然、Emacsを自分好みの色に染めたいものですよね。
個々のユーザの要望にとことん応えてくれるのがEmacsの魅力です。

 Emacsは単なるテキストエディタではなく、テキストエディタの顔をしたLispマシンです。
Lispというプログラミング言語の比類なき柔軟性により、ありとあらゆるタスクがEmacsで実現できます。
Lispは実行中にプログラムそのものを変更できるので、あなたの意のままの形態を変化します。
変数を設定したり、関数を定義したり、Lispファイルをロードすれば、その時点で「世界で1つ、あなただけのためのEmacs」なのです。
elispのおかげで日常的なテキスト編集がより快適になり、突き詰めれば統合開発環境になりますし、ゲームソフトにすらなってしまいます。

 人体は小宇宙と言われていますが、筆者はEmacsも小宇宙であると考えています。
Emacsは人間によって書かれた一プログラムにしか過ぎませんが、あたかも生き物ではないかと思えるときがあります。
生き物は食物を摂取しますが、Emacsにとってはelispパッケージが食物(や薬)に相当します。
健康を維持するには何を食べるかが重要であるように、快適なEmacsもどんなパッケージを使うかが重要です。
薬の飲み合わせがあるように、お互い相性の悪いパッケージのせいで無用なトラブルに巻き込まれることもあります。

 Emacsは標準添付のパッケージも充実していますが、Emacs24からはパッケージシステムが導入されたので、世界中の外部パッケージを簡単に導入できます。
誰もが簡単に外部パッケージを導入し、設定すればすぐにあなたのEmacsに反映されます。
門は開かれました。
あなたのEmacsをデザインしてください。

 こういう話をしていて、いつも頭をよぎるのが筆者の少年時代に遊んだミニ四駆です。
電池2本で一直線にしか走れない玩具の車ですが、当時はいかに速くコースを走るか競われていました。
ミニ四駆本体を買って組み立て電池を入れて電源を入れればすぐに走ります。
しかし、より速く走らせるためにはより強力なモーターに交換したり、軽量化などの改造を施します。
取り換えられるパーツは多くのメーカーが生産していて、選択は多岐に渡ります。
「これは」と思ったパーツに取り換え、自分オリジナルのミニ四駆を構築したものでした。
そして大人になった今、このノリがGNU/Linuxマシン構築やEmacs環境構築に活かされています。

拡大と収縮

 筆者はEmacsを使い始めた途端、いきなり魅了され、数ヶ月しないうちにelispを書くようになりました。
そして、「こんなコマンドあったらいいな」を自分で実装していました。
右も左もわからず、試行錯誤の日々が何年も続きました。

 当時はパッケージシステムという便利な代物は存在せず、公開されているelispは少ないものでした。
お手本となるelispもない中、自分なりに学んでいました。
ネット上でelispを見付けても手動でダウンロードして手動インストールでした。
暗中模索の中だったとはいえ、ミニ四駆の魔改造のようにEmacsにいろいろな機能を追加する作業はとても楽しいものでした。

 一気に大量にelispコードを書いては、しばらく時間がたてばその機能の存在すら忘れてしまうことを繰り返して10年以上になりました。
その間、コードを書いては捨て、書いては捨てという感じでinit.elの総行数は15000行を突破していました。
自作・外部問わずありとあらゆるelispを突っ込みまくり、筆者のEmacsはモンスターのように肥大化しました。

 現在はパッケージシステムがあり、検索すれば何かしら見つかる時代に入り、自分でコードを書く必要性がめっきり減りました。
それに日々使うelispはほんの一部に過ぎないことにも気付きました。
せっかく書いたコードも今となっては役立たないものも多くなりました。
init.elをスリムにした結果、現在は5000行くらいに落ち着いています。
さらにしぼせば数千行くらいになるかもしれませんが、あいにく時間が取れていません。

 このように、筆者のEmacs遍歴は拡大と収縮の繰り返しです。
サイト「日刊Emacs」を更新するために、毎日パッケージをインストールしていますが、実運用しているものは少ないです。
膨大なelispを見てきた中で、システムに対する洞察力が身に付きelispそれぞれの性格、及びトラブルの臭いを嗅ぎ分けられるようになりました。
今回は長年のEmacs歴で学んだ教訓をお伝えしていきます。

外に開かれたEmacs

 今Emacsを始める人はとても恵まれています。
なぜならパッケージシステムにより、世界中の数千ものelispパッケージを簡単にインストールして試せるからです。
パッケージシステムが登場する前はEmacsWikiというEmacs情報集積場にノウハウやelispが集められていましたが、パッケージシステムほど使いやすいものではないので、elisp開発者はパッケージへと移行しました。
なにかパッケージが欲しいと思ったらM-x list-packagesからインクリメンタルサーチやoccurでキーワード検索すればいいだけです。
他の人にも使ってもらいたいとの思いでパッケージを作成した開発者はMELPAに登録しないわけがありません。
パッケージシステムはEmacsの標準機能なので、一度MELPAに登録したら、世界中のEmacsユーザに知れ渡るのです。
とても便利な時代になりました。

 RPGをプレイしたことがあるならば、船や飛空艇などの乗り物を得たときの開放感は忘れられないでしょう。
これまで徒歩のみの移動で世界のごく一部しか行けなかったのが、乗り物によって新しい大陸へ自由に行けるようになったときにものすごくワクワクしたことでしょう。
筆者も夢中になって新しい街や洞窟を見付けに世界を探険したものでした。
今のEmacsは、RPGでいえば飛空艇で世界中のいたるところに行ける状態です。
Emacsは子供の頃のあの楽しかった思い出を想起させてくれます。

 Emacs歴が短いのならば、ぜひともいろいろなパッケージを試してみてください。
パッケージを実際に使うことによってEmacsの経験値が増えます。
新たな角度から問題を眺められるようになり、より便利な方法が見えてきます。

 とはいえインストールするとトラブルが怖いと思うのはよくわかります。
けれどもパッケージからインストールするだけでは、すぐにコマンドが使えるようになるだけで勝手に機能が有効になったりはしません。
筆者は「日刊Emacs」のために毎日新規パッケージをインストールしていますが、インストールしたことによるトラブルは経験したことがありません。
インストールは無害です。

 筆者が知る限り唯一の例外はbetter-defaultsパッケージで、インストールするだけで変数を変更してしまいます。
しかしそれは「よりよりデフォルト設定を提供する」という動機でわざとやっています。
MELPA登録はpull requestによって人力チェックが入るので、その他のパッケージでこのような『不作法』はないでしょう。

円熟してくると

 これは筆者の経験ですが、Emacsに魅了され常にいじくり回し、多くのパッケージを使っていれば、次第にいろいろな事が見えてきました。
ちょうど熱愛から円熟に差し掛かってきます。

 既存のパッケージもそうですが、実現させたい機能が見付からない場合は自分で実装していました。
首尾よく実装できると、最初は作った機能に満足します。
しかし、たいていの場合は次第に使わなくなり、しまいにはその機能の存在すら忘れてしまうようになりました。
見方によっては時間の無駄のように思えますが、プログラミングした経験により学びが得られます。

 昔は機能が欲しければ真っ先に手が動いてプログラミングを始めていましたが、今では以下のように自問しています。これらがNoであれば自分でコードは書いていません。

  • この機能は本当に必要なのか?
  • 自分で実装する必要はあるのか?
  • すでに誰かが実装していないか?

 パッケージを実運用する際も慎重になるようになりました。
「果たしてパッケージを導入してどれくらい操作性が上がるのか?」と自問するようにしています。
なるべく多くの局面で操作性が上がるのならば、そのパッケージを導入すればよいです。
プログラムの最適化ではボトルネックの最適化に集中するのと同じように、Emacsの操作性のボトルネックを改善するパッケージならば導入すべきです。
いわゆる「プロファイリング思考」です。

 すると、無闇に外部パッケージや自前の実装に頼ることが減り、標準機能に回帰するようになりました。
外部パッケージは真新しい実装よりも標準機能を拡張するものを好むようになりました。

 このことははあなたに「外部パッケージに頼るな。標準機能だけを使え」と言っているわけではありません。
Emacsの経験が少ないのならば多くのパッケージを経験するべきです。
ちょうど海外旅行を多く経験して初めて日本のありがたみがわかるように、標準機能がそれなりによく出来ていると悟るようになります。

機能は適切に管理しよう

 スマホを始めとする多くの電化製品は機能性をアピールしています。
そういうセールストークに筆者はうんざりしています。
普通の人は「こんなこともできるんだ!すご〜い」という感じで機能性に魅入られます。
そしていざ購入したとき、アピールされた機能を使いこなしているでしょうか?
多くはNoだと思います。
機能性の感動は一時のものに過ぎず、結局は基本的な機能+αくらいしか使わないことでしょう。

 筆者はEmacsについても同じように感じています。
長年Emacsを使っていて、数多くのパッケージの設定を組み込んでいますが、結局常用している機能はごくごく一部でしかないことに気付きました。
せっかく設定していても長い間使っていないと設定したことすら忘れてしまいます。

 このことから
「できることが多いことが偉大なのではない。要は適切にコントロールすることが大事だ。」
という教訓を得ました。
パッケージを入れまくればいいわけではありません。
せっかく導入しても使い方を忘れているのでは意味がありません。
機能志向は結局は機械に使われるハメになります。

利便性には必ず代償を伴う

 筆者の座右の銘を紹介します。
それは「利便性には必ず代償を伴う」ということです。

 たとえば、インターネットの普及によって人間関係をネットで済ませるような人が出てきました。
常時接続されたインターネットは距離に関係なくいくらでも相手と交信できる利便性を生みました。
しかし、同時に人間関係スキルが磨かれなくなり、リアルでは希薄な関係に終わってしまう傾向になりました。

 携帯電話やスマホの普及により、コンピュータを使っていなくてもいつでもどこでも誰かとリアルタイムに交信できるようになりました。
筆者が初めて携帯メールを使ったときには、あまりの利便性に感動し、一日に何十通のメール交換するようになるほど中毒になってしまいました。
ガラケー時代でもメール中毒になってしまうのに、高機能化されたスマホはさらに中毒性が高いです。
このスマホ中毒というのは現代社会に大きな弊害をもたらしています。
まわりを見渡してみてください。
スマホとにらめっこしている人、人、人…常にスマホが気になり「今」という瞬間に集中できなくなりました。
心がスマホに奪われてしまっているのです。
せっかく人と会っているのに相手がスマホばかり見ていたらいい気分はしませんよね。
スマホは大きな利便性を提供しましたが、同時に精神の退廃を招きました。

 セキュリティと利便性はトレードオフであることが多々あります。
sshのパスフレーズを毎回入力するならばセキュリティは強固ですが、面倒ですね。
そこでkeychainを使ってパスフレーズ入力の手間を省けますが、ちょっとした不注意でスキを与えてしまいます。

 これらの事例を見てわかるように、便利なものにはダークサイドがあるということです。
何か便利なものを発見したときには、単に魅了されるのはきわめて危険です。
きちんとリスクを把握した上で適切にコントロールしておきましょう。

 普段のEmacsの使い勝手を大きく変えるパッケージにはよくよく注意が必要です。
便利だが仕組みが複雑なパッケージは、いざトラブルが起きたときには自分で問題解決することが困難です。
筆者は、パッケージはその利便性の代償を受け入れられる人だけが使うべきだと考えています。
エラーで使えなくなった場合は、その問題を自分で解決するか、代替の手段を講じなくてはなりません。
これがEmacsにおける利便性の代償です。
「特定のパッケージがなきゃ生きていけない」というのは、内部構造を熟知して、すばやく問題解決できるようになって初めて言えることです。

 自分が理解できないパッケージは使わない方がいいです。
自分が何をやっているのかがわからない状態は、機械の奴隷に成り下がっています。

トラブルの少ないパッケージの選び方

 トラブルの少ないパッケージの選び方の指針は、なるべく通常のEmacsからかけ離れないようにすることだと考えています。
「Emacs的に自然」であるということです。

 まず標準パッケージで実現できることであれば標準パッケージで済ませるのが一番です。
なぜなら、Emacs本体とともに継続的にメンテナンスされているからです。
将来のバージョンアップでも間違いなくその機能が使えるからです。

 確かに標準パッケージそのものがobsoleteになってしまうことはありますが、その場合は新しい手段が用意されているものです。
Emacs 24.4ではiswitchbがobsoleteになり、以前からあるidoやicompleteに取って代わられたのは記憶に新しいです。
obsoleteになってもしばらくの間は削除されないので、時間のあるときにゆっくりと移行していけばよいです。

 外部パッケージは放置されて新しいEmacsでは動作しなくなるリスクが伴うことを留意してください。
もっともelispは互換性を重視しているので、昔に書かれたelispもそのまま動くことが多いです。
それでも放置リスクについては頭の片隅に置いてください。

 編集コマンドのみが定義されているのは安全です。
そういうコマンドはいくらあってもいいです。
Emacsが新しいコマンドを学習しただけで、他の影響がないからです。
たとえばzop-to-charパッケージはM-x zop-to-charを実行するだけで使用できます。
そしてそれを便利に感じて初めてM-zに割り当てればいいです。

 特定のファイルの編集を快適にしてくれるメジャーモードも安全です。
なぜなら、対象のファイルを開いたときに初めて有効になるだけだからです。
その他の局面では影響は及びません。
ファイル名とメジャーモードの関係を定義するauto-mode-alistもパッケージをインストールした時点で設定されることが多いです。
たとえば、lua-modeパッケージをインストールすると、その時点で*.luaに対してlua-modeになるように設定されます。
編集したいファイルに対してメジャーモードが標準で存在せずに外部パッケージになっている場合は安心して導入してください。
あまり知られていませんが、 (require 'generic-x) を設定に加えれば、多くの設定ファイル用のメジャーモードが定義されます。

 Emacsの挙動を変更するパッケージは注意が必要です。
そういうのはフックやアドバイスを定義しているので、影響が広範囲に及ぶことがあるからです。
また、他のパッケージとの相性が悪いことがあります。

 自動で動作する機能は、かなり注意して使う必要があります。
Emacsには「タイマー」と「各コマンド実行前後に行うアクション」が定義できます。
前者は、一定時間後に自動で関数を実行します。
後者は、pre-command-hookとpost-command-hookです。
これらの機能はEmacsをとても便利にしてくれる超強力な機能ですが、代償を伴います。
自動実行される関数でエラーが起きた場合、わかりづらいです。
タイマーでのエラーはエコーエリアにerrorと出るだけなので見落とされがちです。
2つのフックでのエラーは自動的にその関数がフックから外されます。
開発者側にとってもこれらの関数のデバッグは困難を極めます。
よって、派手な自動実行に過度に依存しないようにするのもEmacs的処世術です。

 マイナーモードは干渉の恐れがあります。
特にキーバインドを定義しているマイナーモードは、マイナーモードの有効順によっては動作しないことがあります。
うまく解決できない場合はそのマイナーモードを無効にしてください。

 最後に、開発がとても活発なパッケージはしばしば非互換な変更がなされます。
以前のバージョンでは動いてもバージョンアップしたら名称が変更されたり削除された場合は、元の設定では動作しません。

helmは複雑さのコストを上回る利便性

 Emacsの操作性を大きく改善した大人気パッケージhelmは、以前の連載で紹介しました。
ミニバッファにクエリを入力して絞り込み検索を行い、複数の情報源(バッファ、最近開いたファイル、ブックマーク、カレントディレクトリのファイルなど)から多くのアクションが実行できます。
内部はとても複雑ですが、影響範囲は各種helmコマンド(M-x helm-mini, M-x helm-for-filesなど)を実行している間のみなのでEmacs全体にまで及んでいません。
仮にhelm使用時にエラーが起きて使えなくなっても、元の標準コマンドやido(バッファやファイル名を絞り込み選択する標準パッケージ)でしのげばいいです。
よって、利便性が複雑さのコストを上回っていると筆者は考えています。

 ただ、helmのありがたみはEmacs初心者にはわからないものです。
標準コマンドを使っていてそれで不便さを感じるようになって、改めてhelmのよさが実感できるものです。
中級者になればhelmは手放せなくなるでしょう。

キー割り当てを変更するのは安全

 新たなパッケージを模索よりも、なるべく標準コマンドでうまくやりくりする方が賢明と考えます。
前述したように標準機能はずっとメンテナンスされるので安心して使えます。
デフォルトの設定では不便に感じた場合、キー割り当てを変更することで劇的に操作性が上がることがしばしばあります。

 たとえば別ウィンドウに切替える(other-window)にはC-x oと2ストローク必要です。
フレームを3分割以上している場合、C-x oを繰り返すかC-x zでリピートする必要がありストレスがたまります。
頻繁にウィンドウを切替えるのならば、1ストロークのキーに割り当て直すのが無難です。
これはswitch-windowパッケージなどを導入するよりも手軽です。

(global-set-key (kbd "C-t") 'other-window)

 直前のウィンドウ構成に戻すことは標準パッケージのwinnerを使えば可能です。
別のバッファに切替えて後に元のバッファに戻したり、ウィンドウ分割状態を戻すことはよくやります。
winner-undoを1ストローク化してしまえば、それだけでpopwinと同等の操作性を亨受できます。

(winner-mode 1)
(global-set-key (kbd "C-q") 'winner-undo)

 連続して実行されうるコマンドはsmartrepやhydraを導入すればプレフィクスキーを省略できて便利です。
repeat(C-x z)を1ストロークに割り当て直すのもお手軽かつ強力な方法です。

一日の作業の終わりにEmacsを閉じる

 筆者がいつもやっている習慣をお教えします。
無駄なバッファやデータが増えるとEmacsが重くなりますが、そういう場合はEmacsを再起動をすることで軽快さを取り戻します。
よって一日の作業が終わったら、お疲れ様と言ってEmacsを終了しています。
tempbufパッケージはしばらく使っていないバッファを自動的に削除しますが、一日ごとにEmacsをリセットすればそれも不要です。
パッケージも最新版が使われるようになります。
ちょうど使ったものを片付けるようにEmacsを閉じ、明日は新しい気持ちで作業が始められる心理的なメリットもあります。
あなたも試してみては?

Emacsは人生

 Emacsはいくらでも強くなれます。
しかし強力な機能はそれなりの代償が伴うので、あくまでもあなたの理解の範囲内に限られます。
理解を超えたパッケージは、逆に機械に使われてしまいます。

 なので、便利なパッケージに惚れ込んだ場合「もっと早く出会いたかった」と後悔する必要はありません。
Emacs力が未熟な段階で出会っても受け入れ態勢ができていなかったことでしょう。
「今、その便利なパッケージを使っている」…この事実に満足しましょう。

 これは、算数と数学の関係と同じです。
方程式を使えばあっさり解けてしまう算数の難問奇問がありますが、限られた知識の範囲内で悪戦苦闘したからこそ、方程式という飛び道具のありがたみを感じるものです。
いきなり方程式を教えられても、小学生当時のあなたは理解できたでしょうか。

 Emacsは人生です。
洞察力を深めるには多くのパッケージに触れて理解に努めましょう。
欲しいパッケージが存在しなければ、自分でelispを書きましょう。

終わりに

 いかがだったでしょうか?
今回は総論的な話題で退屈していたかもしれません(笑)

 筆者は「日刊Emacs」以外にもEmacs病院兼メルマガのサービスを運営しています。Emacsに関すること関しないこと、わかる範囲でなんでも御答えします。「こんなパッケージ知らない?」「挙動がおかしいからなんとかしてよ!」はもちろんのこと、自作elispプログラムの添削もします。集中力を上げるなどのライフハック・マインド系も得意としています。登録はこちら→http://www.mag2.com/m/0001373131.html

本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。