メインコンテンツまでスキップ

ローカルファーストである理由

skillshare はランタイム依存のない単一バイナリです。その理由を説明します。

その決断

skillshare は単一の Go バイナリとして配布されます。Node.js も、Python も、パッケージマネージャーも、デーモンも不要です。インストールして実行するだけで完了です。

これは単に楽な道を選んだのではなく、3 つの原則に基づく意図的な選択です。

原則 1: 依存関係チェーンをゼロにする

すべての依存関係は攻撃対象領域であり、保守の負担でもあります。

もし skillshare が Node.js を必要としていたら、Node のバージョン管理、node_modules の扱い、プラットフォーム固有のネイティブモジュールへの対応、そして npm のサプライチェーン全体への信頼が必要になります。AI の Skill——それ自体が信頼できないコンテンツ——を管理するツールにとって、信頼できない依存関係チェーンを追加することは受け入れられません。

Go は静的バイナリにコンパイルされます。依存関係チェーンはコンパイル時点で終わります。ダウンロードしたものがそのまま実行されるものです。

原則 2: どこでも同じように動く

skillshare は次の環境で動作します。

  • macOS(Intel および Apple Silicon)
  • Linux(amd64 および arm64)
  • Windows(amd64)
  • Docker コンテナ(特別なセットアップ不要)
  • CI/CD パイプライン(言語ランタイム不要)
  • Dev Container と Codespaces

単一バイナリであることは、すべてのプラットフォームで同一の挙動を意味します。「自分のマシンでは動く」というデバッグも、CI 環境のずれもありません。

原則 3: デフォルトでオフライン動作する

skillshare のコア操作——syncliststatusbackuprestore——はネットワークアクセスなしで動作します。明示的に remote を必要とする操作(installsearchcheckupdatepushpull)だけが接続を必要とします。

これは次のような場面で重要になります。

  • エアギャップ環境: 防衛、医療、金融機関ではネットワークアクセスが制限されることが多い
  • 不安定な接続: 電車、飛行機、カンファレンスの Wi-Fi
  • 速度: ローカル操作は秒単位ではなくミリ秒単位で完了する

なぜパッケージマネージャーのプラグインにしなかったのか

npm パッケージ、Homebrew formula(現在は追加のチャネルとしてサポート)、pip パッケージとして配布することも検討しました。しかしどれも同じ問題を抱えていました。skillshare のユーザーが持っていない、あるいは望まないランタイム依存を追加してしまうのです。

Windows で Cursor を使っている開発者が Homebrew をインストールする必要はないはずです。Alpine Linux 上で動く CI パイプラインが Node.js を必要とするべきではありません。ツールはユーザーの環境に合わせるべきであり、その逆であってはなりません。

トレードオフ

単一バイナリのアプローチには代償があります。

  • ビルドの複雑さ: 6 以上のターゲットへのクロスコンパイル、CGO は無効化
  • 更新の仕組み: npm update は使えないため、skillshare 独自の upgrade コマンドを用意している
  • UI の配布: Web ダッシュボードはバイナリに同梱できないほど大きいため、実行時にダウンロードしてキャッシュする

これらのトレードオフを受け入れているのは、それによってユーザー体験をシンプルに保てるからです。ダウンロードして、実行して、それで完了です。

関連項目