DBFluteというオープンソースソフトウェアの開発。 失敗し、学んで、うまくいって、また失敗して学んで... ようやく六年という年月が経って、 そのスタイルが明確になってきたかもしれません。 DBFluteが教えてくれた、 オープンソースプログラミング
# # インクリメンタルな開発 # 六年前に今のDBFluteが出せたでしょうか? いや、確実に無理です。 そんなお金と時間はどこにもない。 そんな能力、jfluteにはない。 そもそもプロダクトには、 多くのフィードバックが必要だ。 たくさんメールが来ます。 要望だったりバグ報告だったり。昼夜問わず。 DBFluteの場合は、ブログのコメントも多かったですね。 一秒でも早く返事を書こうとやっきでした。 要望を送ってくれる人は、貴重な貴重なテスターです。 そして新機能(or 修正機能)の実績の場を作ってくれる人です。 大抵の場合は、現場では問題になってからメールを送ります。 すぐに返事がこなければ、 なんとか別の回避策で済ませてしまうでしょう。 少しでも遅れたら「いや、もういいです」と言われてしまう 「その問題をDBFluteは解決できなかった」という実績が生まれ、 その積み重ねは弱い弱いDBFluteにとって命取りになるもの。 しかも、要望を送ってくれる人はユーザーの中のほんの一部です。 それだけに、とてもとても、貴重なイベントなのです。 ときには臨海線の東京テレポートのホームでリリースしたり、 ときにはアクアラインの海ほたるで実装して返事をしたり、 ときにはディズニーシーで実装してSNAPSHOT公開したり、 返事の返事をすぐに見るためにブログやGメールをF5連打したり... とにかく実装してSNAPSHOTを公開してメールを返すわけですが、 「100%の実装」をしてからではやはり間に合わない。 まずは、 その人が必要としている最小セットの機能だけ、 迅速に実装して提供します それが一番求められている状況だから。 わりとボロボロでも出して要望をcatchしないといけない。 その後、返事の返事を待っている間に、 残りの実装やボロボロな部分を直したりします。 場合によっては一日二日では終わらないものも多いので、 そのバージョンでは30%の機能だけでリリースしたりします。 まずはその要望をくれたユーザー最優先。 「小さな単位で機能提供を繰り返すインクリメンタルな開発」 ただ、そう単純にはうまくいかないです。
# # インターフェース指向 # その機能の足りない実装は後から補うことはできるが、 その機能のインターフェース(利用方法)は後から変えられない。 「最小セットの機能だけ」と言っても、 最小セットに合わせたインターフェースで提供してはだめなのです。 その機能には既にユーザーがいるのですから、後から変えられない。 程度の問題は色々あるとはいえ、ユーザーとなかなか連絡の取れない オープンソース運営においてインターフェースを変えるというのは、 命取りになりかねない行為です。そういった運用の繰り返しは、 その後のDBFluteの発展の「確実に大きな」足かせとなります。 ただひたすらユーザーの要望を付け足して いっただけのプロダクトでは、 後にメンテ不能に陥るか、 混沌とした機能セットになってしまうのです。 つまり、 最小セットの機能だけを提供しつつ、 最大セットの機能を想定したインターフェースを 最初の時点で提供していかないといけない そんな無茶な... ユーザーに試してもらって正式版を出すまでの間に考え直して、 微調整してもらうこともあります。とはいえ、 その期間も随分短いもの。 電車の中、布団の中、ご飯を食べながら、お風呂入りながら、 ずっっっと「インターフェース、これでいいのか!?」 と考えていたり。 正式版をすぐに出してと言われながら、 でも出したらもう変えられない。 限られた時間でそれはもう必死に考えたものでした。 (メソッド名、プロパティ構成、 戻り値の型あらゆる細かいところまで) 実際にDBFluteでは幾度となく失敗してきた部分があります。 変えるチャンスがあって助かったものもあれば、 今もそのままのものも。 ということから真っ先に考え始めるもの、 それがインターフェース。 迅速なインターフェース指向、これがどうしても求められること。
# # リファクタリング # 内部的な実装も同じ話です。まずはボロボロで提供するのですが、 後でその機能を拡張するときに、確実に大きなブレーキになります。 経験からではありますが、 「なんとなくいいかなぁ」と通り過ぎてしまった懸念、 面倒に思って省いた分の実装やリファクタリングのしっぺ返し、 これらはその後、高い確率で落とし穴となって自分に襲いかかります 何度も何度も、昔の自分に襲われました。 「時間がないからやれないから仕方がない、だから許される...」 わけがない! ロジックの神様はそんな人間の都合は知りません。 やらなかったことはやらなかったこととして、 遠慮なくトラブルを授けてくれます。 「今のスピードを取るか、後のスピードを取るか」 まあ、今のスピードを取らざるを得ないのですが、 ユーザーとのやり取り次第では、 「三日は待てないけど一日なら待てる」とか、 「一日は待てないけど一時間なら待てる」とか、 「一時間は待てないけど、十分なら待てる」とか、 一言で「急いでる」といっても、そこには色々な濃さが存在します。 その分析をせずに「無意味に最速」もしくは「無意味にリッチ」に するのはもったいないと。 空気を読んでチャンスを見つけた瞬間に、 限られた時間でできる限りの拡張考慮の 実装やリファクタリングをやりました。 それでもリファクタリングは足りません。 ちゃんとした土台を作るのにはもっと時間がかかるもの。 でも、後のリファクタリングを考慮した リファクタリングをすることも大事。 いま生き延びても、 一年後に確実に終わるのであればやはり意味がないから。 サバイバルの中で隙を伺って見つけてはリファクタリング。 また、どうせ考えてもすぐにわからないような 難度の高い課題の時、考え続けても先は見えないので、 そういうときはリファクタリングします。 本命の問題の解決を考えながら、 手はリファクタリングしています。 すると、今まで見えてなかったロジックの本質、 それが少しずつ見えてきて、 結果的にリファクタリングしたことによって 問題の解決を見つけることも。 ベタベタな状態で考え続けていたときと、 どっちが早く解決しただろうか!? リファクタリングは単なる将来の投資ではない、 今を見つめる思考のツールでもある 【追記】 リファクタリングはプログラミングの一部とも言える -> リファクタリングは思考のツール | jfluteの日記
# # 自動テスト # また、こういったインクリメンタルな開発を可能にするには、 JUnitなどを利用した自動テストを書くことが必須です。 DBFluteが命を落とす一番のリスクはなんでしょう? それはなんといっても「品質」でしょう。 顧客は厳しい現場で戦うプログラマ、 もしデグレの多いプロダクトであれば、 もう二度と使ってはくれません。 別にDBFluteが唯一のツールでもないから。 ちょっとでも変な動きをした瞬間に、 「DBFluteはちょっとあやしい」というイメージが付きます。 ただでさえ、ラップした独自のロジックを提供するものですから、 プログラマからすると最も怪しげに思いやすいツールでもあるのです。 有料商品であれば、それでも「安い」とか特典を付けられますが、 ライバルだってオープンソース、値下げ合戦なんて最初からできない。 品質が武器であり、品質が生命線であることは明白。 あれだけ複雑な処理を実現しているConditionBeanがバグなしで しっかり動くように保っていくというのは、そう簡単ではありません。 そして、先ほどから語っているようなインクリメンタルな開発、 一度書いたソースは高い確率でまた修正するのです。 普通に考えてデグらないわけがない。でもそれでは成り立たない。 いかに継続的でバランスの良いアサートロジックが書けるか それができなければ、そもそも迅速なインターフェースの提供や 段階的なリファクタリングなんてできないのです。 逆に、固定的なインターフェースやリファクタリングで 小分けされたロジックがなければ、 継続的でバランスの良いテストができないという相互関係も。
# # イメージプログラミング # オープンソースの開発は、(多くの場合)業務ではありません。 日中のメインの(給料がもらえる)業務があって、 昼休みとか、夜とか、休日とかに作業をします。 つまり、連続した集中時間を確保するのが難しく、 細切れの作業時間をつなぎつなぎに利用してやっていくものです。 そんな状態で全体像なんかそう簡単に見えてきませんよ。 頭の中に展開したメモリ領域はすぐに解放せざるを得ないから。 短い時間、かつ、連続していない時間、 これを効率よく使うためにjfluteがやったことは... 「イメージプログラミング」 勝手にそう呼んでいますが、 要は頭の中だけでプログラミングすること。 プログラミングって、 文字を入力し続けるばかりではないですよね。 考えては文字を入力して、考えては文字を入力して、 の繰り返し。 ほんの少しでも、 その考える行為と文字を入力する行為を分離させて、 考える時間と場所は... それこそ先ほどインターフェースの話で述べた、 電車の中、布団の中、ご飯を食べながら、お風呂入りながら、 ディズニーシーに行きながら、ショーを待ちながら... ソースコードを見ることができないですから、 知るべき情報を頭の中に叩き込んでから出かけます。 頭の中でコードを展開させて、 ぐにゃぐにゃした映像でありながらも、 ロジックを組み立てていき、その軌跡を頭に焼き付けて、 いざEclipseの前に立ったときにそのイメージを打ち込む。 とはいっても限界がありますから、 そもそも実装の方でも工夫を入れます。 お出かけ前にちょっと実装できるとしたら、 ベタに上から順番に実装せず、 まずはコントロールロジックを実装、 つまり「流れ」だけをまず実装します。 ある意味「適当プログラミング」をします。 クラス名など命名も適当で。 適した名前はハンガーステージの前で考えればいい。 そして個別処理の詳細ロジックで、 わりと考える時間の必要なものはTODO。 できるだけロジックを独立性をはっきりさせて小分けに。 そうすることで、頭の中だけで実装イメージがつきやすくなる。 目的と手段が混在した長いメソッド、長いfor文は禁物です。 スピードは求められている状況とはいえ、 連続した時間を確保しづらい。 ベタベタに書く方が逆にできあがりが 遅くなってしまうこともあります。 考える時間も含めてプログラミング であれば、 考える時間を別の時間に割り振ることがスピードにつながるし、 考える時間を短くすること、つまり思考スピードを速くすること、 それも結果的にスピードにつながる(リファクタリングの話と関連)。 【追記】 で、それを四六時中やり始めると... -> 四六時中プログラミング | jfluteの日記
# # 期待値と準備 # インターフェース考えるスキル、リファクタリングスキル、 単体テスト実装スキル、イメージングスキル、これらが求められます。 jfluteのプログラミング姿を眺めたことのある人であれば、 自分がリファクタリングを息を吸ったり吐いたりするのと 同じような感覚でやっているのを知っているでしょう。 小さなリファクタリングにおいては、本題をぶつぶつ考えながら、 手が勝手にリファクタリングしてる感じ。 えっとですね...ちょっと怖いって言われることも......... と、と、とにかく! やはり期待値を知っていることが大事なのかなと思います。 インターフェースにおいても、初期の実装においても、 リファクタリングにおいて、テスト実装においても。 とはいってもオーダーメイドだから、 期待値なんてわかるわけがない。 その通り、そのまま当てはまる期待値なんて誰も知らない。 でも... その期待値を創造するために、 様々なケースの期待値を予め知っておくこと、 その積み重ねから、限られた時間の中でも、 追い求める姿を見いだすことができる o プログラミングし続けること o ソースコードを読み続けること o インターフェースに着目し考え続けること o ロジックの本質を分析し続けること そしてそして、追われ続けるDBFluteの冒険ですが、 365日24時間、 同じ濃度で追われ続けるわけではありません。 その濃さをしっかり感じて、 行動と判断を最適なものにしていくことが大事。 突発的に求められたときに迅速な対応が できるようにするために、 そこまで切羽詰まってないときに、 いざってときの準備をしておくこと 振り返りながら、 まだこれからのjflute自身に課すべき重要な意識として、 ここに書いておこうと。自分はもっと成長できるはず。