So-net無料ブログ作成
検索選択

今日で一ヶ月目が終り [その他]

転職しての一ヶ月目が今日で終りです。で、この一ヶ月で何が変わったかというと
  • 飲み会が激減。以前は、Java教育の日に教育が終わった後に生徒の人達との飲み会が月に2回、部門の月例飲み会、それに「飲みに行こうか?」という会社帰りの飲み会。私の肝臓には非常に良いことかもしれません。
  • フレックス勤務ではないので、朝、家を出る時間が毎日同じです。
  • 通勤時間が長くなり、多くの本が読めるようになりました。(「長くなった通勤時間」)
  • (まだ何も開催していないので)朝の勉強会がありません。(そのうち開催しようかと考えています)
  • 当然ですが、新しい職場で多く人達と仕事をするようになり、知り合いが増えました。
  • 通勤のために歩く距離が前よりも長くなりました。
  • 今のところ、職場の自分の机の上が綺麗です。以前は、1台のWindows PCと2台のLinux PCの合計3台のPCに加えて、書籍が何十冊とありました。今は、1台のWindows PCと本が数冊だけです。

Writing code without tests ... [プログラマー現役続行]

Joshua Bloch氏の今日のつぶやき(Twitter)から・・・・
Writing code without tests is like doing surgery without washing hands.

テストなしでコードを書くのは、手を洗わないで手術するようなものだ。
Joshua Bloch
あえて言えば、「自動実行可能なテストなしでコードを書くのは、・・・」ですね。

自動実行可能なテストは、ソフトウェア業界では今では常識です。しかし、昔は、『リファクタリング』の著者マーチン・ファウラー氏や『クリーンコード』の著者ロバート・マーチン氏でさえも自動実行可能なテストは書いていませんでした。

(書籍『Coders at Work』の中で)Joshua Bloch氏は、もっとも苦労したデバッグは何かと聞かれて、Transarc社に勤務していた時に自分達が開発したシステムの不具合を調査するために様々なテストコードを書いて一週間ほど費やして調査したことだと述べています。しかし、その結果は、Solaris用に会社内で作成していたmutex実装のバグだったのです。その件に関して、「そのmutexの作者は十分なテストを書いていたと思うか」という質問されて、次のように回答しています。
Bloch: I think a good automated unit test of the mutex facility could have saved me from this particular agony, but keep in mind that this was in the early 90's. It never even occurred to me to blame the engineer involved for not writing good enough unit tests. Even today, writing unit tests for concurrency utilities is an art form.

mutex機構の優れた自動テストがあれば、そのような苦労をせずに済んだと思います。しかし、 それは90年代の初めだったことを踏まえてください。関係したエンジニアが十分に良い単体テストを書かなかったことを非難することさえ私には思い付かなかったのです。今日でさえ、並列ユーティリティのために単体テストを書くことは、芸術なのです
私も90年代初めは、自動化された単体テストというのは、全然頭に無かったです。

HashMapの大きさ [Java]

Javaのソースコードをレビューしていると、HashMapを作成して、キーと値の組を数個しか入れていないものを見かけたりしています。実際、マッピングとして、3個のキーと値の組しか入れていなくて、そのようなHashMapを3個作成しているコードがありました。

そこで、HashMapのオブジェクトの大きさを調べてみました。HashMapを作成すると、そのインスタンスには、以下のインスタンスフィールドが含まれます。

 (配列)参照型 1個、int型 3個、float型 1個

これだけで、5個×4バイト=20バイトです。参照型は、ネストしたクラスであるEntry型の配列となっており、最初にデフォルトでは大きさ16の配列が生成されています。つまり、16×4バイト=64バイトの大きさの配列です。したがって、デフォルトのままでHashMapを生成すると、84バイトは最低限消費します。

そこに、3個のキーと値の組を入れたとすると、ネストしたクラスであるEntryクラスは4個のフィールドを持ちますので、4×4バイト×3個=48バイトを消費します。HashMapとの合計で84バイト+48バイト=132バイト。

そして、このようなHashMapを3個作ると、132バイト×3個=396バイトとなります。さらにキーがIntegerクラスで値がBooleanクラスであり、個別にインスタンスを生成していました。つまり、キーと値の9個の組だけで、9×2×4バイト=72バイト。すべてを合計すると、396バイト+72バイト=468バイト。

これに対して、大きさ3の配列と大きさ3×3の配列で書き直したので、12×4バイト=48バイト。元々の3個のHashMapで表を構築しようとしているコードは非常に可読性が悪かったのですが、すっきりと書き直すことができ、使用するメモリー量も1/10になりました。

大量のデータを取り扱う場合に、O(1)の計算スピードを得るためにHashMapを利用します。しかし、データが3個しかない場合には、O(N)であるアルゴリズムでも問題ない訳です。通常のプログラミングでは、HashMapの大きさを気にすることはありませんが、単純な配列で表現できる小さなデータをHashMapで表現しようとすると、コードの可読性が低くなり、不必要にメモリを消費する可能性もあるということです。

「ソフトウェアエンジニアの心得」教育 [プログラマー現役続行]

今日は土曜日ですが出勤日です。有給休暇年末まで4日しかないので、出勤します。今日の午前中は、会社の新卒新人向けに「ソフトウェアエンジニアの心得」教育を行います。内容は、講演で話していることとほぼ同じです。今日が新卒新人の集合研修の最終日であり、無理にスケジュールに入れてもらいました。

日程がまだ確定していませんが、11月の金曜日の夕方に横浜で講演する予定です。ある会社主催のセミナーです。他のスピーカーもおられるので、おそらく1時間の短縮版(普通は2時間半)で話をします。日時が確定次第、お知らせします。

(「新人からの育成の重要性」、「講演」)

Integrating unit testing into the organization [プログラマー現役続行]

The Art of Unit Testing: With Examples in .net

The Art of Unit Testing: With Examples in .net


昨日通勤中に読み終えたので、そのまま会社に置いてきました。自動実行可能な単体テストを定着させる活動をこれから行うのですが、役立ちそうなことが多くの述べられている書籍でした。

この出版社の本で良い点は、本を買うと、PDF版も入手可能なことです。本は会社にそのまま置いておいて、自宅ではPDF版を参照できます。それと、この書籍の場合、PDF版はカラーなので、白黒印刷された本と違って、図が見やすいです。

自動実行可能な単体テストを組織に定着させるには、色々な問題や障害が発生すると思っていますが、成功しても失敗しても、私自身が何かを学ぶことができる機会だと思っています。

デバッガー [プログラマー現役続行]

Coders at Work

Coders at Work

  • 作者: Peter Seibel
  • 出版社/メーカー: Apress
  • 発売日: 2009/09/11
  • メディア: ペーパーバック

昨日やっと届きました。とりあえず、Joshua Bloch氏のインタビューだけ読みました。"How did you get into programming?"という質問に対して、1971年に彼がまだ10歳の時に父親がプログラミングコースでFortranを習っていたので、父親からFortranを教えてもらったという話から始まっています。1971年といえば、私は12歳で佐賀県の嬉野に住んでいましたが、コンピュータに触れる環境など全くない頃でした。私が始めてプログラミングを覚えたのは、大学に入学してからですので18歳でした。

このインタビューの中で一番驚いたのは、大学院を修了して、Sunで働きはじめる1996年まではずっとC言語でプログラミングをしてきており、真剣に使った最初のオブジェクト指向言語がJavaだということです。1996年からJavaを始めて、コレクションフレームワークを設計・実装し、2001年に『Effective Java プログラミング言語ガイド』を出版するのですから、やはり、普通の人ではないということでしょう。

色々と興味深い内容が書かれているのですが、デバッグではどんなツールを使うのかとうことに関して、次のように回答しています。

Bloch: I'm going to come out sounding a bit Neanderthal, but the most important tools for me are still my eyes and my brain. I print out all the code involved and read it very carefully.

少しばかりネアンデルタール人のように聞こえるかもしれませんが、私にとって最も重要なツールは今もなお私の目と私の脳です。関連するコードを印刷して、それを注意深く私は読みます。

Debuggers are nice and there are times when I would have used a print statement, but instead use a breakpoint. So yes, I use debuggers occasionally, but I don't feel lost without them, either. So long as I can put print statements in the code, and can read it thoroughly, I can usually find the bugs.

デバッガーは素晴らしいですし、いつもならprint文を入れるような時に、代わりにブレークポイントを使うこともあります。だから、たまにはデバッガーを使うこともあります。しかし、デバッガーがないと困るわけではありません。コードにprint文を入れることができて、じっくりと読むことができれば、大抵はバグを見つけることができます。

As I said, I use assertions to make sure that complicated invariants are maintained. If invariants are corrupted, I want to know the instant it happens; I want to know what set of actions caused the corruption to take place.

先ほども述べたように、複雑な不変式が維持されているかを確認するために、アサーションを使用します。もし、不変式が破られていたら、それが破られ時にすぐに知りたいのです。つまり、破壊を起こした処理が何であるかを知りたいのです。
私も実は、デバッガーはほとんど使いません。それに、コードにやたらデバッグ用のトレース文を入れたりするのも嫌いです。本来のロジックがトレース文の中に埋もれているようなコードを見るとうんざりする時があります。

デバッグの時に、自分の仮説を検証するための最低限のprint文を入れてデバッグし、デバッグが終わったらそのprint文を削除します。

デバッガーに頼りすぎると、デバッガーがないとデバッグできませんという人も現れてきます。さらに、デバッガーが知りたい情報を表示してくれないので、デバッグできませんと言う人まで現れてきます。

(「デバッグの科学的手法」)

業務を通した学習の落とし穴 [プログラマー現役続行]

拙著『プログラマー現役続行』では、「業務を通した学習の落とし穴」(110頁)として次のように述べています。
 新たな技術を習得するのに最も効率的な方法は、業務で使用している技術について学習することです。業務で使用していますので、すぐに業務に役立ちますし、多くの時間その技術に接しているため、効果的に学習することができます。
 業務を通じての知識の蓄積は効果的なのですが、落とし穴もあります。それは、業務をこなすのに最低限必要な事柄だけしか学ばないで終わってしまうことです。
業務で使用する技術が自分にとって初めての場合に、その技術を学習方法には、大きく次のどちらかのパターンに分かれるのではないかと思います(極端な分類ですが)。
  1. 初心者本を買ってきて、それを読んで、あとは、詳細を理解することなく、他人のコードをコピーペーストしてソフトウェア開発を行う。
  2. その技術のバイブルとなるような書籍を探して、それを読んで、技術の詳細まで学ぶ努力をしながら、ソフトウェア開発を行う。
業務で使用する新しい技術の経験はなくても、その技術習得のための態度が重要です。(A)と(B)の差は、非常に大きいです。たとえば、社会人になって5年目の人を考えてみると、(A)で5年間過ごした人と、(B)で5年間過ごした人では、大きな差として現れます。それをソフトウェア開発組織に適応してみると、物凄い差となります。

つまり、(A)で5年間過ごした人ばかりの集団は、(B)で3年間過ごした人の集団に絶対に負けます。それは、可読性も含めた作り出されるソフトウェアの品質に大きな差となって現れ、結果として組織としての生産性の大きな差となります。

たとえば、仮に20名のソフトウェアエンジニアから構成される開発組織でJava言語を用いた開発だとして、そのほとんどの人が『プログラミング言語Java 第4版』『Effective Java 第2版』 を読んでソフトウェア開発をしている場合と、どちらも全く読んだことなく単なる初心者本だけでしか学習したことがない場合では、必然的に大きな差となって現れてきます。

前職で2000年に始めて、今年の8月まで継続していた「プログラミング言語Java教育」は、今振り返ってみると(B)を経験させる教育だったと思います。

(「Don't Live with Broken Windows」)

Java 7のArrays.sort(Object[]) [Java]

Java 7のEarly Access版をダウンロードしました。昨日、Joshua Bloch氏にProject Coinへ彼が提案している言語仕様の変更はすでに実装されているのかと聞いたところ、まだプロトタイプされていないということでした。で、その話のついでに、ソートの話になり、Java 7にはTimSortが入っているということで、調べてみました。

従来、コレクションフレームワークのArraysクラスのsort(Object[])は、今まではマージソートで実装されていました。しかし、Java 7にはパッケージプライベート宣言されているTimSortクラス(TimSort.java)が追加されており、Arrays.sort(Object[])(と関連する他のsortメソッド)はデフォルトでTimSortクラスのsortメソッドを使用するように書き換えられています。

TimSort.javaクラスのソースコードに書かれているJavadocコメントは以下のようになっています。
A stable, adaptive, iterative mergesort that requires far fewer than n lg(n) comparisons when running on partially sorted arrays, while offering performance comparable to a traditional mergesort when run on random arrays. Like all proper mergesorts, this sort is stable and runs O(n log n) time (worst case). In the worst case, this sort requires temporary storage space for n/2 object references; in the best case, it requires only a small constant amount of space.

This implementation was adapted from Tim Peters's list sort for Python, which is described in detail here:

http://svn.python.org/projects/python/trunk/Objects/listsort.txt

Tim's C code may be found here:

http://svn.python.org/projects/python/trunk/Objects/listobject.c

The underlying techniques are described in this paper (and may have even earlier origins):

"Optimistic Sorting and Information Theoretic Complexity"
Peter McIlroy
SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms),
pp 467-474, Austin, Texas, 25-27 January 1993.
Tim Peters氏の実装に基づいているので、TimSortと呼ばれているようです。

200万個のデータでベンチマークしてみました。ランダムなデータ、ソートされたデータ、逆順にソートされたデータの3種類で従来のマージソートと比較してみました。結果は、マージソートの処理時間を100とすると、ランダムなデータの場合は109.3。ソートされたデータでは44.4。逆順にソートされたデータでは27.3でした。

ランダムなデータに関しては、従来のマージソートの方が早いですが、ソートされたデータや逆順にソートされたデータの場合には、TimSortの方が圧倒的に早いようです。

ランダムなデータに関しても、(環境がないので測定していませんが)HotSpot Server VMで遜色ないスピードが出れば、ほとんどのデータでに関しては、スピードアップが図られることになると思います。また、Collections.sort(List)も内部的には、Arrays.sort(Object)を使用していますので、Java 7ではソートの高速化が行われることになります。

今回のJavaへのTimSortの移植作業は、Joshua Bloch氏が行っています。

Learn to Love Maintenace [プログラマー現役続行]

The Passionate Programmer: Creating a Remarkable Career in Software Development (Pragmatic Life)

The Passionate Programmer: Creating a Remarkable Career in Software Development (Pragmatic Life)

  • 作者: Chad Fowler
  • 出版社/メーカー: Pragmatic Bookshelf
  • 発売日: 2009/07
  • メディア: ペーパーバック

項目27「Learn to Love Maintenace」で、ソフトウェアの保守に関して、保守はソフトウェアを動作し続けることが求められるのですが、バグを修正したり、新たな小さな要求を実装したりしながら動作させ続けるということです。そして、次のように述べられています。
What if a bug turns up the need to redesign a subsystem in the application? That's all part of bug fixing, right? The designs may be old and moldy, and broken windows may be scattered throughout the system. That's an opportunity to put your refactoring chops to the test. How elegant can this system be? How much faster can you fix or enhance this section next time because of the refactoring you're doing this time?

もしバグのためにアプリケーションの一つのサブシステムを再設計する必要性が発生したらどうなりますか? それがバグ修正ですよね?設計は古く錆び付いていて、割れた窓がシステム全体に散乱しているかもしれません。まさに、あなたのリファクタリングの技の真価が問われる機会です。どれだけ洗練されたシステムにできますか?今回行うリファクタリングのおかげで、同じモジュールの修正や機能拡張を次回あなたはどれだけ素早く行うことができるでしょうか?

As long as you're keeping it running and responding to user requests in a timely fashion, maintenace mode is a place of freedom and creativity. You are project leader, architect, designer, coder, and tester. You can flex your creative abilities all you like, and measurable success or failure of the system is yours to bear.

動作し続けて、ユーザからの要求に遅れることなく対処できている限り、保守モードには自由と創造性があります。あなたは、プロジェクトリーダー、アーキテクト、設計者、コーダー、テスターなのです。好きなだけあなたの創造的能力を発揮できますし、システムの成功や失敗はあなた次第です。
今週は、仕事である小さなモジュールを理解するためにずっとリファクタリング※1をしていました。大規模なシステムの一部を構成する非常に小さなモジュールなのですが、理解できないのです。理解できない最大の理由は、名前付けでした。

※1 厳密にはリファクタリングではありません。自動実行できるテストコードも存在しないので、理解のために単に自分の環境でソースコードを修正していただけです。

ソースコードのあちこちを調べて、インスタンスフィールドの役割を理解してみるとフィールド名が全く不適切だったり、メソッドの処理内容がメソッド名から想像できるものではなかったりという具合です。それらの名前付けを修正したり、分かりにくいフローを書き直したりして、理解に努めました。オリジナルのコードのままなら、数ヶ月後に見ても、再度理解するのに多分非常に苦労するだろうと思えるものです。
Good naming is a skill that requires practice; improving this skill is the key to be a truly skillful programmer

良い名前を付けることは、訓練を必要とするスキルです。このスキルを伸ばすことが、本当に熟練したプログラマとなるために重要です。

既存のコードを理解するためにコードを修正するというのは、良い方法です。EclipseやNetBeansなどのIDEを使用すれば、クラス内のprivateのフィールドやメソッド、メソッドのパラメータ名、ローカル変数名を修正することは、テストコードがなくてもかなり安全に行うことができます。名前を変えるだけでなく、Extract Methodなどのいくつかの方法も注意深く行えばある程度安全に行うことができます。

可読性を上げるための制御フローの書き直しは、結構慎重に行わないと間違える可能性がありますので、自動実行可能なテストコードなしでは、かなり危険なゾーンに入る書き直しになります。

既存の汚いコードをリファクタリングするというのは、ソフトウェアエンジニアとしての技量を発揮する機会だと思います。逆に考えると、ソフトウェアエンジニアの技量を知るための良い方法なのかもしれません。汚いコードとそのテストコードを渡して、コードを書き直させてみて、どのように良くなっているかを採点してみると良いかもしれません。

Don't Live with Broken Windows [プログラマー現役続行]

仕事で私自身が他の人のコードをレビューするようになったのは10年ぐらい前からです。レビューを受けている担当者が他の人から引き継いだ場合もありますし、最初からその人が書いた場合もあります。

ソースコードというのは、詳細にどれだけ注意を払って書かれているか、逆に、不注意に余分なことが書かれているかによって、書いた人のレベルが分かったりします。

実際のレビューでは、「ここの部分は、なぜ、こうなっているのですか?」と聞いた場合に、「他の人のコードをコピーしてきただけなので、分かりません」という回答があったりします。あるいは、「参考にしてくださいと見せられたコードがそうなっていたので、それがルールだと思っていました」とか。

言い換えると、仕事でソフトウェアを開発している場合には、自分が書いたソースコードは、誰かに真似されることがあるのです。したがって、出来る限りきちんと書いておく必要があります。残念ながら、きちんと書いていても、詳細を理解することなくコピーして修正(改悪)してしまう人がいます。

コードレビューの際に、「あなたが他の人のコードを真似(参考に)したように、あなたが書いたコードを誰かが将来また真似(参考に)する可能性はあります。悪いコードを真似されるよりは、良いコードを真似される方が良いので、この際、書き直してください」と指導したこともあります。

他人が書いたコードでも、そのコードを引き継いだ場合には責任がありますので、悪い部分は修正していく必要があります。
ヒント4: 割れた窓を放置しておかないこと
Don't Live with Broken Windows
しかし、割れていると認識できるレベルに自分の技量を高めないと、割れている窓は、割れていないように見えてしまいます。