TinyPilot:38か月目
原文は Michael Lynch により に公開されました。 このブログを購読する
一言サマリー
ソフトウェアへの投資は適切にできているだろうか?
初めての方へ
こんにちは、Michaelです。私はソフトウェア開発者で、独立系コンピューターハードウェア企業TinyPilotの創業者です。2020年に創業し、現在は月商6万〜8万ドルの収益を上げ、他に7名の従業員を抱えています。
毎月、このような振り返りを公開して、ビジネスや仕事全般の状況を共有しています。
ハイライト
- TinyPilotのライセンスの継続課金サブスクリプションの販売に失敗した。
- TinyPilotを設定可能にしすぎていたことに気づいた。
- TinyPilotの開発への投資がうまくいっていないと思っていたが、この振り返りを書くことで、おおむね順調だと気づいた。
目標の評価
毎月の初めに、その月に達成したいことを宣言しています。目標に対する結果は以下のとおりです。
製造をできるだけ早く委託製造業者へ移管する
- 結果:製造業者からのブロックを素早く解消したが、スピードアップの機会を逃した。
- 評価:B-
委託製造業者からフィードバックを求められて作業が止まっているときは、迅速かつ完全な返答を優先し、その点ではうまくできたと思います。
一方で、もっと主体的にプロジェクトを管理すべきだったと遅れて気づきました。先方にはプロジェクトマネージャーがいるので任せきりにしていましたが、遅延した際に最も損をするのは自分自身なのです。
箱のデザインや取扱説明書についてフィードバックを求められたときは、すぐに返信して、その後は先方から連絡があるまで忘れてしまっていました。最終サンプルが出荷される段階になって、フィードバックを出して以来、箱や取扱説明書の最終案を一度も確認していなかったことに気づきました。デザインにはさらに修正が必要で、不要な遅れが生じてしまいました。
TinyPilotのローカルオフィスからの退去に向けた詳細な計画を作る
- 結果:目標日とマイルストーンを含む、月ごとの退去計画を作成した。
- 評価:A
計画はでき、全員がスケジュールを共有できています。
売却したい機材にはニワトリと卵のような問題がまだ残っています。例えばプリンターを売ってしまったら、他のものを売るための配送ラベルをどうやって印刷するのか、といった具合です。ただ最悪の場合は、残りを自宅で保管して、ここから売ればいいと考えています。
TinyPilotライセンスの自動更新の選択肢を検証する
- 結果:いくつかの選択肢を検討したが、どれもうまくいかなかった。
- 評価:B
TinyPilot Proの継続課金を販売するためのShopifyアプリを探していましたが、見つかりませんでした。詳細は後述します。
TinyPilotの統計
| 指標 | 2023年7月 | 2023年8月 | 増減 |
|---|---|---|---|
| ユニーク訪問者数 | 7,800 | 6,900 | -900 (-12%) |
| 販売収益 | $79,635.02 | $91,670.46 | +$12,035.44 (+15%) |
| エンタープライズサブスクリプション | $290.70 | $290.70 | 0 |
| ロイヤリティ | $3,777.52 | $2,969.62 | -$807.90 (-21%) |
| 総収益 | $83,703.24 | $94,930.78 | +$11,227.54 (+13%) |
| 利益 | $26,359.62 | $28,454.42 | +$2,094.80 (+8%) |
収益と利益は引き続きほぼ横ばいです。7月に比べて収益がやや増えているのは、7月の大半でAmazonの掲載順位が下がっていたことが主な要因だと思います。
継続課金サブスクリプションでの失敗
先月、TinyPilotのライセンス制限をより厳格に適用する価値があるかどうかを評価する方法を考えました。そして、最も費用対効果の高い解決策は、ライセンス購入時に自動更新オプションを提供することだと判断しました。
Shopifyには継続課金のサブスクリプションにネイティブ対応する機能がないため、50以上のサードパーティ製Shopifyアプリの中から探す必要がありました。問題は、そのほとんどが物理的な商品向けに作られていることです。デジタル商品に対応している数少ないアプリも、ネイティブなShopifyストアでしか動作せず、私のストアはそうなっていません。
余談ですが、Shopifyアドオン探しは最悪です。オープンなデモを提供しているものがほとんどないため、何ができるかを確認する唯一の方法は、実際にストアにインストールして、すべての商品や顧客データへのフルアクセスを与えることです。私はそれをする気になれないので、実際の顧客データがないダミーストアを使いましたが、十分にデータが入っていないストアでは機能の多くが動きません。さらに、アドオン側が私の本物のShopifyのメールアドレスを把握しているため、1時間ほどダミーストアにインストールしてすぐ削除したアプリから大量のスパムが届くようになりました。
現時点での選択肢は次のとおりです。
- Shopifyの外で継続課金サブスクリプションを販売する(例:Paddle、LemonSqueezy、Stripeを利用)。
- TinyPilotの購入フローをネイティブなShopifyストアに移行してから、Shopifyのサードパーティ製サブスクリプションアプリを再検討する。
(1)は、Shopify外でのチェックアウトをサポートし、サポートチームがShopify外でも顧客情報にアクセスできるようにするための多くのインフラを開発チームが構築する必要があります。
(2)はすべてをShopify内に集約できますが、こちらも大規模なプロジェクトです。前回見積もりを取ったときは、移行費用として2万ドルと言われました。ネイティブなShopifyストアには他にも多くの利点があるので、いずれはやりたいと思っていますが、今はそこにリソースを割く余裕がありません。
TinyPilotのコンフィグ可能性を下げる
TinyPilotの大きな技術的負債の一つは、Ansibleの使い方です。TinyPilotを作った当初、Linuxでのソフトウェアの配布方法がわかりませんでした。Ansibleの使い方は知っていたので、TinyPilotのインストーラーはAnsibleを起動する最小限のシェルスクリプトとし、実際のインストール作業はAnsibleに任せる形にしました。
時間が経つにつれ、Ansibleが適材適所ではないことが明らかになりました。より微妙な間違いは、インストーラーをあまりにも設定可能にしすぎたことでした。
Ansibleロールを公開する際は、OSやハードウェアアーキテクチャ間の違いを抽象化するのが良いとされています。例えば、ファイル一式をディレクトリにコピーする場合、「すべてを/opt/whateverにインストールする」と直接書くのではなく、「すべてを{{ my_target_dir }}にインストールする」と書き、defaults.ymlファイルでmy_target_dir: /opt/whateverと定義します。そうすれば、FreeBSDでは別の場所にインストールしたい場合に、FreeBSDでのみmy_target_dirを/usr/local/whateverのような値に上書きできます。
しかしTinyPilotがサポートするのは、Raspberry Pi 4上のDebianという1つのOSと1つのハードウェアプラットフォームだけです。
習慣でパスや名前、値を別ファイルに抽象化していましたが、そのせいでコードの挙動を追うのがずっと難しくなっていました。実際のインストールでAnsibleがどのように変数を展開するかを理解するために、3つ以上のファイルを行き来しなければならないこともよくありました。
もちろん、この柔軟性を評価してくれたユーザーもいました。公式にはサポートしていないシステムでTinyPilotを使えるようにするためです。しかし彼らのほとんどは有料顧客ではなく、TinyPilotの開発を支えてくれている顧客のためにならない柔軟性のために、多大なコストを払っていたことになります。
最新のTinyPilotリリースでは、Ansibleを廃止しただけでなく、Web UI以外のほとんどの設定オプションも削除しました。アップグレードに関する不具合報告は一件もなく、この設定可能性が顧客にとってまったく必要なかったことが強く示唆されています。
TinyPilotの開発における本質的作業と偶発的作業
Fred Brooksは有名なエッセイ「No Silver Bullet」の中で、ソフトウェア開発の作業を「本質的な困難さ」と「偶発的な困難さ」に分けています。
本質的な困難さには、要件定義やUI設計などが含まれます。完璧なツールと無限のリソースがあったとしても、ソフトウェアが何をするのか、ユーザーがどう操作するのかを考えなければ、有用なアプリケーションは作れません。
偶発的な困難さには、ツールの制約のためにやらざるを得ないことが含まれます。例えば、C言語でのメモリ管理は、自動参照カウントや無限のRAMがあれば気にする必要のないことです。
最近、TinyPilotの開発作業についてこのエッセイのことをよく考えています。私たちがやっていることの多くが、偶発的な困難さのように感じられるのです。
前回のスプリントのタスクを「本質的な困難さ」(緑)と「偶発的な困難さ」(赤)に分けてみました。

TinyPilot 2.6.1のタスクを、本質的な困難さ(緑)と偶発的な困難さ(赤)で色分けしたもの
9つのタスク(24%)が機能の追加や改善といった本質的な困難さに関するもので、28タスク(76%)がリグレッションやパッケージ更新、リファクタリングといった偶発的な困難さに関するものでした。
開発工数で正確に規模を測る良い方法はありませんが、偶発的な困難さのタスクの方が平均して時間がかかっている気がします。時間の最大90%を偶発的な困難さに費やしている可能性もあります。
偶発的な困難さをどう減らすか?
この内訳についてさらに考えてみると、私がTinyPilotの開発作業について考えている捉え方とは少しずれがあることに気づきました。私が重要視しているのは次の3つのカテゴリで、それぞれにどれくらいの時間を割きたいかという理想は次のとおりです。
| カテゴリ | 理想的な工数配分 |
|---|---|
| プロダクトの改善 | 70% |
| 自動化と複雑さの削減 | 20% |
| 定期的なメンテナンス | 10% |
問題は、これらの数値のバランスを取るのが難しいことです。コードが1行増えるごとにメンテナンスコストは増加します。5万行のコードベースは、3千行のコードベースに比べて少なくとも1桁多くのメンテナンスが必要になります。
もちろん、複雑さをなくすための20%の投資はメンテナンスコストを下げるはずですが、新機能による負荷を常に相殺できるわけではありません。昨年、H.264ビデオのサポートを追加しましたが、そのためにサードパーティのWebRTCサーバーであるJanusを統合する必要がありました。WebRTCは極めて複雑なので、この1機能だけでメンテナンス負荷が一晩で20〜30%増加しました。
さらに考えてみると、これは50%ルールを適用する良い機会かもしれません。プロダクト改善に50%の時間を使い、必要なメンテナンスを行い、残りを自動化と複雑さの削減に充てるのです。
この視点で前回のリリースを振り返ると、次のようになりました。
| カテゴリ | タスク数 | タスクの割合 |
|---|---|---|
| プロダクトの改善 | 8 | 22% |
| 自動化と複雑さの削減 | 26 | 70% |
| 定期的なメンテナンス | 3 | 8% |

TinyPilotの2.6.1リリースのタスクを、プロダクトの改善(緑)、自動化と複雑さの削減(青)、定期的なメンテナンス(赤)で色分けしたもの
Ansible排除に大きく舵を切ったため自動化に偏りましたが、思っていたよりも理想の配分に近いものでした。
この3カテゴリの見方で考えると、チーム規模を一定に保ったまま機能を無限に増やし続けることはできない以上、開発投資はおおむね正しい分野にできていると感じます。
まとめ
達成したこと
- TinyPilot Pro 2.6.1をリリースした。
- TinyPilotのインストールプロセスからAnsibleを削除し、大幅なパフォーマンス向上と複雑さの削減を実現した。
- 「Aardvark’d: The Fog Creek Documentary, 18 Years Later」を公開した。
学んだこと
- ソフトウェアの新機能は永遠に作り続けられない。
- ソフトウェアプロジェクトが成熟するにつれ、増えたメンテナンスをこなすために開発者を増やすか、シンプルさを重視する方向へ舵を切る必要がある。
- 設定可能性は目に見えにくいメンテナンスコストを生む。
- プロジェクトにおける設定オプションは1つ増えるごとに挙動の理解を難しくし、変更のコストを上げる。本当に必要なオプションだけに絞るべきだ。
- プロジェクトマネージャーがいるからといって、プロジェクトが最適に管理されていると思い込んではいけない。
- 委託製造業者側にプロジェクトマネージャーがいることを理由に、製造移管のプロジェクト管理について考えるのをやめてしまった。振り返れば、未完了のタスクをもっと積極的に追うべきだった。
来月の目標
この振り返りを月末近くに書いているので、これは事実上来週の目標のようなものです。
- 製造をできるだけ早く委託製造業者へ移管する。
- TinyPilotのオフィス整理のためのタスクを委任する。
- 残りのRaspberry Piをすべて使ってTinyPilotデバイスを組み立てる。
記事をランダムに読む
コメント
ログインしてコメントする