CubeRSS Reader の開発動機などについて

CubeRSS Reader メイン画面

先日、RSS/Atom feed reader(RSS リーダ)である CubeRSS Reader の最初のバージョンを公開しました。この記事では、なぜ今さら RSS リーダを開発しようと思い至ったのか、その動機などについて記載します。

RSS リーダを開発した動機

RSS リーダと呼ばれる分野においては Google Reader(~2013 年)を始め、livedoor Reader(~2017 年*1)、AOL Reader(~2018 年)、Digg Reader(~2018 年)と国内外を問わず Web サービスが次々と提供を終了しています。現時点ではまだ Feedly など有名な Web サービスがいくつか残っていますが、これらを含めても今後どうなっていくかを考えた時に不安を覚えたため、自らが選択肢の一つになる事に挑戦したいと思ったのが CubeRSS Reader の開発動機となります。

当初、新たな RSS リーダを開発する上で、個人的に設定した方針は以下の 2 点でした。

  1. OSS として公開する
  2. ユーザ端末においてスタンドアローンで動作する

1 点目は良いとして、2 点目のスタンドアローンで動作する事に拘った理由ですが、前述したように RSS リーダと言う機能を提供する Web サービスは先行きが暗い状況となっています。実際、RSS/Atom フィードの仕組み自体は今後も様々な場面で利用され続けると思いますが、汎用的な RSS リーダ と言うもの自体に対する需要は低下傾向が続くだろうと予想されます。このような状況で新たに Web サービスを公開したとしても、そう遠くないうちに諸々の維持費などを考慮した上で、サービスの提供を継続するかどうかの判断を迫られる時がやってくる事は想像に難くありませんでした。したがって、少し言い方は悪いですが、下火となっている分野において長期間、継続的に選択肢の一つとして提供し続けるには、Web サービスではなく各ユーザ端末においてスタンドアローンで動作する形の方が可能性があると判断しました。

今後も開発が継続されそうと期待できるような体制の確立

CubeRSS Reader は今後も開発を続けていく予定ですが、RSS リーダの選択肢の一つとして認識してもらうには、少なくとも同じプログラマ位には「口先だけではなく、本当に開発が継続されそう」と言う期待感を持ってもらえるような何かが必要と感じていました。これに対する現時点での回答としては、ここ 1 年の AppVeyorCodecov などに対する習熟の成果と言う意味も込めて、継続的インテグレーション (CI) の整備、そして最低限のテストは用意されていると言う事を分かりやすい形で外部に見せると言うものになりました。

テストのないコードは悪いコードである。どれだけうまく書かれているかは関係ない。どれだけ美しいか、オブジェクト指向か、きちんとカプセル化されているかは関係ない。テストがあれば、検証しながらコードの動きを素早く変更することができる。テストがなければ、コードが良くなっているのか悪くなっているのかが本当にはわからない。

レガシーコード改善ガイド

良いコード、あるいは継続的な保守や機能拡張を実現できそうなコードとは何かと考えた時に、現代における回答の一つとして「テストのあるコード」が挙げられます。これについては、最近は自分に関連するプロジェクトでどの程度テストが完備されているかを分かりやすく示す手段として、Codecov の結果をバッジで表示する形を採用しています。カバレッジはテストが十分である事を必ずしも保証するものではないですが、分かりやすい指標が何もないよりは良いのではないかと言う感触を得ています。

最初のリリースを終えての感想

私自身は、ここ 2, 3 年、C# をベースとして以下のような事を重点的に習熟してきました。

  • UI をブロックしないための非同期プログラミング(Task および async/await の利用)
  • Presentation Domain Separation (PDS) の実現

断片的な情報に依存している部分も多く、なかなか「これで良い」と確信できる境地に達する事ができずにいますが、今回、これまでに作成したものよりもやや複雑さを増した View を持つアプリケーションを概ね満足できるコード状態を保ったままリリースできた事には、それなりの達成感を抱いています。最初のリリースでは基本的な機能に留まっていますが、最初のスクリーンショットにあるように、100 件程度の RSS/Atom フィードと数千件の未読記事程度であればひとまずストレスを感じるような事もなく*2、出発点としてはまずまずかなと思います。

View の部分を除くと、クライアントのみで動作する RSS リーダで重要になるのは「登録されたフィードに対して、どのように定期巡回を実行するか」と言う点かと思います。これに関しては、基本的に RSS/Atom フィード(Web サイト)の追加は行うが削除はあまり行わないと言うユーザの性質と、追加された少なからぬ Web サイトがいずれ更新を停止してしまうと言う性質を鑑みて、現時点では更新頻度に応じて巡回頻度を変えると言う方法を採用しています。こうする事で愚直な定期巡回よりは、購読フィード数に対するスケーラビリティを確保できると期待していますが、実際どうなるかはもう少し様子を見る必要がありそうです。

Chrome ブラウザを利用する実験バージョン

ダウンロードページ にて配布している CubeRSS Reader 公式版では、Web ページ等の内容を表示するためのコンポーネント(内部ブラウザ)に .NET Framework 標準の WebBrowser を利用しています。このコンポーネントInternet Explorer (IE) のレンダリングエンジンで実現されていますが、2018 年現在では、最終版の IE11 であっても表示速度や Web ページの表示のされ方などに様々な問題を抱えています。

そこで CubeRSS Reader では、実験的な branch として Google Chrome、より具体的に言うと CefSharp と言うライブラリを利用するバージョンを並行して開発・公開しています。.NET Framework 標準の WebBrowser とのプログラム的な差異に関しては Behavior と呼ばれる機能を利用したクラス内でほぼ吸収できているため、比較的保守が容易な事もあり、当面はこの形を続けていく予定です。

尚、Chrome バージョンに関しては、現時点ではインストーラ等の正式な配布用ファイルは用意していません。AppVeyor 上でビルドする度にスナップショットが作成されますので、試してみたい方は x86 or x64 の Artifacts で表示されるリンクから Zip ファイルをダウンロードし、展開してご利用下さい。

Cube.Net.Chrome - AppVeyor

今後の方針

今後しばらくは、基本的な動作が安定しているかどうかの確認と「RSS リーダとしての minimal set」がどこまでなのかを探りなら実装していく段階になるかと思います。最初のリリースに対する反響を見ている限りでは、やはり複数端末で同期して利用する事への需要は根強く、この点をどうするのかが課題になると感じています。スタンドアローンでも動作すると言う原則を崩さないためには、現時点では Dropbox などのストレージを同期するような Web サービスを利用する形がベストではないかと思っていますが、この辺りも含めていろいろ検討していく予定です。

*1:2014~2017 年は Live Dwango Reader として運営

*2:もちろん実行環境のスペックにも強く依存するとは思います。

広告を非表示にする

GitHub の Activity を意識し始めて 1 年が経ちました

2017 年の振り返りとして、GitHub の Activity を意識し始めて変化した事を記述してみます。

GitHub の Activity (2017/02 ~ 2018/02)

GitHub 自体は利用し始めて 10 年くらい経ちますが、長い間「Git のリモートリポジトリ」以上の役割を考えた事はありませんでした。しかし、去年の 2 月頃に何となく「Activity など GitHub 上の見栄えにも少し気を配ってみよう」と思い立ち、それ以降、できるだけ Activity を途切れさせずにコミットし続ける事を 1 年間続けてみました。

その結果、法事や旅行などパソコンに触る事の難しい時以外は毎日何らかのコミットを行う事ができた点は、それなりに満足のいくものとなりました。また、去年の主な成果の一つとなった CubeICE のゼロからの改修 でも、小さな事を毎日継続すると言う習慣化が最終的に「今後も保守可能なレベルまでリポジトリを整理する事ができた」と言う達成感の遠因になったのではないかと感じています。

毎日の起動スイッチとしての役割

この 1 年で気付いた事として、GitHub の Activity が毎日、作業を始めるための起動スイッチの役割を果たしている と言うものがあります。

私の一日の多くはこんな感じだ: (1) 仕事にとりかかる。(2) emailをチェックしたり、Webを見たり、そのほかのことをする。(3) 仕事に取りかかる前にランチを取ったほうがいいと判断する。(4) ランチから戻る。(5) emailをチェックしたり、Webを見たり、そのほかのことをする。(6) いい加減はじめたほうがいいと心を決める。(7) emailをチェックしたり、Webを見たり、そのほかのことをする。(8) 本当に始めなきゃいけないと、再び決心する。(9) くそエディタを立ち上げる。(10) ノンストップでコードを書いていると、いつのまにか午後7:30になっている。

ステップ8とステップ9の間のどこかにバグがあるようだ、私は必ずしもこの溝を飛び越えられないからだ。私にとっては、ただ始めることが唯一困難なことなのだ。(中略)たぶんこれが生産性の鍵なのだ: ただ始めることペアプログラミングが機能するときにそれがうまくいく理由は、たぶんペアプログラミング セッションを相棒とスケジュールするときには取りかかるために2人が力を合わせるからだ。

射撃しつつ前進 - Joel on Software

非常に有名なコラムの一節です。私自身も、プログラムを書くと言う行為は好きなはずなのに、開発環境またはエディタを起動するのが億劫になる日がしばしばやってきます。経験的に一度やり始めさえすればストレスなく開発に没頭できる事を頭の中では理解しているのですが、そう言った理解とは別の何かが、始めることを拒絶します。

しかし、ここ 1 年は「取りあえず何でも良いから 1 コミットしなければ」と言う小さな義務感が、この状態を飛び越えるのに役に立っていると実感します。何でも良いから 1 コミットするために開発環境を起動し、プログラム全体を取りあえず眺めている内に気付けば……と言うサイクルが自分の性格や生活リズムにうまく嵌っているようです。当初「GitHub の Activity を途切れさせない」と言う事が変な義務感になるのではないかと言う懸念を持っていたのですが、この類の義務感が必ずしも悪い結果をもたらす訳ではないと言うのは少し意外な発見でした。

2017 年は、GitHub の Activity や Codecov を用いたカバレッジの可視化など、日々の作業結果をグラフなどで一目で分かるようにする事が大きなテーマの一つとなりました。このような可視化の懸念点として「可視化される結果を良くするためだけに、意義の低いコミットやテストコードを書いてしまう」と言うものがあり、実際、そう言う行動に走る時もあるのですが、総合的に見ると現状では「悪くない」と言う感触を得られた 1 年でした。

広告を非表示にする

圧縮・解凍ソフト CubeICE をゼロから改修

気付けば数年ぶりの更新となってしまいました。私は、普段 キューブ・ソフト (CubeSoft) と言う会社で様々な Windows ソフトウェアを開発・公開していますが、その一つに CubeICE と言うファイルの圧縮・解凍(展開)を行うソフトウェアがあります。今回、この CubeICE に対して 6 月~ 8 月にかけてゼロから書き直す大改修を行ったので、その記録として何かを書きたいと思い、久々にブログを執筆しています。

なぜ CubeICE をゼロから書き直したのか?

CubeICE は、7-Zip と言う圧縮・解凍ソフトウェアのライブラリ部分を修正して日本語の文字コード推測・変換処理を追加し、そのライブラリを利用した GUI アプリケーションとともに公開しているソフトウェアです。

CubeICE メイン画面

2011 年に最初のバージョンを公開して以降、Zip ファイルを WindowsMac 間でやり取りするユーザを中心に、文字化けが発生しにくいと言う一定の評価を頂いていました。また、圧縮ファイルにマウスカーソルを合わせるとファイルの一覧を確認できるシェル拡張機能なども好評で、現在でも多くのユーザにご利用頂いています。この CubeICE ですが、公開からしばらく経った段階で私の方でもいくつかの問題点を把握しており、その中でも大きな問題は以下の 2 点でした。

  • ボタンのクリック等、GUI の反応に大きな問題が存在する
  • ファイル数の多い圧縮ファイルを解凍する際、非常に長い時間を要する

これらはともに GUI プログラミングや 7-Zip を利用する上での(初期開発当時の)私の知識不足が原因で発生したものですが、ソフトウェアの根幹部分に存在する問題であった事もあり改修に多くの時間を要する事が予想されたため、長らく保留事項となっていました。しかし、現在でも引き続き多くのユーザにご利用頂いており、何とかしたいと言う気持ちは強くありました。また、「7-Zip」v16.00には危険な脆弱性の修正も。「PeaZip」にもアップデートが提供される - 窓の杜 などを始めとして、ここ 1, 2 年、圧縮・解凍ソフトウェア(ライブラリ)に脆弱性が見つかり、修正バージョンがリリースされる頻度が高まっている傾向が伺えます。そうした緊急度の高い修正に対して素早く追随するための開発体制を整えると言う意味でも、改修の必要性を強く感じていました。そこで、今年の大きなテーマの一つとして、CubeICE にあるこれらの問題の根本的な解決を図るべく、ゼロから書き直す事を決定しました。

CubeICE 改修の概要

改修に際しての一番大きな決断はプログラミング言語C++ から C# に変更する事でした。

CubeICE は当初 C++ と Win32 API のみで開発されていました。これは、開発開始当時においては、一般ユーザの .NET Framework に対するネガティブな印象がまだ完全には払拭されたとは言えないのではないかと言う判断によるものでしたが、その後の保守作業の大変さを生んだ要因の一つともなりました。2017 年時点においては、さすがにもう .NET Framework も広く認知されたと見なして良いだろう事と、GUI の非同期処理をまともに実装するにあたり、他はともかく async/await と呼ばれる機能だけはどうしても利用したいと言う個人的な思いから、この決断に至りました。その甲斐もあって、GUI の反応の悪さに関しては問題ないレベルまで改善できたと思います。

もう一つの課題は 7-Zip との連携に関する部分で、具体的には COM インターフェースから 7-Zip ライブラリ (7z.dll) を利用する方法の改修となります。従来の CubeICE では 7-Zip との連携に不完全な部分があり、これが「多数のファイルを含む圧縮ファイル」を解凍する際に処理時間が異常に長くなってしまう現象の原因でした。7-Zip との連携に関しては、随分昔に @rofi に詳細を調べてもらっていたのですが、前述したような都合で実際には活用されないまま時間が過ぎてしまいました。今回、当時の調査結果等も参考にしながら、ようやく該当部分の実装を終える事ができたので、この場を借りて御礼申し上げます。

尚、修正効果については、CubeICE 0.8.0β のリリースノート でも触れましたが、サンプルケースとしてハードディスク上(not SSD)で「59,763 個のファイルを持つ 135MB の Zip ファイル (boost_1_64_0.zip)」を解凍したところ、CubeICE 0.7.3β では約 35 分かかっていたのが、0.8.0βでは約 7 分まで改善しましたWindows 標準の展開機能を含めていくつか比較してみましたが、少なくとも CubeICE だけが特別遅いと言う現象は解決できたのではないかと思います。

まともな開発および保守環境の構築

今回ゼロから書き直すに当たり、ソフトウェアのバージョンアップと言う最終目的とは別に、開発中に設定したテーマとしてまともな開発および保守環境を構築すると言うものがありました。具体的には、以下のような項目となります。

まず、バージョン管理は、自ソフトウェアの開発プロジェクトは 2010 年の頃から git によるバージョン管理を続けているので大きな変化はないのですが、既存の OSS プロジェクトをカスタマイズする際におざなりになる傾向がありました。このせいで、前述した 7-Zip脆弱性に対する修正をカスタマイズ版に反映する時に苦労した経験から、何とかしたいと感じた課題です。7-Zip に関しては、フォークしたリポジトリ (cube-soft/7z) に対していくつかのブランチを用意し、オリジナル版の修正を反映しやすくする事で改善を試みました。改修後に発生した 7-Zip 側のアップデートは 1 度しかないのですが、この時は git の自動 merge のみで完了できたので、従来に比べて随分と楽になった事を実感できました。

ユニットテストに関しては、ライブラリ部分に関しては当初からそれなりにテストケースを作成していましたが、View 側に近づくにつれて不十分になっていくと言う実感がありました。また、旧 CubeICE では、ユーザ設定に応じて圧縮・解凍結果が正常に変化しているかどうかの確認を人力テストに依存している部分が残っていたため、これを自動化する必要性も感じていました。今回は、改修当初からアプリケーション部分のユニットテストも後回しにしないように注意しながら進めた結果、コマンドラインとユーザ設定を指定して圧縮・解凍処理を実行すると言う実アプリケーションとほぼ同様の流れをユニットテスト上で再現できる形まで持っていく事ができました(ArchiveTest.cs, ExtractTest.cs)。また、解凍処理で対応している圧縮形式に関しても、可能な限りサンプルファイル (Examples) を用意する事で、特定の圧縮形式の解凍処理にのみ発生する問題も早期に検知できる体制となってきました。

最後に、CI 環境の構築については、ごく少数で開発している事でローカル環境で十分と思っていた所もあり、ずっと後回しになっていました。しかし、1 年位前に AppVeyor と言う Windows アプリケーションの CI に特化したような Web サービスが存在する事を知り、github との連携で比較的簡単に導入できる事もあって基本的なライブラリ用プロジェクトから少しずつ導入を進めていました。そこで、今回、アプリケーションまで含めた導入プロジェクトの第一弾として CubeICE のプロジェクト全てを CI 環境上に構築する事を決めました。

CI 環境での都合により途中でリポジトリを 2 つに分割しましたが、Cube.FileSystem および Cube.FileSystem.SevenZip が C# の実装(≒ CubeICE のアプリケーション部分)、cube-soft/7z が 7-Zip のカスタマイズ部分となっています。共有ライブラリ部分を含めてまだ NuGet には公開していない事で AppVeyor の設定ファイルの記述に 1, 2 日悩みましたが、何とかテストを自動実行できる所まで構築できました。また、AppVeyor と同時にコード・カバレッジを可視化する Web サービスである Codecov とも連携しましたが、テストケースを記述していく上で当初の予想以上にここから得られる情報が役に立っていると実感しています。AppVeyor と Codecov を利用して実感した利点については、また別の機会にまとめたいと思います。

おわりに

CubeICE も最初の公開が 2011 年と言う事で、気付けばもう 6 年位もの間、多くのユーザに利用されている事になります。CubePDF 等でも同様の感想を抱く事が多いのですが、世に出たアプリケーションの寿命は、自分が開発を始めた頃(2010 年位)に漠然とイメージしていたよりもずっと長いものなのだなと改めて実感させられます。

圧縮・解凍と言う処理の観点から見ると、世の中全体としては文字コードUTF-8 に統一される方向にあり、いずれは文字コードが異なるせいで文字化けが発生するような状況もなくなっていくかもしれません。しかし、完全にそう言った時代がやってくるにはもうしばらく時間が必要で、後 10 年位は引き続き CubeICE のような機能も必要とされるのではないかと感じています。これから 10 年、様々な修正、改良を続けていく上で、今回少し時間をかけて構築したものが役に立ってくれる事を期待しています。

広告を非表示にする