効率よくデバッグする方法

Eclipseデバッガを活用する31のTipsにたくさんのはてブがつきました。たくさんの方に見ていただけたようで、とてもうれしいです。どうもありがとうございました。
デバッガの使い方のスライドを作ってみたものの、効率良くデバッグする方法については書いていませんでした。例えば、ブレークポイントをどこに貼ると効率が良いのか、教えてほしいという声がありました。デバッガ機能をどう使うとより効率的にデバッグできるのか、考えてみました。

デバッグにおける2つのポイント

突然ですが、僕は、デバッグには下記の2つのポイントがあると考えてます。

  • 障害の再現方法を調査する。
  • ソフトウェアの内部状態を調査する。

みなさんはどうやってデバッグしていますか?僕がデバッグを行う時の流れを書いてみると、

  1. 報告された情報を元に、障害がどうやって起きるのか、再現方法を確認します。
  2. 再現方法が報告されていない場合は、再現方法を調査します。
  3. ソフトウェアの内部状態が障害発生時にどうなっているか把握するため、再現方法の調査中、変数などソフトウェアの内部状態も観察します。
  4. 再現方法と障害発生時の内部状態がわかれば、障害が起きる内部状態にならないよう、ソースコードを修正します。
  5. 再現手順を実施して障害が修正されている事を確認します。
  6. 障害の修正により、デグレードが起きていないかを簡単に確認します。

こんな感じでデバッグを行っています。

「障害の再現方法」と「ソフトウェアの内部状態」をデバッグのポイントとして上げたのは、デバッガとは、これらのポイントの調査を支援するものだからです。それぞれについて、どんな機能があるか、少しTipsをふりかえってみましょう。

障害の再現方法を調査するための機能

僕は、デバッガを知る前は、何度も何度も繰り返し操作し、再現する操作を調査していました。しかし、デバッガの機能を使うと、繰り返し操作しなくてもデバッグできるようにします。

例えば…
変数ビューでの値書き換えられます。
f:id:kompiro:20131013191415p:plainf:id:kompiro:20131013191414p:plain

表示ビューから例外をthrowできます。手元にソースコードがないクラスの中で例外が起きていて、その再現が難しい場合とかに重宝します。
f:id:kompiro:20131013200812p:plain

Drop to Framef:id:kompiro:20131013191339p:plainを使うと実行状態を破棄できるので、何度でも繰り返し実行できます。(※インスタンス変数や
ローカル変数は元に戻りますが、クラス変数など元に戻らないものもあることに注意)
f:id:kompiro:20131013191340p:plain

ソフトウェアの内部状態を調査するための機能

僕がデバッガを知らない頃は、標準出力に変数の値を出力して内部状態を確認してました。
標準出力に変数を出力するなど、デバッグソースコードを書き換えてしまうと、そのままコミットしてしまう事もあるでしょう。
デバッグ情報がコンソールに出力され、意図せずに内部状態が見えてしまう状態は良いものではないですよね。
しかし、デバッガを使えば、ソースコードを書き換えずに内部状態を調査できます。

例えば…
変数ビューでは変数の値が見られます。
f:id:kompiro:20131013191422p:plain

式ビューでは、各オブジェクトのメソッドの実行結果を監視できます。
f:id:kompiro:20131013191343p:plain

コードの上の変数も、実行中であれば選択してInspectできます。
f:id:kompiro:20131013191424p:plain

表示ビューではデバッグ中のプロセスに対し、コードを書くことで状態をInspectできます。
f:id:kompiro:20131013203119p:plain

こうしてみると、デバッガの機能の多くは、これらの2つのポイントを調査するためのものだとわかると思います。

得られている情報による障害の分類と、効率的なデバッグ

さて、報告された障害は、得られている情報によりいくつかの状態に分類できます。

  • 再現手順が報告されていて、その通りに実施すると障害を再現できる
  • 再現手順が報告されているが、その通りに実施しても障害を再現できない
  • 再現手順は不明だが、スタックトレースなどで例外が発生する箇所がわかっている
  • 再現手順は不明だが、再現しそうなコードの箇所を推測できている
  • 再現手順は不明の上、どこでその処理が行われているかよく分からない
  • 障害が報告されているが、再現手順が不明で報告されており、調査してみたが原因が推測できない

それぞれどうやってデバッグするでしょうか。順に見て行きましょう。

再現手順が報告されていて、その通りに実施すると障害を再現できる場合

障害の再現手順が明確にわかっていて、その通りに実施したら障害を再現できる場合、障害が起きているコードの場所がわかればかなりの確率で解決できるでしょう。最近は、障害報告に動画が使われる事もありますが、動画で報告されている場合は、この分類に入るでしょう。
この場合、予めログなどを埋め込み、どの処理が呼び出されているかわかるようにしておけば、呼び出される処理の場所にブレークポイントを貼り付けられるので、障害が発生する箇所の特定にそれほど時間をかけずに済むでしょう。

再現手順が報告されていて、その通りに実施しても障害を再現できない場合

再現手順の通りに実施しても障害を再現できない場合は、

  • 実行環境が違う(OSやブラウザ、バージョン、環境変数など)
  • 再現手順を実施する前処理が足りていない
  • 再現手順が漏れている

など、障害を再現できない要因がいくつか考えられます。例えば、

  • 報告者と実行環境が異なる事が明確な場合、実行環境をできるだけ揃えてみる
  • 前処理として書かれている項目の手順が不明瞭な場合、前処理が足りていない事を疑う
  • 再現手順を実施してみると、実際は操作できない手順があるなど、手順が怪しい場合は手順の漏れを疑う

等々が考えられます。それでも再現できない場合は、現象と再現手順が報告されていることを意識しながら、再現手順を実施した時に呼び出されるソースコードを読んでみましょう。障害の原因を推測できる場合があります。障害の原因が推測できれば、その周辺にブレークポイントを貼り、デバッガを開始します。障害が起きそうな内部状態にならないか、観察しましょう。特に実行環境が異なる場合など、デバッグしづらい場合は、内部状態を書き換えて再現しないか、試してみてください。

再現手順は不明だが、スタックトレースなどで例外が発生する箇所がわかっている

再現手順が不明の場合、本当にその障害があるのか、確認できていません。そういう意味では、修正しないでも良さそうなものです。しかし、スタックトレースなどで例外が発生している事が判明している場合、それは障害が発生した証拠が残っている事なので、速やかに調査を始め、修正を試みましょう。

例外が発生する箇所がわかっている場合、例外が発生した箇所周辺に原因があることを特定できているといえます。そのため、その周辺コードを読み、どういう状態で例外が起こるか推測し、例外が発生する箇所の周辺にブレークポイントを貼るか、例外自体にブレークポイントを貼り、その処理が呼び出される操作を行い、デバッガを使って例外が再現する内部状態をシミュレートしてみます。意図した通り例外が発生するのであれば、そういう内部状態にならないようにガードするなど、コードを修正しましょう。

再現手順は不明だが、再現しそうなコードの箇所を推測できている

再現手順は不明でも、障害の内容から、再現しそうなコードの箇所が推測できている場合があります。この場合も調査してみるべきでしょう。
障害の内容から再現しそうなコードの箇所が推測できてるのであれば、デバッガを使って障害が発生する内部状態を再現してみます。そして、内部状態を再現して障害が発生するのであれば、その内部状態が発生しそうな手順を推測し、再現するか試します。障害が再現するのであれば、その内部状態にならないように修正しましょう。

再現手順が不明の上、どこでその処理が行われているかよく分からない

障害の内容を見て、どこでその処理が行われているか推測できない場合は、その処理が行われている場所がどの辺りなのか、チームの他のメンバーに聞いてみましょう。チームに話してみて、推測できない場合は、再現不能として障害の修正を諦めるべきかもしれません。

障害が報告されているが、再現手順が不明で報告されており、調査してみたが原因が推測できない

障害を調査してみても原因が推測できない場合、チームの他のメンバーに調査を引き継いでもらいましょう。他のメンバーが引き継げるよう、チケットなど障害を管理しているシステムに、調査した内容を追記し、調査を代わってもらいます。
調査した内容をまとめてみると、コードと障害の理解が深まり、原因に気づく事もあります。他のメンバーに引き継いでもらった場合も、自分では気づかなかったことに気づくかもしれません。

忘れてはならない大事な事

障害を修正すると、デグレードを起こすリスクがあることを忘れないでください。障害の影響が軽微なのに修正による影響が広範囲に及びそうな場合は、チームに相談しましょう。場合によっては障害を修正しない、という判断になるかもしれません。
また、修正内容が心配な場合、チームメンバーにレビューを依頼する勇気を持ちましょう。

最後に、そもそも論でデバッガを使ったデバッグを考えてみると・・・

ただ、そもそも論で考えると、デバッガを使ったデバッグは、案外負けパターンなのかもしれません。
と言うのも、最初に書きましたがデバッガでできることは、内部状態の調査と障害の再現の2つです。これらはxUnit等のテスティングフレームワークとテストコードを用意する事で、素早く実施することができます。
テスティングフレームワークを使って十分に検証されていれば、どういう操作が行われた時に状態がどうなるのか、テストコードから内部状態を推測できます。また、デバッガを使ったデバッグよりもテスティングフレームワークを使った方が、短い時間で再現を確認できるでしょう。そして、テストコードで検証しているレベルでデグレードの発生が確認できるのもメリットです。

テスティングフレームワークとテストコードはとても便利なツールです。しかし、テストコードをただ書くだけでは、時間を費やす事が多く、効果を上げられません。テストコードを書くにも、スキルが入ります。このスキルは、上達させる事ができるものです。効果的にテストコードを書くにはどうすればよいでしょうか?それはまた、別の機会に。

Eclipseデバッガを活用する31のTips

speakerdeckに貼ろうかどうか迷ったけれども、どこかで話したわけではないのでslideshareに。

Eclipseのデバッガを活用すると開発が捗ります。自宅ではIntelliJを使い始めてみて、さくさくコードが書ける事を体感しているのですが、デバッグEclipseの方がやりやすいです。で、自分の知っているノウハウをチームで共有するために作りはじめたんですが、広くみんなに公開したほうがいいと思っておすそ分け。調べてみると、結構知らなかったネタがゴロゴロでてきました。Run to Lineとかお手軽で強力な機能だと思う。

「こんなネタ知りたい」とか、フィードバックを是非お寄せください。調査して追記していきますので、コメントとかよろしくお願いします。

Strategyパターン

とあるきっかけで、Strategyパターンとはなんなのか、考えてみたくなった。Strategyパターンはオブジェクト指向でコードを書いていると随所に見られるパターンだからだ。例えばWebサイトの入力チェックを行うValidatorなんかは、Fieldオブジェクトにいくつか持たせられる形で実装しておく事が多い。例えば下記のような形で実現されていないだろうか。

f:id:kompiro:20130929194340p:plain

会員登録のページを想像するとわかりやすいと思うのだけど、ページの中に複数のフィールドがあり、それぞれのフィールド毎に入力チェックをしなければならないとする。上図のように入力チェックのアルゴリズム毎にクラスを用意しておき、それぞれのフィールドに必要な形で設定していく事ができる。この形の優れているところは、入力チェックのアルゴリズムを再利用できるところだ。会員登録のような機能は、様々なサイトで利用される機能だし、どれも似通ったものだからだ。

そのアルゴリズムを、上図のEmptyValidatorのように、空文字かどうかチェックするだけのValidatorを用意しておけば、必須チェックかつEmailのフォーマットをチェックすると言った、ユーザーを識別用のEmailの入力フィールドを作成するなんてことも簡単だ。

さて、デザインパターンの原典であるGoF本によると、Strategyパターンの目的は

アルゴリズムの集合を定義し、各アルゴリズムをカプセル化して、それらを交換可能にする。Strategyパターンを利用することで、アルゴリズムを、それを利用するクライアントからは独立に変更することができる。

とある。上記のように、入力チェックはアルゴリズムをカプセル化して交換可能になっているので、Strategyパターンが見受けられる。Strategyパターンは別名Policyパターンと呼ばれる。Policyと名付けられるクラス群も同様に交換可能な形で実現されることが多いから、そういう別名がつけられているのだと思う。

最近は、テストコードを書くために、mockで差し替えられるようにある処理の単位でクラスを作成し、テストコードからのみ差し替えられるよう、defaultスコープのsetterを用意する事もよくやる。SWTとかSwingとかのアプリは、警告ダイアログを表示することがあるけど、これをそのまま表示すると、テスト時にダイアログが表示されてしまう。それが邪魔なので、テストコードから利用するときは、差し替えられるようにしておくのだ。

Erich Gammaによると、デザインパターンとは、オブジェクト指向プログラミングの上級実装者がコードによく表現する構造等をパターンとしてまとめたものだ。InfoQにErich Gammaがデザインパターン等について語ったインタビューによると

私はEclipseを発展させている間、実際にEclipseアーキテクチャーをパターンを使って説明したのは本当に楽しかったです。
私が説明した、「Contributing to Eclipse:(和名:Eclipseプラグイン開発 デザインパターン×テスト駆動開発)」では、あるチャプターで…、あ、その本の共著もKent Beckでしたね。私はEclipseアーキテクチャについて、パターンを使って説明することに挑戦しました。
それは私にとってとても良いテストとなりました。なぜならEclipseはまだ全然、ある種の「私達はパターンを使っている」と言ってきたわけではありませんからね。それは開発者たちの経験からできたものなのです。
彼らはオブジェクトの設計技術についてとても理解していて、だから私は最後のほうは、もし、あなたがEclipseの中にあるアーキテクチャや設計について探してみると、どれだけパターンによって、キーとなる部分を説明できると思いますか?それは私にとってちょっとした喜びでしたし、幾つかのよい感じの対象を見つけることができました。

とある。

XUnit Test Patternsでちなみに、GoF本が書かれたのは1995年。JUnitが産まれたのは2000/12/3なので、たぶんユニットテストが一般的になる前。テスト時にモックオブジェクトで差し替えられるようにするなどという話はまだなかっただろう。(テスト時にモックオブジェクトで一部処理を差し替えられるようにするのは、XUnit Test Patternsでまとめられている。というか、それで知った。)*1

Strategyパターンというのは、コードを書く時にある部分だけ別のクラスに委譲し、入れ替えられるようにする時によく見られる構造にだ。テストコードを書く時にも助けになるパターンなので、覚えておくといいと思う。

*1:自動テストは、既にオブジェクト指向が産まれる前から取り組まれている。そのコードをユニットテストと呼ばれていたか、調べ切れなかったが、テスト用のドライバと呼ばれていた。また、テスト用のスタブを作る事で、開発前のコードでもテストできるように先人は取り組んでいた。ただ、ここで述べたかったのは、Strategyパターンを使って、テスト時にテスト用の処理を行うように置き換える事は有効ということでした。

Continuous Modeling

みなさまご無沙汰しております。僕はここの所、残業はしないまでも毎日クタクタになるほど忙しい毎日を過ごしています。どんな仕事か一言でいうと、あるプロダクトのアーキテクチャを刷新するお仕事です。今までできなかったあれやこれやを実現するために、既存のアーキテクチャを改善したり、作りなおすお仕事です。今はまだ始まったばかりで、方針を決めるために、既存のアーキテクチャ上に機能拡張してみて問題点を調査したり、どう改善するのか方針案を考えたり、実際に改善案を少しずつやってみたりしています。
このプロジェクトは、それほど大所帯ではないですが、他の会社のエンジニアさんも加わるなど、結構スキルセットがバラバラです。そのため、久しぶりにペアプロで作業を回しています。1日じゅうペアプロすると、一日の終わりの頃には頭がクタクタです。久しぶりです、この感覚。楽しい。
さて、既存のアーキテクチャを見ていくと、10年以上続いているプロジェクトなので、継ぎ足し継ぎ足し増築を重ねた温泉旅館のような風情を持ったクラスがゴロゴロあります。リリースする前に時間のプレッシャーに負け、十分にリファクタリングしきれなかった部分が積み重なり、かなり訳が分からない構造になっているクラスが結構あるわけです。10年以上前はJUnitが世の中に広まる前のコードなので、テストコードも十分にありません。ここに、ほんものの、れがしーこーどがあるぞ。
レガシーコード改善ガイドよろしく、テストコードを書いてリファクタリングを進めていく事もできます。しかし、いきなりその作業には入れません。今実現されている姿はこうなっているけど、本来どうなっているべきなのかを考える段階なのです。だから、どうやってアプリが実現できているのか、機能を拡張してみて問題点を探り、感じた問題点をチームに共有するために、2,3日に1回は朝会の後にモデリングのワークショップをしています。
思い返せば、以前自分が所属したアジャイルなプロジェクトでは割とモデリングをしてきていました。アジャイルソフトウェア開発宣言に記名した方々の多くはOOPSLAで発表するようなOOスペシャリストの皆さんです。実は、オブジェクト指向設計の技術がアジャイルソフトウェア開発の基盤技術です。
少し前の自分は、TDDで実装を進めれば自然といい感じのOO設計ができるんじゃないか、モデリングはしなくてもいいんじゃないか、と思っていました。でも、2,3日に1回、短時間のモデリングワークショップをしてみると、割とメンバー毎にコードに対して抱いているクラス構造が違う事が多く、メンバー間のモデル認識を揃える意味で、この活動は重要なんじゃかろうかと感じるようになりました。この活動の事を、Continuous Integrationや、Continous Deliveryという名前が流行しているので、僕はContinuous Modelingと名づけてみました。同僚からはDaily Modelingじゃないか、とか色々言われています>< Kanbanの中で毎日30分モデリングする時間を取ると品質が向上する、という話が書かれていたので、実践してみました。
ところで、ちょっと前に書籍「ドメイン駆動開発」を読み返していたのですが、この本の中では「オブジェクト指向はモデルをコードに表現するための手段」と言うような事が書かれていました。(正確な表現は失念しました。スミマセン。)ただ、僕はこの表現に「我が意を得たり」と膝を叩きました。クラスに責務を割り当てたり、適切な名前をつけるのは、会話の中で登場するモデルをコードの中に表現するための活動だったんですね。
自分が考える良くないコードの代表例の1つは、モデリングを全くせずに拡張を続け、一つのクラスに様々な責務を割り当ててしまう、と言うものです。言い換えると、1つのクラスにだらだらと処理が書かれているクラス。メタファに例えるなら、クリスマスのプレゼント袋とか、福袋というものでしょうか。(これを僕は「モデルが薄まったクラス」と表現してみたものの、同僚から「よく分からない」と言われました。名前付けはいつも本当に難しいですね。)要求が実現されているので、確実に役に立つものが中に入っているけど、妥当な名前がついていないから中に何が入っているか分からない状態になっている状態。後で機能拡張する時に処理を追いかけてみると、なんかよくわからないけど呼ばれているコードとか、ありませんか?そういうクラスです。こういうクラスが、コードの中にモデルをうまく表現できていないクラスです。
オブジェクト指向設計は、いかにこういう責務が曖昧なクラスを減らし、明確な責務をクラス構造に落としこみ、コードに実装するか、という活動なんじゃないかと最近考えるようになりました。だから「チーム」で「定期的」に「モデリング」を行う事が割と重要だと思うのです。
チームでモデリングする、と言ってもそんな大した事をしていません。ホワイトボードの前に立って共有したい疑問点や、違和感をUMLなどのモデル図に描きだしてみます。モデル図は、あくまで概要的なもので、どこに違和感があるのか、疑問点があるのか、解説しながら描いていきます。そうすれば、単に解説を口頭で話をするよりも、どこの話をしているのか指し示せたり、関係を目に見える形で議論できるので、より具体的に話を進められます。こういう疑問点や違和感の共有が、より良いオブジェクト指向設計について議論するきっかけになるので、単に構造を改善に留まらず、オブジェクト指向設計のスキル伝達になるような教育も兼ねられます。
例えば僕はどんな事に違和感を感じるのか、例をあげてみます。

  • 構造的な違和感
    • 分割すべき責務
    • 過剰な継承
      • 継承階層が深くなると、上位クラスの変更が下位クラスに影響を及ぼす事が増えるため、修正が難しくなる
    • 過剰なif文の改善
    • 過剰なユーティリティクラスの導入
      • モデルが知っているべき情報や処理であれば、モデルに移しましょう
    • 適切なパターンの導入
      • ValidationをStrategyパターンにする
    • 過剰なパターンの導入
      • 特に不要なSingletonに注意する
    • 過剰なinstanceofによるStrategyの切り替え
      • クラスとStrategyをEntryにしたMapの導入
    • 類似クラスの発見
    • アーキテクチャを拡張するようなレイヤーの発見
  • 振る舞い的な違和感
    • 相互関連から片方向関連へ
    • 循環参照の解消
      • 相互にメッセージが飛ぶ構造は理解しづらさを生む。メッセージが片方向から流れるようにモデルの振る舞いをとらえ直す
      • コミュニケーション図を描いてみる
    • 実装を共有するための継承
      • 委譲を使うようにする。
  • 整理すべき依存関係
    • 過剰に多くのクラスに依存したクラスの発見
    • パッケージ間の依存を整理する
      • インタフェースやAdapterの導入による実装の隠蔽
      • コンストラクタやメソッドのパラメータ数の削減
        • パラメータオブジェクトの導入
  • テスタビリティを向上させるための試み
    • 依存するオブジェクトの削減
      • fieldに保持するオブジェクト数が多いとsetupしづらいクラスになる
    • テストケースが多い実装は責務過多の兆候
      • 新たな責務を抽出し、クラスを作成し、テストケースを分担する
    • 過剰なUIへのアクセス
      • Strategyパターンを導入し、テスト中はテストダブルに置き換える

割とこういう事はこれまでの開発経験によって異なってくると思うので、一度チームのメンバーで話し合ってみると面白いでしょう。ということで、今日はContinuous Modelingを紹介してみました。オブジェクト指向の設計力を向上させたいチームは、試してみてください。

オブジェクトデザイン (Object Oriented SELECTION)

オブジェクトデザイン (Object Oriented SELECTION)

  • 作者: レベッカ・ワーフスブラック,アラン・マクキーン,株式会社オージス総研藤井拓,辻博靖,井藤晶子,山口雅之,林直樹
  • 出版社/メーカー: 翔泳社
  • 発売日: 2007/09/13
  • メディア: 大型本
  • 購入: 3人 クリック: 52回
  • この商品を含むブログ (41件) を見る

レガシーコード改善ガイド (Object Oriented SELECTION)

レガシーコード改善ガイド (Object Oriented SELECTION)

  • 作者: マイケル・C・フェザーズ,ウルシステムズ株式会社,平澤章,越智典子,稲葉信之,田村友彦,小堀真義
  • 出版社/メーカー: 翔泳社
  • 発売日: 2009/07/14
  • メディア: 大型本
  • 購入: 45人 クリック: 673回
  • この商品を含むブログ (145件) を見る

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)


Clean Code アジャイルソフトウェア達人の技

Clean Code アジャイルソフトウェア達人の技


Kanban

Kanban

Quick JUnitのプロジェクト構造の改善と開発用のドキュメント作成開始

4/25はQuick JUnitにとって大事な日。と言っても、今回は新機能の開発はできず、プロジェクト構造の整理と開発用のドキュメントを書き始めました。
https://github.com/kompiro/quick-junit
https://github.com/kompiro/quick-junit/wiki/DevelopmentGuide

実験的に開発していたプロジェクトをみんなexperimentalの中に移動しました。僕が手を付け始めていた、よくわからない機能群がプロジェクト直下にたくさんあり、なんとかしようと常々思っていました。この機会に整理しました。

僕が日常で常用プラグインはstableの下にあります。それ以外の開発中のものはexperimentalの下です。APIの動きを把握するためのコードは、learningの下にあります。QuickJUnitのオリジナルのソースコードはstable/originalの下にあるので、覗いてみてください。

ところで、プロジェクトの構造化にはMavenが役にたちました。みんなあんまり好きじゃないMavenですよね。でも、今はTychoプラグインがあるので、Eclipseプラグインのビルドが本当に楽になりました。

Eclipseのプラグインのビルドは、以前からantが黒魔術的に使われていました。build.propertiesの内容を元にプラグインビルド用にbuild.xml生成してそれをサブプロセスで実行するとか、変態的な事が行われており、ビルド環境の設定がとても煩雑でした。それがpom.xmleclipse-pluginって書くだけでプラグインとしてビルドしてくれるとか、超らくちんです。

http://quick-junit.sourceforge.jp/updates/beta/ に今回整理した後のp2リポジトリを配置しました。良かったらそちらからQuick JUnitのインストールをしてみてください。

また、開発用のドキュメントですが、不足がありましたら@kompiroまでご連絡ください。お待ちしてます。

Notification Center経由で時報を流す

遅ればせながらMountain Lionに切り替えた。

アプリケーション毎にフルスクリーン表示ができるってことは、作業に集中できそう。そして、三本指で切り替えられるし便利、これは重宝する!と思ったら、メニューバーが非表示で、時間が分からない。時報を音声で外でマシンを使ってる時、大体の時間を知りたいので、時報できるようにしてみた。

やったこと

terminal-notifierのインストール

terminal-notifierはコマンドラインで通知できるruby製クライアント。パッと見た感じかなり重宝しそうなgemですね。

$ [sudo] gem install terminal-notifier

使い方をざっと書くと

$ terminal-notifier -[message|group|list] [VALUE|ID|ID] [options]
-message VALUE - 本文
-title VALUE - タイトル
-subtitle VALUE - サブタイトル
-group ID - 通知グループの指定。IDが同じ通知が重複した場合、一つの通知にまとめる。
-remove ID - 指定したIDの通知をNotification Centerから消す。
-list ID - 指定したIDの通知の内容を詳しくをまとめて表示。

と言う物。べんりですなあ。

スクリプトの準備

launchdから定期的に呼び出すので、下記のようにスクリプトを~/bin/time_signal.shとして作成しておきます。

/usr/local/opt/rbenv/shims/terminal-notifier -group time_signal -remove time_signal -message $(date +%H:%M)になりました -title 時報 > /dev/null

僕はrbenvを使っているので、terminal-notifierのパスが上記のパスになってます。ご自分の環境にあわせて適切に設定してください。

launchdの設定

~/Library/LaunchAgentsの下に、下記の設定ファイルを作りましょう。ファイル名は「[launchctlに登録するID].plist」という形式です。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>ファイル名で指定したlaunchctlに登録するID</string>
    <key>ProgramArguments</key>
    <array>
      <string>絶対パスでtime_signal.shを指定</string>
    </array>
    <key>WorkingDirectory</key>
    <string>/tmp</string>
    <key>StartCalendarInterval</key>
    <dict>
      <key>Minute</key>
      <integer>0</integer>
    </dict>
    <key>StandardOutPath</key>
    <string>/dev/null</string>
    <key>StandardErrorPath</key>
    <string>/dev/null</string>
  </dict>
</plist>
launchctlに登録する
launchctl load [launchctlに登録するID]

これで時報が表示されるようになります。

時報の表示時間を変更したい時

[launchctlに登録するID].plistファイルのStartCalendarIntervalの値を変更し、

launchctl unload [launchctlに登録するID]
launchctl load [launchctlに登録するID]

と読み込み直しましょう。

UbuntuでDNSサーバーが見られなくなった時に気をつけること

/etc/resolv.confを自動生成するresolvconfというツールが使われている模様。設定は/etc/resolvconf/resolv.conf.d/baseの中に記述する。下記はさくらVPSの例

search sakura.ne.jp
nameserver 210.188.224.10
nameserver 210.188.224.11

ところでこれって何でこうなったんだろう。