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は太ってるなという感じ。
それと、ホームボタンと画面の感触が良くなった感じ。気のせいかもしれないけど柔らかい。
電波
期待したほどの差は無かった。(私の活動範囲では。)
ただ、山手線を移動してる最中でもガンガン切れるソフトバンクと違って「入るべき」ところではきっちり入るのがau。
地下鉄などはあまり変わらない。旧800MHz帯が使えないとこんなもんだよね、という感じ。
それより、Softbankを使っていると「ソフバンだから入らなくても仕方ないか」とか「電話したいけど、ここってソフバンの電波入るかな」などと考え、実際に電波が入らない辛さよりも精神的な苦痛の方が大きかったので、それが無くなっただけで十分価値があった。
ezwebメール
3つ文句がある。
自動受信は15分に1回だけ
まず「自動受信は15分に1回」しかできない。
そのため「ezwebメアド取得→me.comに転送設定」する人が多いと思うけど(店頭でも勧められた)、それってただの転送だから。
me.comにメールが来る→手動でezwebを受信する→返信、という手順が必要。
怠慢、短気、傲慢なプログラマにこんな手順やらせたら精神崩壊してもおかしくない。
me.comにきたものをそのまま「返信」したい。むしろ何も考えないで返信したらそうなって「あれ?違うアドレスで来ましたよ」と言われた。
もうezweb要らないんだけど、1月までガマンできるならキャリアメールの方が何も言われなくていいし、耐えるしかない。(「me.comって何?」とか言われるのが面倒。)
絵文字
絵文字が使えない。おそらく全部。
他社に使えないだけならともかく、ezweb同士でも使えない。なんだこれ。
iPhone4Sにして、しかも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年くらい前に出たウェブのリボン、その後のハートに続いて、近頃のかわいらしいデザインは日本の女性に似合うと思う。
「リファクタリング」の完全読破。その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章は次回に続く。
「リファクタリング」の完全読破。その6、第6章後半。
前回は「第6章 メソッドの構成」から『総論と「メソッドの抽出(P110) 」「説明用変数の導入(P124)」』について書いたので、今回は残りの項目を。
大きなものは「メソッドオブジェクトによるメソッドの置き換え」くらいで、あとは項目名のとおりという印象。
(※下記のコード片は、本書の例を元に短縮等を行ったもの。)
第6章 メソッドの構成
「メソッドのインライン化(P117)」
不要な間接化、つまり委譲のみ行っているようにみえたら行う。単純な場合にのみ行い、複雑な場合は避ける。
return (moreThanFive()) ? 10 : 0; boolean moreThanFive(){ return _preAmount > 5; } ↓ return (_preAmount >5) ? 10 : 0;
「一時変数のインライン化(P119)」「問い合わせによる一時変数の置き換え(P120)」
「一時変数のインライン化(P119)」は、よく「問い合わせによる一時変数の置き換え(P120)」の一部として使う。
先に変数をfinalにしてみるのがコツ。エラーがなければ一度しか代入されていないことがわかる。
これらも、一度だけ代入されるか副作用がない場合に行う。
複数回代入されるなら「一時変数の分離(P128) 」、副作用があるなら「問い合わせと更新の分離(P279)」を適用することを考える。
//一時変数のインライン化 double todayPrice = anOrder.getTodayPrice(); return (todayPrice > 1000); ↓ return (anOrder.getTodayPrice() > 1000); //問い合わせによる一時変数の置き換え double basePrice = _quantity * _itemPrice; return basePrice * 3; ↓ return basePrice() *3; private double basePrice() { return nowPrice * quantity; }
「一時変数の分離(P128)」
複数回代入される一時変数は、代入ごとに別の一時変数に分ける。
複数回設定されるのは、複数の責任を担っていることを示す。 複数の責任を担う変数は、コードを読む人を混乱させる。
double temp = 2 * (_height + _width); System.out.println(temp); temp = _height * _width; ↓ final double perimeter = 2 * (_height + _width); System.out.println(perimeter); final double area = _height * _width;
「パラメータへの代入の除去(P131)」
int discount(int inputVal) if(inputval > 50) inputVal -= 2; ↓ int discount(int inputVal) int result = inputval; if(inputval > 50) result -= 2; //代入が悪いだけで、メソッドの使用はなんら悪いことではない。 void aMehod(Object foo) foo.modifyInSomeWay(); //OK foo.setBar(); //OK foo = anotherObject; //NG
この項目で重要なのは、上記の例よりも ”Javaは、厳密にはすべて値渡しを使っている””本質的に、オブジェクトへの参照は値渡し”ということ。
「メソッドオブジェクトによるメソッドの置き換え(P135)」
メソッドの分解を困難にするのはローカル変数である。Method Objectパターンを使う。
ちょっとこれは大きいので、無意識に出来るようになるまで何度か本書を読み直した方が良さそう。
class Account int gamma(int a, int b, int c){ int value1 = (a * b ) + delta(); int value2 = (a * c) +100; if ( (c - value1) >100 ) value2 -=20; int value3 = value2 *7; return value3 - 2 * value1; } ↓ class Account int gamma(int a, int b, int c){ return new Gamma(this, a, b, c,).compute(); }
TDDの調子で、抽出したGammaクラスとcomputeメソッドを書く。
これでリファクタリングの対象はGamma.compute()になる。というテクニック。
「アルゴリズムの取り替え(P139)」
文字通り、よりよいアルゴリズムに変更する。項目として必要なのはわかるんだけど、内容はタイトル以上のものでもないので割愛。
以上で第6章は終了。