
Salesforce Developer
Ship Apex on Salesforce with service-layer patterns, bulk-safe SOQL/DML, and trigger-friendly business logic for solo builders on CRM customizations.
Install
npx skills add https://github.com/jeffallan/claude-skills --skill salesforce-developerWhat is this skill?
- Service layer pattern separating business logic from triggers and controllers
- Bulkified SOQL and DML patterns with null-safe aggregation examples
- Documented Apex class structure with sharing rules and exception handling hooks
- Opportunity-to-Account rating workflows as a reference implementation
- Single Responsibility Principle guidance for maintainable org code
Adoption & trust: 2.4k installs on skills.sh; 9.7k GitHub stars; 2/3 security scanners passed (skills.sh audits); trending (+100% hot-view momentum).
Recommended Skills
Journey fit
Canonical shelf is Build because the skill teaches implementing Salesforce server-side logic (Apex classes, queries, bulkification), not discovery or launch work. Backend fits Apex service classes, SOQL, and domain operations that sit behind Lightning, Flow, or external APIs.
Common Questions / FAQ
Is Salesforce Developer safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Salesforce Developer
# Apex Development --- ## Apex Class Structure ### Service Layer Pattern Separate business logic from triggers and controllers using service classes. ```apex /** * AccountService - Business logic for Account operations * Follows Single Responsibility Principle */ public with sharing class AccountService { /** * Updates account ratings based on opportunity history * @param accountIds Set of Account IDs to process * @throws AccountServiceException on validation failure */ public static void updateAccountRatings(Set<Id> accountIds) { if (accountIds == null || accountIds.isEmpty()) { return; } // Bulkified query - single SOQL for all records Map<Id, Account> accountsToUpdate = new Map<Id, Account>(); for (Account acc : [ SELECT Id, Rating, (SELECT Amount, StageName FROM Opportunities WHERE StageName = 'Closed Won') FROM Account WHERE Id IN :accountIds ]) { Decimal totalRevenue = 0; for (Opportunity opp : acc.Opportunities) { totalRevenue += opp.Amount != null ? opp.Amount : 0; } String newRating = calculateRating(totalRevenue); if (acc.Rating != newRating) { accountsToUpdate.put(acc.Id, new Account( Id = acc.Id, Rating = newRating )); } } if (!accountsToUpdate.isEmpty()) { update accountsToUpdate.values(); } } private static String calculateRating(Decimal revenue) { if (revenue >= 1000000) return 'Hot'; if (revenue >= 100000) return 'Warm'; return 'Cold'; } } ``` ### Domain Layer Pattern Encapsulate object-specific logic in domain classes. ```apex /** * Accounts Domain Class * Encapsulates Account-specific business rules */ public with sharing class Accounts { private List<Account> records; public Accounts(List<Account> records) { this.records = records; } public static Accounts newInstance(List<Account> records) { return new Accounts(records); } /** * Validates accounts before insert/update * @return List of validation errors */ public List<String> validate() { List<String> errors = new List<String>(); for (Account acc : records) { if (String.isBlank(acc.Name)) { errors.add('Account Name is required'); } if (acc.AnnualRevenue != null && acc.AnnualRevenue < 0) { errors.add('Annual Revenue cannot be negative'); } } return errors; } /** * Sets default values for new accounts */ public void setDefaults() { for (Account acc : records) { if (String.isBlank(acc.Rating)) { acc.Rating = 'Cold'; } if (acc.NumberOfEmployees == null) { acc.NumberOfEmployees = 0; } } } } ``` --- ## Trigger Framework ### Handler Pattern Never put logic directly in triggers. Use a handler framework. ```apex /** * AccountTrigger - Delegates all logic to handler */ trigger AccountTrigger on Account ( before insert, before update, before delete, after insert, after update, after delete, after undelete ) { AccountTriggerHandler handler = new AccountTriggerHandler(); switch on Trigger.operationType { when BEFORE_INSERT { handler.beforeInsert(Trigger.new); } when BEFORE_UPDATE { handler.beforeUpdate(Trigger.new, Trigger.oldMap); } when BEFORE_DELETE { handler.beforeDelete(Trigger.old, Trigger.oldMap); } when AFTER_INSERT { handler.afterInsert(Trigger.new, Trigger.newMap); } when AFTER_UPDATE { handler.afterUpdate