読者です 読者をやめる 読者になる 読者になる

OSS開発の活発さの維持と良いソフトウェア設計の間には緊張関係があるのだろうか?

YAPC::Asia Tokyo 2015 前夜祭に参加して、柴田さん( hsbt さん)とモリスさん*1( tagomoris さん)の講演を聴いた。特に最後のモリスさんの講演を聴いていて、ちょっとした衝撃を受けると共に、気づきや疑問もあったので、久しぶりに blog エントリを書こうという気になった。

なお、このエントリは講演メモや浮かんだ疑問、その後の議論等を記したものであり、すっきりとした結論は無いのでご注意。

モリスさんの講演

講演資料が公開されていた

講演時に取ったメモがこちら

我々にできるOSSとそのコミュニティの育てかた
=======================

id:tagomoris
TD のモリスさん
TD はデータ処理そのものが競争の源泉なのでソフトウェアはどんどん公開できる

OSS は開発してメンテナンスすることが大事
公開しているだけでは使われない。メンテナンスも行われない。


### では何が必要なのか

All OSS products needs:

- More users
- More use-cases
- More contributions

なぜそうなのか


### なぜそのソフトウェアを OSS として公開しているのか

そもそも目的が異なるケース

1. 社内でつくったけどちょっくら公開してみるかパターン
-> 外の人と協業するつもりは全くない

2. 最初から OSS として作ったパターン

2.1. 内部で使うために作ったが、外部からなにか来たら嬉しいな、程度の空気感
2.2. 内部で主に使い、外部でも使う
2.3. 外部で主に使い、内部でも使う
2.4. そもそも外に向けて開発していて、広めたい

これらの違いはコントリビューションへの対応に現れる
OSS 利用者としては、コントリビューションがどういう重みで受け入れられるかにつながる


### OSS コミュニティ

OSS コミュニティを作るために何が大事か

1. オープンな開発者のチーム
密室で決めないこと
実際にはそうでなくとも、密室で決まっているような印象があるのが問題
2. オープンなコントリビューション手順
3. 企業のサポート

どんな言語で作られているかも影響を与える
例: Perl で書いたら Scala の人は興味を示さない
例: データプロセッシングの世界は JVM で動く言語でなければ受け入れられない


### バージョニング

バージョンは、外部の人から見てどう見えるかが大事

patch バージョンが 0 -> 枯れてないように見える
semver で 0.x.y -> これからいくらでも破壊的変更が入るように見える

unstable に見えるバージョンは「空気を読む」必要が発生する
例: miyagawa さんの 0.99.x はプロダクションに使える!
なかなかバージョン 1 に着地しない問題


### やりとり

常に英語を使う。これが絶対的に大事。
ロシア語わからん問題
ロシア語の issue や PR を見ると、見た瞬間に使う気が無くなる。
非日本語話者から見た日本語の issue や PR も同じ。
英語のみを使うという意思が必要。日本語で来た issue は却下する勢いでも良い。
なにより英語を使うということは、コントリビューションを受け入れます、という意思表示になる。


### どうやってコミュニティをつくるか

作って公開しても反応がないとつらい問題
ソフトウェアの質に突っ込みどころがあると結構反応が来る
最初から上手く動作するコードを書くと反応が来ない(例: Woothee)
孤独だとつらい

コミュニティは良いメンテナンスが継続的に使われる必須条件
contribution にとって open であること
issue や PR を使う

stable であってかつメンテナンスされているというイメージが大事
OSS ソフトウェアを評価するときに、 github のリポジトリの最終コミット日付を見たりする
最終コミットが古かったりコミット頻度が低いと不安になる
メンテナンスされているという印象を与えるには ML に反応するのが良いが、 ML の維持はなかなか難しい
issue や PR に素早く反応することも良い

世界中の人と英語でコミュニケーションする
コントリビューションしてくれる人は常に一定割合しかいない
なので、分母を広げるために英語を使う


### 開発者コミュニティをつくる

開発者コミュニティをつくるコツは、プラグイン機構を作ること
拡張機能をプラガブルにすることで、開発に参加する間口を広げる
ユーザコミュニティから開発者コミュニティへの質の転換を行う


### 有名(人|企業)問題

有名(人|企業)が公開した OSS の方が注目されやすい
何であっちの方が……と心が濁る
考えるな
有名だから広まっているのではなく、それなりに叩かれ磨かれているから注目され評価される
だから気にするな。


### OSS 開発者として

最初から皆が使ってくれる素晴らしいソフトウェアを作ることは出来ない
継続的なメンテナンスから、良いものは生まれる
継続的なメンテナンスをしている、という態度を見せることが必要

"Do it, and keep doing it."

OSS 開発の活発さの維持と良いソフトウェア設計の間には緊張関係があるのだろうか?

この講演を聴いていて心を揺さぶられると共に、後半になるにつれて疑問が首をもたげてきた。このエントリのタイトルにもある「OSS 開発の活発さの維持と良いソフトウェア設計の間には緊張関係があるのだろうか?」という疑問だ。

ここで良いソフトウェア設計と言っているのは、 UNIX 哲学的な価値観の中核にある「ひとつのことをうまくやれ( Make each program do one thing well )」や、オブジェクト指向の文脈で言うところの 単一責務原則( SRP: Single Responsibility Principle ) などから連なる「自分がやること/やらないことがハッキリしている設計が良い設計である」というような価値観のことだ。コードベースの小ささのことではなく、設計理念として小ささ、少なさ、統一感を志向している様と考えてもらえば良いだろうか。最近のプログラミング言語で言えば、 Go 言語が相当するだろう。当日は「ソフトウェアとして小さく美しいこと」と表現したと思う。

UNIXという考え方―その設計思想と哲学

UNIXという考え方―その設計思想と哲学

エレガンスは、力とシンプルさの組み合わせから生まれる。エレガントなコードは、ただ正しいだけではなく目に見える透明な形で正しい。 (エリック・レイモンド)

モリスさんの講演によれば、 OSS 開発の活発さを志向する、つまりソフトウェアとして選択されやすくなる、使われやすくなることを意識すると、たとえば github の issue や PR などのコントリビューションを意識的にいざない、そしてそれらを積極的に採用するスタイルを採ることになる。確かに、私も github で公開されているソフトウェアを見るときに、コミット頻度や最終コミット日付、 open なままの issue/PR の量を判断材料にして、メンテされてなさそうなので敬遠しようかな……などと考えることは多々あるし、 gem を Ruby Toolbox で探すときも、 "Development activity" のところを気にしたりする。

OSS 開発にバイアスはかかっているか

しかし、それは結果的にソフトウェアの構造をゆがめることにつながらないだろうか。活発さを志向するあまり、機能やコードベースの肥大化を招いてしまい、統一感のある小さく単機能なソフトウェアの姿を保てなくならないだろうか。もし活発さを志向する OSS 開発にそのようなバイアスがかかるのであれば、そこには構造的な問題、不幸な構図があるように見えてしまう。

思い出すのは『プログラマが知るべき97のこと』に収録されている miyagawa さんのエッセイ「Noといえることの大事さ」の一節だ(本書の日本語訳を出すにあたりエッセイを依頼したら快諾いただき、二本も書いてくださったうちの一本だ)。

ソフトウェアが人気になり、ユーザが増えるにつれ、「あの機能を追加してくれ」「ここの動作をオプションで On/Off できるようにしてくれ」という要望が出てきます。実際にそうした機能やオプションが欲しいとおもっているのは、ごく一部であるにもかかわらず、声の大きいユーザからの要望を無視することができず、忠実に応えようとするあまり、あなたはそれをすべて実装してしまいます。ユーザからのフィードバックはうれしいものですからね。はじめて公開したソフトウェアでとくにおこりがちなことです。

こうしてあなたのソフトウェアは、ほとんどのユーザが使わないようなニッチな機能と、それを有効にするための複雑怪奇な設定画面または設定ファイルが必要になり、またそれによってメンテナンスがしづらく、バグのでやすいソフトウェアになってしまいました。こうしたソフトウェアは Feature Creep (creep: いつの間にか忍び寄る、からみつく) とよばれ、ソフトウェアが破滅に向かう第一歩(あるいはもう手遅れ)の状態になっているといえます。

こうした悲劇を避けるポイントはただひとつ、そうした要望に「No」といえる勇気です。ソフトウェアのコアではないもの、他のソフトウェアと組み合わせて実装できるものに関しては、明確に No といえることが、結果としてよいデザインやシンプルさを達成する原動力になります。

「Noといえることの大事さ」(宮川達彦)

プログラマが知るべき97のこと

プログラマが知るべき97のこと

  • 作者: 和田卓人,Kevlin Henney,夏目大
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/12/18
  • メディア: 単行本(ソフトカバー)
  • 購入: 58人 クリック: 2,107回
  • この商品を含むブログ (342件) を見る

例えば上手く設計できたソフトウェアがあるとして、「これ以上減らすところがなく、実質的に完成していて、手を入れるところもほとんどない」ことによって「開発が活発ではなく、メンテナンスされていない」というイメージを与えてしまい、それが悪い評価につながりかねないのは、不幸なことではないだろうか。

これを個人レベルの OSS ライブラリ開発の文脈で考えると、小さく完成されたソフトウェアは、 stable ですというアピール( semver でいうところのバージョン 1.0.0 以上)と活発にメンテナンスしてますというアピールを両立させるのがなかなか難しい問題、と言い換えても良いかもしれない。ソフトウェアが十分に小さい場合は 1.0.0 でおおよそ完成してしまうからだ。細かく patch バージョンを上げていくくらいしかアピール手段がないが、小さく無矛盾である場合はその頻度すら低くなってしまう。

何事においても、完璧に到達するのは、 付け加えるものが何もなくなったときではなく、 削るものが何もなくなったときである。 (アントワーヌ・ド・サン=テグジュペリ)

OSS にとって開発の活発さが文字通り死活問題であるならば、その開発の活発さと設計の統一感を両立する手段はあるだろうか。解はあるのだろうか。

たまらず、質問してみた。

上記 Tweet にあるように、当日の質問は「良い OSS 開発と良いソフトウェア設計の間には緊張関係があると思いますか?」から始めたが、この単文では意図が間違って受け取られる可能性があるので、本エントリでは少し表現を変えた。実際当日はかなり長めの質問になったが、モリスさんはもちろん質問の意図を正確に把握してくれた。ありがたや……

モリスさんの回答

仰るとおり、構図的な問題はある。 OSS 開発における活発さの維持を志向すると、ソフトウェアのエントロピーは増大し、肥大化し不格好になる。多くのユーザ、ユースケース、コントリビューションを得ることと、ソフトウェアとして小さく美しさを保つこととを両立させるのは難しい。

すると、やがて同じ事を綺麗に上手くやる後発プロダクトに打倒されることもある。 だが、それは開発者コミュニティの新陳代謝にはなる。 例えば、出たばかりの OSS が最もコントリビューションのチャンスがあるからだ。

総体としては、健全な OSS 社会になる

循環する OSS 社会。まるで後光が差しているような回答ではないか……

そしてつまり、健全な OSS 社会ときれいなソフトウェア設計との間には、やはり緊張関係はある、ということになるのだろうか。

あと、ソフトウェアは使われることで育てられ、磨かれることも忘れてはならない。誰も使わないソフトウェアは、本当に問題を解決するのか実証できていないようなものだ。

プラグイン機構による開発者コミュニティへの質的な転換

その意味で、モリスさんの講演にあったようにソフトウェアの構造に「プラグイン機構」を設け、ユーザコミュニティから開発者コミュニティへの質的な転換を図るのは、ソフトウェア設計からエコシステム設計へとつながる、非常に重要な考え方であると再認識した。組織構造がソフトウェアの構造に影響を及ぼすというのは最近よく聞く話だが(コンウェイの法則)、ソフトウェアの構造がコミュニティの構造に影響を及ぼしうるというのは重要な気づきであったと思う。

OSS プロダクトがメジャーになればなるほど、コントリビューションを取り入れつつ、全体の整合性は壊さないような舵取りが大事になってくるのだろう。大きめの OSS プロダクトや言語設計者のバランス感覚や調整能力が際立つのもわかる。

自分はどうしているか

私はというと、自分が書くコードは設計哲学としての UNIX 哲学と、加えて Clojure 作者 Rich Hickey の考え方に影響を受けている。

つまり、ひとつのことをうまくやる( Make each program do one thing well ) 小さいモジュールを志向し、かつシンプルさ( simple )と簡単さ/便利さ( easy )の違いを意識し、それらを混ぜずに分けて提供できるような構造に注力している。 power-assert も、そのような構造になっている。

便利さは相対的な概念

そして、簡単さ/便利さ( easy )に関してはコントリビュートしてくださる方々に任せるようにしている。便利さは相対的な概念であり、一人一人によって便利さの文脈が異なるからだ。 Babel で使いたい人もいれば、 webpack で使いたい人もいる。 TypeScript や CoffeeScript で使いたい人もいる。それぞれの使いたい文脈で使いたい人がプラグインを作り、公開し、共有する。これはモリスさんが講演で話していたプラグイン構造や開発者コミュニティへの転換に近いのかな、と考えている。

モジュール
espower-cli コマンドラインツール
espower-loader Node 用のモジュールローダー
intelli-espower-loader espower-loader を設定ファイル無しで簡単に使えるモジュール (まさに easy のためにある)
espower-coffee CoffeeScript 用モジュールローダー
espower-typescript TypeScript 用モジュールローダー
espower-traceur ES6 用モジュールローダー (Traceur Compiler 版)
espower-babel ES6 用モジュールローダー (Babel 版)
babel-plugin-espower Babel 用プラグイン
espowerify Browserify 用プラグイン
webpack-espower-loader webpack 用プラグイン
karma-espower-preprocessor Karma 用プリプロセッサ
gulp-espower Gulp 用プラグイン
grunt-espower Grunt 用タスク

そのために、power-assert を organization にして 、コントリビュートしてくださった方々と全権を共有した。このエントリを読んでいる方で、手元で新たな環境で動かすものを作ってみたという方は、ぜひお気軽にご連絡ください。

別言語への移植というかたちの相互作用

もうひとつ起こったコントリビューションとして、別言語への移植というかたちの相互作用、つまり各言語の power-assert 実装も生まれ始めた。

言語/環境
Ruby test-unit-power_assertをリリース - 継続にっき(2014-05-31)
Perl Test::Power - search.cpan.org
Go gopwt(PowerAssert for golang)がだいたいできた - コンドルが飛んでいる。
Android 君はPower Assertを知っているか #potatotips // Speaker Deck
Vim Script Vim script版 power-assert! テスト書いてないとかお前それ Vim script の前でも同じこと言えんの? - haya14busa
Swift XCTest - SwiftでもPowerAssertしたい - Qiita
Crystal crystal - power_assert.cr 作った - Qiita

元はといえば私の JavaScript 実装も元祖となる Groovy 版の PowerAssert から着想を得ている。このような形で考えが伝播していくのは本当に嬉しい驚きだったし、相互に影響を与え合って発展しつつ、考えが広まっていく様には刺激がある。

柴田さんと話したこと

前夜祭から帰ろうとしていたら、柴田さんからメンションがあった。

議論したい欲が高まっていたので、柴田さんと合流して帰りのゆりかもめでずっと「良い設計はどこから来るのか」みたいな話をしていた。

まつもとさんは意識的に燃料を投下している

話したのは、主に Ruby 自身の開発の話だった。曰く「 まつもとさんは意識的に燃料を投下している」。

Ruby も活発さを大事にしている。そして、まつもとさんは Ruby エコシステムに燃料を投入するため、意識的に炎上させている、とのこと。まつもとさんは Ruby の開発において既にあまり言語処理系の実装をしておらず、代わりに言語デザイナー及び開発ディレクターのロールを担っている。ナチュラルに炎上体質なのではなく(少しはそうかもしれないが)、意識的に燃料を投下しているらしい。

ここで言う燃料とは、まつもとさんが主に壇上で話す Ruby の新機能や方向性のことだ。まつもとさんは今回の YAPC::Asia 1日目の講演「 TBD 」(本当にこのタイトル)にて、 Ruby 3.0 に盛り込みたい内容を「 JIT, Concurrency, Soft Typing 」と語っていた。これらも Ruby への期待感を維持し言語の方向性を示しつつ、開発を活発にする燃料というわけだ。

まつもとさんは講演の中でよく OSS をサメに例える。サメは泳ぎ続けないと死んでしまう。

では Ruby の開発はコントリビューションを何でも取り込む方向性かというと、そうではない。 Ruby は何でも採択するわけではない。外部からのコントリビューションには本当に良いものは決して多くなく、むしろ却下が多い。そしてもちろん下位互換性も重要視しているので、手を出せないものや外せないもの、外すのに年単位の時間がかかるものもある。要望を取り込んでいけば良いソフトウェアが生まれるわけではない。

だからこそ、勢いをつけるためにまつもとさんが火をくべる。内発的に火を付けるプロセスの話は、聞いていて大変面白かった。

OSS 開発最前線の荒々しさと活き活きさ

行儀の良いプロセスと野生のパッチも面白かった。

普段の仕事では WIP PR であるとか、きちんとしたコードレビューとか、コミットをきれいにまとめるとか、そういったエンジニアリング的な行儀のよさが大事とされるが、 OSS 開発の最前線はそことは何かが違う。もっと荒々しく、勢いのある野生のパッチが飛び交う世界だったりする。

ソフトウェアパターンの適用等が良い設計の指針として挙げられる現場もあるが、 OSS の最前線でパターンを単に当てはめるのも何かが違う。むしろ、新たなパターンがそこで生まれているからだ。後から振り返り、背景と制約を明らかにし、名前がつけられたものがパターンである。というのを再度思い出したりしていた。

ソフトウェアの良い設計はどこから生まれるのか。議論は尽きない。 Ruby コミッターのどなたかが後年回顧録みたいのを出してくださると、面白そうだなと思ったりしたのだった。

予告通りこのエントリにオチや結論はない。 柴田さん、モリスさんをはじめ、お読みくださった皆様にも意見があると思いますので、反応エントリをお待ちしています!!

後日談

私にとってこの日の経験は、その 5 日後に power-assert バージョン 1.0.0 をリリースするくらいのインパクトがあった。 1.0.0 リリースする意義、きっかけ、そして覚悟をありがとうございました!

後日談その2

モリスさんがより詳細な考察のエントリを書かれたので、必読です。

後日談その3

rebuild.fm でも話題に上りました。議論のネタになって嬉しいです。

*1:本名は田籠さん