2013年1月19日土曜日

ほとんどペアプロだけの本

知り合って間もない人とペアプロの話になると、「ペアプロって結構疲れるんですよね。」「そうっすね。ペアプロは結構疲れるっすよね。」ってな感じで会話が終わってしまう事が多いが、本当はもっと語る事がたくさんある。そんな感じの本。

Pair Programming Illuminated
『Pair Programming Illuminated』

250頁くらいの洋書で、ペアプロだけでそんなに書くことあるのかと思いきや、意外と面白い(2002年6月の出版で、ちょっと古いが)。

例えば、ペアプロに関するよくある誤解として以下のような事項が挙げられていて、それぞれ詳しく解説されている。

  • Myth 1: 1人でできる仕事のコストを倍にしてるだけ。
  • Myth 2: ソロ作業が禁止されている。
  • Myth 3: 良いパートナーに当たった時にしか上手く行かない。
  • Myth 4: 教育効果はあるが、ある程度習熟したらもう意味はない。
  • Myth 5: 良い仕事の手柄がパートナーと半分ずつになってしまう。
  • Myth 6: コンパイラが構文エラーを見つけてくれるのでナビは不要。
  • Myth 7: ペアプロだとフロー状態に入れないから仕事にならない。

ペアプロ者はこうした事柄について、「そうじゃないんだよね」と自分の中でなんとなく納得してるだけではなく、例えばペアプロを導入しようとしてい>るときや、誰かがペアプロを止めさせようとし始めたときなどに、他者をも説得できるように言葉や論理を用意しておく必要があるが、そのためにも先人達の意見が参考になる。

またちょっと細かい話のようだけど、以下のようなペアの組み合わせについて、それぞれに章を設けてページ数を割いて、上手く行っている場合の効能と、起こりがちな問題が記述されている。

  • エキスパート/エキスパート
  • エキスパート/平均的プログラマ
  • エキスパート/初心者
  • 初心者/初心者
  • 外交的な人/外交的な人
  • 外交的な人/内向的な人
  • 内向的な人/内向的な人
まあ、やってくうちに自然と分かってくる事でもあると思うけど、先達の経験を共有できるってのは助かる。どうせ本に書かれてない問題もいろいろ出てくる訳だし、予備知識があるに越したことはない。(あと各章の冒頭に挿絵入りで書いてある小コントみたいなのがちょっとシュールで面白い。)

その他、ローテーションの仕方とか仕事場のレイアウトとか導入の仕方とか、いろんな知恵が書かれてる。「できるペアプロ者の7つの習慣(意訳)」もシンプルでなかなか良い。

豆知識:三人組でプログラムを書く事を Triplet Programming と言うらしい。1人がキーボード、1人がホワイトボード、もう1人が顧客役に徹するパターンについて、Coplien が語った事があるとの事。

2013年1月7日月曜日

煩雑な Javaコードを簡単な Clojure に直してみる

仕事始めでつかれたが、寝る前にちょっと Clojure やってみる。

以下は、Neal Ford の 『プロダクティブ・プログラマ』に載ってるのとほぼ同じコードで、ファイルを読み込んでから行番号をつけて標準出力に書き出すというもの。

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;

public class LineNumbers {
    public static void main(String...args) {
        File file = new File("sample.txt");
        LineNumberReader reader = null;
        try {
            reader = new LineNumberReader(new FileReader(file));
            while (reader.ready()) {
                System.out.printf("%d:%s%n",
                        reader.getLineNumber(), reader.readLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException ignored) {}
        }
    }
}

本ではこの後、Groovy を使うと同じ処理がいかに簡単に書けるかというくだりに続くわけだけど、今日はこれをClojure で書いてみる。

(use 'clojure.java.io)
(def zip (partial map vector))
(with-open [r (reader "sample.txt")]
  (doseq [[n line] (zip (iterate inc 1) (line-seq r))] 
    (printf "%d:%s%n" n line)))
なるほど。
  • Haskell 等でよく使う zip は、 (partial map vector) で、代用できるらしい。
  • try で囲って finally の中でリソースを開放する辺りまでを、with-open で書けるらしい。C# のあれみたいだな。
  • doseq の代わりに map とかを使うと、printf が返す nil が行数分返されてきてしまう。
  • Haskell でいう [1..] みたいのは (iterate inc 1) と掛ける。無限リストは iterate でなんとかするのが定石らしい。
  • Groovy ほどではないが、Java よりは簡潔に書ける。

寝よ。

2013年1月6日日曜日

Clojure で超簡単な問題を解いてみる

正月休みの最終日だが、また Clojure をいじってみた。

今日は、Project Euler の Problem 4をやってみる。問題の内容は、3桁の数を二つ掛け合わせて得られる最大の回文数は何かというもの。

まあ、使い慣れた言語だったら何てことない問題だけど、始めたばかりなの Clojure なので何かと難航する。 とりあえず効率は無視して書いたのがこんな感じ。

(ns euler.pe004
  (:use clojure.contrib.generic.math-functions))

(def digits 3)
(def max' (int (dec (pow 10 digits))))
(def min' (int (pow 10 (dec digits))))

(defn palindromic? [n]
  (let [original (str n)
        reversed (apply str (reverse original))]  
    (= original reversed)))

(defn solve [] 
  (apply max (for [x (range min' (inc max')) 
                   y (range x (inc max'))
                   :when (palindromic? (* x y))]
               (* x y))))

ほぼ総当たりのかなり遅いコードだけど、これだけでも、:use と :require の違いや project.clj での dependencies の指定の仕方だとか、Clojure での リスト内包表記のやり方だとかが、だんだんわかってきて面白い。

ただ、この手の問題で非効率なのはやはり気になるので、無駄な計算を排して瞬時に答えが得られるように修正してみた。

(ns euler.pe004
  (:use clojure.contrib.generic.math-functions))

(def digits 4)
(def max' (int (dec (pow 10 digits))))
(def min' (int (pow 10 (dec digits))))

(defn palindromic? [n]
  (let [original (str n)
        reversed (apply str (reverse original))]  
    (= original reversed)))
(defn cols [row] (range max' (dec row) -1))

(defn find-col [row cols max']
  (let [[col & cols'] cols 
        product (* col row)]
    (if (< product max') 0 
      (if (palindromic? product) product
        (if (seq cols') (find-col row cols' max') 0)))))
      
(defn find-product [current-max rows] 
  (let [[row & rows'] rows
        product (find-col row (cols row) current-max)
        larger (max product current-max)]
    (if (and (seq rows') (< larger (* max' (first rows')))) 
        (find-product larger rows')
        larger))) 

(defn solve [](find-product 0 (range max' min' -1)))

これだと桁数が4桁でも、元のコードで数分かかる計算が、ほぼ一瞬で終わる

しかしやっぱり、効率のために「手続き」を考慮するようになると、宣言的に書いた時の表現力が失わるっつうのは、何かと惜しいがまあしょうがないんだな。

2013年1月5日土曜日

Three Extremos と Three Amigos

M.Fowler の『ドメイン特化言語』を読んでいると、Ron Jeffries について「エクストリームプログラミング(XP)の父と呼ばれる3人の1人」とする訳注があった。

Ron Jeffries は かの有名なC3プロジェクトにいたはずだから分かるし、もう1人は言わずと知れた Kent Beck だろうと思ったけど、もう1人は誰だっけと思って調べてみると、Ward Cunningham らしい。

The Three Extremos の1人に列せられていて、c2wikiによるとこうなっている(見覚えはある気がするが、記憶に定着してなかった)。

The Fathers of eXtreme Programming
WardCunningham - the inventor
KentBeck - the articulator
RonJeffries - the realizer
古くからの Kent Beck の盟友で CRC カードを考案したりしたのは知ってたけど、inventer って言われるほどだとは思わなかった。

"TheThreeExtremos"という呼称は、『The Three Amigos』という映画からとったらしいけど、UML 業界でも、同様にこの映画からとった "Three Amigos" が、UML がでた当初からいる。まあ、なんか最近は余り見かけなくなった呼び名だけど。

昔はオブジェクト指向と言えば、ブーチって感じだったけど、昨今の開発でもお馴染みなのは意外とヤコブソンだったりする。

ICONIX なんかで大々的に使われてるロバストネス分析も元はヤコブソンだし、ユースケースなんかもコーバーンが大々的に普及させる以前にそもそもヤコブソンの発明だったりする。近年だとAOPとユースケースを結びつける仕事も興味深かった。

由来となった映画(邦題(『サボテン・ブラザース』)は去年鑑賞したが、なかなか良かった。ちなみに、この映画の元ネタは『七人の侍』だったりするが、こちらは不定期的に20回くらいは観ている。

2013年1月4日金曜日

Java の BitSet を使った Clojure の篩

昨日、Eclipse 環境で Clojure を使う準備をしたので、今日は簡単なプログラムを書いてみた。

簡単といえば Project Euler の1〜10番辺りかと見当をつけて眺めてみると、3番で素数を使っているのがあったので、エラトステネスのふるいでも書いてみることにした。

いろんな書き方があると思うけど、数ある関数型言語の中で敢えて Clojure を使うのは、やはり既存の Java 資産が使えるからというのが大きいと思うので、ここでは java.util.BitSet を使って実装してみることにした。

(ns euler.pe003)
(import 'java.util.BitSet)

(defn initial-bits [upper-bound] 
  (let [bits (BitSet. upper-bound)]
    (doall (map #(.set bits % true) (range 2 (inc upper-bound)))) bits))

(defn next-prime [pos upper-bound bits]
  (let [pos+ (inc pos)]
    (if (.get bits pos+) pos+ (next-prime pos+ upper-bound bits))))

(defn update-bits [pos upper-bound bits]
  (doall
    (map #(.set bits % false) (range (+ pos pos) (inc upper-bound) pos))) 
  [(next-prime pos upper-bound bits) bits])

(defn seive [n upper-bound bits sq] 
  (let [[m bits2] (update-bits n upper-bound bits)]
    (if (< sq m) bits2 (seive m upper-bound bits2 sq)))) 

(defn primes [upper-bound]
  (let [sq (int (Math/sqrt upper-bound))
        bits (seive 2 upper-bound (initial-bits upper-bound) sq)] 
    (filter #(.get bits %) (range upper-bound))))
 

実行してみると、以下のような結果が得られて、Haskell で計算してみたものと一致する。ただ 1,000,000 までの素数を数えているところでは、予想外に時間がかかっていた。もうちょい Clojure に慣れたら、なんで遅いのか調べてみたい。
=> (primes 100)
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)
=> (count (primes 1000000))
78498

ここまでできたら、Problem 3 を解くのは簡単で、以下のように書き足して実行したら、正答が得られる。
(defn divmod [m n] [(long (/ m n)) (mod m n)])

(defn solve [a bits] 
  (let [[h & t] bits
        [q r] (divmod a h)]
    (if (not= r 0)
      (solve a t)
      (if (= 1 q) h (solve q bits)))))

(defn -main [& args]
  (solve 600851475143 (primes 10000)))
 
新しい言語で初めて書くプログラムとしては、当初の想定よりちょっと難しかったが、テキストを読んでるだけでは分からない事がいろいろあって、実際に書いてみるとやっぱり面白い。

2013年1月3日木曜日

Eclipse で Clojure プラグインを使ってみる

まだ入門書をちょっと読んだばかりだけど、なんか実にいい感じで期待が持てるので、Eclipse で使う準備をしてみたい。


■ インストール

"Eclipse Marketplace" で Counterclockwise で検索するとヒットするので、そのままインストール。特に記すことはない。

( Counterclockwise というのは Leiningen のプラグインで、Leiningen というのは Clojure での maven のようなもの。)


■ プロジェクト作成

File メニューとかパッケージエクスプローラ上の右クリから、[ New ] -> [ Leiningen Project ]でプロジェクト生成のダイアログボックスを開いて、適当なプロジェクト名を指定して [ Finish ]。ここでは ex01 とした。

こんな感じでファイルができてくる。


■ ソース:core.clj

プロダクトコード側の自動生成ソース。
(ns ex01.core)

(defn -main
  "I don't do a whole lot."
  [& args]
  (println "Hello, World!"))

実行は、まず右クリから [ Run As ] → [ Clojure Application ] で REPLを開く。下段に (-main) と入力すると、こんな感じで評価結果が上段に表示される。
=> (-main)
Hello, World!
nil

■ ソース:core_test.clj

テストコード側の自動生成ソース。
(ns ex01.core-test
  (:use clojure.test
        ex01.core))

(deftest a-test
  (testing "FIXME, I fail."
    (is (= 0 1))))

core.clj と同様に右クリから REPL を開いての実行だけど (run-tests)でいける。
=> (run-tests)

Testing ex01.core-test

FAIL in (a-test) (core_test.clj:7)
FIXME, I fail.
expected: (= 0 1)
  actual: (not (= 0 1))

Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
{:type :summary, :pass 0, :test 1, :error 0, :fail 1}

■ 雑感

  • 上矢印キー押して、入力履歴が出てこなかったので一瞬困惑したが、Ctrl と上下矢印の同時押しでヒストリが使える。
  • コマンドラインでプロジェクトのフォルダに入れば、lein 自体も普通に使える。ただし、lein run は事前に project.clj に":main ex01.core"みたいな感じで追記する必要がある。
  • やっぱ常時 Eclipse を使ってる人には、こういうのが楽ではないかと。
  • マスコットキャラのおじさんの顔が怖い。

2013年1月2日水曜日

どうして多読するか?

これまで、いろんな現場を渡り歩いてきて、どちらかというと自分は技術系の本を割と読んでいる方ではないかと思うに至った。あえて多読派と寡読派に分けるとすれば、どうやら前者に入るのではなかろうかと思うので、ここでちょっと見解をまとめておく。

なぜ多読するか?

もちろんIT技術の話題に触れてるのが好きだからと言うのもあるけど、仕事に関係があるからというのが、やっぱり第一義という事になる。でなければ、ジャンル的にプログラミング・パズル系の本がもっと多くなるし、逆に、オブジェクト指向やアジャイルや Java等の Algol系言語の本はあまり読まなくなると思う。

じゃあ、どんな風に多読が仕事と関係するか。

生産性を上げてかっちょいいコードを書いてチームの中で一目置かれるため---なんかでは全然ない。ましてや他人を論破したり知識量で威圧するための理論武装でもない。

むしろ逆で、ある長所をもっているのがチームの中で自分だけという状況を極力避けるためだったり、また議論の場で同僚の顔を潰すことなく一定のデリカシーを保持するためだったりする。

そもそも自分さえちゃんとできていれば良いという態度は、ある程度の職歴を経たプログラマとしてはちょっと物足りないし(それに自分だけちゃんとするためだけの最小限の読書量は、だいぶ越えてるはず)、良いプラクティスやスタイルを少しでも周りに波及させるところまで含めて仕事なのだと、個人的には思ってたりする(別に頼まれてはいないけど)。

つうわけで、自分が良かれと認識する開発習慣を広めたり、そのために必要な議論を文明人らしいものにするために、いろいろ本を読んでるというのが自分の場合は当てはまる。

例えば、他人のプラクティスやコーディング習慣を改めてもらいたい場面で、読書が足りない人はどう言うか。

「それ時代遅れですね。今どき、そういうの聞いたこと無い。」
「自分はそういうのやらないな。つか普通、誰もやらないと思う。」
「そういうのオブジェクト指向っぽくないから、自分嫌いっす。」

定義の曖昧な、「みんな」とか「普通」とかが多くなって、主観的な価値判断が随所に織り込まれる。で、相手も主観で応酬してくるから、収集がつかない。多読派の立場で見るとどっちもどっちで、客観性を欠いたアホとアホの争いでしかない。

一方、多読派はどう言うか。

「おっしゃる事に一理あると私も思うし、○○氏も2001年の著作『△△』で同じ事を述べてましたね。ただ、それとは別の意見を◎◎氏が著作『▲▲』で述べていて、ホニャホニャフレームワークの開発者の●●氏もそれを支持していたりして、2000年代後半以降はこっちが主流のように見えます。一連の議論について詳細に検討している面白い本があるので、なんなら貸しましょうか?」

とか言える。まあこんなにクドクドしく言わなくても「『▲▲』でアンチパターンとして既に批判されてますね」で終わる事もある。とにかく無駄な主観の応酬になりにくい。

もちろんサジ加減一つで相手に恥をかかせる事もできるけど、多読派は断じてそういう事やらない。なぜなら、そうした行動に見られるデリカシーの欠如の恥ずかしさをさておいたとしても、多読派は1998年の『Anti Patterns』で「Intellectual Violence」として警告されている事を、とっくの昔に読んで既に知っているから。

====

いろいろ書いたけど、自分の場合は案件ごとに雇われていろんな現場にお邪魔させてもらってるだけなので、「議論は良いから、一番偉い俺の主観的価値判断と美意識に黙って従いなさい。」みたいにしにくい立場だからってのもある。

まあ、自分がそんな権限を持ったとしても、そんなやり方はしないけど。だってアホみたいだからね。