Salesforce 開発者として、変化の速いビジネスニーズに対応し、高品質なソリューションを効率的に提供することは常に課題です。ここでは、Salesforce の開発プロセスを劇的に改善し、モジュール性、バージョン管理、継続的インテグレーション(CI/CD)を強力にサポートする second-generation packaging (2GP)(第2世代パッケージング)について深く掘り下げていきます。
概要とビジネスシーン
second-generation packaging (2GP) は、Salesforce のアプリケーションライフサイクル管理 (ALM) の中心となる、ソース駆動型開発に特化したパッケージングモデルです。従来の第一世代パッケージ (1GP) や変更セット (Change Set) の限界を克服し、コンポーネントの再利用、独立したバージョン管理、そして堅牢な CI/CD パイプラインの構築を可能にするコアな価値を提供します。
実際のビジネスシーン
シーンA:ISV(独立系ソフトウェアベンダー)の製品開発
- 業界:SaaS プロバイダー(Salesforce ISV)
- ビジネス課題:従来の 1GP では、製品が大規模になるにつれて、機能の追加やバグ修正のデプロイが複雑化し、複数の機能モジュール間の依存関係管理が困難でした。また、顧客ごとのわずかなカスタマイズが製品全体のリリースサイクルに影響を与えることもありました。
- ソリューション:2GP を導入し、製品を複数の小さなパッケージ(feature package, utility package など)に分割しました。各パッケージは独立して開発、バージョン管理、テストが行われ、Salesforce DX (開発者経験) 環境と連携する CI/CD パイプラインを通じて自動デプロイされます。
- 定量的効果:新機能のリリースサイクルを 25% 短縮し、デプロイ時のエラー率を 30% 削減。顧客固有のカスタマイズも、ベースパッケージの上にアドオンパッケージとして提供できるようになったため、本番環境への影響を最小限に抑え、開発者生産性が 15% 向上しました。
シーンB:大規模企業の社内アプリケーション開発
- 業界:金融サービス
- ビジネス課題:複数の開発チームが Salesforce Platform 上で異なる業務アプリケーション(顧客管理、契約管理、規制対応など)を開発しており、リリースの競合、デプロイの複雑さ、そして環境間の一貫性の維持が課題となっていました。変更セットでは、頻繁な変更に対応しきれませんでした。
- ソリューション:各業務アプリケーションをそれぞれ 2GP のパッケージとして定義し、専用の Git リポジトリと CI/CD パイプラインを構築しました。これにより、チーム間の独立性を保ちつつ、各パッケージのテストとデプロイを自動化しました。共通で利用されるコンポーネントは独立したユーティリティパッケージとして管理しました。
- 定量的効果:デプロイ関連のダウンタイムを 50% 削減し、品質保証(QA)サイクルの効率を 20% 向上。複数チーム間の開発コンフリクトが大幅に減少し、本番環境への安全なリリースが保証されるようになりました。
技術原理とアーキテクチャ
2GP は Salesforce DX のエコシステムの上に構築されており、ソースコードを唯一の信頼できる情報源 (Single Source of Truth) とします。その基礎的な動作メカニズムは、プロジェクト内のソースコードを基にパッケージのバージョンを作成し、それを Salesforce 組織にインストールするというサイクルにあります。
基礎的な動作メカニズム
開発者は Salesforce CLI (Command Line Interface) を使用して、Salesforce DX プロジェクトを作成し、そこでアプリケーションのコンポーネント(Apex クラス、LWC、Visualforce ページなど)を開発します。これらのコンポーネントは、sfdx-project.json ファイルで定義されたパッケージディレクトリ(Package Directory)に整理されます。2GP では、このディレクトリ内のソースコードからパッケージを作成し、バージョンを付与してリリースします。このプロセスは、スクラッチ組織(Scratch Org)での迅速な開発とテストによって支えられます。
主要コンポーネントと依存関係
- Salesforce CLI:パッケージの作成、バージョン管理、インストール、Dev Hub (開発ハブ) およびスクラッチ組織の管理を行うための主要ツール。
- Salesforce DX Project:アプリケーションのソースコード、設定ファイル、パッケージ定義を含む標準的なプロジェクト構造。
- Dev Hub Org:パッケージを作成し、スクラッチ組織を管理するための組織。
- Scratch Org:一時的な、設定可能な Salesforce 組織。パッケージ開発中のテストや検証に利用される。
- Package Directory:
sfdx-project.jsonで定義され、パッケージに含めるコンポーネントのソースコードが配置されるディレクトリ。 - Package Version:特定のパッケージのソースコードのスナップショットであり、一意のバージョン番号(例: 1.0.0.0)を持つ。
- Package Ancestry (パッケージ系統):パッケージバージョンの継承関係を示し、アップグレードパスを管理する。
データフロー
| ステップ | 説明 | CLI コマンド例 |
|---|---|---|
| 1. プロジェクト初期化 | Salesforce DX プロジェクトを作成し、パッケージディレクトリを定義します。 | sfdx force:project:create -n My2GPProject |
| 2. ソース開発 | スクラッチ組織でコンポーネントを開発し、ローカルプロジェクトと同期します。 | sfdx force:source:pushsfdx force:source:pull |
| 3. パッケージ定義 | パッケージ(パッケージエイリアスとタイプ)を定義します。 | sfdx force:package:create --name "MyFeature" --path "force-app/main/default" --packagetype "Unlocked" --containeroptions "Mixed" |
| 4. パッケージバージョン作成 | 定義されたパッケージのソースコードからバージョンを作成します。 | sfdx force:package:version:create --package "MyFeature" --path "force-app/main/default" --versionnumber "1.0.0.0" --wait 10 --installationkey "test1234" --codecoverage --skipvalidation |
| 5. パッケージインストール | 作成されたパッケージバージョンを、対象組織(スクラッチ組織、サンドボックス、本番組織)にインストールします。 | sfdx force:package:install --package "MyFeature@1.0.0-0" --targetusername "dev-org" --wait 10 |
ソリューション比較と選定
Salesforce でのアプリケーション展開にはいくつかの方法がありますが、それぞれに適用シーンと特性があります。2GP を他のソリューションと比較検討することで、その優位性と適切な利用シーンが明確になります。
| ソリューション | 適用シーン | パフォーマンス | Governor Limits | 複雑度 |
|---|---|---|---|---|
| second-generation packaging (2GP) | ソース駆動型開発、モジュール化された大規模アプリ、CI/CD連携、ISV製品開発、大規模企業内開発 | デプロイは高速、開発サイクル効率的 | パッケージ自体にはなし、内部コンポーネントは通常のApex Limitsに従う | 初期学習コストとセットアップは高いが、運用で簡素化 |
| first-generation managed package (1GP) | IP保護が最重要、AppExchangeでの配布、アップグレードパス提供、限定的なカスタマイズを許容 | デプロイは比較的遅く、柔軟性に欠ける | パッケージ自体にはなし、内部コンポーネントは通常のApex Limitsに従う | 開発時の柔軟性は低い、CI/CD統合が難しい |
| 変更セット (Change Set) | 簡単な設定変更、少量のコードデプロイ、開発チームが小規模で手動プロセスが多い場合 | 手動操作が多く非効率、大規模なデプロイは困難 | パッケージではないため直接関係なし、通常のApex Limitsに従う | 導入は容易だが、大規模開発では非常に高い |
| アンマネージドパッケージ (Unmanaged Package) | シンプルなコンポーネント共有、サンプルコード配布、IP保護不要なケース | インストールは迅速 | パッケージではないため直接関係なし、通常のApex Limitsに従う | 最も低い、ただしバージョン管理やアップグレードパスがない |
second-generation packaging (2GP) を使用すべき場合
- ✅ ソースコードを信頼できる唯一の情報源として、Git などのバージョン管理システムと完全に統合したい場合。
- ✅ 継続的インテグレーション/継続的デリバリー(CI/CD)パイプラインを構築し、開発から本番へのデプロイを自動化・効率化したい場合。
- ✅ 複数の開発チームが同時に Salesforce アプリケーションを開発しており、それぞれのチームが独立したモジュールを所有し、依存関係を明確に管理したい場合。
- ✅ ISV として、モジュール化されたスケーラブルな製品を開発・配布し、柔軟なアップグレードパスを提供したい場合。
- ✅ パッケージのアップグレードおよびロールバックを柔軟に行い、デプロイ時のリスクを最小限に抑えたい場合。
- ❌ 単一の簡単なコンポーネントを共有するだけで、本格的な開発ライフサイクル管理が不要な場合(アンマネージドパッケージが適切)。
- ❌ Salesforce DX 環境のセットアップや Salesforce CLI の操作に慣れていない、またはその学習に時間をかけられない小規模な開発チーム。
実装例
ここでは、2GP を用いてシンプルな Apex クラスと LWC (Lightning Web Component) をパッケージ化する基本的なステップを示します。この例では、まず Salesforce DX プロジェクトを作成し、続いてパッケージを定義し、そのパッケージのバージョンを作成、そして組織にインストールするまでの流れを追います。
ステップ1:Salesforce DX プロジェクトの作成
まず、新しい Salesforce DX プロジェクトを作成します。
sfdx force:project:create --projectname My2GPApp --outputdir ./ --template standard
このコマンドは、My2GPApp という名前の新しいプロジェクトフォルダを作成し、標準的な Salesforce DX プロジェクト構造を初期化します。
ステップ2:パッケージの定義とソースコードの追加
プロジェクト内に Apex クラスと LWC を作成し、パッケージのソースとして定義します。ここでは、例としてユーティリティクラスとコンポーネントを追加します。
force-app/main/default/classes/MyUtilityService.cls:
// MyUtilityService.cls
public with sharing class MyUtilityService {
/**
* @description 与えられた文字列を大文字に変換するメソッド
* @param inputString 入力文字列
* @return 大文字に変換された文字列
*/
public static String convertToUpperCase(String inputString) {
return inputString != null ? inputString.toUpperCase() : '';
}
}
force-app/main/default/lwc/myDisplayComponent/myDisplayComponent.js:
// myDisplayComponent.js
import { LightningElement, api } from 'lwc';
import convertToUpperCase from '@salesforce/apex/MyUtilityService.convertToUpperCase';
export default class MyDisplayComponent extends LightningElement {
@api inputText = 'Hello Salesforce';
convertedText = '';
connectedCallback() {
this.convertAndDisplay();
}
async convertAndDisplay() {
try {
this.convertedText = await convertToUpperCase({ inputString: this.inputText });
} catch (error) {
console.error('Error converting text:', error);
this.convertedText = 'Error converting text.';
}
}
}
force-app/main/default/lwc/myDisplayComponent/myDisplayComponent.html:
<template>
<lightning-card title="My Display Component" icon-name="utility:display">
<div class="slds-m-around_medium">
<p>Original Text: <b>{inputText}</b></p>
<p>Converted Text: <b>{convertedText}</b></p>
</div>
</lightning-card>
</template>
sfdx-project.json にパッケージディレクトリを追加します。packageDirectories の path は、ソースコードが格納されているディレクトリを指します。
// sfdx-project.json の抜粋
{
"packageDirectories": [
{
"path": "force-app", // パッケージのソースコードのパス
"default": true,
"package": "My2GPPackage", // パッケージエイリアス
"versionName": "Ver 1.0",
"versionNumber": "1.0.0.LOCAL"
}
],
"namespace": "",
"sfdcLoginUrl": "https://login.salesforce.com",
"sourceApiVersion": "60.0"
}
ここで "package": "My2GPPackage" は、後で参照するパッケージのエイリアスとなります。このエイリアスは、パッケージを作成する際に使用されます。
ステップ3:Dev Hub を有効にし、組織に認証
パッケージを作成するには Dev Hub が有効な組織が必要です。次に、その組織に認証します。
sfdx org:login:web --set-default-dev-hub --alias MyDevHub
ステップ4:パッケージの作成
sfdx-project.json で定義したエイリアスを使用してパッケージを作成します。このコマンドはパッケージの ID (0Ho...) を返します。
sfdx force:package:create --name "My2GPPackage" --path "force-app" --packagetype "Unlocked" --description "A sample Unlocked Package for 2GP" --targetdevhub MyDevHub
--packagetype "Unlocked" は、インストール後にパッケージ内のコンポーネントを変更できるアンロックドパッケージ(Unlocked Package)として作成することを意味します。
ステップ5:パッケージバージョンの作成
作成したパッケージ ID またはエイリアスを使用してパッケージバージョンを作成します。これにより、現在のソースコードのパッケージスナップショットが作成されます。
sfdx force:package:version:create --package "My2GPPackage" --path "force-app" --versionnumber "1.0.0.0" --installationkey "MyKey1234" --wait 10 --targetdevhub MyDevHub --codecoverage --skipvalidation
--package "My2GPPackage": 作成するパッケージのエイリアス。--path "force-app": ソースコードのパス。--versionnumber "1.0.0.0": パッケージのバージョン番号。SemVer (Semantic Versioning) に従うことが推奨されます。--installationkey "MyKey1234": インストール時にパスワードが必要な場合。不要なら省略可能。--wait 10: コマンドが完了するまで最大 10 分間待機。--targetdevhub MyDevHub: パッケージバージョンを作成する Dev Hub 組織のエイリアス。--codecoverage: パッケージ内の Apex コードのカバレッジを計算します。本番リリースには通常 75% 以上のカバレッジが必要です。--skipvalidation: (開発・テスト用) パッケージバージョン作成時のセキュリティ検証をスキップします。本番リリース時には絶対に使用しないでください。
ステップ6:パッケージのインストール
作成したパッケージバージョンを、対象の Salesforce 組織(スクラッチ組織、サンドボックス、または本番組織)にインストールします。
sfdx org:login:web --alias MyTargetOrg // ターゲット組織に認証 sfdx force:package:install --package "My2GPPackage@1.0.0-0" --targetusername "MyTargetOrg" --installationkey "MyKey1234" --wait 10
--package "My2GPPackage@1.0.0-0": パッケージのエイリアスとバージョン番号。--targetusername "MyTargetOrg": インストール先の組織のエイリアス。
これにより、パッケージ内の Apex クラスと LWC が指定された組織にデプロイされます。このフローを CI/CD パイプラインに組み込むことで、Salesforce 開発の自動化と効率化が実現します。
注意事項とベストプラクティス
2GP を最大限に活用するためには、いくつかの重要な考慮事項とベストプラクティスを理解しておく必要があります。
権限要件
- Dev Hub の有効化: パッケージを作成・管理する組織(通常は本番組織または特別な Dev Hub 組織)で「Dev Hub を有効化 (Enable Dev Hub)」設定が必要です。
- CLI ユーザーの権限: Salesforce CLI を使用するユーザーは、Dev Hub 組織でシステム管理者プロファイル(System Administrator Profile)であるか、または Dev Hub 機能を管理するための適切な権限セット(Permission Set)が付与されている必要があります。具体的には、「Create and Update Second-Generation Packages」や「View Dev Hub」などの権限が必要です。
Governor Limits
2GP 自体には直接的な Governor Limits はありません。しかし、パッケージ内に含まれる Apex コードや Flow、その他のコンポーネントは、通常の Salesforce Governor Limits の対象となります。例えば、Apex の同期トランザクションでは以下の制限が適用されます(2025年最新版の制限値は変更される可能性があります。必ず公式ドキュメントで確認してください)。
- SOQL クエリの合計数:100
- DML ステートメントの合計数:150
- ヒープサイズ:6MB
- CPU 時間:10,000 ms
- コールアウトの合計数:100
- 非同期 Apex キュー投入回数:1日あたり最大 250,000 回(組織全体)
パッケージ開発においても、これらの制限を意識した効率的なコード設計が不可欠です。
エラー処理
- パッケージバージョン作成時のエラー:
- 原因: ソースコードの構文エラー、コンポーネント間の依存関係の欠如、メタデータの不整合、不十分なコードカバレッジなど。
- 解決策: Salesforce CLI の出力メッセージを詳細に確認し、エラーを修正します。
sfdx force:package:version:report -p [packageVersionId]コマンドで詳細なレポートを確認できます。
- パッケージインストール時のエラー:
- 原因: 対象組織の既存コンポーネントとの名前の競合、必要な権限セットがない、Apex テストの失敗(管理パッケージの場合)、組織設定の不整合。
- 解決策: インストールログを確認し、競合するコンポーネントの名前変更、必要な権限の付与、組織設定の見直しなどを行います。
パフォーマンス最適化
2GP 開発におけるパフォーマンス最適化は、開発プロセス全体の効率とアプリケーションの実行速度の両方に関わります。
- 適切なパッケージ粒度の設計:
アプリケーションを小さく、再利用可能なモジュールに分割することで、開発の独立性を高め、パッケージバージョンの作成やデプロイ時間を短縮します。依存関係は最小限に抑えるように設計します。
- スクラッチ組織の積極的な活用:
スクラッチ組織は一時的な環境であり、必要なコンポーネントのみをプロビジョニングできるため、テストや開発のサイクルを迅速化します。本番組織のような大規模なメタデータを同期する必要がないため、開発環境の準備時間を大幅に短縮できます。
- CI/CD パイプラインの導入と最適化:
Git などのバージョン管理システムと連携し、自動テスト、パッケージバージョンの作成、デプロイを CI/CD パイプラインで自動化します。これにより、手動プロセスに伴うエラーを減らし、デプロイの信頼性と速度を向上させます。テスト実行時間を短縮するための並列テストの導入なども検討します。
- パッケージエイリアスとバージョン管理の徹底:
sfdx-project.jsonでパッケージエイリアスを定義し、CLI コマンドでの参照を簡素化します。SemVer (Semantic Versioning) に従い、明確なバージョン管理戦略を確立することで、パッケージの依存関係を適切に管理し、アップグレード時の混乱を避けます。
よくある質問 FAQ
Q1:1GP (第一世代パッケージ) と 2GP のどちらを使うべきですか?
A1:新規の開発や既存のアプリケーションの刷新を検討している場合は、原則として 2GP を強く推奨します。2GP はソース駆動型開発、CI/CD 連携、モジュール性、柔軟なバージョン管理において圧倒的な優位性を持っています。1GP はレガシーなパッケージングモデルであり、特に知的財産保護が必要な一部の AppExchange アプリケーションを除き、新しいプロジェクトでの採用は避けるべきです。
Q2:2GP のデバッグはどのように行いますか?
A2:2GP で開発されたコードのデバッグは、主にスクラッチ組織内で行われます。Salesforce DX の Debug Log 機能、VS Code の Apex Debugger 拡張機能、および LWC Local Development Server を活用して、コードレベルでの問題を特定します。また、CI/CD パイプラインで実行される自動テストの結果を詳細に分析することで、パッケージバージョン作成前の問題を早期に発見し解決することが重要です。
Q3:2GP でのバージョン管理のベストプラクティスは何ですか?
A3:2GP におけるバージョン管理のベストプラクティスは、SemVer (Semantic Versioning) に厳密に従うことです(例: Major.Minor.Patch.BuildNumber)。破壊的変更はメジャーバージョンアップ、新機能追加はマイナーバージョンアップ、バグ修正はパッチバージョンアップと明確に区別します。Git などのバージョン管理システムと完全に連携させ、各パッケージバージョンに対応する Git タグを作成することで、追跡可能性とロールバックの容易さを確保します。また、パッケージエイリアスを活用して CLI コマンドを簡素化し、依存関係を明確に管理することも重要です。
まとめと参考資料
second-generation packaging (2GP) は、Salesforce 開発の未来を形作る重要なテクノロジーです。ソース駆動型開発の原則に基づき、CI/CD とのシームレスな統合、モジュール性の向上、そして柔軟なバージョン管理を可能にすることで、開発プロセス全体の効率と信頼性を劇的に向上させます。特に ISV や大規模な企業内開発において、スケーラブルで持続可能なアプリケーション開発を実現するための不可欠なツールと言えるでしょう。
重要ポイントの要約
- 2GP はソース駆動開発と CI/CD に最適化されたパッケージングモデルです。
- モジュール化された開発、独立したバージョン管理、柔軟なアップグレードパスを提供します。
- Salesforce CLI と Salesforce DX プロジェクト構造がその基盤となります。
- 適切なパッケージ設計、スクラッチ組織の活用、CI/CD の導入が成功の鍵です。
- Governor Limits はパッケージ内のコンポーネントに適用され、従来の Apex Limits と同様です。
公式リソース
- 📖 公式ドキュメント:Salesforce DX Developer Guide: Second-Generation Managed Packages
- 📖 公式ドキュメント:Salesforce CLI Command Reference
- 🎓 Trailhead モジュール:Develop Against an Org with Salesforce DX
- 🔧 関連 GitHub サンプル:Salesforce Packaging Samples
コメント
コメントを投稿