🏋️‍♀️

【個人開発】収益化したサービスのコードを50%以上削除して得られた境地

2022/12/14に公開2

先に境地を

個人開発の場合、少ないコード・最低限のシステム構成は正義。
なぜなら、時間やお金に制限がある個人開発者にとってサービスの継続に関わる問題だからです。
例えば、自分のサービスを世に広めたいとか、一発当てたいとか、作ったサービスで生活をしたいとか、 なにか目標があるなら達成する方法は、達成するまでやめないことです。 なのでサービスを提供し続けることは最も大切なことです。


これまで個人開発者としては↓の気持ちで開発を進めてきました。

しかし、この経験の後にこの↓の名言の大切さを改めて感じることができました。

シンプルにしておけ愚か者

また、本記事本文より

たくさんプラグインやモジュールを入れたシステムはメンテナンスがしんどいです。「デフォルトで使う」ということの魅力を改めて実感しています。リソースが限られている個人開発の場合、このような時間の消費は極力なくす方向にしていくべきです。

この記事では 個人開発者が心が折れそうになりながらも一人で3万行のコードを3ヶ月で1.5万行に減らし、サイトをフルリニューアルさせた感想・Tipsを紹介していきます。


筆者について

兼業個人開発者です。 現在はNulab Inc.勤めながら個人開発は個人事業として細々とやっております。
フロントエンドを中心に7年間くらいアプリケーションコードを書いています。

個人開発サービスを作っている方・運用している方の参考になれば幸いです。
一応ツイッターやっておりますので、個人開発やOSSについて興味がある方はぜひ友達になってください..!
https://twitter.com/labelmake


サービスについて

サービスは labelmake.jp というPDF作成のサービスを一人で4年ほど運用しており、
3年前にアドセンスで収益化、2年前から有料プラン提供開始、1年ほど前からB2B向けのAPIサービス提供開始などを行なってきました。
https://labelmake.jp/

上記のサービスのコア部分(PDF作成・テンプレート作成のGUI)は pdfme というOSSのPDFライブラリとして公開しており、このライブラリを使ってサービスを作っています。
https://pdfme.com/

サービスの規模感的はこんな感じです。

  • 登録ユーザー: 1万5000ユーザー
  • 月間アクティブユーザー: 10万ユーザー
  • 月間PV: 30万
  • 月間収益: 約40万円

なぜフルリニューアルをやりたくなったのか、動機としては下記です。

  • 数年単位で空いた時間で作ったもののため古くなっていたり、使われていない機能があった。
  • 一人で運用しており、メンテナンス性を上げる必要があった。

コードからは不吉な臭いが漂っていました... (いろんな機能・依存、連携を増やしすぎたと反省)
コード量を少しでも減らし、個人開発の限られた時間でもしっかりハンドリングできるアプリケーションに戻すというのが一番大きな目的です。


フルリニューアルについて

リニューアル前のシステム構成

以前 個人Webサービスシステム構成事典 v3 に公開さてせいただいた画像 を引用させていただきます。

個人開発界隈ではよくあるのJAMStackサイトです。
画像にあるように、ひと昔前に作ったGatsby x Netlify の構成をNext.js x Vercel に変更するというありがちな変更です。

Gatsby x Netlifyが嫌になった理由

Gatsbyが嫌になった理由としては複数プラングインを入れ、その当時は開発しやすい環境を頑張って作っていましたが、Next.jsであればほぼ設定なくで開始できるものとなったためです。

Netlifyに関しても似たような理由で、いろいろなプラグインを組み込めるようになっていますが、その影響かビルドの時間が異様にかかったり落ちたりなどのトラブルがありました。また、東京のCDNはHigh-Performance CDNと呼ばれるカスタムプライスのプランにしか無いなどの理由です。

あとは、この大規模なリファクタリングのタイミングで開発者友達に教えてもらった良さそうなライブラリを試しました。
具体的にはアプリケーションの状態管理にMobXを入れ、CSSフレームワークをBulmaからTailwind CSSに変えました。


フルリニューアルした感想

3ヶ月かかりながらフルリニューアルして思ったことを下記に書き出しました。

よかったこと😋

  • 改めてコーディング手法を学び、新しい技術を試すことができた
    • コードベースを小さくことを意識して、改めてコーディングテクニックや手法を学んだ
    • サイトをモダンにしながら触りたかった技術をガッツリ触ることができた
      • 自分の環境だとNext.jsは開発サーバー立てるのがGatsbyの20倍くらい早くていい感じ
      • MobX入れてアプリケーションの状態管理で冗長なコードが簡潔に描けるようになった MobXみんな使おうよ!
      • Tailwind CSSはTailwind UI からコピペでUI構築できて楽だし、移植性が高くていい感じ
  • 無料ユーザーをうまく活用して安心してリニューアルを行う手法を試せた
    • プランを見て、無料ユーザーから徐々にアクセスを流し、Sentryでエラーチェックしながら移行を行えた
    • BETA版としてリリースし、デバッグを手伝ってもらうことができた。問い合わせから本番以降前に気がつけたバグもあった
  • 短期間にサービスのコード全体を見ることで理解度が深まり俯瞰してサービスのコードを見れた
    • 長い時間をかけてちょこちょこ作っていたので改めて全体の理解ができた
    • ほとんどの機能を維持しながら50%もコード量を減らすことができた✌️
    • package.jsonのdependenciesも約半分にまで減らすことができた

よくなかったこと🤮

  • ユーザーに還元できる価値がでない・直接収益に結びつかない開発というフラストレーション
    • リニューアル自体は1円も利益を産まない作業かつ、本流の開発が完全に止まる
  • 長すぎるプロジェクトで心が折れそうになる
    • 限られた時間で少しづつしかリニューアルできず一人なので進みも遅い
    • 途中でマジでやめたくなりました👎
  • 興味がなく専門性がない分野の作業を1から調べてやっていかないといけない
    • 得意なところだけではフルリニューアルはできない(サブドメインの生やし方知らなかったw)
    • モチベがなく、ごく稀にしかやらない作業であるというメンタルだったのであまり楽しめなかった

BETAデプロイした時やサービスが完全に移行できた時などは達成感はあったが、収益には全く影響せずなので、本当に良かったと思えるのは、これからの長期的な運用の中で感じると信じたい。
なので今の段階では、開発者としてはやって良かったと思うけど、事業者としてはまだ判断はできないというのが本音です。


リファクタリング・リニューアルに使える便利ツールとTips

リファクタリングの時に便利だったツール

リファクタリング時に下記の2つのツールは本当に便利でしたので紹介します。

  • ts-prune: 未使用のexportをコマンド1つで検出することができるツール
  • cloc: コードの行数を把握できるツール

自分はpackage.jsonで下記のようにスクリプトを設定しています。

{
  "scripts": {
    "prune": "ts-prune src | grep -v src/pages",
    "cloc": "cloc src/ --exclude-lang=Markdown,JSON,SVG --by-file"
  },
}

1. ts-prune

ts-pruneを実行してみると、下記のように出力され、プロジェクト内で使用されていない src/components/Test.tsx のコンポーネントを検出してくれます。もちろんReactコンポーネントではない、普通の関数でも同様に一覧にしてくれます。
特に一部機能を削った際にそれに紐づくコンポーネントや関数が取り残されることがあるのでts-pruneで削除し忘れがないか確認しましょう。

npm run prune

> labelmake.jp@0.1.0 prune
> ts-prune src | grep -v src/pages

src/components/Test.tsx:24 - default

2. cloc

clocを実行してみると、下記のように出力され、プロジェクト内のソースコードをファイル別で出力してくれます。
非常に原始的ではありますが、コード量を定期的に確認したり、大きすぎるファイルがないかなどの検出に便利です。
行数の大きすぎるファイルからリファクタリングの手掛かりにして、どうすれば機能を維持しつつコードを減らせるかなど考えるきっかけになります。

npm run cloc

> labelmake.jp@0.1.0 cloc
> cloc src/ --exclude-lang=Markdown,JSON,SVG --by-file

     166 text files.
     163 unique files.
      12 files ignored.

github.com/AlDanial/cloc v 1.94  T=0.08 s (1979.7 files/s, 202096.4 lines/s)
------------------------------------------------------------------------------------
File                                             blank        comment           code
------------------------------------------------------------------------------------
src/pages/print-api.tsx                             11              0            308
src/pages/mypage/settings.tsx                       16              1            305
...
src/components/Reward.tsx                            5              0             20
src/components/CTAButton.tsx                         0              0             19
src/schema.ts                                        1              0             11
src/firebase/functions.ts                            3              0              9
src/firebase/storage.ts                              2              0              9
src/utils/index.test.ts                              2              0              8
src/types/specialSites/certificate-generator.d.ts    0              0              7
src/types/integrates/index.d.ts                      0              0              6
src/firebase/app.ts                                  1              0              5
src/types/integrates/shopify.d.ts                    0              0              5
src/components/Image.tsx                             1              0              4
------------------------------------------------------------------------------------
SUM:                                              1113             98          14714
------------------------------------------------------------------------------------

リニューアルの時にやって良かった施策

フルリニューアルした感想 > よかったこと にて軽く触れていますが、今回のリニューアルはBETA版が完成した後に段階的に行いました。

個人開発の場合、自分で全てテストする必要がありますが、そもそもWindows持っていないとか現実的に全ての端末でテストすることが難しいです。

そのため下記の2つの施策を実施しました。

1. 無料ユーザーから徐々にアクセスを流し、エラーチェックしながら移行を行う

下記のような簡単なスクリプトをページ読み込み時に発火させ、プラン・デバイス・割合等を判別し BETA版のサイトに遷移させていました。

import { once, getOSName, getPlan } from "./somewhere";

const goBetaLot = () => {
  const BETA_RATE = 30;
  const isElected = Math.floor(Math.random() * 100) <= BETA_RATE;
  if (!isElected) return;

  const { pathname, search } = window.location;
  window.location.href = `https://beta.labelmake.jp${pathname}${search}`;
};

export const redirectToBeta = once(() => {
  const plan = getPlan();
  if (plan !== "FREE") return;

  const osName = getOSName();
  if (osName !== "Windows") return;

  goBetaLot();
});
  1. 自分の端末でもろもろ不具合がないかチェックする
  2. 無料ユーザーで持っていないデバイスのユーザーを 30%遷移させる
  3. 無料ユーザーの30%を遷移させる
  4. 無料ユーザーの50%を遷移させる
  5. 全ユーザーの30%を遷移させる
  6. 全ユーザーの50%を遷移させる
  7. DNS設定等を変更し、完全にフルリニューアルしたサイトに遷移させる

というステップで 1~6 を2週間ほどかけて行い、Sentryでエラーをチェックし、あらかじめバグを潰しておきました。

実際に本番に切り替えた時に致命的なエラーなどなく、大急ぎで対応に追われるということはありませんでした。

2. BETA版としてリリースし、任意でデバッグを手伝ってもらう

上記の施策と同時にお知らせからBETA版へのアクセスを任意で流していきました。

一部の有料会員ユーザーはすぐにBETA版をご利用いただけて、実際にお問い合わせから有料会員の挙動に関わる割と致命的な不具合を報告していただきました。
このようなタイミングでフィードバックしていただけるユーザーからは厳しい意見もありますが、サービスをしっかり使ってくれるユーザーなので問い合わせにはしっかりと返事・対応をしていきました。

*サービスへの簡単なお知らせの導入は Headway が無料で使えて便利です。
https://headwayapp.co/

まとめ

個人開発の場合、少ないコード・最低限のシステム構成は正義。


なぜなら、時間やお金に制限がある個人開発者にとってサービスの継続に関わる問題だからです。
例えば、自分のサービスを世に広めたいとか、一発当てたいとか、作ったサービスで生活をしたいとか、なにか目標があるなら、それを達成する方法は達成するまでやめないことです。 なのでサービスを提供し続けることは最も大切なことです。

少ないコード・最低限のシステム構成で、サーバー代・不具合対応を含めた運用コストをできるだけ0に近づけた上で、ユーザーへ価値提供、収益を上げることができれば、サービスの生存確率はグッと上がります。

大好きな本の一つのBasecampのGetting Realでも CHAPTER 54: Less Software というタイトルで同様のことが語られていました。

これからはコードからは不吉な臭いが漂わないよう、
Done is better than perfect と、Keep it simple stupid をうまく融合させて開発いきたいと思いました。

具体的には

  • コード、プラグインなど、依存は極力少なく
  • 機能追加後、計測して使われてない or 価値提供できていないなら消す
  • イレギュラーケースを極力作らない
  • 設定をむやみに作らない
  • 要望に対して安易にYesと言わない

などですね。


最後までお読みいただきありがとうございました。

これからも個人開発に関することなど発信していくのでフォローよろしくお願いします
https://twitter.com/labelmake

それでは良い個人開発ライフを👋

Discussion

ctrlzrctrlzr

・ユーザーに還元できる価値がでない・直接収益に結びつかない開発というフラストレーション
・リニューアル自体は1円も利益を産まない作業かつ、本流の開発が完全に止まる
開発者としてはやって良かったと思うけど、事業者としてはまだ判断はできないというのが本音です。

リプレースは何度か経験しています。
上に話を通すのが一番大変なので、そこは関わりません(^^;

・アーキテクトが古くて人が集まらない(COBOLは分かりやすい例と思います)
・今後も施策が予定されている(システムの更新が発生する)

上記を満たすのであれば、事業者としてリプレースに踏み切れると思います。
個人開発でも参考になるかと思います

Kyohei FukudaKyohei Fukuda

コメントありがとうございます!!

・アーキテクトが古くて人が集まらない(COBOLは分かりやすい例と思います)

確かにそうですね、採用の観点はあると思います。
ただ、個人開発の場合は規模的にエンジニアの採用はあまり考えられないのです....

・今後も施策が予定されている(システムの更新が発生する)

これはそうですね、システムを小さく、シンプルにしておくことでシステムの更新には強くなると思いました。

リプレース・リニューアルをやるべきという判断は長期的(3,4,5年スパン)に考えないと難しいなーと改めて思います。