読者です 読者をやめる 読者になる 読者になる

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

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

RSpecでGZipされたファイルのopenをmockするメモ

require 'open-uri'
binary = open(filepath,'rb')
read = mock('open')
read.stub(:readpartial).and_return{|length| 
  binary.readpartial(length)
}
if (defined? content_encoding).nil? or content_encoding.nil?
  read.stub(:content_encoding).and_return([])     
else                               
  read.stub(:content_encoding).and_return(content_encoding)
end