CoPiPe-Shareの開発記録
こんにちは!今回は、私が最近開発した「CoPiPe-Share」というReact + Electronで作ったデスクトップアプリについて、その開発の経緯や苦労した点、学んだことなどを共有したいと思います。特に、Windsurfを使ってVibe Codingをする際に苦労した点について記載します。
なお、下書きはAIが行っていますので、文体がたまに変わります。
プロジェクトの概要
CoPiPe-Share(コピペシェア)は、画像やファイルをクラウドにアップロードして簡単に共有できるデスクトップアプリケーションです。名前は「コピー&ペースト」と「共有」を組み合わせたもので、アプリの主要機能を表現しています。
当初は「Azure Blob Uploader」という名前でしたが、将来的にAzure Blob Storage以外のクラウドストレージサービス(例:AWS S3など)にも対応する予定があるため、特定のサービス名を含まない汎用的な名前に変更しました。
開発の動機
このアプリを開発したきっかけは、オンラインメモツールで画像の実体を保存したくないときや、URLだけで画像を共有したいときに、既存のサービスでは手間がかかりすぎると感じたからです。特に以下のような状況で役立ちます:
- オンラインメモツールで画像を扱いたいが、容量制限を気にしたくない
- スクリーンショットを素早く共有したい
- 一時的なファイル共有が必要な場面
開発プロセス
要件定義
まず、実際にAIを使って開発を始める前に、requirements.mdファイルを作成して要件定義を行いました。このファイルには以下の内容を記載しました:
- アプリケーションの概要と目的
- 実装の方針とステップバイステップの実装計画
- 技術スタック(React、TypeScript、Electron、Effect-tsなど)
- クリーンアーキテクチャの采用と各層の役割
- 関数ベースの実装方針(クラスを利用せず)
- 接続設定や詳細仕様
実際はこの内容では足りずにその都度指示を行いましたが、ある程度規模が大きくなるアプリの場合は要件定義は必須となります。もちろん要件定義書自体もAIに指示する形で作成しています。なお、使ったモデルはClaude 3.7 Sonnetで、WindsurfのProプラン($15/月)を使っています。
特に実装のステップを明確に定義し、以下のような順序で開発を進める計画を立てました:
- Electronアプリの基本機能
- Effect-tsを使ったエラーハンドリング
- Azure Blob Storageへの接続機能
- ファイルアップロード機能(ファイル選択、クリップボードからのペースト、進捗表示、URL表示とコピー)
- サムネイル生成機能
- ファイル一覧表示と削除機能
- 設定画面
- Macアプリケーションとしてのdmgファイル生成
AIは只でさえ言われたこと以上のことをガンガン実装しようとして、いざ実行してみるとエラーで動作せず、エラーの修正を延々繰り返して無限ループに陥ることがよくあります。なので、まずは最低限確認したいことを先に検証的に実装してもらうのがおすすめです。今回ならば、まずElectronアプリとして起動するかどうかのHello World的な内容です。
作成を始めた当初は「一歩ずつ進める」という指示がなかったため、windsurfが一度に多くの機能を実装してしまい、エラーが発生したときに原因特定が困難になりました。この経験から、requirements.mdに「一気に実装を行わずに、基本的な部分からステップバイステップで進めてください。指示されたこと以外は行わないでください。」と明記し、各ステップをチェックボックス形式で管理するようにしました。
AIへの指示は「ステップnを実装して」という感じです。
このアプローチは非常に効果的で、各ステップを確実にテストしながら進めることができ、問題が発生した場合も局所的に対応できるようになりました。
技術スタックと設計思想
使用技術
- フレームワーク: Electron(クロスプラットフォームデスクトップアプリ開発)
- フロントエンド: React, TypeScript, Styled Components
- バックエンド: Node.js, Effect-ts(エラーハンドリング)
- クラウドストレージ: Azure Blob Storage
- ビルド/パッケージング: Webpack, electron-builder
アーキテクチャ
クリーンアーキテクチャを採用し、以下のような層に分けて実装しました:
- ドメイン層: ビジネスモデルとエンティティの定義
- アプリケーション層: ユースケースの実装とビジネスロジック
- インフラストラクチャ層: 外部サービスとの連携
- プレゼンテーション層: UIコンポーネント
特に、TypeScriptではクラスを利用せず、関数ベースの設計を採用しました。これにより、コードの可読性と保守性が向上し、テストも容易になりました。Repositoryを差し替えればAWS S3に対応するのも容易そうです。
開発で苦労した点
1. Electronアプリのコード署名と公証
macOS向けにアプリをリリースする際、Apple公式の要件であるコード署名と公証(ノータリゼーション)の設定に苦労しました。特に以下の点が難しかったです:
- Apple Developer Programへの登録と証明書の取得
- 適切なentitlementsファイルの設定
- electron-builderでのコード署名設定
2. GitHub Actionsの設定
CI/CDパイプラインとしてGitHub Actionsを利用しましたが、以下の点で苦労しました:
- macOS環境でのビルド設定
- シークレット(証明書やパスワード)の安全な管理
- ビルド成果物の自動公開設定
結果的にはほぼほぼWindsurfにActionsのworkflowを作ってもらって無事動作しました。最初はエラーが発生していたのですが、エラー内容を伝えて再実行を数回繰り返して動作しました。Azure DevOpsのpipelineは書いたことがあったものの、GitHubは初めてだったので、ここはAI様々といった感じです。
今回は使いませんでしたが、ローカルでActionsの動きを再現できるパッケージもあるようなので導入予定です。
3. ビルドアセットの管理
当初はbuild
ディレクトリに直接アセット(アイコンやentitlementsファイル)を配置していましたが、GitHub Actions CIでのビルドを容易にするために、resources/build-assets
ディレクトリに移動しました。CI実行時には、これらのファイルをbuild
ディレクトリにコピーする方式を採用しています。
なお、アプリアイコンはApple IntelligenceのImage Playgroundで作成しました。
Vibe Cordingをやる上で学んだこと
上記の繰り返しになりますが、まずは要件定義書が重要です。実装方法に好みがあれば、可能な限り詳しくサンプルコード付きで定義書に書いてしまったほうが良いです。逆に自分が詳しくない部分についてはAIにすべて任せてしまっても大丈夫です(今回はGitHub Actions部分は丸投げしました)
なので、ステップごとに実装してもらう、というのがもう1つ重要な部分です。実装からテストからCD/CIから一気に実装を始めてしまうのがAIなので、明確に区切りをつけて実装ステップを定義して要件定義書に入れておきます。ステップで迷う部分はAIに相談しながら作りましょう。
また、実装中にWindsurfは実装方法を変更してきます。今回の場合はReactのフロントエンドの処理から、IPC通信を使ったNode.jsでの処理に変更をしようとしました。Electronを知らない自分はそもそもIPC通信の意味がわからなかったのですが、その都度理由をWindsurfに聞いて、理解しながら進めました。このように自分の知識外の技術が利用できるのがVibe Cordingのすごい部分だと思うのですが、度が過ぎると全くメンテができないソースコードが出来上がってしまうので、できるだけ理解しながら進めるのが重要です。
感想
そもそもElectron自体がほぼ初めてだったのにアプリが一本作れてしまうのはさすがVibe Cordingといったところです。LLMのモデルはどんどん進化していきますが、Claude 3.7 Sonnetはコスト・パフォーマンス・スピードのバランスがよく使いやすいです。