2011年6月30日木曜日

技術者と英語:「読める」だけで嬉しい三つの事

TOEIC 800点前後というと、レベルBに当たる。

TOEIC が提示している相関表の説明によると、「どんな状況でも適切なコミュニケーションができる素地を備えている」、「日常会話は完全理解」、「業務上も支障なし」とされている。

なんて言っても、実は「話す」「書く」が未経験でも「聴く」「読む」がソコソコできれば、割と取れる点数だったりする。自分もだいぶ前に 800を越えたが、恥ずかしながら全然喋った事なんかない。

つうか話す相手も機会も今のところ一切無いし、従って興味も沸かず努力のしようもないんだけど、ソフトウェア開発技術者としては、「読める」だけで結構役に立つ事がある。

以下の3つ。

◆ 英語でググれる
言うまでもなくインターネットは日本語情報より英語情報の方が圧倒的に多いし、技術情報は特に英語圏発のものが時間的にも先行している事が多い。

英語が読めると、Google の search settings で、English を設定しておいても別に問題ないから、情報量の少ない日本語サイトを避けて効率的に検索できる。

技術系BBSでのディスカッションやトラブルシューティングでも、海外の方が盛んで検索にもヒットしやすい。


◆ 技術系の洋書が読める
最近は、少しだけ改善したようだけど、一昔前の邦訳書は、かなり読みにくいものが多かった。APIリファレンス的なものはまだマシな方だけど、ちょっとユーモアを交えた語り口になったり、思想的に難解な話になったりすると、途端に日本語がおかしくなる。

邦訳書の日本語に対する文句は至る所で聞くけど、最初から原書にしておけば、無駄なイライラをせずにすむ。つうか、無駄な変換レイヤーが無いという点で情報処理の視点からもある意味合理的なわけで、技術者ならなおさら原書を選択すべき。


◆ ソースコードが英語に見えてくる
意外と意識されていない事が多いが、ほとんどの高級プログラミング言語は英語ベースだったりする。

まず単語の面で、言語のキーワードにおいても、各種 API の識別子においても、そのほとんどは英語の語彙、つまり何百年も前からアングロサクソンが日常のコミュニケーションの中で使ってきた言葉で構成されている。

また文法の面でも、意識的にか無意識的にか知らないけど、メソッド呼び出しの文が、「subject.verb(object)」みたいな感じで、だいたい英語の語順に従うようになっていたりする。

なので、上手に書いたプログラムは自然言語としての英語に近くなり、下手なコメントやダイアグラムなんかよりも、書き手の意図を読者に、より効率的、より直截に伝える高い表現力を持つ事ができる。

英語が「読める」ようになるだけでも、人間同士が意思疎通するコトバという観点から見たプログラムの良し悪しがより分かるようになり、ソースの読み書き両面に良い効用が出てくる。

====
ちなみに、逆に英語が全然読めない人の場合、英文としての表現力さえ備えるに至った良質なコードを前にしても、解読を要する意味不明な記号の羅列か、もしかすると ASCII アート的な図形にしか見えていないのでは、と疑わしくなる場面がよくある。

こういう人達って、「ソースを読む」ではなく「ソースを解析する」という言い回しを好む。「ソースが言葉である」なんて事は脳内ですら成立したためしがないから、「読める」コードなんか自分でも書ける訳もなく、必然的に無駄なコメントだらけの残念なコードを書いてしまうことになる。

2011年6月27日月曜日

java の static メソッドの mocking

しばらく .net 案件とかやってた間に、いつの間にか Java でもstatic メソッドに mocking が適用できるようになっていたらしい。

ググってみると、今のところ PowerMock と JMockit が、どうやら使えそうな感じ。

前に Java をやっていた頃、mocking には jMock(いわゆる「流れるようなインターフェイス」が何とも素敵な奴だったのだが)を使っていたが、この jMock の制約のせいで java では static メソッドは迂回もすり替えもできないと諦めていた(final 外しはあったが)。

考えてみれば、.net の Mole も TypeMock も instrumentation を使っていたわけだけど、Java だって 5.0 からは instrumentation があったんだから、とっくにできていて不思議はなかった。

しかし、どっちを使えば良いか悩む。

つうか、昔と同じく jMock を使うという選択肢も捨てきれないから、3択になる。いや、PowerMock は EasyMock か Mockito と組み合わせるからもっと選択肢が増える(jMock との組み合わせもできないことないらしいが、ちょっと不安)。

カバレッジツールとの相性とか、微妙な使い勝手の優劣とかもあるだろうし、急いで決めねばならない状況ではあるんだけど、拙速な決断は危ない。

うーん、もっと早く気づいていればなあ…

2011年6月24日金曜日

Fedora 15/Jenkins/Maven3/Subversion/Helios

空きマシンに入れていた Fedora 12を Fedora 15 Lovelock に入れ替えて、自宅環境の筆頭開発マシンに昇格させ、ついでにその他開発ツールもセッティングした。その作業の超ザックリメモ。

====

Helios: Fedora の「ソフトウェアの追加と削除」から GUIでインストール。Fedora 12の時は Galileo だったが、Fedora 15 では Helios (Eclipse 3.6)になっていた。

Maven 3: apache のダウンロードサイトからバイナリを落としてきて適当に展開。README.txtを見ながら適当に設定、"mvn --version" で 3.0.3 が入ったことを確認。

Subversion: これも「ソフトウェアの追加と削除」でインストール。バージョン 1.6.16 が入ってきた。"svnadmin create" で適当にリポジトリを作っておく。差し当たり file://でアクセスするだけなので、これ以上の設定は保留。

m2eclipse: Helios の「新規ソフトウェアのインストール...」で、更新サイトに[このURL]を指定してインストール。

Subclipse: Helios の「新規ソフトウェアのインストール...」で、更新サイトに[このURL]を指定して、Subclipse, Client Adapter, JavaHLを選択してインストール。

Jenkins: [ここ]を見てインストール。"sudo /etc/init.d/jenkins start"で起動し、ブラウザで localhost:8080 を開いて確認。で、とりあえず stop しておく。

テスト用プロジェクト作成:

  • Helios に戻る。
  • maven-archetype-quickstart を指定して新規 Maven Projectを作成。
  • pom.xml で JUnit のバージョンを4.8.2に変更して、依存性を更新。
  • App.java を書き換える
    public class App {
        public String getMessage() {
            return "Hello World!";
        }
    }
  • AppTestを書き換える
    public class AppTest {
       @Test
          public void testGetMessage() {
          String message = new App().getMessage();
          Assert.assertEquals("Good-Bye World!", message);
       }
    }
  • Maven package を実行して、テストでビルドが失敗するのを確認。
  • 上で作ったリポジトリを指定して"プロジェクトの共用"を実行し、適当にファイルを選んでバージョン管理に追加して、敢えてテスト失敗版をコミット。

Jenkins に Jobを追加:

  • "java -jar /usr/lib/jenkins/jenkins.war"で起動する。(init.d/jenkins startだと、file:// で SVNリポジトリにアクセスできなかったので、とりあえず war を直接起動。)
  • ブラウザから開いて、[Manage Jenkins]/[Configure System] から、右のように Maven の設定 → Install Automatically をアンチェックして、上でインストールした Maven のパスをMAVEN_HOMEに指定。
  • Jenkins の[New Job] で [Build a maven2/3 project] を選択。"Source Code Management" で Subversion を選択し、上で作ったリポジトリを指定。

Build 確認:

  • [Build Now] を実行し、テストでビルドが失敗している事を確認。
  • Helios に戻ってテスト・メソッドの"Good-Bye"をHelloに変えて、SVNコミット。
  • 再び[Build Now] でビルド。今度はテストを含むビルドが成功している事を確認。

====

TODO

  • svn+ssh でのリポジトリアクセス
  • サービス化
  • Trac の導入とSVNとの連携
  • SVNコミットをトリガーとする自動ビルド
  • FishEye導入
  • Emma 導入

2011年6月21日火曜日

アジャイルの資格

アジャイル関連の資格について調べてみた。

アジャイルと認定資格って、なんとなく相容れないイメージで、開発者の間でも物議を醸しているらしいが、最近は結構、動きが活発になってきている。

まあ他の資格と同じで、保有しているからといって実務能力があるって事にはならないだろうが、少なくとも会話が成立するレベルの語彙を持っている事の表明くらいにはなると思う。もちろん実践で成功している人なら、我流に偏らないお墨付きの正統な知識も持っているという事になり、鬼に金棒で言う事が無い。

====
◆ Scrum Alliance: 認定スクラムマスタ 等
すでに日本でも取得者が増え始めている、Scrum Alliance の認定資格。

トレーニングコースに参加する必要があり、日本開催時の受講体験記をネットでも散見する。ただ、これが結構高い。ざっと検索したところ、同時通訳付きで20万、通訳なしで15万といったところか。会社の金ではなく個人で受けるとすると、ちょっとした決断が必要になる。

なんか昔のイメージだと、お金を払って2日間の講習に座ってるだけで取れるって感じだったけど、調べてみると、今は一応、インターネット経由の試験で知識を証明する必要があるらしい。

ちなみに Master 以外には、ProductOwner, Developer, Professional, Trainer, Coach といったものがある。


◆ Scrum.org: Professional Scrum Master 等
URLはここ

Professional Scrum Master I (Fundamental) :
トレーニング・コースも提供されているが必須ではなく、自信があればいきなりネット試験を受験してもよく、そこで 85%とれば合格らしい。

Professional Scrum Master II (Intermediate):
これもネット試験だが、小論文もあるらしい。費用もやや高額。

Professional Scrum Developer:
これはコース受講と試験の両方が要るらしいが、ただトレーニング・コースの方は欧米中心の開催。アジアでは今のところインドだけっぽい。

Professional Scrum Product Owner:
これもコース受講とネット試験。


◆ PMI: PMI-Agile Certified Practitioner

先月、Pilot Programが始まったばかりの PMIのアジャイル認定試験。

以前、PMP の勉強をしていたとき、使っていた問題集でも参考書でも、道路の延伸工事プロジェクトだとか、小売業の店舗拡大プロジェクトだとか、予想外にソフトウェア開発と離れた設問ばかりで、PMBOKってそう言うものだったのかと、ちょっと驚いた。

でも、同じ PMI の資格でも、PMI-Agile のFAQを見ると、馴染みのあるアジャイル開発の用語ばかりで、ソフトウェア開発者としてちょっとテンションが上がってくる。


◆ ICAgile:
ユースケースで有名なコーバーンとかが創立した、ICAgile なる組織でも、認定試験を提供する計画らしい。

組織自体が発足したてで、試験などはまだまだ形になっていないようだけど、この記事を読む限り、結構おもしろそうではある。

Java のスレッドプール

『More Effective C#』の item 11 に、"Use the Thread Pool Instead of Creating Threads"というのがある。new で スレッドを生成するのではなく、.Net で提供されるプールを使えと。

で、昨日『Effective Java (2nd edition)』を調べていると、item 68 で、ThreadPoolExecutor が紹介されていたので、ちょっと試してみた。

====

以下のような状況を想定する。

  • クライアントが Socket をつなぐと、サーバは ServerSocket で accept()して、1から10までの整数乱数を 1000個返す。
  • クライアントはその整数を一つずつ読み取り、幾ばくかの処理時間を要する何らかの処理を行う。ここでは、読み込んだ整数をミリ秒の時間間隔と捉えて、その分だけ sleep() させるようなコードを書く事にした。

クライアントは以下のようなコード。

public class Receiver {

   private static final short LISTEN_PORT = 3434;
   private static final int CORE_SIZE = 1;
   private static final int MAX_SIZE = 100;
   private static final int KEEP_ALIVE = 10;

   private static final ExecutorService pool = 
      new ThreadPoolExecutor(
         CORE_SIZE, MAX_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, 
         new LinkedBlockingQueue());

   public static void main(String[] args) throws IOException {
      Socket socket = new Socket("localhost", LISTEN_PORT);
      DataInputStream in = new DataInputStream(socket.getInputStream());

      long start = System.nanoTime();
      for (int i = 0; i < 1000; ++i) test(in.readInt());
      System.out.println((System.nanoTime() - start) / 1000000000.0);

      in.close();
      socket.close();
  
      pool.shutdown();
   }

   private static void executeTimeConsumingProcess(int interval) {
      try {
         TimeUnit.MILLISECONDS.sleep(interval);
      } catch (Exception e) {}
   }

   private static void test(int interval) throws IOException {
       //ここを書き換えて比較する
   }
}

で、この test() メソッドの中身を変えて、①逐次実行(並列なし)、②スレッドを生成する方式、③スレッドプールを使う方式で比較してみる。(サーバー側は、DataOutputStream で整数を返すようなコードになるが、ほぼ自明なので省略。)

① まず、並列処理をしない逐次実行のパターン

private static void test(int interval) throws IOException {
   executeTimeConsumingProcess(interval);
}
実行時間は、約 5.6秒と出た。平均 5ms の処理が1000回なので、だいたい想定どおりの結果。

② 次に、スレッドを生成するパターン。

private static void test(final int interval) throws IOException {
   new Thread(new Runnable() {
      @Override public void run() {
         executeTimeConsumingProcess(interval);  
      }
   }).start();
}
これは約 0.14秒と出た。当然ながら、逐次実行よりは大幅に速い。

③ 最後に、スレッドプールを使うパターン。

private static void test(final int interval) throws IOException {
   pool.execute(new Runnable() {
      @Override public void run() {
         executeTimeConsumingProcess(interval);
      }
   });
}

結果は約 0.028秒で、スレッド生成の5倍のスピードが得られた。やっぱり、それなりにパフォーマンスは良いらしい。

====

プールの初期サイズ、最大サイズなどを調整すると、若干値が変わってくる。実務で使うときは、実行環境に応じて調整できるような仕組みを作っておくと良いかもしれない。

ThreadPoolExecutor よりさらに手軽に使えるスレッドプールが、Executors の newCashedThreadPool() や newFixedThreadPool() などのメソッドで得られるが、一応試してみたところ、ThreadPoolExecutor を直に使うより、若干遅かった(倍くらいの所要時間)。もちろん、簡易な分、調整は利かない。

2011年6月20日月曜日

Effective Java からperformance 関連項目

以下、『Effective Java (2nd Edition)』 から、パフォーマンスに関係する項目。

赤:パフォーマンスに特に関係する項目
橙:パフォーマンスに割と関係する項目
黄:パフォーマンスに一部だけ関係する項目

Item 1: Consider static factory methods instead of constructors
オブジェクトの生成が抑えられるという static factory methods の利点について、instance-controlled class というキーワードで記述されている。Flyweight パターン(GoF)的に活用するとパフォーマンス向上に効果あり。

Item 5: Avoid creating unnecessary objects
「immutable なオブジェクトは常に再利用しよう」とか、「boxing / unboxing による暗黙のオブジェクト生成に気をつけよう」などといった注意喚起。

Item 6: Eliminate obsolete object references
メモリリーク対策として紹介されているが、オブジェクトへの参照を常に null out することは、無駄に内部品質(すなわちコーディングの生産性)を損なうバッド・プラクティスとされている。null 代入するなら、メモリリークを起こし易い場所に見当を付けて集中的に行うべき。

Item 7: Avoid finalizers
デストラクタ感覚で使うのは止めましょうという話だが、往々にして期待通りに動かないし、そもそも必要性からして疑わしい。さらに深刻なパフォーマンス劣化さえもたらしうるとの記述がある。

Item 9: Always override hashCode() when you override equals
極端な例だが、hashCode()で定数を返したりなんかすると、リニアなアクセス時間になって、本来 のHashXXX の パフォーマンスが得られないって話。

Item 15: Minimize mutability
クラスを定義する際には、できるだけ immutable にして行こうという、今ではかなり普及したプラクティス。パフォーマンスとの関連でいえば、無駄なオブジェクト生成を抑えられるという利点と、値が変わる度に新規インスタンスが必要になるという欠点の、両面があるので注意。

Item 48: Avoid float and double if exact answers are required
業務アプリのプログラマには常識的な話。ただ、あるデータ項目について、どの程度正確な値が求められているか、必ずしも自明ではない。BigDecimal で精度をとるかプリミティブ型でパフォーマンスをとるか、やはり要件によりけり。

Item 49: Prefer primitive types to boxed primitives
Integer や Long などを無自覚に使うと、暗黙の boxing / unboxing で深刻にパフォーマンスが落ちうると言う話。

Item 50: Avoid strings where other types are more appropriate
特にパフォーマンスへの言及は無いが、普通に考えればわかるとおり、本来それ専用の型定義で表現されるべきデータ構造を、下手に文字列なんかで扱ったりすると、内部品質にもパフォーマンスにも悪影響がある。

Item 51: Beware the performance of string concatenation
まあ常識。StringBuilder を使いましょうと。

Item 53: Prefer interfaces to reflection
普通のメソッド呼び出しより reflection の方が遅いという普通の話。

Item 54: Use native methods judiciously
昔と違って JVM が大幅に速くなった今では、JNI経由の native メソッド使用は、期待するほど効果がないという話。

Item 55: Optimize judiciously
「未熟な最適化は諸悪の根源」という Knuth の言葉など、今よりもメモリが小さくCPUが遅くてパフォーマンスが難問だった時代から受け継がれる先人の警句を引用して、やみくもなコード最適化/パフォーマンス・チューニングについて警告している。このブログでも書いてきた(これとかこれ)。

Item 57: Use exceptions only for exceptional conditions
Exception をループ境界の判定などの制御フローに使ったりするのは、本来の使い方から逸脱しているだけでなく、パフォーマンスにも悪影響がある。まあ、そこまでバカな事する人なんか見たことないけど。

Item 66: Synchronize access to shared mutable data
「アトミックなデータならば、パフォーマンス向上のための同期コード省略が可能」という迷信を批判。

Item 67: Avoid excessive synchronization
同期コードによる待ちが増えると、並行性の機会が奪われたりしてパフォーマンスが上がらないという普通の話。synchronize ブロックから alien method を呼ばないとか、synchronize ブロックを小さく留めるとかヒントが書かれているけど、まあ普通はそれほど簡単にいかないので、工夫のしどころではある。

Item 68: Prefer executors and tasks to threads
スレッドプールが標準APIで提供されているので活用すべし。

Item 69: Prefer concurrency utilities to wait and notify
高パフォーマンスな concurrent collection の紹介など、java.util.concurrent パッケージ活用のすすめ。

Item 71: Use lazy initialization judiciously
パフォーマンスに良かれと思って lazy initialization を書いても、大抵は逆効果だから止めておけと。どうしても必要なら、static field には lazy initialization class イディオム、instance field には double-check イディオムを使うこと。

Item 75: Consider using a custom serialized form
デフォルトのシリアライズ形式は、ロジカルなデータ形式に着目したカスタムのシリアライズより、パフォーマンスが悪い事が多い。

2011年6月19日日曜日

CodeComplete からパレートの法則など

『リファクタリング』第2章 の「リファクタリングとパフォーマンス」を読んでいたら、Steve McConnell の『Code Complete (下巻)』への参照があった。

以下、「25章 コードチューニング戦略」から抜粋。

パレートの法則:
成果の80%は作業の20%から得られる

Barry Boehm:
20%のルーチンがプログラムの実行時間の80%を消費

Donald Knuth:
プログラムの4%未満がプログラムの実行時間の50%を占める

Jon Bentley:
あるプログラムで、0.5%の行が実行時間の80%を占めていた

Steve McConell:
あるプログラムで、1%未満のコードが実行時間の90%を占めていた

まあ、数字は異なるが言ってる意味は一緒で、要するにパフォーマンスに影響を及ぼしている部分はプログラム中のかなりちっちゃい部分だって事。まあ、アプリケーションのパフォーマンス改善の経験者には、割と常識かと。

「25章 コードチューニング戦略」では、この他に「コードを書くそばから最適化すべきだ」という稚拙な戦略についても、バッサリ斬っている。これは以前の自分のポストでも同じような事を書いた。

また、チューニングを段階的に繰り返して効果を累積させる戦術を、さかんに奨励している。ただし当然ながら、それをやるには、それ相応の内部品質=コード保守性が維持されていなければならない。例えば、パフォーマンスと引換えに内部品質が落ちるような箇所に関して、これを局所化するようなリファクタリングを併用しつつ、コードチューニングを積み重ねるというやり方が必要になると思われる。

あと、コード・チューニングはパフォーマンス改善策の一部であって、実は、アーキテクチャやデータ構造によるパフォーマンスへの影響に比べたら意外と大したことない場合が多いとも言っている。当たり前のことだけど結構大事だと思う。