1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

# プログラマーから個人開発者へ。会社では書かなかったコードを、一人で書き始めた

1
Posted at

プログラマーから個人開発者へ。会社では書かなかったコードを、一人で書き始めた

長いことソフトウェア開発の仕事をしてきました。

昔は普通にコードを書いていました。設計して、実装して、テストして、レビューして、リリースする。それを何年も繰り返しているうちに、いつの間にか「コードを書くこと」よりも、「どういうシステムにするか」を考える時間のほうが増えていきました。

要件定義、アーキテクチャ、チーム間の調整、レビュー、会議。気がつくと、エディタを開いている時間より、Excelやドキュメントを開いている時間のほうが長い日もありました。

もちろん、それもソフトウェア開発の大切な仕事です。ただ、そんな日々を過ごしているうちに、少しずつこんなことを考えるようになりました。

「自分でゼロから作ってみたいな」

会社で作るソフトウェアと、個人で作るソフトウェアは別物だった

会社でソフトウェアを作る場合、基本的には役割分担があります。誰かが要件を決め、誰かがデザインを担当し、誰かがインフラを見て、誰かがテストをする。自分はその中の一部分を担当することが多いと思います。

ところが、個人開発になると話が変わります。仕様を決めるのも自分、UIを作るのも自分、サーバーを設定するのも自分、データベースを触るのも自分。料金プランを決めるのも、問い合わせに返信するのも、バグを直すのも全部自分です。さらに、ユーザーが増えなかったときには、「次に何をするべきか」を考えるのも自分になります。

つまり、

Developer
    ↓
Designer
    ↓
Product Manager
    ↓
DevOps
    ↓
Support
    ↓
Marketing
    ↓
またDeveloper

という、かなり不思議な一人チームになります。

始める前は「全部自分で決められるなんて楽しそうだ」と思っていました。実際、自由です。そして、思っていた以上に大変です。

一人でやると、Code Reviewまで自分になる

個人的に面白かったのが、Code Reviewです。

会社にいた頃は、コードを書いたら誰かにレビューしてもらうのが当たり前でした。ところが個人開発では、Pull Requestを作るのも自分、レビューするのも自分です。

const pullRequest = createPullRequest();

review(pullRequest);

if (reviewer === author) {
  console.log("LGTM");
}

もちろん、実際のコードがこんなことになっているわけではありません。

ただ、感覚としてはかなり近いものがあります。「この設計、本当にこれでいいのか?」と考えながらコードを書いて、しばらくすると「まあ、動くからいいか」となってしまう。止めてくれる人がいないというのは、個人開発の便利なところでもあり、怖いところでもあります。

会社では誰かが「ちょっと待って、その実装で大丈夫?」と言ってくれます。個人開発では、その役割まで自分で持たなければなりません。

そしてAIに手を出した

そんなことを考えていた頃、AIの進化が一気に加速しました。特に興味を持ったのが、画像生成と動画生成です。

以前なら、ある程度クオリティの高い映像を作るには、カメラや編集ソフトだけではなく、素材の準備、撮影、編集など、多くの工程が必要でした。それが今では、1枚の画像とテキストから動画を生成できるようになっています。

しかも、新しいモデルが登場するたびに、以前なら難しかった表現が少しずつ現実的になっています。技術的にも、プロダクトとしても、個人開発者が挑戦するにはかなり面白い領域だと思いました。

そこで、AIによる画像・動画生成を扱うサービスを作り始めました。

「APIを呼べば終わり」だと思っていた

最初はかなり甘く考えていました。

「AIモデルのAPIを呼ぶだけなら、そんなに難しくないだろう」

実際、APIを呼ぶだけなら難しくありません。

const response = await fetch(API_URL, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    prompt,
    imageUrl,
  }),
});

ここで終われば楽なのですが、当然そんなに甘くありませんでした。

動画生成は、普通のWeb APIと少し違います。リクエストを送ってすぐ結果が返ってくるとは限らず、まずキューに入り、その後処理され、最終的に完成するまで待つ必要があります。

queued
   ↓
processing
   ↓
completed

もちろん、途中で失敗することもあります。タイムアウトすることもあります。APIによってレスポンス形式も異なり、生成にかかる時間も違えば、コストも違います。

さらに難しいのが、ユーザーから見たときの体験です。

ユーザーは単純に「生成」ボタンを押します。そこから数十秒、あるいはそれ以上待つことになります。その間に何も表示されなければ、「壊れたのかな?」と思われても不思議ではありません。

そこで、生成処理を非同期のJobとして扱う必要が出てきました。概念的には、たとえばこんな感じです。

type GenerationStatus =
  | "queued"
  | "processing"
  | "completed"
  | "failed";

async function processGeneration(jobId: string) {
  const job = await getJob(jobId);

  if (!job) {
    throw new Error("Job not found");
  }

  await updateJob(jobId, {
    status: "processing",
  });

  try {
    const result = await generateVideo(job);

    await updateJob(jobId, {
      status: "completed",
      resultUrl: result.url,
    });
  } catch (error) {
    await updateJob(jobId, {
      status: "failed",
      errorMessage: String(error),
    });
  }
}

コードだけを見ると、そんなに難しそうには見えません。

ところが、実際にはすぐ次の問題が出てきます。

「このJobが二回実行されたらどうなる?」

すると今度は、冪等性について考えることになります。

さらに、

「生成リクエストが二重送信されたら?」

「外部APIは成功したのに、DB更新だけ失敗したら?」

「処理途中でサーバーが落ちたら?」

といった問題まで考える必要があります。

一つ解決すると、その先からまた新しい問題が出てくる。個人開発では、この繰り返しがかなり多いです。

AIサービスで一番怖いのは、バグよりコストだった

普通のWebサービスなら、「この処理が10回実行されても大丈夫かな」と考えることが多いと思います。

AI生成では、少し考え方が変わります。

「これが10回実行されたら、いくらかかるんだ?」

特に動画生成は、モデルによって消費量やコストが大きく違います。そのため、単純に生成処理を動かすだけではなく、アプリケーション側でもユーザーの使用量を管理する必要があります。

たとえば概念的には、こんな処理になります。

async function createGeneration(userId: string, model: Model) {
  const cost = getCreditCost(model);
  const balance = await getCreditBalance(userId);

  if (balance < cost) {
    throw new Error("Insufficient credits");
  }

  await reserveCredits(userId, cost);

  return createJob({
    userId,
    model,
  });
}

ここでも終わりではありません。

reserveCredits() が成功したあとにJob作成が失敗したらどうするのか。同じリクエストが二回来たら、クレジットを二重に消費しないか。外部APIの失敗時にクレジットをどう扱うのか。

普通のWebアプリでも難しい部分ですが、AI生成では「一回のミスが、そのままコストになる」という現実があります。

このあたりは、実際に作り始めるまであまり深く考えていませんでした。

AIプロダクトを作るというのは、単純にAIモデルを呼び出すことではありません。AIモデルとユーザーの間に、どんな仕組みを作るのか。その部分が、想像以上に大きな仕事でした。

一番難しかったのは、コードではなかった

技術的な問題は、時間をかけて調べれば、ある程度は解決できます。

本当に難しかったのは、

「何を作ればユーザーが使ってくれるのか」

という問題でした。

エンジニアは、何か問題があるとコードを書きたくなります。バグなら修正する。遅ければ高速化する。UIが悪ければ改善する。

でも、「そもそも誰も必要としていない」という問題だけは、コードでは解決できません。

これは個人開発を始めてから何度も思い知らされました。

完璧にしてから公開する、をやめた

会社で開発していると、「ちゃんと作ってから出したい」と考えがちです。

個人開発を始めた頃の自分も同じでした。

UIを修正して、エラー処理を追加して、またUIを修正する。少し気になるところがあれば直す。もう少し良くできそうなら、また直す。

そして、ある日ふと気づきます。

「これ、いつ公開するんだ?」

そこで、考え方を変えました。

まず公開する。

実際に使ってもらう。

問題があれば直す。

必要なら作り直す。

Idea
  ↓
Build
  ↓
Release
  ↓
User
  ↓
Feedback
  ↓
Fix
  ↓
Repeat

最初から正解を作ろうとするよりも、実際のユーザーからの反応を見ながら次の一手を決めたほうが、個人開発には向いていると感じるようになりました。

もちろん、公開したあとにバグが見つかることもあります。

「公開前に気づけよ」と自分で思うこともあります。

でも、それも含めて個人開発なのかもしれません。

プログラマーから、個人開発者へ

振り返ってみると、僕は突然「個人開発者」になったわけではありません。

これまでやってきたことが、そのまま別の形でつながってきた感じです。

これまで学んできたプログラミング、システム設計、障害対応、ユーザーの要求を理解すること。そして、長い間ソフトウェアに関わってきた経験。

ただ、一つだけ大きく変わりました。

以前は、

「決められた問題を、どうやって解決するか」

を考えることが多かった。

今は、

「そもそも、どの問題を解くべきなのか」

から考えるようになりました。

この違いは、思っていた以上に大きいです。

そして、かなり面白いです。

もちろん、まだまだ失敗します。

たぶん明日も何か壊します。

「ここを直したら、なぜか別の場所が壊れた」ということも普通にあります。

深夜にログを見ながら、

Why is this happening?

と独り言を言っていることもあります。

それでも、以前とは少し違う感覚があります。

今は、自分で問題を見つけて、自分で考えて、自分で作って、それを実際に世の中に出してみることができます。

まだ旅の途中です。

そして、たぶん個人開発には「完成」というものがないのかもしれません。

とりあえず、今日もコードを書きます。

その前に、まずログを確認します。

npm run dev

今日も何も壊れませんように。

今作っているもの

ここまで読んでいただき、ありがとうございます。

今、僕が個人開発で作っているのが VioEvo というAI画像・動画生成サービスです。テキストや画像からAI画像・AI動画を生成したり、複数のAIモデルを試したりできるようにしています。

まだ改善したいところもたくさんありますし、個人開発だからこそ見えていない問題もあると思います。

もしこの記事を読んで、個人開発やAIプロダクト開発について何か気づいたことがあれば、ぜひコメントで教えてください。

「こういう設計のほうがいい」「ここは別の方法がある」「その考え方は違うと思う」など、技術的な指摘も大歓迎です。

まだまだ勉強中なので、いろいろとご指導いただけると嬉しいです。

VioEvoはこちらです。

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?