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?

【Genspark体験記】AIで経費精算システムを作ってみた

Last updated at Posted at 2025-10-06

はじめに

最近話題のAI開発プラットフォーム「Genspark」を使って、経費精算システムを作ってもらいました。
結果的に入力したプロンプトが雑な割に、予想以上のクオリティで驚いた一方、感じたことを書いていこうと思います。

あまり時間とれておらず、とりあえずbackendは動作できることを確認しました。
今後もう少し時間とってちゃんと見ていこうと思います。
とりあえず、気づいたことを書いてみました。

作成した経費精算システムの概要

今回作成したのは、経費精算システムです。主な要件とリポジトリは以下の通り:

システム要件

  • フロントエンド: React + TypeScript
  • バックエンド: Node.js + Express
  • データベース: インメモリ

主な機能

  • 経費管理
  • ユーザー管理
  • カテゴリ管理

リポジトリ

Gensparkでの開発体験

初期セットアップ

今回は、スマホから、AIデベロッパーを選択し、GitHubを認証し
以下からモデルを選択し、プロンプトを記載しました。(簡単)
image.png

最近リリースされたClaude Sonnet 4.5/GPT-5 Codexで悩み、Sonnetを選択

プロンプト

以下のような非常に簡単なプロンプトを利用。
本来はもっとこだわった方がいいですが、とりあえずのたたき台作成ということで。

経費精算システムをGoで作成してください。
DDDやクリーンアーキテクチャの考え方を取り入れてください。
テストを記載し、エラーが出たらすべてPassできるようにしてください。
先ほど作成したGoのフロントエンドをReactで作成してください。
DDDやクリーンアーキテクチャの考え方を取り入れてください。
テストを記載し、エラーが出たらすべてPassできるようにしてください。

成果物について

作成した成果物はこちらです。
https://github.com/HirokazSase/my-project

フロントとバックのAPIパス不一致

バックエンドは POST /api/v1/users/:id/expenses や POST /api/v1/expenses/:id/submit を用意しています(router.go 49-85、expense_handler.go)。
しかしフロント (frontend/src/infrastructure/api/ExpenseApiService.ts) は POST /expenses や PUT /expenses/{id}/status を叩こうとしており、パスもメソッドが噛み合いません・・・

YAGNI違反:インターフェースを作りすぎ

以下のインターフェースを作成してくれたが、プロンプトが雑すぎたせいで、利用していないIFが生成。レビュー時にどこでつかってるんだ・・・?となってしまう
→丁寧なプロンプトを打っていないせいなので、Gensparkというより、私の指示の問題。

type ExpenseRepository interface {
    Save(ctx context.Context, expense *entity.Expense) error
    FindByID(ctx context.Context, id *valueobject.ExpenseID) (*entity.Expense, error)
    FindByUserID(ctx context.Context, userID *valueobject.UserID) ([]*entity.Expense, error)
    FindByUserIDAndStatus(ctx context.Context, userID *valueobject.UserID, status entity.ExpenseStatus) ([]*entity.Expense, error)
    FindByCategoryID(ctx context.Context, categoryID *valueobject.CategoryID) ([]*entity.Expense, error)
    FindByDateRange(ctx context.Context, userID *valueobject.UserID, from, to time.Time) ([]*entity.Expense, error)
    FindAll(ctx context.Context) ([]*entity.Expense, error)
    Update(ctx context.Context, expense *entity.Expense) error
    Delete(ctx context.Context, id *valueobject.ExpenseID) error
    Exists(ctx context.Context, id *valueobject.ExpenseID) (bool, error)
}

IDのオブジェクト

IDは値オブジェクトしなくてもいいかもしれない

type Expense struct {
    id          *valueobject.ExpenseID      // ← これ必要?
    userID      *valueobject.UserID         // ← これも?
    categoryID  *valueobject.CategoryID     // ← これも?
    amount      *valueobject.Money          // ← これは良い
    description string
}

ポインタ使いすぎ?

値の書き換えしないのに、ポインタをわざわざ使用しているように見える
値渡しでシンプルにすることで、可読性や若干のパフォーマンス向上になるかも

// CreateExpense 経費を作成
func (uc *ExpenseUseCase) CreateExpense(ctx context.Context, userID string, req *dto.CreateExpenseRequest) (*dto.ExpenseResponse, error) {
	// ユーザーIDの検証
	uid, err := valueobject.NewUserID(userID)
	if err != nil {
		return nil, errors.NewApplicationError(errors.ValidationFailed, err.Error())
	}

	// ユーザーの存在確認
	user, err := uc.userRepo.FindByID(ctx, uid)
	if err != nil {
		return nil, errors.NewApplicationError(errors.UserNotFound, "ユーザーが見つかりません")
	}

	// カテゴリIDの検証
	cid, err := valueobject.NewCategoryID(req.CategoryID)
	if err != nil {
		return nil, errors.NewApplicationError(errors.ValidationFailed, err.Error())
	}

	// カテゴリの存在確認
	category, err := uc.categoryRepo.FindByID(ctx, cid)
	if err != nil {
		return nil, errors.NewApplicationError(errors.CategoryNotFound, "カテゴリが見つかりません")
	}

	// 金額の作成
	currency := req.Currency
	if currency == "" {
		currency = "JPY"
	}
	amount, err := valueobject.NewMoney(req.Amount, currency)
	if err != nil {
		return nil, errors.NewApplicationError(errors.ValidationFailed, err.Error())
	}

	// 新しい経費を作成
	expense, err := entity.NewExpense(uid, cid, amount, req.Title, req.Description, req.Date)
	if err != nil {
		return nil, errors.NewApplicationError(errors.ValidationFailed, err.Error())
	}

	// 経費を保存
	if err := uc.expenseRepo.Save(ctx, expense); err != nil {
		return nil, errors.NewApplicationError(errors.ExpenseCreationFailed, "経費の作成に失敗しました")
	}

	return uc.buildExpenseResponse(expense, user, category), nil
}

レビューがつらい

約3000行のPRで、レビューに時間がかかる
というか、今回は全部見れていない
→Code rebbitやGithub Copilotの導入して負荷軽減したい

クレジット消費

Gensparkはクレジットを与えられ、それを消費する形で利用します
今回は、Plus Planで月額4000円で10,000クレジットでした
このアプリを作成するのに、約2000クレジットなので、あと5回は回せます
複数モデルで気軽に試したいならありかもしれない

エラーの頻出

・AI実装時
スマホから指示した影響か、AIの作業が止まっていることがありました。
都度、リロードや「作業の続きをして」と指示して、完成しました。
PCからなら問題ないかもしれません。

・プッシュ時
GitHubへのプッシュに何度か失敗しており、原因不明だが、何度か支持することで成功しています。
なんでだろう・・・

・実装後
しばらくしてから、AIにコードの意図を聞こうとしたところ、エラーが発生しました。
そのため、再度AIデベロッパーを起動して、再度リポジトリの読み込みからになるので、ちょっとクレジットが無駄になっているかも

余談

フォルダ構成を修正したくて、スマホからGitHub CopilotのCoding Agentを利用してみました。
確か以下のようなプロンプトです。

goのコードをbackendにまとめて。
他におかしいところあったら全体的に修正してください。

結果、main.goが削除されました。
丁寧に.gitignoreにも記載されていました。

Coding Agentに対して、若干の不安を覚えつつも
結論、ちゃんとレビューしとかないといけないですね。

最後に

Gensaporak(というか、Sonnet4.5)を利用して、簡単な経費精算システムを利用してみました。
雑なプロンプトである程度書いてくれて、ちょっとの手直しで動作するコードなので生産性は向上しそうです。
ただ、やっぱり細かいタスクに分ける、詳細な内容、レビューをしっかりするというのは重要ですね。

Gensparkでいうと、2025/12/31まで、AIチャットで、Opus4.1,Sonnet4.5,Groq,Gemini Pro,GPT-5 Thinking-Highなどがクレジット消費無しで利用できます。コンテキストは意図的に短くなっていて会話をあまりできないかも?
ただ、クレジット消費無しはでかいので、いいのではないでしょうか?
また、コードレビューをしっかりしたら、修正していこうと思います。

見てくれてありがとうございました。

1
0
0

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?