salesforce-developer

salesforce-developer

熱門

撰寫與除錯 Apex 程式碼、建立 Lightning Web Components、最佳化 SOQL 查詢、實作觸發器、批次作業、平台事件及 Salesforce 平台整合。適用於開發 Salesforce 應用程式、自訂 CRM 工作流程、管理 Governor Limits、大量資料處理,或設定 Salesforce DX 與 CI/CD 管線。

1.1萬星標
974分支
更新於 2026/5/20
SKILL.md
唯讀
名稱
salesforce-developer
描述

撰寫與除錯 Apex 程式碼、建立 Lightning Web Components、最佳化 SOQL 查詢、實作觸發器、批次作業、平台事件及 Salesforce 平台整合。適用於開發 Salesforce 應用程式、自訂 CRM 工作流程、管理 Governor Limits、大量資料處理,或設定 Salesforce DX 與 CI/CD 管線。

Salesforce Developer

核心工作流程

  1. 分析需求 - 了解業務需求、資料模型、Governor Limits、可擴展性
  2. 設計解決方案 - 選擇宣告式或程式化方式、規劃大量資料處理、設計整合
  3. 實作 - 撰寫 Apex 類別、LWC 元件、SOQL 查詢,並遵循最佳實務
  4. 驗證 Governor Limits - 確認 SOQL/DML 次數、Heap 大小及 CPU 時間在平台限制內,再繼續進行
  5. 徹底測試 - 撰寫測試類別,達到 90% 以上程式碼覆蓋率,測試大量資料情境(200 筆記錄批次)
  6. 部署 - 使用 Salesforce DX、Scratch Org、CI/CD 進行中繼資料部署

參考指南

根據情境載入詳細指引:

主題 參考文件 載入時機
Apex 開發 references/apex-development.md 類別、觸發器、非同步模式、批次處理
Lightning Web Components references/lightning-web-components.md LWC 框架、元件設計、事件、Wire Service
SOQL/SOSL references/soql-sosl.md 查詢最佳化、關聯、Governor Limits
整合模式 references/integration-patterns.md REST/SOAP API、平台事件、外部服務
部署與 DevOps references/deployment-devops.md Salesforce DX、CI/CD、Scratch Org、Metadata API

限制

必須執行

  • 將 Apex 程式碼大量化 — 在迴圈前收集 ID/記錄,在迴圈外執行查詢/DML
  • 撰寫測試類別,程式碼覆蓋率至少 90%,並包含大量資料情境
  • 使用具選擇性的 SOQL 查詢,搭配已建立索引的欄位;善用關聯查詢
  • 對長時間執行的工作使用適當的非同步處理(Batch、Queueable、Future)
  • 實作適當的錯誤處理與記錄;使用 Database.update(scope, false) 處理部分成功
  • 使用 Salesforce DX 進行原始碼驅動開發與中繼資料部署

禁止事項

  • 在迴圈內執行 SOQL/DML(違反 Governor Limits — 請參考下方大量化觸發器模式)
  • 在程式碼中硬編碼 ID 或憑證
  • 建立沒有保護機制的遞迴觸發器
  • 跳過欄位層級安全性與共用規則檢查
  • 使用已棄用的 Salesforce API 或元件

程式碼模式

大量化觸發器(正確模式)

// 正確:收集 ID,在迴圈外查詢一次
trigger AccountTrigger on Account (before insert, before update) {
    AccountTriggerHandler.handleBeforeInsert(Trigger.new);
}

public class AccountTriggerHandler {
    public static void handleBeforeInsert(List<Account> newAccounts) {
        Set<Id> parentIds = new Set<Id>();
        for (Account acc : newAccounts) {
            if (acc.ParentId != null) parentIds.add(acc.ParentId);
        }
        Map<Id, Account> parentMap = new Map<Id, Account>(
            [SELECT Id, Name FROM Account WHERE Id IN :parentIds]
        );
        for (Account acc : newAccounts) {
            if (acc.ParentId != null && parentMap.containsKey(acc.ParentId)) {
                acc.Description = 'Child of: ' + parentMap.get(acc.ParentId).Name;
            }
        }
    }
}
// 錯誤:在迴圈內執行 SOQL — 違反 Governor Limits
trigger AccountTrigger on Account (before insert) {
    for (Account acc : Trigger.new) {
        Account parent = [SELECT Id, Name FROM Account WHERE Id = :acc.ParentId]; // 錯誤
        acc.Description = 'Child of: ' + parent.Name;
    }
}

Batch Apex

public class ContactBatchUpdate implements Database.Batchable<SObject> {
    public Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator([SELECT Id, Email FROM Contact WHERE Email = null]);
    }
    public void execute(Database.BatchableContext bc, List<Contact> scope) {
        for (Contact c : scope) {
            c.Email = 'unknown@example.com';
        }
        Database.update(scope, false); // 允許部分成功
    }
    public void finish(Database.BatchableContext bc) {
        // 發送通知或串接下一個批次
    }
}
// 執行:Database.executeBatch(new ContactBatchUpdate(), 200);

測試類別

@IsTest
private class AccountTriggerHandlerTest {
    @TestSetup
    static void makeData() {
        Account parent = new Account(Name = 'Parent Co');
        insert parent;
        Account child = new Account(Name = 'Child Co', ParentId = parent.Id);
        insert child;
    }

    @IsTest
    static void testBulkInsert() {
        Account parent = [SELECT Id FROM Account WHERE Name = 'Parent Co' LIMIT 1];
        List<Account> children = new List<Account>();
        for (Integer i = 0; i < 200; i++) {
            children.add(new Account(Name = 'Child ' + i, ParentId = parent.Id));
        }
        Test.startTest();
        insert children;
        Test.stopTest();

        List<Account> updated = [SELECT Description FROM Account WHERE ParentId = :parent.Id];
        System.assert(!updated.isEmpty(), '子記錄應設定描述');
        System.assert(updated[0].Description.startsWith('Child of:'), '描述格式不符');
    }
}

SOQL 最佳實務

// 選擇性查詢 — 在 WHERE 子句中使用已建立索引的欄位
List<Opportunity> opps = [
    SELECT Id, Name, Amount, StageName
    FROM Opportunity
    WHERE AccountId IN :accountIds      // 已建立索引的欄位
      AND CloseDate >= :Date.today()    // 已建立索引的欄位
    ORDER BY CloseDate ASC
    LIMIT 200
];

// 關聯查詢,避免額外往返
List<Account> accounts = [
    SELECT Id, Name,
           (SELECT Id, LastName, Email FROM Contacts WHERE Email != null)
    FROM Account
    WHERE Id IN :accountIds
];

Lightning Web Component(計數器範例)

<!-- counterComponent.html -->
<template>
    <lightning-card title="計數器">
        <div class="slds-p-around_medium">
            <p>計數:{count}</p>
            <lightning-button label="增加" onclick={handleIncrement}></lightning-button>
        </div>
    </lightning-card>
</template>
// counterComponent.js
import { LightningElement, track } from 'lwc';
export default class CounterComponent extends LightningElement {
    @track count = 0;
    handleIncrement() {
        this.count += 1;
    }
}
<!-- counterComponent.js-meta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>59.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

文件