※本記事は2026年3月12日に米国で公開された React vs. Salesforce: How I Rebuilt My “Vibe-Coded” App on the Platformの抄訳です。本記事の正式言語は英語であり、その内容および解釈については英語が優先されます。
私は2026年の初めにデベロッパーアドボケイトとしてSalesforceに入社しました。それまでのキャリアで、さまざまなツールの良さを発信してきましたが、研修時に告白しなければならないことがありました。実は、Salesforceがどのようなものなのか、よくわかっていなかったのです。
「SalesforceがCRMであること」と、多種多様な「クラウド製品」であること以外は知らないことだらけで、まるで未知の言語を一から学んでいるような気分でした。そこで、無駄に手を広げすぎないように、基本に立ち返ってシンプルな問いに向き合うことにしました。それは、「開発者にとってのコアプラットフォームは何か」ということです。
答えを見つけるために、何か作ってみることにしました。ただ「Hello World」と表示させるだけではなく、状態管理、UIロジック、データ永続化が必要なインタラクティブなものを。そこで作成したのが、オフィスでよくつまむ軽食をドラッグ&ドロップでランク付けするリストです。
ただし、同じものを2つの方法で作ります。まず私が得意とするReactで構築し、次にSalesforceで、Lightning Webコンポーネント(LWC)を使って一から作り直しました。
Reactバージョンは、AIを使ってバイブコーディングで一気に作成しましたが、Salesforceバージョンは別のやり方で進めました。公式ドキュメントとTrailheadを参照して、AIにペアプログラミングの相棒になってもらいました。目標は、単に動くコードを書くことではなく、アーキテクチャーをしっかり理解することでした。
(注 – 経験豊富なSalesforce開発者の方にとっては、多分この記事に感心することや驚きは何もないと思います。ここに書いたようなエラーにも、何度も遭遇してきたことでしょう。しかし、私のようにSalesforceエコシステムにまだ馴染みがない方たちのために、Salesforceを使い始めるときに感じたことをまとめておこうと思いました)
では、マーケティング資料を読むのをやめて、実際にコードを書いてみてわかったことを紹介します。
フェーズ1:比較基準(React + Vite)
公平な実験のために、比較する基準が必要でした。そこで、20分ほどですばやくReactバージョンを作成しました。Reactのstateは理解していたので、ここで特に何かを学ぶことが目的ではありません。Salesforceエコシステムで作るときの手間や違いを正確に測るための、「対照群」を用意する必要があったのです。
実を言うと、Reactバージョンは「バイブコーディング」で作りました。LLMにランクリストのスクリーンショットを渡して、「React(Vite)とTailwind CSSを使って、この画像にあるようなオフィスの軽食をドラッグ&ドロップでS、A、B、C、Dにランク分けして、localStorageでデータを永続化できるアプリを作成してください」と指示したのです。
できあがったアプリは、少し手を加えただけで完璧に動作しました。ベーグルをSランクに、キャンディコーン(激甘の砂糖菓子)をDランクにドラッグできました(これはDしかないでしょう。オフィスで食べようとは思えないですからね)
しかし、生成されたコードを見て、2つのことに気付きました。
- 外部への依存 – LLMは、ドラッグ&ドロップを実装するために、すぐにサードパーティライブラリー(dnd-kit)に頼りました。Salesforce Platformで開発する場合、どうやって実装するのだろうという疑問が浮かびました。
- 手作業でのデータ永続化 – このアプリでランクを保存するには、ブラウザーの
localStorageを読み書きするためだけに、40行の関数を書かなければなりませんでした。Salesforceエコシステムなら、もっと効率的に処理する方法があるだろうと思いました。そして、その考えは当たっていました。
このアプリをちゃんと「使えるもの」にする、つまり同僚と共有し、デバイス間で保存内容を維持できるようにするには、バックエンド(Node、Supabase、またはFirebase)を用意して、APIエンドポイントを書かなければなりません。
さて、ではSalesforceに移行します。
フェーズ2:比較対象 – Salesforce LWC
目標はシンプルです。まったく同じアプリをSalesforce Platformのツールだけで再作成します。外部データベースも、Nodeサーバーも使いません。使うのは自分の腕とSalesforce組織だけです。
ライブラリーか、Web標準の機能か
独自仕様だらけの悪夢のような、それともわけのわからない古めかしい言語に苦しめられるのかと、戦々恐々としましたが、ふたを開けてみると、使うのはJavaScriptでした。
Salesforceでは、Lightning Webコンポーネント(LWC)を使用します。コードは驚くほどReactに似ていると感じましたが、肝心なところがもっとシンプルでした。ドラッグ&ドロップのロジックに、巨大なnpmパッケージが不要だったのです。私は標準のHTMLイベント(ondragstart、ondrop)を使いました。LWCは重い仮想DOMレイヤーを介さずに、そのままブラウザー上で動作するため、標準のWeb APIを使えたのです。
フェーズ3:Reactではバックエンドが必要になるが、Salesforceはバックエンドも担う
ここで、目からうろこが落ちました。Reactバージョンのアプリでは、データを「保存」するには、JSON形式をシリアライズしてブラウザーのlocalStorageに入れる処理のために、40行のコードを書かなければなりませんでした。さらに、データを永続化したい場合は、SQLを覚え、Postgresデータベースを用意し、Node APIを作成して、CORSにも対応しなければなりません。
Salesforceでは、このような手間はかかりません。カスタムオブジェクトを作成するだけですみます。
私はオブジェクトマネージャーでTier_List_Itemを作成しました。すると、すぐにセキュアでスケーラブルなリレーショナルデータベースと、自動生成されたAPIが利用可能になりました。さらに、このプロジェクトでは深く掘り下げませんでしたが、本格的なエンタープライズ向けセキュリティモデルも用意されていることに気付きました。Sランクの軽食はマネージャーのみに編集を許可するなど、細かい権限管理が必要な場合も、1週間かけて認証ミドルウェアを実装することなく、標準のUIだけで設定できます。
データをコンポーネントに取り込むために、@wireサービスを使いました。これは、データベースに直接接続し、データをリアクティブに取得する仕組みです。
Reactでの手作業の状態管理
Salesforceでの宣言型のデータバインド
わかったこと
- React – ライブラリーとローカルストレージの管理に時間をかけた。
- Salesforce – プラットフォームがデータベースを用意し、ブラウザーがインタラクティブな動作を提供してくれるため、ロジックの記述に時間をかけた。
変更の反映には時間がかかりましたが(ホットリロードは使えません)、データの永続化に必要な定型コードの量は大きく減りました。始める前にSalesforce Live Preview(英語)を知っていれば、プロセスをもっと速く進められたはずです。
フェーズ4:デプロイ時の確認「卵が先か、ニワトリが先か」
第2フェーズのフロントエンドを第3フェーズのバックエンドに接続する段階で、厄介なことになりました。データベースとやり取りするためにLWCとApexコントローラーを作成し、デプロイすると、ターミナルに次のように表示されたのです。
まず頭に浮かんだのは、作業のどこかでタイプミスか、何かつまらないミスをしてしまったのだろう、ということでした。スペル、ファイル名、ファイルパスなど、ありそうな間違いを一とおり調べましたが、コードに問題はありませんでした。
Reactだったら、いつものように単純にエラーをLLMに貼り付け、出てきた修正をコピーし、そのまま先へ進んでいたでしょう。しかし今回は、AIとドキュメントを使って自分の理解度を確かめることが目的だったので、立ち止まって原因を考えました。そこで、重要な違いに気付いたのです。それは、プラットフォームのコンパイルモデル。
Salesforceの正式な用語ではありませんが、これはプラットフォームがコードをどのように検証するかを理解する思考モデルとして役立ちます。Reactでは、ブラウザーだけがコードを検証します。まだ存在しないAPIを呼び出すフロントエンド関数を書いても、実行するまでは、ブラウザーは問題にしません。
Salesforceでは、サーバーがコードの正否を判断します。デプロイ時にプラットフォームがコードをコンパイルし、その有効性を確認します。その結果、私のLWCがサーバー側にまだ存在していないバックエンドメソッド(getAllItems)とやり取りしようとしていることを検出したというわけです。
先にApexクラス(バックエンド)をデプロイし、その後でLWC(フロントエンド)をデプロイする必要がありました。ミスは、構文エラーではありませんでした。ブラウザーに対してではなく、緊密に統合されたプラットフォームに対してコードを書いているということを思い出させてくれたのです。
フェーズ5:ローコード開発の威力(いわゆる「開発」)
アーキテクチャーを理解したら、データベースのほかにも、さまざまな機能を利用できることがわかりました。「軽食」が実際のデータレコードになったので、Salesforceの自動化エンジンの力をフルに使えるようになりました。
ここで、「軽食がDランクに落ちたら、Slackでチームに通知する」という複雑なビジネスロジックを加えることにしました。
Reactバージョンのアプリでは、楽しい部分はここまでで、ここからはインフラ周りの作業が始まります。webhookかcronジョブ、場合によってはZapierのサブスクリプションも必要になります。一方、Salesforceでは、1行もコードを書きませんでした。Flowを使っただけです。
Tier項目が「D」に変わったことを検知する「レコードトリガーフロー」を作成しました。軽食がDランクになると、Slackチャンネルにメッセージが送信されます。
手痛い失敗(500エラー)
とはいえ、すべてが順調に進んだわけではありません。自信がついてきた私は、2つ目の機能を追加しようとしました。軽食がSランクに入ったら、社内フィード(Chatter)に「おめでとう!」というメッセージを投稿する機能です。
設定して実行してみると、……500エラーが出ました。
ロジックに問題はなかったので、このエラーメッセージは謎でした。フローのデバッグに悪戦苦闘したあげく、AIの助けを借り、プラットフォームのドキュメントを読み返して、ようやくオブジェクトの設定にたどり着きました。
私のカスタムオブジェクトには「Feed Tracking(フィードの追跡)」という小さなチェックボックスがあったのですが、それをオンにしていませんでした。システムは、まだ存在していないフィードに投稿しようとしていたのです。
思わず突っ伏したくなりましたが、自分の考えが当たっていたこともわかりました。ローコードでも、開発の知識がいらないわけではないということを再認識させられました。ローコードであっても、開発者のように考え、プラットフォームを機能させるためにどの設定を有効にすればよいかを理解しておく必要があります。
まとめ:SalesforceはただのCRMではなく、プラットフォーム
さて、最初の3週間で、私は何を学んだのでしょうか。
「最先端のWeb開発者」と「Salesforce開発者」の違いは、思っていたよりもずっと小さいということがわかりました。JavaScriptを知っていれば、構文の大部分はすでに頭の中に入っています。
それより重要だったのは、Salesforce Platformが何をするかを理解できたことです。Salesforce Platformは、認証、データベース、ホスティング、APIといった、地味ではあっても欠かせない部分を引き受けてくれるので、開発者は重要なロジックに集中できます。ロジックが「100万ドルの案件を成約させること」であっても、「クラッカーをDランクに設定すること」であっても、使うツールは根本的には同じです。
…ちなみに、ベーグルはSランク以外はあり得ません。
一緒に学びませんか?
私もまだ初心者ですが、基礎を学ぶためにAIを相棒に「開発者初級」のTrailmixを使いました。このような軽食のランキングリスト(またはもっと役に立つもの)を作ってみたいと思った方は、以下のリソースを参考にしてみてください。
- 初級から上級までの開発者ロードマップ(Trailhead)
- Lightning Webコンポーネントガイド(英語)(開発者向けドキュメント)
- データモデリング(Trailhead)
- Salesforce Flowの基本(Trailhead)
執筆者について
Sean Keeganは、Salesforceのニューヨークオフィスに勤務するリードデベロッパーアドボケイトです。元数学教師で、複雑なテクノロジーを誰にとっても身近なものにすることに情熱を注いでいます。仕事を離れると、ゲームや観葉植物の世話、アルティメットフリスビーを楽しんでいます。ぜひX(Twitter)とLinkedInでフォローしてください。