はじめまして。
株式会社ROBOT PAYMENTで請求管理ロボ for Salesforce の開発をしている森岡です。 株式会社ROBOT PAYMENTには11月に入社し、4ヶ月がたちました。
これまで約3年間PHPで開発をしていましたが、縁あって現在はSalesforce AppExchangeアプリ開発をおこなっています。
今回は、PHPエンジニアからSaleforce AppExchangeエンジニアに転身して4ヶ月が経過した現状の振り返りができればと思います。
難しかったこと:Salesforce特有の「自由度」と「組織(Org)」
PHPでの開発は、基本的にサーバーがあって、DBがあって、コードを書くというシンプルさがありましたが、Salesforceは「プラットフォーム」ということで考え方の違いによる難しさがありました。
まず驚いたのが、プロファイルや権限セットの仕組みです。正しい手順でデプロイしたはずなのにデータが表示されなかったり、レイアウトが想定しているもので表示されなかったとき、確認するのはそのユーザーの権限だと思います。しかし、Salesforceにはこの権限を設定することができる箇所が複数あります。それがプロファイルと権限セットです。この自由度の高さが得体の知れなさにつながり、理解に苦しみました。
開発環境の概念も様々です。
PBO、PDE、DE、Sandbox、DevHub組織、スクラッチ組織 etc…
上記のように組織(Org)と呼称されるものが複数あります。そして各組織は似たようなところから作成できたり、払い出す方法が異なったりと様々です。そのため、「何のための環境を何の組織から作成する」という整理が自分の中でできるまでは、組織(Org)に苦手意識を持っていました。
特に困らなかったこと:言語仕様とAIの恩恵
Salesforceの操作感などとは異なり、プログラミングそのものについては、入社前に想像していたよりスムーズに馴染めました。独自言語であるApexですが、大まかな構文はJavaライクであり、PHPで開発していた私は違和感なく読めました。「ここはPHPでいうアレだな」と変換できたので、構文自体で詰まることはほとんどありませんでした。
重ねて、会社からも推奨されていたためGeminiやCursor、AgentforceVibesなどのAIをフル活用できました。
- このApexで記述された構文をPHPで例えてほしいとき、またその逆
- 各メソッドの処理内容について知りたいとき
『PHPとApexの違いまとめ』のような記事がなくても、AIで確認することができるので私が理解しやすい言葉で学習を進めることができました。そして、馴染みのないメソッドやSalesforce固有のクラスについても、同様に進めることができました。また、オンボーディング中にソースコードを一読する機会があったこともあり、AIを活用しながらアプリ全体のロジックを早期に確認できたことが全体像の掴みやすさに繋がったと思います。
戸惑ったこと:PHPとApexの考え方の違い
PHPの「ゆるふわ」な部分に慣れていた私は、Apexの厳格さに初めは何度かコンパイルエラーを発生させました。 最近は「型を定義し、厳格に管理しよう」という風潮になってきましたが、もともとは「緩い型付け」とされてきたPHPでは、いい感じに解釈してくれていた部分も、Apexは一切許してくれません。 今は型宣言をしっかりしていることで、コードの可読性も上がっていて便利だなと思っていますが、初めは「もっと上手に解釈してよ。」と思っていました。
また、特に戸惑ったのが、sObjectの配列での挙動です。「配列を新たに作成したから、元の変数を書き換えても影響しないだろう」思っていたのですが、実はsObjectの参照を保持しているだけなので、元のデータも書き換わる…という現象にかなり混乱しました。正確には、DBから取得してきたデータの型による扱い方の違いでした。
PHPの場合:DBから連想配列でデータを取得して、新たに配列を作成する(コピー)
<?php // PHP: DBから連想配列で取得 $row = $stmt->fetch(PDO::FETCH_ASSOC); // $row = ['id' => 1, 'name' => 'suzuki']; $list = []; $list[] = $row; // この時、値がコピーされる $row['name'] = 'tanaka'; // 元の値を書き換え echo $list[0]['name']; // 結果は 'suzuki' のまま。
Apexの場合:sObjectでデータを取得して、新たに配列を作成する(参照)
// Apex (SOQLで取得) Account acc = [SELECT Id, Name FROM Account LIMIT 1]; List<Account> accList = new List<Account>(); accList.add(acc); // 「参照」をリストに追加 acc.Name = 'tanaka'; // 元の値を書き換え System.debug(accList[0].Name); // 結果は 'tanaka' (同じ実体を見ているので変わる!)
PHPでもクラスのインスタンス(オブジェクト)を扱えば参照渡しになりますが、私の場合はパフォーマンスや安全性のために、連想配列に成形したりして「値渡し(コピー)」で実装するクセがついていました。そのため、Apexでは常に「これは参照か?」を意識するために、考え方を変える必要がありました。
振り返ってみて
振り返ってみると、AIに助けられていた3ヶ月間だったように思います。それもSalesforceの利用者が世界中にいて、公式ドキュメントがきちんと整備されているからこそ、確度の高い回答が返ってきていたのだと思っています。
SalesforceやApexについては、まだまだ知らないこと、分からないことがたくさんあります。しかし、Trailheadや資格など、勉強する環境がとても整っているプラットフォームです。これらをうまく活用しながらエンジニアとして成長していきたいです。
We are hiring!!
ROBOT PAYMENTでは一緒に働く仲間を募集しています!!!