オープンソースを開発し続けて得たもの


 自分のGitHubのファーストコミットの時期を確認したら2014年だった。私はその時からオープンソースを作って来たんだなと改めて認識した。もう7年近くやっているのかという感慨もあれば、同時にまだ7年しかやってないのかという思いもある。

 まぁ、この7年という月日が自分にとって長いのか短いのかは置いておくとして、オープンソース開発を通じて私が得られたものを、開発したプロダクトと一緒に紹介していこうと思う。

まずは何よりも英語力

 私が全世界向けにオープンソースとして配布した処女作プロダクトが、WordPress用プラグイン「Custom DataBase Tables」通称「CDBT」だ。自身初のWordPressの公式プラグインで、コンセプトとしてはWordPressの管理画面にphpMyAdminやAdminerのようなデータベース管理ツールを実装しようとしたものだ。今思い返してみると、WordPressプラグイン開発者として駆け出しだったのに、よくもまぁいきなりこんな大作プラグインをリリースしたものだ……とその無謀っぷりを讃えたい。

 このプラグイン開発で最も苦労したのが自分の英語力の乏しさである。公式リポジトリへの登録審査からしてよく合格できたもんだと思うが、リリースした後の世界各国のユーザさんから寄せられる問い合わせやバグ報告はほとんど全て英語で、そのやり取りにかなり疲弊していたのが懐かしい。
 まず、質問の英文が理解できない、四苦八苦して読み解いてみても症状が再現できない、こっちから(もちろん拙い英文で)返信してもなかなか理解してもらえない……そんな感じで1つのIssueを処理するにも時間がかかるのに、何気に初期リリース版はバグが多くてIssueの数も多かった。趣味で開発したプロダクトなのに、当時勤めていた会社から帰宅後は、ひたすらこのプラグインのIssue対応をしなきゃ……という一種の強迫観念的なものに囚われてイライラしていたものだ。
 何度か英語対応に心折れそうになった事もあったが、ダウンロード数と利用してくれるユーザ数だけは右肩上がりで伸び続けてくれて、そのおかげで私のモチベーションが維持できたのは確かだ。
 
 このプラグインをリリースし、保守したことで、飛躍的に英語力が上達したのは確かである。今となっては英文を読んで・書くことについてはもう苦労しなくなったし、苦手意識もさっぱりなくなった。会話は全然ダメだろうけど、ネットやメール経由でコミュニケーションする分には特に問題を感じなくなっている。とは言え、私の英語の読解力と記述力は、特定分野の技術的コミュニケーションにしか通用しないだろう。日常的なフランクな語彙力は今もまだ乏しいままだと思う。それでも、オープンソース開発を続けていく上で、この英語力を得られたことは凄まじく大きかったと云える。

 私が「CDBT」の開発シーンでとあるユーザに言われた言葉は今でもはっきり覚えている。「あなたの英語は恐ろしい。もっと英語を勉強してください」だ(笑)
 それもそのはずで、バージョン1.xの頃の「CDBT」はUIの言語を「英語」と「日本語」で多言語化していたのだが、英記UIは私の乏しすぎる英語力によって操作ミスや機能不全を発生させるほど酷かった。正常に使うには日本語UIを自前で翻訳しながら使う方が良かったらしい……(苦笑)
 ちなみに、この言語不全はバージョン2以降は解消している(1年ぐらいかけて私の英語力が向上した成果とも云える)。

 この「CDBT」プラグインはおよそ4年前にバージョン2.1.34で開発を中断していて、現在の最新WordPressで利用するのは推奨されない「死亡プラグイン」になっている。しかしながら、トータルでのべ7万件以上ダウンロードされていて、ダウンロード数は今も微増を続けているうえに、現在アクティブで使っているユーザが1000サイト以上もある。何気に、かつてはNY市役所の一部署とか、北欧の航空会社、アラブ圏の中古車販売会社などでも使われていた(運用のお問合せと感謝を頂いたことがある)。こういうレスポンスを貰うと、自分がワールドワイドなオープンソースを提供しているんだなぁ……と実感できて、達成感が得られる。

 いつになるかわからないが、「CDBT」は将来的にバージョン3を作りたいと思っているプロダクトでもある。バージョン3では、是非WordPressのDBMSとしてPostgreSQLが使えるようにしたいなぁ……とか企んでいたり。

英記UI・ドキュメントの作成力

 私が作ったオープンソースプロダクトの『CSSフレームワーク「sloth」』と『短縮URL生成サービス「forkor」』はUIやドキュメント、ソース内コメント、紹介ページのコンテンツといったすべての表記を英語で統一してある。これは、私はオープンソースとして世界に向けて配布するプロダクトの基本言語は英語とするべきだと思っているからだ。基本的に世界中のエンジニアは英語が読める人が多いし、英語が苦手な人だったとしても英文なら読んでくれる。だからオープンソースプロダクトの基本言語は英語にしておくべきだ。もし他の言語のUIも作りたいのであれば、プロダクトを多言語化するのがベストだろう。
 
 ぶっちゃけ、UIとReadme等が日本語のオープンソース・プロダクトは世界のエンジニアの目に留まらないし、使ってもらえる機会も少ないだろう。そうなると、Issueも溜まらず、安定性や発展性もごく一部のユーザのみの集合知だけで閉じてしまう。
 完全に日本人向けのプロダクトであるならば、日本語固定でも良いかもしれないが、せっかくオープンソースとして世界に向けて発表するのであれば、使ってもらうユーザのすそ野は広く取っておくに越したことはないはずだ。

 蛇足だが、つい最近リリースした「SVG Japan」という日本地図のJSライブラリも、自ブログの紹介ページ以外は全て英語で統一してある。このJSライブラリは、今は日本地図だけに対応しているのだが、将来的に世界地図や世界の各国のリージョン化にも対応できるような汎用化を目論んでいて、それも見越してドキュメントは英記にしている(次は中国の地図を作りたいなぁと思っていたり……)。

 もう日本国内だけに閉じたような「ガラパゴス感覚」でのプロダクト開発はするべきではない──というのが、私個人の意見だ。 

世界の時制を知る

 水平型タイムライン生成JQueryプラグイン「jQuery.Timeline V2」は私が結構前にリリースしたプロダクトなのだが、息が長く利用してもらっているものだ。私のGitHubのプロダクトの中でも最もStarをいただいているので、愛着も大きい。
 このプロダクトを開発・保守していて痛感したのが、世界の時制の厄介さだ。とにかく、時制だけは日本の仕組みを世界標準にして欲しいものだ……と思ってしまうぐらい、世界の時制は複雑で面倒だ。どのぐらい厄介なのか、その一端を紹介していこう。

タイムゾーン

 ぶっちゃけ、タイムゾーンによる時差は次に紹介するサマータイムに比べれば全然可愛い方である(面倒ではあるんだけどね……)。
 タイムゾーンは協定世界時(UTC)からのどれだけ時間差があるかという値で、日本なら+9時間の時差がある。まぁ、およそシステム開発に携わっているエンジニアであれば、タイムゾーンを知らない人はいないだろうし、同一タイムゾーン内で稼働するプロダクトであれば、そこまで意識するような仕組みでもない。
 しかし、国境を意識しないようなオープンソース、特に時制を取り扱うようなプロダクトを開発していると異なるタイムゾーン地域同士との連携等を考慮した処理を設計・実装しなければならない。例えば、特にアメリカ合衆国など国土が広い国では、国内だけでも東部・中部・山間部・西部とでタイムゾーンが変わって来るので、それをあらかじめ考慮して時制処理は作る必要があるのだ。

PHP
function show_dt( string $datetime_string ): array {
    $_dt = [];
    $timezones = [
        'UTC',
        'America/New_York',   // Eastern
        'America/Chicago',    // Central
        'America/Denver',     // Mountain
        'America/Los_Angeles',// Pacific
        'America/Anchorage',  // Alaska
        'America/Adak',       // Hawaii
        'Asia/Tokyo',
        'Australia/Sydney',
        'Europe/Berlin',
        'Europe/London',
        'GMT',
    ];
    foreach ( $timezones as $tz ) {
        $date = new DateTime( $datetime_string, new DateTimeZone( $tz ) );
        $_dt[$tz] = $date->format( DATE_RFC2822 );
    }
    return $_dt;
}

 上記のような、日時文字列を与えたらタイムゾーン別の日時が取得できる関数で、現在の時間をnowで取得してみた結果はこれだ。

PHP
var_export( show_dt( 'now' ) );// now: 2020/12/18 14:07:06 JST
/* 結果
array (
  'UTC'                 => 'Fri, 18 Dec 2020 05:07:06 +0000',
  'America/New_York'    => 'Fri, 18 Dec 2020 00:07:06 -0500',
  'America/Chicago'     => 'Thu, 17 Dec 2020 23:07:06 -0600',
  'America/Denver'      => 'Thu, 17 Dec 2020 22:07:06 -0700',
  'America/Los_Angeles' => 'Thu, 17 Dec 2020 21:07:06 -0800',
  'America/Anchorage'   => 'Thu, 17 Dec 2020 20:07:06 -0900',
  'America/Adak'        => 'Thu, 17 Dec 2020 19:07:06 -1000',
  'Asia/Tokyo'          => 'Fri, 18 Dec 2020 14:07:06 +0900',
  'Australia/Sydney'    => 'Fri, 18 Dec 2020 16:07:06 +1100',
  'Europe/Berlin'       => 'Fri, 18 Dec 2020 06:07:06 +0100',
  'Europe/London'       => 'Fri, 18 Dec 2020 05:07:06 +0000',
  'GMT'                 => 'Fri, 18 Dec 2020 05:07:06 +0000',
)
*/

 アメリカでは、国内だけでかなりの時差が出るのがわかるだろう。例えばニューヨークとハワイにオフィスがある会社で同じ時制イベントを管理する場合、そのイベントの登録処理が登録地点のローカル時制でDBに書き込まれていたら、複数地点間での時制イベントの取り扱いに時差が発生してしまうことになる。それを回避するためにはDBやアプリケーション内で取り扱うインターナルな時制はすべてUTCに統一して、フロントエンドへの出力時にのみローカル時制にフィルターする等の設計が必要になって来る。
 
 日本国内だけで利用されるようなプロダクトであれば、アプリケーション内でタイムゾーンをAsia/Tokyoに固定して処理できてしまうので、そこまでタイムゾーンに気を付けることはないのだが、ユーザごとにタイムゾーンが異なるユーズケースを持つようになると、設計や処理が急に複雑化してくるのだ。オープンソースの開発をしていると、その辺の勘所が鍛えられる。

サマータイム(DST)

 最も厄介なのがサマータイム(DST)だ。近年になって廃止する国や地域が増えてきたが、アメリカ合衆国をはじめとした多くの国で使われていて、この概念がもはや異次元に近い。
 サマータイムは夏時間とよばれる日照時間の長い日の一定期間の時間をいくらか進めて、夏時間終了時に進めた分の時間を戻すという仕組みだ。進める時間は地域によって異なり、30分進めるところもあれば、1時間のところもある。実施期間も地域によってまちまちなうえ、毎年変わる。およそシステム的に破綻しているのではないかと思うほどにまさに最悪の仕組みで、時制にとってカオスの根源でもある。最近は、EUなど制度自体を廃止するところが増えて来ているので、根絶されることを心から望んでいる(多くの国で採用されている制度なので、そうそうなくならないとは思うが……)。

 サマータイムは夏時間開始時に時間が増える。つまり開始日のみ一日が24時間ではなく24時間30分になったり25時間になったりする。そして、夏時間終了時に時間が減り、一日が24時間より少なくなるのだ。時制を取り扱うプロダクトにとってはこのキャズム日をまたぐような処理が鬼門となる。つまり、このサマータイムの特長を考慮して2点間時間のインターバル計算などをしてあげないと、イベントが消失したり時間がズレたりと意図しない不具合が発生するのだ。
 私もjQuery.Timelineでこのサマータイムから発生する不具合をイギリスのユーザさんに指摘されて、開発マシンのタイムゾーンをGMT(グリニッジ標準時≒イギリスのタイムゾーン)に変更して四苦八苦しながら対応した記憶がある。

 つとにアメリカは、同じタイムゾーン内でもサマータイムを持つ地域と持たない地域があったりして、もし私がアメリカ国内向けのスケジューラとか開発していたら、心が折れてしまうかもしれないな……w
 例えば、先のshow_dt()関数にアメリカ山間部とハワイのタイムゾーンにサマータイムありなしの種別を追加すると下記のようになる。

PHP
    $timezones = [
        'UTC',
        'America/New_York',   // Eastern
        'America/Chicago',    // Central
        'America/Denver',     // Mountain
        'America/Phoenix',    // Mountain no DST
        'America/Los_Angeles',// Pacific
        'America/Anchorage',  // Alaska
        'America/Adak',       // Hawaii
        'Pacific/Honolulu',   // Hawaii no DST
        'Asia/Tokyo',
        'Australia/Sydney',
        'Europe/Berlin',
        'Europe/London',
        'GMT',
    ];

 デンバーとフェニックスは同じタイムゾーンに属するが、サマータイムのありなしによってサマータイム中の時差が変わって来る。ちなみに今年2020年のアメリカ合衆国のサマータイムは3/8 2:00開始で、11/1 2:00に終了したので、それぞれのタイミングで時刻を表示してみよう。

PHP
var_export( show_dt( '2020-3-8 2:00' ) );
/* 結果: Denverは3/8 1:59:59までは時差 -7時間でPhoenixと同じだ
array (
  'UTC' => 'Sun, 08 Mar 2020 02:00:00 +0000',
  'America/New_York' => 'Sun, 08 Mar 2020 03:00:00 -0400',
  'America/Chicago' => 'Sun, 08 Mar 2020 03:00:00 -0500',
  'America/Denver' => 'Sun, 08 Mar 2020 03:00:00 -0600',
  'America/Phoenix' => 'Sun, 08 Mar 2020 02:00:00 -0700',
  'America/Los_Angeles' => 'Sun, 08 Mar 2020 03:00:00 -0700',
  'America/Anchorage' => 'Sun, 08 Mar 2020 03:00:00 -0800',
  'America/Adak' => 'Sun, 08 Mar 2020 03:00:00 -0900',
  'Pacific/Honolulu' => 'Sun, 08 Mar 2020 02:00:00 -1000',
  'Asia/Tokyo' => 'Sun, 08 Mar 2020 02:00:00 +0900',
  'Australia/Sydney' => 'Sun, 08 Mar 2020 02:00:00 +1100',
  'Europe/Berlin' => 'Sun, 08 Mar 2020 02:00:00 +0100',
  'Europe/London' => 'Sun, 08 Mar 2020 02:00:00 +0000',
  'GMT' => 'Sun, 08 Mar 2020 02:00:00 +0000',
)
*/
var_export( show_dt( '2020-11-1 2:00' ) );
/* 結果: PhoenixやHonoluluはサマータイム前後で時差に変更がない
array (
  'UTC' => 'Sun, 01 Nov 2020 02:00:00 +0000',
  'America/New_York' => 'Sun, 01 Nov 2020 02:00:00 -0500',
  'America/Chicago' => 'Sun, 01 Nov 2020 02:00:00 -0600',
  'America/Denver' => 'Sun, 01 Nov 2020 02:00:00 -0700',
  'America/Phoenix' => 'Sun, 01 Nov 2020 02:00:00 -0700',
  'America/Los_Angeles' => 'Sun, 01 Nov 2020 02:00:00 -0800',
  'America/Anchorage' => 'Sun, 01 Nov 2020 02:00:00 -0900',
  'America/Adak' => 'Sun, 01 Nov 2020 02:00:00 -1000',
  'Pacific/Honolulu' => 'Sun, 01 Nov 2020 02:00:00 -1000',
  'Asia/Tokyo' => 'Sun, 01 Nov 2020 02:00:00 +0900',
  'Australia/Sydney' => 'Sun, 01 Nov 2020 02:00:00 +1100',
  'Europe/Berlin' => 'Sun, 01 Nov 2020 02:00:00 +0100',
  'Europe/London' => 'Sun, 01 Nov 2020 02:00:00 +0000',
  'GMT' => 'Sun, 01 Nov 2020 02:00:00 +0000',
)
*/

 いやぁ、カオスだねぇ……。いかに時間ってものが非ロジカルなシステムで、単なる人のエゴの産物でしかないんだなってことが身に染みてわかる。欧米のエンジニアってこういうカオス時制に元から慣れ親しんでいるから、生産性や開発力が高いのかも知れないな。
 

2桁の年を自動マッピング

 これは世界の時制の問題ではなく、PHPやJavaScriptといった言語特有の時制仕様の問題である。PHPやJavaScriptの時制オブジェクトであるDateTimeやDateクラスには2桁の年を1900~2069年に自動マッピングするというロクでもない仕様があり、例えばJavaScriptだとDate.getFullYear()Date.setFullYear()を頑張って使ってこの自動マッピングを回避していても、時制計算とか行った途端、どこかの内部処理で自動マッピングが行われてしまい欲しい結果が得られないといった事がしばしば起こる。

PHP
$date = new DateTime( '1-1-1' );
var_dump( $date->format( 'Y-m-d' ) );
// string(10) "2001-01-01"
$date = new DateTime( '69-1-1' );
// string(10) "2069-01-01"
var_dump( $date->format( 'Y-m-d' ) );
$date = new DateTime( '70-1-1' );
var_dump( $date->format( 'Y-m-d' ) );
// string(10) "1970-01-01"
$date = new DateTime( '99-1-1' );
var_dump( $date->format( 'Y-m-d' ) );
// string(10) "1999-01-01"

PHPでは1~69の年を2001~2069年に、70~99の年を1970~1999年にマッピングする。

JavaScript
[ 0, 1, 69, 70, 99, 100 ].forEach((y) => {
    let dt = new Date( y, 0 )
    console.log(`${y}: ${dt}`)
})
/* 結果: JavaScriptは1900~1999年にマッピングされる
0: Mon Jan 01 1900 00:00:00 GMT+0900 (Japan Standard Time)
1: Tue Jan 01 1901 00:00:00 GMT+0900 (Japan Standard Time)
69: Wed Jan 01 1969 00:00:00 GMT+0900 (Japan Standard Time)
70: Thu Jan 01 1970 00:00:00 GMT+0900 (Japan Standard Time)
99: Fri Jan 01 1999 00:00:00 GMT+0900 (Japan Standard Time)
100: Fri Jan 01 0100 00:00:00 GMT+0918 (Japan Standard Time)
*/

 JavaScriptでは1~2桁年は1900~1999年にマッピングされる。さらに、年の引数を数値でなく文字列型で定義すると……

JavaScript
for(let y=0; y<=100; y++) {
    let dt = new Date( y.toString() )// 月の指定はなし
    console.log(`${y}: ${dt}`)
}
// 結果は……かなりカオスw

 上記のサンプルの結果はかなりカオスな感じになるので、気になる人は実際やってみてください(笑)

 ちなみに、Rubyでは、

Ruby
require "date"
for year in 0..100 do
  dt = Date.new(year)
  puts dt
end
/* 結果: そう、こういう結果を望んでいるのよね…
0000-01-01
0001-01-01
:
0099-01-01
0100-01-01
*/

──期待値どおりの結果が得られる。

 基本的に西暦1年~99年までの時制を取り扱うようなプロダクトは実用シーンではあまり必要にならないため、ほとんど問題が顕在化しないのかも知れないが、私のjQuery.Timelineのような汎用的に過去時制から未来時制までサポートするようなオープンソースだとニーズがあったりして、対応を迫られることがある。
 まぁ、どこまで対応するかはオープンソース作者のポリシー次第なので、ニッチ過ぎるニーズはコアに取り込まずに切り捨てるという選択肢もある。どうしても対応したい時のために、フォークという手段が用意されているのもオープンソースの良いところだ。

消失時間のミステリー

 これは、今のところJavaScriptのDateオブジェクトだけで見つけた問題だ。おそらくコアのバグなのではないだろうか?
 システムのタイムゾーンがGMT(グリニッジ標準時≒UTC)の場合、1847年12月1日0:0:0~0:1:15の1分15秒が消失するのだ。下記のスクリプトを見て欲しい。

JavaScript
let DateLoc  = new Date(1847,0,1,0,0,0),// 指定日時: 1847/1/1 0:0:0
    DateLoc1 = new Date(1847,10,30,23,59,59),// 指定日時: 1847/11/30 23:59:59
    DateLoc2 = new Date(1847,11,1,0,0,0) // 指定日時: 1847/12/1 0:0:0
console.log(`loc : ${DateLoc.toString()}`)
console.log(`loc1: ${DateLoc1.toString()}`)
console.log(`loc2: ${DateLoc2.toString()}`)
/* 結果:
loc : Fri Jan 01 1847 00:00:00 GMT-0001 (Greenwich Mean Time)
loc1: Tue Nov 30 1847 23:59:59 GMT-0001 (Greenwich Mean Time)
loc2: Wed Dec 01 1847 00:01:15 GMT+0000 (Greenwich Mean Time)
*/

 1847年12月1日以降はUTCと同期するが、1847年11月30日以前のグリニッジ標準時には協定世界時(UTC)と常に1分15秒時差が発生してしまうミステリーな現象が発生するのだ。しかもGMTのタイムゾーンでは1847年12月1日の0:0:0.0~0:1:14.999の1分15秒の間は1分15秒加算された時間が返ってくる。この時差は紀元1年の1月1日0:0:0までさかのぼっても解消されず、つまりGMTでは1847年12月1日の1分15秒が失われていることになる。バグなのか、歴史的に何か原因があるのか、暇な時にちょっとだけ調べてみたがよくわからなかった。
 その日その時、イギリスで何があった!? と、まさにJavaScriptにおけるミステリーで、中二病的なネタになりそうで興味深いのではあるが、JavaScriptで時制関連のライブラリを作っている私としては、勘弁してほしいクソ仕様の一つである。 

 さらに、そんな感じのミステリーっぽいのが日本標準時(JST)にもある。日本では、下記の通りだ。

JavaScript
let DateLoc  = new Date(1888,0,1,0,0,0), // 指定日時: 1888/1/1 0:0:0
    DateLoc1 = new Date(1888,0,1,0,18,58,999), // 指定日時: 1888/1/1 0:18:58.999
    DateLoc2 = new Date(1888,0,1,0,18,59,0), // 指定日時: 1888/1/1 0:18:59.0
    optJST   = { hour12: false, timeZone: 'JST', timeZoneName: 'short', era: 'long' }
console.log(`loc : ${DateLoc.toString()}`)
console.log(`loc1: ${DateLoc1.toString()}`)
console.log(`loc2: ${DateLoc2.toString()}`)
console.log(`JST : ${DateLoc.toLocaleString('ja-JP-u-ca-japanese', optJST)}`)
console.log(`JST1: ${DateLoc1.toLocaleString('ja-JP-u-ca-japanese', optJST)}`)
console.log(`JST2: ${DateLoc2.toLocaleString('ja-JP-u-ca-japanese', optJST)}`)
/*
loc : Sun Jan 01 1888 00:00:00 GMT+0918 (Japan Standard Time)
loc1: Sun Jan 01 1888 00:18:58 GMT+0918 (Japan Standard Time)
loc2: Sun Jan 01 1888 00:18:59 GMT+0900 (Japan Standard Time)
JST : 明治21年1月1日 0:00:00 GMT+9:18:59
JST1: 明治21年1月1日 0:18:58 GMT+9:18:59
JST2: 明治21年1月1日 0:18:59 GMT+9
*/

 1888年(明治21年)1月1日の0時18分59秒より前は日本のタイムゾーンの時差が18分59秒増えるのだ。こちらはグリニッジ標準時のミステリーとは違って時間の消失は発生しない。この原因はこのタイミングで日本標準時が実施されたからだ。JSTが実施される前は日本のタイムゾーン時差は9時間18分59秒だったということになる。まぁ、歴史的な経緯もあって納得はできるのだが、この仕様を時制システムに適用させるとなると、1888年1月1日前後の2点間の時間にてインターバル計算等を行うと変動する時差分を加味しなければ時間ズレが発生することになる。
 ちなみに、PHPはこの18分59秒の時差は発生せず、JSTのタイムゾーン時差は一律で+9時間だ。RubyはJavaScriptと同じように1888年0時18分59秒より前は時差が+9時間18分59秒となる。

 オープンソース開発に限らないが、言語毎の時制仕様がこうもバラバラであることを知っておくことは重要である。こういう知見の積み重ねは開発スキルとして重宝することになるだろう。

──ちなみに、この項で紹介した「jQuery.Timeline」は現在Vanilla JS(ネイティブJavaScript)版を開発中である。私がjQueryなしでVue.jsのサイトで使いたいからだ。

モダンな作り方

 WEB/ITCの業界は変化が速い。昨年流行った技術はすぐにレガシー化して、さらに効率の良い最新技術が登場してくる。そんな中で、オープンソースのプロダクト開発を続けていると、新規プロダクトには新しい技術を採用したくなる。そして、公開済みのプロダクトはもっと保守しやすくするために新技術を導入してリファクタリングしたくなる。
 
 そのためには、常に「学ぶ」ことを止めないことだ。

 2014年当時は、クロスブラウザ対応のために各ブラウザ毎に処理を作っていたJavaScriptやCSSは、今やBabelやsass/scssでトランスパイルすればクライアント差なんて開発時に気にする必要はないし、ドキュメントはソース内にコメントを書いておけばそこからESDoc等で自動でデプロイしてくれるし、Jest等でテスト駆動開発を行えば、開発サイクルのスピードはどんどん早くなる。これらの新しい技術を使うためには、もちろんそれらを都度々学習する必要がある。でも、「学ぶ」ことを止めなければいつまでも第一線で開発し続けられるだろう。

 私の場合、学んだ基礎を応用してこそはじめて技術が習得できたと実感することが多い。プロダクトを完成させることはその応用の集大成だ。チュートリアルの基礎しか知らない状態では、その技術を「使える」とは云えないだろう。オープンソースに限らず、プロダクトをモダンな作り方で新しく作る、もしくは作り直すことは、多くの技術的恩恵を自分にもたらしてくれるのだ。そして、新陳代謝が続いているプロダクトも根強く利用され続けることになる。

寄附金

 長年オープンソースを作り続けて、いくばくかの寄付金もいただいた。オープンソースを発表するのであれば、寄付がもらえるかどうかは関係なく、寄付を受け付ける入口だけは準備しておくべきだろう。
 GitHubであれば、申請すればGitHub Sponsorのリンクが設置できるので、もしGitHubでプロダクト公開しているのであれば是非設置しておくべきだ。

 海外のユーザは、自分にとって有益なプロダクトに出会った時に、寄付することに抵抗がほとんどない。額に関わらず寄付してもらえる機会は意外と多いのだ。寄付してもらえると開発のモチベーションはかなり上がるので、プロダクトの改善や保守継続への貢献度としては非常に大きいと云える。その窓口を設けないのはまさにもったいないだろう。

 ちなみに、今まで日本の方から寄付いただいたのは一度だけだった。日本人って寄付する風習があまりないうえ、国内法的に個人間送金が規制されていたりと文化的な影響が大きいんだろうな……とも思う(PayPalもいまだに日本国内では寄付できないようになっているしね)。
 それでも、最近はLINEで送金できるようになったりと、だいぶそのあたりの敷居が下がって来ている感じも見受けられる。クラウド・ファンディングという手もあるので、自分にあった方法を見つけるのも良いかもしれない。
 
 ただ、元々無料で使えるオープンソース・プロダクトにあえて寄付するって気持ちにならない人々は世界的にも多いだろうから、あまり寄付金に期待してはいけない。

仕事のオファー

 オープンソース開発というより、GitHubでプロダクト公開していると、仕事のオファーや転職のお誘い、ヘッドハンティング等々がしばしば来るようになる。それも世界中から来る。
 私は今現在、フリーランスで好きに生きているので、オファーが来ても食指が動くことはほとんどないが、もし会社に勤めていた頃にこれらのオファーに出会っていたら、確実に検討対象にしていただろう。

 オープンソースのプロダクトを自分で作って公開するのは、自分のエンジニアとしてのポートフォリオにそのまま直結するので、この業界内でお仕事欲しいと思っているなら、挑戦する価値は高いだろう。

 また、GitHubの活動内容などを含めて個人の開発スキルをアグリゲートしてくれる求人サポートサービスもいくつかあるので、GitHubで何かしら活動しているならそれらのサービスに登録してみるのもオファー促進の良い手段だ。私も自分のスキルを見える化するという目的のために、下記の三つのサービスに登録している。どれもGitHubのアカウントで無料でサインアップできるので、お手軽なのだ。

エンジニアスキルをスコア化してくれる転職サイト

 これらのサービスを使って、第三者的視点で自身のスキルが業界的にどの程度か知れるのは何かとメリットが大きいはずだ。まぁ、私みたいにフリーでやっていて就職すること自体に興味がない人は「転職に興味なし」というステータスに設定して、通知や勧誘を極力抑えて、参考指標用に利用するのもアリかと。

フリーランス用のお仕事マッチングサイト

 Findy Freelanceはスコア化されたエンジニアスキルの偏差値から最小時間単価の指標をシミュレートしてくれるので、フリーになってお仕事する時の見積り単価の設定に利用できて便利だったりする。ちなみに、ここで算出された最小単価より評価が低い仕事は、私は基本受けないようにしてる。

最後に

 オープンソースの開発だけで食べていくには、プロダクトがだいぶバズらないと難しい。でも、これって自分でWEBサービスなどを創ってバズらせるよりは、初期投資的にはずっと安価だし、失敗作を世に出そうが非難されることもないし、アイデアとモチベーションが続く限り何度でも挑戦できる──と、ローリスクなメリットが多々あると私は思っている。

 サービスだったら、一度ローンチしてしまったら最後、定期的なマーケティングや会員サポート、サーバ運用費用など、運営コストがどんどん増加していくことになる。まぁ、軌道にさえ乗ればそれだけで食べていけるので、起業家としては新しいサービスを生み出すという方向性こそが正しいのだろうとは思うが……。

 フリーでエンジニアリングやっていると、極論的に、サービスを育てて経営側へシフトしていくか、現役エンジニアを継続して職人路線でまい進するかのどちらかしかないのかなとも思う。最終的には前者で成功できれば万々歳だろう。後者で生涯現役を貫くのは結構いばらの道っぽい。しかし、数多くのプロダクトを生み出せば、その中から発展性のあるプロダクトをフォークしてサービス化するという可能性は大いにあり得るのだ。

 おそらく、オープンソースに限らず何かしらプロダクトを作り続けることは、エンジニアにとってとても有益なことで、まず間違ってはいないハズだ。だから、私から云えることは一つだ。

 さあ、みんなもプロダクトを作ろうぜ!