南極の図書館

ペンギンが寝ていた…。

Eclipseをvimっぽく使うVrapperプラグインを入れた

「イージーモードが許されるのは小学生までだよねー。」

という有名なネタがある。
それはゲームの話なわけだが、仮にゲームはそうだとして、現実は、

「イージーモードに入れるのは工夫をした人間だけだよね。」

というのが正しいと思っている。
何かをやりとげなければならない。その志が高いほど、何も考えずにぶつかっていけば難易度が高くなっていく。
ゲームでいえばハードモードとかルナティックとかいうものになる。


私は最近、膨大な量のコードを読んでいて、もともと作業量が限界に近かった。
ジリ貧になっていたところ、今週から更に忙しくなり、これはもう絶対無理という感じに。
その一番大きな原因はEclipseの習熟度の低さというか、思うような移動ができないことだ。


「もうちょっとVimみたいに動いてみろよ!」


そんなことも言いたくなる。
ああ、そうだ。
考えてみたら「もうちょっとVimみたいに動いてみろよ!」と思う人はいくらでもいるだろう。
なら、解決策もいくつかあるだろう、と検索すると出てくる。


いくつかあったが、Vrapperというのを選んだ。
Vrapper — Vim-like editing in Eclipse
Eclipseの更新サイトに入れるならこれ。
http://vrapper.sourceforge.net/update-site/stable


いくつか設定をしたけどそれは今度書くので割愛。
結果だけ書くと、超便利。
今までハードモードを強制されていたゲームがイージーモードになった。
ゲームじゃなくて仕事だけど。


こうなるともう楽しくなってくるもので、今日はたっぷりと働いてきたし、明日からのスケジュールにも光が射した。


「イージーモードの入り方を探さないなんて、小学生までだよね。」

SoftbankからauのiPhone4Sに乗り換えた感想

数日使ってみたので、つらつらと書いていく。
主にezwebメールに対する不満だが、考えると最初はSoftbankもそうだったし、Androidも各社どうしようもなかったので、やむなしとも思う。

3GSと4Sの違い

ファミコンスーパーファミコンくらい違った。特に画面。


デザインは背面カーブの方が好きなんだけど、これでもさすがAppleというくらいはカッコイイ。
持ってはじめて気づくのは、4Sは一回り小さい。3GSは太ってるなという感じ。
それと、ホームボタンと画面の感触が良くなった感じ。気のせいかもしれないけど柔らかい。

結局、Softbankとauどちらがいいのか

電波が悪すぎるSoftbank、メールがひどすぎるauということで、引き分け。

電波

期待したほどの差は無かった。(私の活動範囲では。)
ただ、山手線を移動してる最中でもガンガン切れるソフトバンクと違って「入るべき」ところではきっちり入るのがau。
地下鉄などはあまり変わらない。旧800MHz帯が使えないとこんなもんだよね、という感じ。


それより、Softbankを使っていると「ソフバンだから入らなくても仕方ないか」とか「電話したいけど、ここってソフバンの電波入るかな」などと考え、実際に電波が入らない辛さよりも精神的な苦痛の方が大きかったので、それが無くなっただけで十分価値があった。

ezwebメール

3つ文句がある。

自動受信は15分に1回だけ

まず「自動受信は15分に1回」しかできない。
そのため「ezwebメアド取得→me.comに転送設定」する人が多いと思うけど(店頭でも勧められた)、それってただの転送だから。
me.comにメールが来る→手動でezwebを受信する→返信、という手順が必要。
怠慢、短気、傲慢なプログラマにこんな手順やらせたら精神崩壊してもおかしくない。
me.comにきたものをそのまま「返信」したい。むしろ何も考えないで返信したらそうなって「あれ?違うアドレスで来ましたよ」と言われた。
もうezweb要らないんだけど、1月までガマンできるならキャリアメールの方が何も言われなくていいし、耐えるしかない。(「me.comって何?」とか言われるのが面倒。)

絵文字

絵文字が使えない。おそらく全部。
他社に使えないだけならともかく、ezweb同士でも使えない。なんだこれ。
iPhone4Sにして、しかもauだからモテる!!なんて考えてたら、絵文字も使えないダメ野郎に。
これは絵文字アプリを入れればなんとかなりそうなので、どうしても絵文字送りたくなったら探してみる。(結構どうでもいい。)

iMessage未対応

MMSもダメ。1月対応予定とか。
既に解約したiPhone3GSでiMessageが出来るだけに、なんだかなぁと。


などと文句ばかりですが、私は性格上、Softbankのまま機種変更したら「auにしていたらどうなっていたか」と考え、比較記事を読んでも「そんなこと言っても体験してみないとわかんないよな」とモヤモヤしていたことは間違いないので、乗り換えは必然でした。
結論は最初に書いたとおり現時点では引き分けですが、来年1月頃からauの方が良くなるんじゃないかと思います。

Redmineプラグインチュートリアルについて

Redmineのプラグインを作ろうと思い、redmine.jpを調べてみた。
探してみると「その他の文書」に「プラグインの開発」の項目がある。
プラグインの開発 | Redmine.JP
そこからredmine.orgのチュートリアルの日本語訳を見つけたのでやってみた。
プラグイン チュートリアル - r-labs

チュートリアルの実施

結論から言うと、プラグインを:project_menuにする箇所でエラーとなってしまった。
「メニューを拡張する。」の「プロジェクトメニューを拡張する。」にあるこのコード。

def index
  @project = Project.find(params[:project_id])
  @polls = Poll.find(:all) # @project.polls
end

controllerでvoteを呼んだときにparams[:project_id]に何も入っていないので、エラーとなる。

  @project = Project.find(params[:project_id])
  rescue ActiveRecord::RecordNotFound
    render_404
  end

ちなみに、こうするとちゃんと404が出る。(Redmine本体のコードがこうだった。)
チュートリアルで見落としたところは無いようだったので、自分で書いてみた。
毎回パラメータで渡すのは嫌な感じもあるけど、どうなんだろう。
もっと本家のコードを見て書き方を覚えていかないと。

差分

チュートリアルに記載されているコードとの差分を置いておきます。
vendor/plugins/redmine_polls/app/controllers/polls_controller.rb

class PollsController < ApplicationController
……
  def vote
    poll = Poll.find(params[:id])
    poll.vote(params[:answer])
    if poll.save
      flash[:notice] = 'Vote saved.'
-     redirect_to :action => 'index'
+     redirect_to :action => 'index', :project_id => params[:project_id]
    end
  end
……
end

vendor/plugins/redmine_polls/app/views/polls/index.html.erb

<h2>Polls</h2>
 <% @polls.each do |poll| %>
  <p>
  <%= poll[:question] %>?
-  <%= link_to 'Yes', {:action => 'vote', :id => poll[:id], :answer => 'yes'}, :method => :post %> (<%= poll[:yes] %>) /
-  <%= link_to 'No', {:action => 'vote', :id => poll[:id], :answer => 'no'}, :method => :post %> (<%= poll[:no] %>)
+  <%= link_to 'Yes', {:action => 'vote', :id => poll[:id], :answer => 'yes', :project_id => params[:project_id]}, :method => :post %> (<%= poll[:yes] %>) /
+  <%= link_to 'No', {:action => 'vote', :id => poll[:id], :answer => 'no', :project_id => params[:project_id]}, :method => :post %> (<%= poll[:no] %>)
  </p>
<% end %>

「リファクタリング」の完全読破。その8、7章後半

前回に引き続き、7章の後半。
8月に読み終わる予定が、もう10月も中旬に。

委譲の隠蔽(P157)

カプセル化は、唯一のとは言わないまでも、オブジェクト指向技術の鍵である。

class Client... 
  //before
  _manager = john.getDepartment().getManager();
  //after
  _manager = john.getManager();  }


class Person{
  Department _department;
  public void setDepartment(Department arg){
    _department = arg;
  }

  //before
  public Department getDepartment(){
    return _department;
  }
  
  //after  委譲メソッドを作り、getDepartment()は削除する。
  public Person getManager() {
    return _department.getManager();
  }
}

class Department{
  //このクラスはリファクタリング前後で変更なし。
  private Person _manager;
  public Department(Person manager){
    _manager = manager;
  }
  public Person getManager(){
    return _manager;
  }
}
仲介人の除去(P160)

委譲の隠蔽の逆。
隠蔽をどの程度施すのか見極めるのは困難で、システムが変化すればその基準も変化していく。
適当だったカプセル化もしばらくすると扱いにくくなるが、それは悪いことではない。ひたすら直すこと。

外部メソッドの導入(P162)

「利用中のサーバクラスにメソッドを追加する必要があるが、そのクラスを変更できない」場合に行う。


約束は二つ。
作成するメソッドの第一引数は、サーバクラスのインスタンスとする。
決まったコメントをつける。(//外部メソッド;<サーバ名>クラスにあるべき)


コードの例が古すぎてEclipseが全力で取り消し線をつけてくれるんだけど、ここはDateクラスほどいい例が他に浮かばないのでそのまま写経してみた。
当時のDateクラスは、どこのシステムでも自社フレームワークとして拡張してるんじゃないかな。

Date newStart = new Date(previousEnd.getYear(), previousEnd.getMonth(), previousEnd.getDate() + 1);
↓
Date newStart = nextDay(previousEnd);
private static Date nextDay(Date arg) {
//外部メソッド;Dateクラスにあるべき
  return new Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1);
}
局所的拡張の導入(P164)

外部メソッドの導入は対象メソッドが2つまで、こちらは3つ以上のときに行う。
サブクラスかラッパーか、どちらでも採用できるが、ファウラーは可能ならば作業の少ないサブクラス化を勧めている。
新クラスには元のオブジェクトを引数とする変換用コンストラクタを作る。サブクラスにしたならsuperで、ラッパーなら委譲フィールドを設定する。
以下はサブクラスの場合の手順で、ラッパーの場合については割愛する。

Date newStart = new Date(previousEnd.getYear(), previousEnd.getMonth(), previousEnd.getDate() + 1);
↓
Date newStart = new MfDate(previousEnd).nextDay();
public class MfDate extends Date{
  public MfDate(String dateString) {
    super(dateString);
  }
  public MfDate(Date arg) {
    super(arg.getTime());
  }
  Date nextDay() {
    return new Date(getYear(), getMonth(), getDate() + 1);
  }
}


次回は8章だけど、先は長い。

「岸辺露伴 新宿へ行く」展を見にグッチ新宿に行ってきた

10/6、つまり今週木曜までということで、見れなくなる前に行ってきた。
店舗の前には常に10人ほどが携帯で撮影をしている感じで、私もとりあえず撮ってみた。


3Fでは、実際の原稿などが見れる。
最後には等身大の三次元の露伴が立っている。ここで履いているスニーカーが売れてるらしい。
3Fは撮影禁止と言われたので、写真は外のものだけだが、全体を通して迫力があって良いなぁと思った。
15分もあれば全部見れるだろうと思うので、あと2日、行ける人は是非どうぞ。


久しぶりに商品をぐるっと見たけど、GGを重ねてハート型にしたアイデアはうまいと思った。
4年くらい前に出たウェブのリボン、その後のハートに続いて、近頃のかわいらしいデザインは日本の女性に似合うと思う。

f:id:holypp:20111004180844j:image


こちらも参考に。
JOJO 0120 『岸辺露伴 グッチへ行く』の原画とそこに描かれたグッチ最新コレクション、さらに等身大の露伴を展示!“「岸辺露伴 新宿へ行く」展”の展示風景をご紹介します! - 荒木飛呂彦 公式サイト [JOJO.com]

「リファクタリング」の完全読破。その7、7章前半

7章は2回に分けて。今回は前半部分について。

第7章 オブジェクト間での特性の移動

オブジェクトの設計において根幹をなすのは責任をどこに配置するか。
しかし、ファウラーでも「責任を初めから正しいところに配置することができません。」と言う。
後からでも、リファクタリングを使って適切に配置していけば良い、ということだ。
それに、システムは変化していくということを忘れてはいけない。

P146 ある週では正しく適正であった設計判断も、次の週にはそうでなくなります。それが問題なのではなく、それについてなにもしないことが問題なのです。

このような状況を受け入れなければならない。
受け入れた上で、下記のような方法で解消していく。

メソッドの移動(P142)

メソッドが、定義しているクラスよりも他のオブジェクトを参照することが多い場合に検討する。
移動することでクラスが単純になり、責任の集合をすっきりした実装に収めることができる。
ただし、サブクラスまたはスーパークラスで利用しているメソッドであり、ポリモーフィズムをまるごと表現できないならば移動してはいけない。
メソッドの移動を行うメソッドへの参照が多い場合は、すべて書き換えるのは困難なので委譲メソッドを残す。
(コード例はフィールドの移動と合わせて後述。)

フィールドの移動(P146)

フィールドが、現在または将来に渡って、定義しているクラスよりも他のクラスから使われることが多いときに行う。
はじめに「フィールドのカプセル化(P206)」、「自己カプセル化フィールド(P171)」を行う。つまりprivateにしてアクセサを作る。
その後、フィールドの移動と参照しているメソッドの修正を行う。


上記二つの例を合わせて示す。
まずは、リファクタリング前のコード。

class Account{
  private AccountType _type    = new AccountType();
  private int _daysOverdrawn = _type.daysOverdrawn;
  //メソッドの移動前
  double overdraftCharge(){
    if(_type.isPremium()){
      double result = 10;
      if(_daysOverdrawn > 7) result += (_daysOverdrawn - 7) * 0.85;
      return result;
    }
    else return _daysOverdrawn * 1.75;
  }
  //フィールドの移動前
  private double _interestRate;
  double interestForAmount_days(double amount, int days){
    return _interestRate * amount * days / 365;
  }
}
class AccountType{
  public int daysOverdrawn;
  public AccountType() {
    daysOverdrawn = 8; //本来はもっと複雑な式
  }
  boolean isPremium(){
    return true; //本来はもっと複雑な式
  }
}


上記のコードをリファクタリングすると、下記のようになる。
なお、このコード例はあくまで手法を示すものであり、リファクタリングを適用する状況の判断は自分自身で行う。
(実際に、ここに書いたコードだけを見ると、私はメリットがあるとは思えない。)

class Account{
  private AccountType _type    = new AccountType();
  private int _daysOverdrawn;
  //メソッドの移動後に委譲にする場合。そうでなければ呼び出し元をすべて修正する。
  double overdraftCharge(){
    return _type.overdraftCharge(_daysOverdrawn);
  }
  //フィールドの移動後、アクセサに変更する。
  double interestForAmount_days(double amount, int days){
    return _type.getInterestRate() * amount * days / 365;
    //利用するメソッドが多い場合は_type.getInterestRate()を返すgetInterestRate()を作るのも良い。
  }
}
class AccountType{
  public int daysOverdrawn;
  public AccountType() {
    daysOverdrawn = 8;
  }
  boolean isPremium(){
    return true;
  }
  //メソッドの移動後
  double overdraftCharge(int daysOverdrawn){
    if(isPremium()){
      double result = 10;
      if(daysOverdrawn > 7) result += (daysOverdrawn - 7) * 0.85;
      return result;
    }
    else return daysOverdrawn * 1.75;
  }
  //フィールドの移動後、アクセサも定義する。
  private double _interestRate;
  double getInterestRate() {
    return _interestRate;
  }
  void setInterestRate(double arg){
    _interestRate = arg;
  }
}
クラスの抽出(P149)

クラスは、きっちり抽象化されたものであり、少数の明確な責任を担うべきである。
しかし、実際にはクラスは成長していくので、大きすぎて理解出来なくなったクラスは切り離す必要がある。
切り離し、元のクラスから新クラスにリンクを貼り(必要があるまで双方向にはしない)、低レベルなメソッドから移動していく。

(切り離したNewClassに対して、元のOriginalClassからリンクを貼る)
class OriginalClass...
  private NewClass _newClass = new NewClass();

クラスの抽出後に考えるのはアクセス制御。
publicは問題が多く、複製してから外部に渡すことも混乱の元になる。
ここでは元クラスを利用することを強制するか、新クラスを不変にするか、新クラスの不変インタフェースを用意する方法が薦められている。
また、最後に「クラスの抽出は、並列プログラムの並列実行可能性を向上するための一般的な技法」とも書かれている。

クラスのインライン化(P154)

クラスの抽出の逆。特に注意は無し。


7章は次回に続く。