※ このブログはヌーラバー Advent Calendar 2020 25日目最終日の記事です。
ヌーラボでソフトウェアエンジニアとして働いているvvatanabeです。
私がメンテナを続けているOSSにnulab/zxcvbn4jというものがありまして。先日の12月24日で公開から5年が経ちました。5年という時間にとくに大きな意味はないのですが、なんとなく区切りがいいし年末なので、このnulab/zxcvbn4jのメンテナンスを通じて体験したことを振り返ってみることにしました。
目次
自己紹介
どんな人が本記事を執筆しているのか、筆者のバックグラウンドを簡単に紹介します。
ヌーラボアカウントからBacklog、そしてSREへ
2015年にヌーラボへ中途入社しました。入社してすぐは通称ヌーラボアカウントと呼ばれる、ヌーラボのサービスが共通で使用する認証基盤を開発していました。今でこそScalaやGoを書くことがほとんどですが、当時はJava8+Springでした。ラムダ式に熱狂してた思い出があります。ちなみに、本記事で触れるnulab/zxcvbn4jはこの時期に開発したもので、ソフトウェアの年齢と私のヌーラボ歴はほぼ同じです。
もともとヌーラボアカウントのプロジェクトでBacklogとヌーラボアカウントの統合を進めていたのでBacklogに手を入れることが多かったのですが、そのプロジェクトが完了した後、そこで得た知見を活かすためにBacklogへ異動しました。主にGitホスティングの分野に注力していました。
現在は2019年に課として発足したSREへ移っていますが、やっていることは以前とあまり変わらず、BacklogのGitのバックエンド周りの安定化に注力しています。
ヌーラボ以降がアウトプットのターニングポイント
ヌーラボ以前も学ぶこと自体を楽しんではいたのですが、アウトプットの形態としてはアプリを作って公開するくらいで、ヌーラボ以降がソフトウェアエンジニアとしてのアウトプットに変化があったターニングポイントになっているのは確かです。
会社の技術系ブログを書いたり、技術誌に寄稿したり、GitHub上で活動したり、カンファレンスや勉強会へ発表者として応募するようになりました。
それは確実にヌーラボで一緒に働く人達の影響が大きいです。
nulab/zxcvbn4jとはなにか
本題です。nulab/zxcvbn4jについて簡単に紹介します。
パスワードの強度を測定するJavaのライブラリ
nulab/zxcvbn4jはパスワードの強度を測定するライブラリです。Javaで書かれています。5年前にOSSとして公開した際に紹介記事として「真のパスワード強度を測定する5つのアルゴリズム」を書いてるので詳しくは記事やリポジトリのREADMEをご覧ください。
使用方法を簡単に解説します。
以下のコードは一番簡単な例です。APIとして提供している測定用のメソッドにパスワードを渡すと、そのパスワードの強度を5つのアルゴリズムを使って複雑性を計算し強度を示すオブジェクトを返します。
Zxcvbn zxcvbn = new Zxcvbn(); |
そのオブジェクトには、強度を示すスコアの他にも、そのパスワードの特徴を加味してよりセキュアなパスワードにするための、具体的なフィードバックを含めたメッセージ等の様々な情報が含まれます。
dropbox/zxcvbnのポーティング
nulab/zxcvbn4jは、DropboxがJavaScriptから使用するライブラリとして公開していていたdropbox/zxcvbnをJavaへポーティングしたものです。
dropbox/zxcvbn自体のモチベーションや構成するアルゴリズムについては「zxcvbn: Low-Budget Password Strength Estimation」にまとまっています。
dropbox/zxcvbnの仕組み自体が広く認知されていて、OSSコミュニティに愛されており、有志の手で様々な言語へポーティングされています。以下はREADMEから抜粋したその一部です。
- zxcvbn-python (Python)
- zxcvbn-cpp (C/C++/Python/JS)
- zxcvbn-c (C/C++)
- zxcvbn-rs (Rust)
- zxcvbn-go (Go)
- zxcvbn4j (Java)
- nbvcxz (Java)
- zxcvbn-ruby (Ruby)
- zxcvbn-js (Ruby [via ExecJS])
- zxcvbn-ios (Objective-C)
- zxcvbn-cs (C#/.NET)
- szxcvbn (Scala)
- zxcvbn-php (PHP)
- zxcvbn-api (REST)
- ocaml-zxcvbn (OCaml bindings for zxcvbn-c)
- angular-zxcvbn (AngularJS)
OSSとして公開するまでの経緯
開発のきっかけは5年前ヌーラボアカウントチームにジョインして最初のタスクでした。
開発の動機や詳細な仕組みは、「真のパスワード強度を測定する5つのアルゴリズム」で触れているので要所引用しながら解説します。
パスワード強度を測定する機能を提供する
当時ヌーラボアカウントのパスワード作成フォームに強度測定用のメーターは実装されていなかったので、セキュリティの観点からパスワード強度メーターを設置することになりました。
このUIの要素は、MSR(Microsoft Research)の論文によると類推されづらいパスワードを促してサービスの安全性を高めることに効果的だということが証明されています。お客様自身の大事な情報を守る上でとても重要なパスワード。ヌーラボアカウントでも、類推されにくいより強度の高い設定を促すためにパスワード強度メーターを設置しました。
現在は以下のようなUIで強度測定用のメーターを提供しています。入力したパスワードの特徴によってよりセキュアなパスワードへするための方法をフィードバックをしています。
強度を測定するアルゴリズム 〜 zxcvbnという選択肢 〜
強度測定を実施するための方法について調査を進めると以下のような懸念が生まれました。
強度測定を実装する上で、他のサービスはどのような基準で測定を行っているのか調査しましたが、その基準は各サービスによって異なり、さらにほとんどがブラックボックスな状態でした。あるサービスで強いと測定されたものが、他のサービスでは弱いと測定されることが十分にあり得るのです。
ブラックボックス化された指標によってユーザーを混乱させる可能性を考慮して、オープンな資料やライブラリを調査していたところ、前述した要件を満たすdropbox/zxcvbnと出会いました。
OSSを目標に
Javaアプリケーションで測定用のAPIを設けてサーバーサイドで処理するといった要件もあり、zxcvbnをJavaアプリケーションで利用したいといった声もIssuesに上がっていたため、OSSとして公開することを視野にいれてポーティングすることになりました。
しかし、ヌーラボアカウントとしては測定用のAPIを設けてサーバーサイドで処理したいといった願望がありました。さらに、ヌーラボアカウント自体Javaで構築されているという背景や、zxcvbn自体Javaアプリケーションで利用したいといった声もIssuesに上がっていた事実もあり、思い切ってJavaへのポーティングとJava版ライブラリとしての公開に踏み切りました。
Nashornでzxcvbn.jsの使用を妨げるパフォーマンス課題
dropbox/zxcvbnはあくまでJavaScriptで使用するためのライブラリです。
当時のヌーラボアアカウント認証基盤はJava+Springで動いていました。そこで最初はJavaでJavaScriptを実行するためのエンジンの使用を検討しました。エンジンは当時は2015年末だったのでJava8のNashornです。
しかし、パフォーマンスに大きな課題がありました。dropbox/zxcvbnの初回読み込みに数分かかっていました。そもそもdropbox/zxcvbn自体がライブラリ内に複数の大きな辞書を持っていて、それが初回読み込みの妨げになっていたのです。これもポーティングに踏み切った大きな理由の1つになります。
CoffeeScriptからJavaへ
dropbox/zxcvbnはCoffeeScriptで書かれていました。ソースコードを覗いてみると、思った以上に複雑で尻込みしたのを覚えています。
しかし、大きな辞書を抜いた行数を見るとテストコードも含め2000行程度でした。(ちなみに、Javaへ移植したら5000行くらいに膨れました。)事前に複数の辞書のテキストからコードを自動生成するためのPythonのスクリプトも同梱されていましたが、その仕組み自体は複雑ではありません。一筋の光が射してきました。それから、ミーティングで、「CoffeeScriptからJavaへポーティングしましょう」とどきどきしながら言った記憶があります。
当時のヌーラボアカウントでは上司のBABAがこういった技術的な意思決定の最終ジャッジをやっていたのですが、「いいですね〜、やりましょう!どうせなんでOSSとして公開しましょう〜」といった感じで即決だったと思います。
この件だけではなく、自分がなにかにチャレンジしようと踏み切る一歩手前で悩んでいる時、相談しやすかったり、最後の一押しをしてくれる人達がヌーラボには多いと感じています。
ポーティングするにあたって厄介だったのは、CoffeeScriptの型の無いオブジェクトをデバッグしながらJavaの型に起こす作業と、Androidでも使えるようにJava8の新しい構文は使わず(※2015年当時)Java7のサポートする範囲の構文を使用するところでした。
複雑な文字列評価をやっているので互換性をどう担保するのかといったところが悩ましいところだったのですが、dropbox/zxcvbn自体にユニットテストがしっかり書かれていたことに救われました。
OSSとして公開する
四苦八苦しながらもポーティングを完了させ、ヌーラボアカウントへパスワード測定機能として無事リリースできたので、最終目標のOSSとしてGitHubへの公開、Mavenのアップロードへ踏み切りました。
公開後は「zxcvbn for Java. #123」でJavaへポーティングしたことをお知らせしたら、READMEに追記してくれて、Javaで使用したいといったIssueでも紹介してくれました。
公開してからがスタートライン
OSSとして公開してしまったことである程度満足していたのですが、公開してからがスタートラインということに気付かされました。
タイポの修正が最初に来たプルリクエスト
公開して1ヶ月くらい経つと早速最初のプルリクエストがきました。国外のエンジニアでmagineさんという方からでした。
内容はパスワードのフィードバックメッセージのタイポの修正でしたが、公開したソフトウェアに国外からの反応があるのは初めての経験だったので、初めてプログラミングを通して世界と繋がった気がして小躍りしました。
また、どんなヒトなのかなとGitHubのプロフィールを見たら、組織にJetBrainsと書いてあったので、そんな世界的に有名な会社のエンジニアでも無名なリポジトリのタイポを修正してくれるんだなぁと感心しました。
最初のプルリクエストはほんの挨拶代わり
最初のプルリクエストをマージした後、間髪入れずにmagineさんからIssueが立てられました。内容はフィードバックメッセージのローカライズでした。
zxcvbn4jは当時フィードバックメッセージのローカライズには対応しておらず、必ず英語で返すような仕様でした。ヌーラボ社内でもメッセージをローカライズできる仕組みがあってもいいよねという話しは出ていたのですが、その矢先の出来事でした。
さらに、そのIssueに対してのプルリクエストまで既に作ってくれていたのです。
これで、nulab/zxcvbn4jは多言語化できるようになったので、ヌーラボアカウントでもフィードバックメッセージを言語設定によって分けて表示できるようになりました。
しかし、なぜここまでコントリビュートしてくれたのでしょうか。
背中で教えられた足りないモノをプルリクエストする熱意
同月、さらにmagineさんからプルリクエストがきました。
Added JetBrains Hub to the list of applications using this library
小躍りしました。公開したソフトウェアが初めて他社の製品で導入されたのです。
この件で、自社の製品でOSSを導入する際に足りない機能や問題を自分で解決する姿勢を学びました。それは今でも深く刺さっていて、基本的に自分が使用するライブラリで見つけた問題は、積極的にIssueを作るようにして、できる範囲でプルリクエストも送るように心掛けています。
オリジンへの追従は険しい道のり
あくまでzxcvbn4jはdropbox/zxcvbnのポーティングなので、オリジンとの互換性が大切です。そのためdropbox/zxcvbnに改修が入ると、そのCoffeeScriptの差分をJavaの実装へ落とし込むという作業が必要でした。
大きな粒度で差分を見ると巨大な変更に圧倒されてしまい手が動かなくなってしまいがちなので、コミット単位で少しづつ読み進めながら移植してました。よく仕事なんかでタスクが大きすぎる時に小さく分解していって地道に消化する方法と本質的には同じです。
さらに、このような互換性を保つ取り組みも、コントリビュートに助けられました。
added a test comparing the javascript release and the java port #9
中を覗いてみると、
おお!Nashorn Nashornじゃないか! 久しぶりじゃないか、元気にしてたか??
なんと、ポーティングする前に動作検証していて見送りにしたNashornが帰ってきたのです。
ありがたいことに、dropbox/zxcvbnのJavaScriptをNashornで実行してnulab/zxcvbn4jの結果と比較するといった内容でした。
このような仕組みに支えられて互換性を保てるように努めています。
※ NashornはJDK 11で非推奨、15で廃止されています。そのため、15で上記のテストを実施する場合にGraalJSを使用する必要があり対応を検討しています。
OWASP Web Goatのセキュリティコンテンツで使用される
Web GoatというWebセキュリティ学習用のアプリケーションがあります。セキュリティの第一線であるOWASPが提供しているJava製のOSSです。
Web Goatのセキュリティコンテンツの1つに、「Secure Passwords」というものがあります。パスワードの安全性を高めるために満たすべき要件や、パスワードの安全な取り扱いについて書かれたコンテンツです。
そのコンテンツはdropbox/zxcvbnが提唱する要件をもとに推奨事項が書かれており、さらにnulab/zxcvb4jを使って入力したパスワードの強度を測定するデモ機能が実装されていました。
開発者のWebセキュリティに対するリテラシーを高める活動に間接的にでも関わることができて、メンテナンスを継続するやる気にも繋がりました。
いつのまにか月間13万ダウンロード
実際にどの程度使用されているのか、月間のダウンロード数を見てみました。以下はoss.sonatype.orgのCentral Statisticsで取得した直近のダウンロード数のグラフです。最近では月間で13万程ダウンロードされていました。
nulab/zxcvb4jのスター数は決して多くはないのですが、その割には使われている印象です。
また、自分も以前使用していたアヒルのアイコンのCyberduckや、某セキュリティソフトのAndroidアプリでも導入されているようです。
なぜメンテナンスを継続できたのか
本記事で紹介したnulab/zxcvbn4jは業務で必要にせまられてポーティングしたという背景がありました。今でこそたまに立てられるIssueに回答する程度ですが、OSSとして公開して最初の方は定常業務をこなしながらメンテナンスを続けるのに組織や同僚の助けがとても有難かったです。
ヌーラボのOSS活動への理解
ヌーラボはここまで書いたとおり、OSS活動に理解がある方の組織だと思います。
業務に関連するソフトウェアであれば、自分の裁量で業務中にコントリビュートできます。
ただしそれは明文化されていません。けっこうふわっとしています。そのため、都度チーム内のメンバーや上長に相談する手間がかかったり、人によって判断が偏ってしまう可能性もあります。
決して簡単なことではないのですが、サイボウズさんやZOZOテクノロジーズさんが運用しているOSSポリシーのようなものがあると、明文化されたルールにより安心して活動しやすくなり、今よりもOSSと向き合う文化が育つのではないかと思っています。
余談ですが、ヌーラボの役員には社長のmasaをはじめOSS活動の経験者がいます。組織のトップにこのような思想が根底にあるのは、組織としてOSS活動が理解される大きな要因かと思います。
心強い同僚達のサポート
組織の理解も大事ですが、一緒に働く同僚達に幾度と無く助けられました。
5年間のメンテナンスで全てのIssueを自分自身で調査してパッチを作ったわけではありません。ヌーラボにはJavaが得意なエンジニアが比較的多く、気兼ねなく相談できる雰囲気があります。
Java 9から導入されたNamed Moduleの挙動や、Androidとの互換性を保つためのワークアラウンド等、一歩踏み込むような内容は詳しい同僚に相談してました。
だいたい解決策がみえてきたところで、「せっかくなんでやっときますよ〜」といった感じで気軽に引き受けてくれてました。当時の上司だったBABAもそのうちのひとりです。
また、ヌーラボ内には他にもOSSとして公開しているライブラリやツールが複数あり、継続的にメンテナンスされています。以下はその一部です。同僚達がこういった活動をしていると良い刺激にもなります。
OAuth 2.0 サーバーサイドのScala実装
nulab/scala-oauth2-provider maintained by tsuyoshizawa
GoogleスプレッドシートによるBacklog課題一括登録
nulab/backlog-bulk-issue-registration-gas maintained by shomatan
Backlogへのデータ移行ツール
nulab/BacklogMigration-Jira maintained by shomatan
nulab/BacklogMigration-Redmine maintained by yuichi0301
各サービスのAPIクライアント
nulab/backlog4j maintained by Backlog Developers
nulab/backlog-js maintained by mmktomato
nulab/go-typetalk maintained by Typetalk Developers
価値を紡ぐOSSエコシステム
zxcvbn4jのメンテナとしての活動で垣間見た、OSSエコシステムの価値が紡がれていく様子は、OSSとしてソフトウェアを公開することがもたらす可能性をあらためて再確認させてくれました。
共有して共に作る価値
dropboxがzxcvbnをOSSとして公開して、dropbox/zxcvbnの仕組みが評価され、様々な製品がdropbox/zxcvbnを使いはじめました。そして、ドキュメントのアップデートやバグ修正のような様々なコントリビュートがはじまり、共有した価値が国境を超えて大勢の有志の手で育っていきました。
伝播する仕組みと考え方
その価値はライブラリとしての機能だけではなく構成する仕組みそのものが評価されはじめました。様々な言語へポーティングされはじめOSSとして公開され、プログラミング言語の枠を超えその価値を享受できる範囲が一気に拡大したのです。
さらに、それらのポーティングされたOSS達も、オリジンのdropbox/zxcvbnと同じように使用者からフィードバックを受けて小さなエコシステムが作られていきました。実際にヌーラボもnulab/zxcvbn4jという形でその仕組みの伝播に関わり使用者と共に価値を育てることができました。
その他にも、dropbox/zxcvbnのパスワードの複雑性を測定する観点はOWASP Web Goat上のセキュリティコンテンツとしても紹介されおり、考えたそのものが伝播しています。
まとめ
一つのソフトウェアを起点にエコシステムが拡大していく流れに、少しでも関われたことは自分にとって貴重な体験でした。
オリジンへのリスペクト
オリジンのdropbox/zxcvbnは間違いなく偉大なソフトウェアの一つです。コミュニティに愛され有志の手で数多くの言語にポーティングされています。nulab/zxcvbn4jも数多くダウンロードされて様々な製品で使われていることを紹介しましたが、dropbox/zxcvbnという仕組みが世界中に認められて他の言語でもニーズが生まれた結果に過ぎません。
何者でもなくともOSSのハブにはなれる
ただ一つ自信を持って言えるのは、5年間のメンテナンスを通して、偉大なソフトウェアの価値を届けるためのハブの一つにはなれたのではないかということです。そして、そのハブを継続できているのも間違いなく有志によるコントリビュートのおかげです。
世界に一石投じるようなソフトウェアを生みだすのはほんの一握りかもしれませんが、OSSとの関わり方はそれだけではなく、1つのIssueや1行のコード修正といった形で小さな共創関係を築くことも、大きな価値を形作る大切なピースになるのではないでしょうか。
以上、本記事がどこかの誰かのコントリビュートの後押しになれれば幸いです。
We are hiring!
ヌーラボが運営するのは全てB2Bのサービスです。そしてどのサービスもAPIを提供しています。そのため業務を改善するためのサービスの機能を補助するツールを作りやすく、作ったツールはOSSとして公開しやすいです。そして、ヌーラボはソフトウェアエンジニアの技術的アウトプットを尊重し、業務中にOSSへコントリビュートすることはもちろんですが、業務で得た知見や問題もオープンにしていく気概があります。
先日もヌーラボのカンファレンスNuCon2020でたくさんのメンバーが発表しました。
そんなヌーラボの文化に興味を持っていただいた方は、是非「ヌーラバーの話を聞いてみたい」からお問い合わせください。