{"kind":"AgentDefinition","metadata":{"namespace":"community","name":"apex","version":"0.1.0"},"spec":{"agents_md":"---\ndescription: 'Guidelines and best practices for Apex development on the Salesforce Platform'\napplyTo: '**/*.cls, **/*.trigger'\n---\n\n# Apex Development\n\n## General Instructions\n\n- Always use the latest Apex features and best practices for the Salesforce Platform.\n- Write clear and concise comments for each class and method, explaining the business logic and any complex operations.\n- Handle edge cases and implement proper exception handling with meaningful error messages.\n- Focus on bulkification - write code that handles collections of records, not single records.\n- Be mindful of governor limits and design solutions that scale efficiently.\n- Implement proper separation of concerns using service layers, domain classes, and selector classes.\n- Document external dependencies, integration points, and their purposes in comments.\n\n## Naming Conventions\n\n- **Classes**: Use `PascalCase` for class names. Name classes descriptively to reflect their purpose.\n  - Controllers: suffix with `Controller` (e.g., `AccountController`)\n  - Trigger Handlers: suffix with `TriggerHandler` (e.g., `AccountTriggerHandler`)\n  - Service Classes: suffix with `Service` (e.g., `AccountService`)\n  - Selector Classes: suffix with `Selector` (e.g., `AccountSelector`)\n  - Test Classes: suffix with `Test` (e.g., `AccountServiceTest`)\n  - Batch Classes: suffix with `Batch` (e.g., `AccountCleanupBatch`)\n  - Queueable Classes: suffix with `Queueable` (e.g., `EmailNotificationQueueable`)\n\n- **Methods**: Use `camelCase` for method names. Use verbs to indicate actions.\n  - Good: `getActiveAccounts()`, `updateContactEmail()`, `deleteExpiredRecords()`\n  - Avoid abbreviations: `getAccs()` → `getAccounts()`\n\n- **Variables**: Use `camelCase` for variable names. Use descriptive names.\n  - Good: `accountList`, `emailAddress`, `totalAmount`\n  - Avoid single letters except for loop counters: `a` → `account`\n\n- **Constants**: Use `UPPER_SNAKE_CASE` for constants.\n  - Good: `MAX_BATCH_SIZE`, `DEFAULT_EMAIL_TEMPLATE`, `ERROR_MESSAGE_PREFIX`\n\n- **Triggers**: Name triggers as `ObjectName` + trigger event (e.g., `AccountTrigger`, `ContactTrigger`)\n\n## Best Practices\n\n### Bulkification\n\n- **Always write bulkified code** - Design all code to handle collections of records, not individual records.\n- Avoid SOQL queries and DML statements inside loops.\n- Use collections (`List\u003c\u003e`, `Set\u003c\u003e`, `Map\u003c\u003e`) to process multiple records efficiently.\n\n```apex\n// Good Example - Bulkified\npublic static void updateAccountRating(List\u003cAccount\u003e accounts) {\n    for (Account acc : accounts) {\n        if (acc.AnnualRevenue \u003e 1000000) {\n            acc.Rating = 'Hot';\n        }\n    }\n    update accounts;\n}\n\n// Bad Example - Not bulkified\npublic static void updateAccountRating(Account account) {\n    if (account.AnnualRevenue \u003e 1000000) {\n        account.Rating = 'Hot';\n        update account; // DML in a method designed for single records\n    }\n}\n```\n\n### Maps for O(1) Lookup\n\n- **Use Maps for efficient lookups** - Convert lists to maps for O(1) constant-time lookups instead of O(n) list iterations.\n- Use `Map\u003cId, SObject\u003e` constructor to quickly convert query results to a map.\n- Ideal for matching related records, lookups, and avoiding nested loops.\n\n```apex\n// Good Example - Using Map for O(1) lookup\nMap\u003cId, Account\u003e accountMap = new Map\u003cId, Account\u003e([\n    SELECT Id, Name, Industry FROM Account WHERE Id IN :accountIds\n]);\n\nfor (Contact con : contacts) {\n    Account acc = accountMap.get(con.AccountId);\n    if (acc != null) {\n        con.Industry__c = acc.Industry;\n    }\n}\n\n// Bad Example - Nested loop with O(n²) complexity\nList\u003cAccount\u003e accounts = [SELECT Id, Name, Industry FROM Account WHERE Id IN :accountIds];\n\nfor (Contact con : contacts) {\n    for (Account acc : accounts) {\n        if (con.AccountId == acc.Id) {\n            con.Industry__c = acc.Industry;\n            break;\n        }\n    }\n}\n\n// Good Example - Map for grouping records\nMap\u003cId, List\u003cContact\u003e\u003e contactsByAccountId = new Map\u003cId, List\u003cContact\u003e\u003e();\nfor (Contact con : contacts) {\n    if (!contactsByAccountId.containsKey(con.AccountId)) {\n        contactsByAccountId.put(con.AccountId, new List\u003cContact\u003e());\n    }\n    contactsByAccountId.get(con.AccountId).add(con);\n}\n```\n\n### Governor Limits\n\n- Be aware of Salesforce governor limits: SOQL queries (100), DML statements (150), heap size (6MB), CPU time (10s).\n- **Monitor governor limits proactively** using `System.Limits` class to check consumption before hitting limits.\n- Use efficient SOQL queries with selective filters and appropriate indexes.\n- Implement **SOQL for loops** for processing large data sets.\n- Use **Batch Apex** for operations on large data volumes (\u003e50,000 records).\n- Leverage **Platform Cache** to reduce redundant SOQL queries.\n\n```apex\n// Good Example - SOQL for loop for large data sets\npublic static void processLargeDataSet() {\n    for (List\u003cAccount\u003e accounts : [SELECT Id, Name FROM Account]) {\n        // Process batch of 200 records\n        processAccounts(accounts);\n    }\n}\n\n// Good Example - Using WHERE clause to reduce query results\nList\u003cAccount\u003e accounts = [SELECT Id, Name FROM Account WHERE IsActive__c = true LIMIT 200];\n```\n\n### Security and Data Access\n\n- **Always check CRUD/FLS permissions** before performing SOQL queries or DML operations.\n- Use `WITH SECURITY_ENFORCED` in SOQL queries to enforce field-level security.\n- Use `Security.stripInaccessible()` to remove fields the user cannot access.\n- Implement `WITH SHARING` keyword for classes that enforce sharing rules.\n- Use `WITHOUT SHARING` only when necessary and document the reason.\n- Use `INHERITED SHARING` for utility classes to inherit the calling context.\n\n```apex\n// Good Example - Checking CRUD and using stripInaccessible\npublic with sharing class AccountService {\n    public static List\u003cAccount\u003e getAccounts() {\n        if (!Schema.sObjectType.Account.isAccessible()) {\n            throw new SecurityException('User does not have access to Account object');\n        }\n\n        List\u003cAccount\u003e accounts = [SELECT Id, Name, Industry FROM Account WITH SECURITY_ENFORCED];\n\n        SObjectAccessDecision decision = Security.stripInaccessible(\n            AccessType.READABLE, accounts\n        );\n\n        return decision.getRecords();\n    }\n}\n\n// Good Example - WITH SHARING for sharing rules\npublic with sharing class AccountController {\n    // This class enforces record-level sharing\n}\n```\n\n### Exception Handling\n\n- Always use try-catch blocks for DML operations and callouts.\n- Create custom exception classes for specific error scenarios.\n- Log exceptions appropriately for debugging and monitoring.\n- Provide meaningful error messages to users.\n\n```apex\n// Good Example - Proper exception handling\npublic class AccountService {\n    public class AccountServiceException extends Exception {}\n\n    public static void safeUpdate(List\u003cAccount\u003e accounts) {\n        try {\n            if (!Schema.sObjectType.Account.isUpdateable()) {\n                throw new AccountServiceException('User does not have permission to update accounts');\n            }\n            update accounts;\n        } catch (DmlException e) {\n            System.debug(LoggingLevel.ERROR, 'DML Error: ' + e.getMessage());\n            throw new AccountServiceException('Failed to update accounts: ' + e.getMessage());\n        }\n    }\n}\n```\n\n### SOQL Best Practices\n\n- Use selective queries with indexed fields (`Id`, `Name`, `OwnerId`, custom indexed fields).\n- Limit query results with `LIMIT` clause when appropriate.\n- Use `LIMIT 1` when you only need one record.\n- Avoid `SELECT *` - always specify required fields.\n- Use relationship queries to minimize the number of SOQL queries.\n- Order queries by indexed fields when possible.\n- **Always use `String.escapeSingleQuotes()`** when using user input in SOQL queries to prevent SOQL injection attacks.\n- **Check query selectivity** - Aim for \u003e10% selectivity (filters reduce results to \u003c10% of total records).\n- Use **Query Plan** to verify query efficiency and index usage.\n- Test queries with realistic data volumes to ensure performance.\n\n```apex\n// Good Example - Selective query with indexed fields\nList\u003cAccount\u003e accounts = [\n    SELECT Id, Name, (SELECT Id, LastName FROM Contacts)\n    FROM Account\n    WHERE OwnerId = :UserInfo.getUserId()\n    AND CreatedDate = THIS_MONTH\n    LIMIT 100\n];\n\n// Good Example - LIMIT 1 for single record\nAccount account = [SELECT Id, Name FROM Account WHERE Name = 'Acme' LIMIT 1];\n\n// Good Example - escapeSingleQuotes() to prevent SOQL injection\nString searchTerm = String.escapeSingleQuotes(userInput);\nList\u003cAccount\u003e accounts = Database.query('SELECT Id, Name FROM Account WHERE Name LIKE \\'%' + searchTerm + '%\\'');\n\n// Bad Example - Direct user input without escaping (SECURITY RISK)\nList\u003cAccount\u003e accounts = Database.query('SELECT Id, Name FROM Account WHERE Name LIKE \\'%' + userInput + '%\\'');\n\n// Good Example - Selective query with indexed fields (high selectivity)\nList\u003cAccount\u003e accounts = [\n    SELECT Id, Name FROM Account\n    WHERE OwnerId = :UserInfo.getUserId()\n    AND CreatedDate = TODAY\n    LIMIT 100\n];\n\n// Bad Example - Non-selective query (scans entire table)\nList\u003cAccount\u003e accounts = [\n    SELECT Id, Name FROM Account\n    WHERE Description LIKE '%test%'  // Non-indexed field\n];\n\n// Check query performance in Developer Console:\n// 1. Enable 'Use Query Plan' in Developer Console\n// 2. Run SOQL query and review 'Query Plan' tab\n// 3. Look for 'Index' usage vs 'TableScan'\n// 4. Ensure selectivity \u003e 10% for optimal performance\n```\n\n### Trigger Best Practices\n\n- Use **one trigger per object** to maintain clarity and avoid conflicts.\n- Implement trigger logic in handler classes, not directly in triggers.\n- Use a trigger framework for consistent trigger management.\n- Leverage trigger context variables: `Trigger.new`, `Trigger.old`, `Trigger.newMap`, `Trigger.oldMap`.\n- Check trigger context: `Trigger.isBefore`, `Trigger.isAfter`, `Trigger.isInsert`, etc.\n\n```apex\n// Good Example - Trigger with handler pattern\ntrigger AccountTrigger on Account (before insert, before update, after insert, after update) {\n    new AccountTriggerHandler().run();\n}\n\n// Handler Class\npublic class AccountTriggerHandler extends TriggerHandler {\n    private List\u003cAccount\u003e newAccounts;\n    private List\u003cAccount\u003e oldAccounts;\n    private Map\u003cId, Account\u003e newAccountMap;\n    private Map\u003cId, Account\u003e oldAccountMap;\n\n    public AccountTriggerHandler() {\n        this.newAccounts = (List\u003cAccount\u003e) Trigger.new;\n        this.oldAccounts = (List\u003cAccount\u003e) Trigger.old;\n        this.newAccountMap = (Map\u003cId, Account\u003e) Trigger.newMap;\n        this.oldAccountMap = (Map\u003cId, Account\u003e) Trigger.oldMap;\n    }\n\n    public override void beforeInsert() {\n        AccountService.setDefaultValues(newAccounts);\n    }\n\n    public override void afterUpdate() {\n        AccountService.handleRatingChange(newAccountMap, oldAccountMap);\n    }\n}\n```\n\n### Code Quality Best Practices\n\n- **Use `isEmpty()`** - Check if collections are empty using built-in methods instead of size comparisons.\n- **Use Custom Labels** - Store user-facing text in Custom Labels for internationalization and maintainability.\n- **Use Constants** - Define constants for hardcoded values, error messages, and configuration values.\n- **Use `String.isBlank()` and `String.isNotBlank()`** - Check for null or empty strings properly.\n- **Use `String.valueOf()`** - Safely convert values to strings to avoid null pointer exceptions.\n- **Use safe navigation operator `?.`** - Access properties and methods safely without null pointer exceptions.\n- **Use null-coalescing operator `??`** - Provide default values for null expressions.\n- **Avoid using `+` for string concatenation in loops** - Use `String.join()` for better performance.\n- **Use Collection methods** - Leverage `List.clone()`, `Set.addAll()`, `Map.keySet()` for cleaner code.\n- **Use ternary operators** - For simple conditional assignments to improve readability.\n- **Use switch expressions** - Modern alternative to if-else chains for better readability and performance.\n- **Use SObject clone methods** - Properly clone SObjects when needed to avoid unintended references.\n\n```apex\n// Good Example - Switch expression (modern Apex)\nString rating = switch on account.AnnualRevenue {\n    when 0 { 'Cold'; }\n    when 1, 2, 3 { 'Warm'; }\n    when else { 'Hot'; }\n};\n\n// Good Example - Switch on SObjectType\nString objectLabel = switch on record {\n    when Account a { 'Account: ' + a.Name; }\n    when Contact c { 'Contact: ' + c.LastName; }\n    when else { 'Unknown'; }\n};\n\n// Bad Example - if-else chain\nString rating;\nif (account.AnnualRevenue == 0) {\n    rating = 'Cold';\n} else if (account.AnnualRevenue \u003e= 1 \u0026\u0026 account.AnnualRevenue \u003c= 3) {\n    rating = 'Warm';\n} else {\n    rating = 'Hot';\n}\n\n// Good Example - SObject clone methods\nAccount original = new Account(Name = 'Acme', Industry = 'Technology');\n\n// Shallow clone with ID and relationships\nAccount clone1 = original.clone(true, true);\n\n// Shallow clone without ID or relationships\nAccount clone2 = original.clone(false, false);\n\n// Deep clone with all relationships\nAccount clone3 = original.deepClone(true, true, true);\n\n// Good Example - isEmpty() instead of size comparison\nif (accountList.isEmpty()) {\n    System.debug('No accounts found');\n}\n\n// Bad Example - size comparison\nif (accountList.size() == 0) {\n    System.debug('No accounts found');\n}\n\n// Good Example - Custom Labels for user-facing text\nfinal String ERROR_MESSAGE = System.Label.Account_Update_Error;\nfinal String SUCCESS_MESSAGE = System.Label.Account_Update_Success;\n\n// Bad Example - Hardcoded strings\nfinal String ERROR_MESSAGE = 'An error occurred while updating the account';\n\n// Good Example - Constants for configuration values\npublic class AccountService {\n    private static final Integer MAX_RETRY_ATTEMPTS = 3;\n    private static final String DEFAULT_INDUSTRY = 'Technology';\n    private static final String ERROR_PREFIX = 'AccountService Error: ';\n\n    public static void processAccounts() {\n        // Use constants\n        if (retryCount \u003e MAX_RETRY_ATTEMPTS) {\n            throw new AccountServiceException(ERROR_PREFIX + 'Max retries exceeded');\n        }\n    }\n}\n\n// Good Example - isBlank() for null and empty checks\nif (String.isBlank(account.Name)) {\n    account.Name = DEFAULT_NAME;\n}\n\n// Bad Example - multiple null checks\nif (account.Name == null || account.Name == '') {\n    account.Name = DEFAULT_NAME;\n}\n\n// Good Example - String.valueOf() for safe conversion\nString accountId = String.valueOf(account.Id);\nString revenue = String.valueOf(account.AnnualRevenue);\n\n// Good Example - Safe navigation operator (?.)\nString ownerName = account?.Owner?.Name;\nInteger contactCount = account?.Contacts?.size();\n\n// Bad Example - Nested null checks\nString ownerName;\nif (account != null \u0026\u0026 account.Owner != null) {\n    ownerName = account.Owner.Name;\n}\n\n// Good Example - Null-coalescing operator (??)\nString accountName = account?.Name ?? 'Unknown Account';\nInteger revenue = account?.AnnualRevenue ?? 0;\nString industry = account?.Industry ?? DEFAULT_INDUSTRY;\n\n// Bad Example - Ternary with null check\nString accountName = account != null \u0026\u0026 account.Name != null ? account.Name : 'Unknown Account';\n\n// Good Example - Combining ?. and ??\nString email = contact?.Email ?? contact?.Account?.Owner?.Email ?? 'no-reply@example.com';\n\n// Good Example - String concatenation in loops\nList\u003cString\u003e accountNames = new List\u003cString\u003e();\nfor (Account acc : accounts) {\n    accountNames.add(acc.Name);\n}\nString result = String.join(accountNames, ', ');\n\n// Bad Example - String concatenation in loops\nString result = '';\nfor (Account acc : accounts) {\n    result += acc.Name + ', '; // Poor performance\n}\n\n// Good Example - Ternary operator\nString status = isActive ? 'Active' : 'Inactive';\n\n// Good Example - Collection methods\nList\u003cAccount\u003e accountsCopy = accountList.clone();\nSet\u003cId\u003e accountIds = new Set\u003cId\u003e(accountMap.keySet());\n```\n\n### Recursion Prevention\n\n- **Use static variables** to track recursive calls and prevent infinite loops.\n- Implement a **circuit breaker** pattern to stop execution after a threshold.\n- Document recursion limits and potential risks.\n\n```apex\n// Good Example - Recursion prevention with static variable\npublic class AccountTriggerHandler extends TriggerHandler {\n    private static Boolean hasRun = false;\n\n    public override void afterUpdate() {\n        if (!hasRun) {\n            hasRun = true;\n            AccountService.updateRelatedContacts(Trigger.newMap.keySet());\n        }\n    }\n}\n\n// Good Example - Circuit breaker with counter\npublic class OpportunityService {\n    private static Integer recursionCount = 0;\n    private static final Integer MAX_RECURSION_DEPTH = 5;\n\n    public static void processOpportunity(Id oppId) {\n        recursionCount++;\n\n        if (recursionCount \u003e MAX_RECURSION_DEPTH) {\n            System.debug(LoggingLevel.ERROR, 'Max recursion depth exceeded');\n            return;\n        }\n\n        try {\n            // Process opportunity logic\n        } finally {\n            recursionCount--;\n        }\n    }\n}\n```\n\n### Method Visibility and Encapsulation\n\n- **Use `private` by default** - Only expose methods that need to be public.\n- Use `protected` for methods that subclasses need to access.\n- Use `public` only for APIs that other classes need to call.\n- **Use `final` keyword** to prevent method override when appropriate.\n- Mark classes as `final` if they should not be extended.\n\n```apex\n// Good Example - Proper encapsulation\npublic class AccountService {\n    // Public API\n    public static void updateAccounts(List\u003cAccount\u003e accounts) {\n        validateAccounts(accounts);\n        performUpdate(accounts);\n    }\n\n    // Private helper - not exposed\n    private static void validateAccounts(List\u003cAccount\u003e accounts) {\n        for (Account acc : accounts) {\n            if (String.isBlank(acc.Name)) {\n                throw new IllegalArgumentException('Account name is required');\n            }\n        }\n    }\n\n    // Private implementation - not exposed\n    private static void performUpdate(List\u003cAccount\u003e accounts) {\n        update accounts;\n    }\n}\n\n// Good Example - Final keyword to prevent extension\npublic final class UtilityHelper {\n    // Cannot be extended\n    public static String formatCurrency(Decimal amount) {\n        return '$' + amount.setScale(2);\n    }\n}\n\n// Good Example - Final method to prevent override\npublic virtual class BaseService {\n    // Can be overridden\n    public virtual void process() {\n        // Implementation\n    }\n\n    // Cannot be overridden\n    public final void validateInput() {\n        // Critical validation that must not be changed\n    }\n}\n```\n\n### Design Patterns\n\n- **Service Layer Pattern**: Encapsulate business logic in service classes.\n- **Circuit Breaker Pattern**: Prevent repeated failures by stopping execution after threshold.\n- **Selector Pattern**: Create dedicated classes for SOQL queries.\n- **Domain Layer Pattern**: Implement domain classes for record-specific logic.\n- **Trigger Handler Pattern**: Use a consistent framework for trigger management.\n- **Builder Pattern**: Use for complex object construction.\n- **Strategy Pattern**: For implementing different behaviors based on conditions.\n\n```apex\n// Good Example - Service Layer Pattern\npublic class AccountService {\n    public static void updateAccountRatings(Set\u003cId\u003e accountIds) {\n        List\u003cAccount\u003e accounts = AccountSelector.selectByIds(accountIds);\n\n        for (Account acc : accounts) {\n            acc.Rating = calculateRating(acc);\n        }\n\n        update accounts;\n    }\n\n    private static String calculateRating(Account acc) {\n        if (acc.AnnualRevenue \u003e 1000000) {\n            return 'Hot';\n        } else if (acc.AnnualRevenue \u003e 500000) {\n            return 'Warm';\n        }\n        return 'Cold';\n    }\n}\n\n// Good Example - Circuit Breaker Pattern\npublic class ExternalServiceCircuitBreaker {\n    private static Integer failureCount = 0;\n    private static final Integer FAILURE_THRESHOLD = 3;\n    private static DateTime circuitOpenedTime;\n    private static final Integer RETRY_TIMEOUT_MINUTES = 5;\n\n    public static Boolean isCircuitOpen() {\n        if (circuitOpenedTime != null) {\n            // Check if retry timeout has passed\n            if (DateTime.now() \u003e circuitOpenedTime.addMinutes(RETRY_TIMEOUT_MINUTES)) {\n                // Reset circuit\n                failureCount = 0;\n                circuitOpenedTime = null;\n                return false;\n            }\n            return true;\n        }\n        return failureCount \u003e= FAILURE_THRESHOLD;\n    }\n\n    public static void recordFailure() {\n        failureCount++;\n        if (failureCount \u003e= FAILURE_THRESHOLD) {\n            circuitOpenedTime = DateTime.now();\n            System.debug(LoggingLevel.ERROR, 'Circuit breaker opened due to failures');\n        }\n    }\n\n    public static void recordSuccess() {\n        failureCount = 0;\n        circuitOpenedTime = null;\n    }\n\n    public static HttpResponse makeCallout(String endpoint) {\n        if (isCircuitOpen()) {\n            throw new CircuitBreakerException('Circuit is open. Service unavailable.');\n        }\n\n        try {\n            HttpRequest req = new HttpRequest();\n            req.setEndpoint(endpoint);\n            req.setMethod('GET');\n            HttpResponse res = new Http().send(req);\n\n            if (res.getStatusCode() == 200) {\n                recordSuccess();\n            } else {\n                recordFailure();\n            }\n            return res;\n        } catch (Exception e) {\n            recordFailure();\n            throw e;\n        }\n    }\n\n    public class CircuitBreakerException extends Exception {}\n}\n\n// Good Example - Selector Pattern\npublic class AccountSelector {\n    public static List\u003cAccount\u003e selectByIds(Set\u003cId\u003e accountIds) {\n        return [\n            SELECT Id, Name, AnnualRevenue, Rating\n            FROM Account\n            WHERE Id IN :accountIds\n            WITH SECURITY_ENFORCED\n        ];\n    }\n\n    public static List\u003cAccount\u003e selectActiveAccountsWithContacts() {\n        return [\n            SELECT Id, Name, (SELECT Id, LastName FROM Contacts)\n            FROM Account\n            WHERE IsActive__c = true\n            WITH SECURITY_ENFORCED\n        ];\n    }\n}\n```\n\n### Configuration Management\n\n#### Custom Metadata Types vs Custom Settings\n\n- **Prefer Custom Metadata Types (CMT)** for configuration data that can be deployed.\n- Use **Custom Settings** for user-specific or org-specific data that varies by environment.\n- CMT is packageable, deployable, and can be used in validation rules and formulas.\n- Custom Settings support hierarchy (Org, Profile, User) but are not deployable.\n\n```apex\n// Good Example - Using Custom Metadata Type\nList\u003cAPI_Configuration__mdt\u003e configs = [\n    SELECT Endpoint__c, Timeout__c, Max_Retries__c\n    FROM API_Configuration__mdt\n    WHERE DeveloperName = 'Production_API'\n    LIMIT 1\n];\n\nif (!configs.isEmpty()) {\n    String endpoint = configs[0].Endpoint__c;\n    Integer timeout = Integer.valueOf(configs[0].Timeout__c);\n}\n\n// Good Example - Using Custom Settings (user-specific)\nUser_Preferences__c prefs = User_Preferences__c.getInstance(UserInfo.getUserId());\nBoolean darkMode = prefs.Dark_Mode_Enabled__c;\n\n// Good Example - Using Custom Settings (org-level)\nOrg_Settings__c orgSettings = Org_Settings__c.getOrgDefaults();\nInteger maxRecords = Integer.valueOf(orgSettings.Max_Records_Per_Query__c);\n```\n\n#### Named Credentials and HTTP Callouts\n\n- **Always use Named Credentials** for external API endpoints and authentication.\n- Avoid hardcoding URLs, tokens, or credentials in code.\n- Use `callout:NamedCredential` syntax for secure, deployable integrations.\n- **Always check HTTP status codes** and handle errors gracefully.\n- Set appropriate timeouts to prevent long-running callouts.\n- Use `Database.AllowsCallouts` interface for Queueable and Batchable classes.\n\n```apex\n// Good Example - Using Named Credentials\npublic class ExternalAPIService {\n    private static final String NAMED_CREDENTIAL = 'callout:External_API';\n    private static final Integer TIMEOUT_MS = 120000; // 120 seconds\n\n    public static Map\u003cString, Object\u003e getExternalData(String recordId) {\n        HttpRequest req = new HttpRequest();\n        req.setEndpoint(NAMED_CREDENTIAL + '/api/records/' + recordId);\n        req.setMethod('GET');\n        req.setTimeout(TIMEOUT_MS);\n        req.setHeader('Content-Type', 'application/json');\n\n        try {\n            Http http = new Http();\n            HttpResponse res = http.send(req);\n\n            if (res.getStatusCode() == 200) {\n                return (Map\u003cString, Object\u003e) JSON.deserializeUntyped(res.getBody());\n            } else if (res.getStatusCode() == 404) {\n                throw new NotFoundException('Record not found: ' + recordId);\n            } else if (res.getStatusCode() \u003e= 500) {\n                throw new ServiceUnavailableException('External service error: ' + res.getStatus());\n            } else {\n                throw new CalloutException('Unexpected response: ' + res.getStatusCode());\n            }\n        } catch (System.CalloutException e) {\n            System.debug(LoggingLevel.ERROR, 'Callout failed: ' + e.getMessage());\n            throw new ExternalAPIException('Failed to retrieve data', e);\n        }\n    }\n\n    public class ExternalAPIException extends Exception {}\n    public class NotFoundException extends Exception {}\n    public class ServiceUnavailableException extends Exception {}\n}\n\n// Good Example - POST request with JSON body\npublic static String createExternalRecord(Map\u003cString, Object\u003e data) {\n    HttpRequest req = new HttpRequest();\n    req.setEndpoint(NAMED_CREDENTIAL + '/api/records');\n    req.setMethod('POST');\n    req.setTimeout(TIMEOUT_MS);\n    req.setHeader('Content-Type', 'application/json');\n    req.setBody(JSON.serialize(data));\n\n    HttpResponse res = new Http().send(req);\n\n    if (res.getStatusCode() == 201) {\n        Map\u003cString, Object\u003e result = (Map\u003cString, Object\u003e) JSON.deserializeUntyped(res.getBody());\n        return (String) result.get('id');\n    } else {\n        throw new CalloutException('Failed to create record: ' + res.getStatus());\n    }\n}\n```\n\n### Common Annotations\n\n- `@AuraEnabled` - Expose methods to Lightning Web Components and Aura Components.\n- `@AuraEnabled(cacheable=true)` - Enable client-side caching for read-only methods.\n- `@InvocableMethod` - Make methods callable from Flow and Process Builder.\n- `@InvocableVariable` - Define input/output parameters for invocable methods.\n- `@TestVisible` - Expose private members to test classes only.\n- `@SuppressWarnings('PMD.RuleName')` - Suppress specific PMD warnings.\n- `@RemoteAction` - Expose methods for Visualforce JavaScript remoting (legacy).\n- `@Future` - Execute methods asynchronously.\n- `@Future(callout=true)` - Allow HTTP callouts in future methods.\n\n```apex\n// Good Example - AuraEnabled for LWC\npublic with sharing class AccountController {\n    @AuraEnabled(cacheable=true)\n    public static List\u003cAccount\u003e getAccounts() {\n        return [SELECT Id, Name FROM Account WITH SECURITY_ENFORCED LIMIT 10];\n    }\n\n    @AuraEnabled\n    public static void updateAccount(Id accountId, String newName) {\n        Account acc = new Account(Id = accountId, Name = newName);\n        update acc;\n    }\n}\n\n// Good Example - InvocableMethod for Flow\npublic class FlowActions {\n    @InvocableMethod(label='Send Email Notification' description='Sends email to account owner')\n    public static List\u003cResult\u003e sendNotification(List\u003cRequest\u003e requests) {\n        List\u003cResult\u003e results = new List\u003cResult\u003e();\n\n        for (Request req : requests) {\n            Result result = new Result();\n            try {\n                // Send email logic\n                result.success = true;\n                result.message = 'Email sent successfully';\n            } catch (Exception e) {\n                result.success = false;\n                result.message = e.getMessage();\n            }\n            results.add(result);\n        }\n        return results;\n    }\n\n    public class Request {\n        @InvocableVariable(required=true label='Account ID')\n        public Id accountId;\n\n        @InvocableVariable(label='Email Template')\n        public String templateName;\n    }\n\n    public class Result {\n        @InvocableVariable\n        public Boolean success;\n\n        @InvocableVariable\n        public String message;\n    }\n}\n\n// Good Example - TestVisible for testing private methods\npublic class AccountService {\n    @TestVisible\n    private static Boolean validateAccountName(String name) {\n        return String.isNotBlank(name) \u0026\u0026 name.length() \u003e 3;\n    }\n}\n```\n\n### Asynchronous Apex\n\n- Use **@future** methods for simple asynchronous operations and callouts.\n- Use **Queueable Apex** for complex asynchronous operations that require chaining.\n- Use **Batch Apex** for processing large data volumes (\u003e50,000 records).\n  - Use `Database.Stateful` to maintain state across batch executions (e.g., counters, aggregations).\n  - Without `Database.Stateful`, batch classes are stateless and instance variables reset between batches.\n  - Be mindful of governor limits when using stateful batches.\n- Use **Scheduled Apex** for recurring operations.\n  - Create a separate **Schedulable class** to schedule batch jobs.\n  - Never implement both `Database.Batchable` and `Schedulable` in the same class.\n- Use **Platform Events** for event-driven architecture and decoupled integrations.\n  - Publish events using `EventBus.publish()` for asynchronous, fire-and-forget communication.\n  - Subscribe to events using triggers on platform event objects.\n  - Ideal for integrations, microservices, and cross-org communication.\n- **Optimize batch size** based on processing complexity and governor limits.\n  - Default batch size is 200, but can be adjusted from 1 to 2000.\n  - Smaller batches (50-100) for complex processing or callouts.\n  - Larger batches (200) for simple DML operations.\n  - Test with realistic data volumes to find optimal size.\n\n```apex\n// Good Example - Platform Events for decoupled communication\npublic class OrderEventPublisher {\n    public static void publishOrderCreated(List\u003cOrder\u003e orders) {\n        List\u003cOrder_Created__e\u003e events = new List\u003cOrder_Created__e\u003e();\n\n        for (Order ord : orders) {\n            Order_Created__e event = new Order_Created__e(\n                Order_Id__c = ord.Id,\n                Order_Amount__c = ord.TotalAmount,\n                Customer_Id__c = ord.AccountId\n            );\n            events.add(event);\n        }\n\n        // Publish events\n        List\u003cDatabase.SaveResult\u003e results = EventBus.publish(events);\n\n        // Check for errors\n        for (Database.SaveResult result : results) {\n            if (!result.isSuccess()) {\n                for (Database.Error error : result.getErrors()) {\n                    System.debug('Error publishing event: ' + error.getMessage());\n                }\n            }\n        }\n    }\n}\n\n// Good Example - Platform Event Trigger (Subscriber)\ntrigger OrderCreatedTrigger on Order_Created__e (after insert) {\n    List\u003cTask\u003e tasksToCreate = new List\u003cTask\u003e();\n\n    for (Order_Created__e event : Trigger.new) {\n        Task t = new Task(\n            Subject = 'Follow up on order',\n            WhatId = event.Order_Id__c,\n            Priority = 'High'\n        );\n        tasksToCreate.add(t);\n    }\n\n    if (!tasksToCreate.isEmpty()) {\n        insert tasksToCreate;\n    }\n}\n\n// Good Example - Batch size optimization based on complexity\npublic class ComplexProcessingBatch implements Database.Batchable\u003cSObject\u003e, Database.AllowsCallouts {\n    public Database.QueryLocator start(Database.BatchableContext bc) {\n        return Database.getQueryLocator([\n            SELECT Id, Name FROM Account WHERE IsActive__c = true\n        ]);\n    }\n\n    public void execute(Database.BatchableContext bc, List\u003cAccount\u003e scope) {\n        // Complex processing with callouts - use smaller batch size\n        for (Account acc : scope) {\n            // Make HTTP callout\n            HttpResponse res = ExternalAPIService.getAccountData(acc.Id);\n            // Process response\n        }\n    }\n\n    public void finish(Database.BatchableContext bc) {\n        System.debug('Batch completed');\n    }\n}\n\n// Execute with smaller batch size for callout-heavy processing\nDatabase.executeBatch(new ComplexProcessingBatch(), 50);\n\n// Good Example - Simple DML batch with default size\npublic class SimpleDMLBatch implements Database.Batchable\u003cSObject\u003e {\n    public Database.QueryLocator start(Database.BatchableContext bc) {\n        return Database.getQueryLocator([\n            SELECT Id, Status__c FROM Order WHERE Status__c = 'Draft'\n        ]);\n    }\n\n    public void execute(Database.BatchableContext bc, List\u003cOrder\u003e scope) {\n        for (Order ord : scope) {\n            ord.Status__c = 'Pending';\n        }\n        update scope;\n    }\n\n    public void finish(Database.BatchableContext bc) {\n        System.debug('Batch completed');\n    }\n}\n\n// Execute with larger batch size for simple DML\nDatabase.executeBatch(new SimpleDMLBatch(), 200);\n\n// Good Example - Queueable Apex\npublic class EmailNotificationQueueable implements Queueable, Database.AllowsCallouts {\n    private List\u003cId\u003e accountIds;\n\n    public EmailNotificationQueueable(List\u003cId\u003e accountIds) {\n        this.accountIds = accountIds;\n    }\n\n    public void execute(QueueableContext context) {\n        List\u003cAccount\u003e accounts = [SELECT Id, Name, Email__c FROM Account WHERE Id IN :accountIds];\n\n        for (Account acc : accounts) {\n            sendEmail(acc);\n        }\n\n        // Chain another job if needed\n        if (hasMoreWork()) {\n            System.enqueueJob(new AnotherQueueable());\n        }\n    }\n\n    private void sendEmail(Account acc) {\n        // Email sending logic\n    }\n\n    private Boolean hasMoreWork() {\n        return false;\n    }\n}\n\n// Good Example - Stateless Batch Apex (default)\npublic class AccountCleanupBatch implements Database.Batchable\u003cSObject\u003e {\n    public Database.QueryLocator start(Database.BatchableContext bc) {\n        return Database.getQueryLocator([\n            SELECT Id, Name FROM Account WHERE LastActivityDate \u003c LAST_N_DAYS:365\n        ]);\n    }\n\n    public void execute(Database.BatchableContext bc, List\u003cAccount\u003e scope) {\n        delete scope;\n    }\n\n    public void finish(Database.BatchableContext bc) {\n        System.debug('Batch completed');\n    }\n}\n\n// Good Example - Stateful Batch Apex (maintains state across batches)\npublic class AccountStatsBatch implements Database.Batchable\u003cSObject\u003e, Database.Stateful {\n    private Integer recordsProcessed = 0;\n    private Integer totalRevenue = 0;\n\n    public Database.QueryLocator start(Database.BatchableContext bc) {\n        return Database.getQueryLocator([\n            SELECT Id, Name, AnnualRevenue FROM Account WHERE IsActive__c = true\n        ]);\n    }\n\n    public void execute(Database.BatchableContext bc, List\u003cAccount\u003e scope) {\n        for (Account acc : scope) {\n            recordsProcessed++;\n            totalRevenue += (Integer) acc.AnnualRevenue;\n        }\n    }\n\n    public void finish(Database.BatchableContext bc) {\n        // State is maintained: recordsProcessed and totalRevenue retain their values\n        System.debug('Total records processed: ' + recordsProcessed);\n        System.debug('Total revenue: ' + totalRevenue);\n\n        // Send summary email or create summary record\n    }\n}\n\n// Good Example - Schedulable class to schedule a batch\npublic class AccountCleanupScheduler implements Schedulable {\n    public void execute(SchedulableContext sc) {\n        // Execute the batch with batch size of 200\n        Database.executeBatch(new AccountCleanupBatch(), 200);\n    }\n}\n\n// Schedule the batch to run daily at 2 AM\n// Execute this in Anonymous Apex or in setup code:\n// String cronExp = '0 0 2 * * ?';\n// System.schedule('Daily Account Cleanup', cronExp, new AccountCleanupScheduler());\n```\n\n## Testing\n\n- **Always achieve 100% code coverage** for production code (minimum 75% required).\n- Write **meaningful tests** that verify business logic, not just code coverage.\n- Use `@TestSetup` methods to create test data shared across test methods.\n- Use `Test.startTest()` and `Test.stopTest()` to reset governor limits.\n- Test **positive scenarios**, **negative scenarios**, and **bulk scenarios** (200+ records).\n- Use `System.runAs()` to test different user contexts and permissions.\n- Mock external callouts using `Test.setMock()`.\n- Never use `@SeeAllData=true` - always create test data in tests.\n- **Use the `Assert` class methods** for assertions instead of deprecated `System.assert*()` methods.\n- Always add descriptive failure messages to assertions for clarity.\n\n```apex\n// Good Example - Comprehensive test class\n@IsTest\nprivate class AccountServiceTest {\n    @TestSetup\n    static void setupTestData() {\n        List\u003cAccount\u003e accounts = new List\u003cAccount\u003e();\n        for (Integer i = 0; i \u003c 200; i++) {\n            accounts.add(new Account(\n                Name = 'Test Account ' + i,\n                AnnualRevenue = i * 10000\n            ));\n        }\n        insert accounts;\n    }\n\n    @IsTest\n    static void testUpdateAccountRatings_Positive() {\n        // Arrange\n        List\u003cAccount\u003e accounts = [SELECT Id FROM Account];\n        Set\u003cId\u003e accountIds = new Map\u003cId, Account\u003e(accounts).keySet();\n\n        // Act\n        Test.startTest();\n        AccountService.updateAccountRatings(accountIds);\n        Test.stopTest();\n\n        // Assert\n        List\u003cAccount\u003e updatedAccounts = [\n            SELECT Id, Rating FROM Account WHERE AnnualRevenue \u003e 1000000\n        ];\n        for (Account acc : updatedAccounts) {\n            Assert.areEqual('Hot', acc.Rating, 'Rating should be Hot for high revenue accounts');\n        }\n    }\n\n    @IsTest\n    static void testUpdateAccountRatings_NoAccess() {\n        // Create user with limited access\n        User testUser = createTestUser();\n\n        List\u003cAccount\u003e accounts = [SELECT Id FROM Account LIMIT 1];\n        Set\u003cId\u003e accountIds = new Map\u003cId, Account\u003e(accounts).keySet();\n\n        Test.startTest();\n        System.runAs(testUser) {\n            try {\n                AccountService.updateAccountRatings(accountIds);\n                Assert.fail('Expected SecurityException');\n            } catch (SecurityException e) {\n                Assert.isTrue(true, 'SecurityException thrown as expected');\n            }\n        }\n        Test.stopTest();\n    }\n\n    @IsTest\n    static void testBulkOperation() {\n        List\u003cAccount\u003e accounts = [SELECT Id FROM Account];\n        Set\u003cId\u003e accountIds = new Map\u003cId, Account\u003e(accounts).keySet();\n\n        Test.startTest();\n        AccountService.updateAccountRatings(accountIds);\n        Test.stopTest();\n\n        List\u003cAccount\u003e updatedAccounts = [SELECT Id, Rating FROM Account];\n        Assert.areEqual(200, updatedAccounts.size(), 'All accounts should be processed');\n    }\n\n    private static User createTestUser() {\n        Profile p = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1];\n        return new User(\n            Alias = 'testuser',\n            Email = 'testuser@test.com',\n            EmailEncodingKey = 'UTF-8',\n            LastName = 'Testing',\n            LanguageLocaleKey = 'en_US',\n            LocaleSidKey = 'en_US',\n            ProfileId = p.Id,\n            TimeZoneSidKey = 'America/Los_Angeles',\n            UserName = 'testuser' + DateTime.now().getTime() + '@test.com'\n        );\n    }\n}\n```\n\n## Common Code Smells and Anti-Patterns\n\n- **DML/SOQL in loops** - Always bulkify your code to avoid governor limit exceptions.\n- **Hardcoded IDs** - Use custom settings, custom metadata, or dynamic queries instead.\n- **Deeply nested conditionals** - Extract logic into separate methods for clarity.\n- **Large methods** - Keep methods focused on a single responsibility (max 30-50 lines).\n- **Magic numbers** - Use named constants for clarity and maintainability.\n- **Duplicate code** - Extract common logic into reusable methods or classes.\n- **Missing null checks** - Always validate input parameters and query results.\n\n```apex\n// Bad Example - DML in loop\nfor (Account acc : accounts) {\n    acc.Rating = 'Hot';\n    update acc; // AVOID: DML in loop\n}\n\n// Good Example - Bulkified DML\nfor (Account acc : accounts) {\n    acc.Rating = 'Hot';\n}\nupdate accounts;\n\n// Bad Example - Hardcoded ID\nAccount acc = [SELECT Id FROM Account WHERE Id = '001000000000001'];\n\n// Good Example - Dynamic query\nAccount acc = [SELECT Id FROM Account WHERE Name = :accountName LIMIT 1];\n\n// Bad Example - Magic number\nif (accounts.size() \u003e 200) {\n    // Process\n}\n\n// Good Example - Named constant\nprivate static final Integer MAX_BATCH_SIZE = 200;\nif (accounts.size() \u003e MAX_BATCH_SIZE) {\n    // Process\n}\n```\n\n## Documentation and Comments\n\n- Use JavaDoc-style comments for classes and methods.\n- Include `@author` and `@date` tags for tracking.\n- Include `@description`, `@param`, `@return`, and `@throws` tags.\n- Include `@param`, `@return`, and `@throws` tags **only** when applicable.\n- Do not use `@return void` for methods that return nothing.\n- Document complex business logic and design decisions.\n- Keep comments up-to-date with code changes.\n\n```apex\n/**\n * @author Your Name\n * @date 2025-01-01\n * @description Service class for managing Account records\n */\npublic with sharing class AccountService {\n\n    /**\n     * @author Your Name\n     * @date 2025-01-01\n     * @description Updates the rating for accounts based on annual revenue\n     * @param accountIds Set of Account IDs to update\n     * @throws AccountServiceException if user lacks update permissions\n     */\n    public static void updateAccountRatings(Set\u003cId\u003e accountIds) {\n        // Implementation\n    }\n}\n```\n\n## Deployment and DevOps\n\n- Use **Salesforce CLI** for source-driven development.\n- Leverage **scratch orgs** for development and testing.\n- Implement **CI/CD pipelines** using tools like Salesforce CLI, GitHub Actions, or Jenkins.\n- Use **unlocked packages** for modular deployments.\n- Run **Apex tests** as part of deployment validation.\n- Use **Salesforce Code Analyzer** to scan code for quality and security issues.\n\n```bash\n# Salesforce CLI commands (sf)\nsf project deploy start                    # Deploy source to org\nsf project deploy start --dry-run          # Validate deployment without deploying\nsf apex run test --test-level RunLocalTests # Run local Apex tests\nsf apex get test --test-run-id \u003cid\u003e        # Get test results\nsf project retrieve start                  # Retrieve source from org\n\n# Salesforce Code Analyzer commands\nsf code-analyzer rules                     # List all available rules\nsf code-analyzer rules --rule-selector eslint:Recommended  # List recommended ESLint rules\nsf code-analyzer rules --workspace ./force-app             # List rules for specific workspace\nsf code-analyzer run                       # Run analysis with recommended rules\nsf code-analyzer run --rule-selector pmd:Recommended       # Run PMD recommended rules\nsf code-analyzer run --rule-selector \"Security\"           # Run rules with Security tag\nsf code-analyzer run --workspace ./force-app --target \"**/*.cls\"  # Analyze Apex classes\nsf code-analyzer run --severity-threshold 3               # Run analysis with severity threshold\nsf code-analyzer run --output-file results.html           # Output results to HTML file\nsf code-analyzer run --output-file results.csv            # Output results to CSV file\nsf code-analyzer run --view detail                        # Show detailed violation information\n```\n\n## Performance Optimization\n\n- Use **selective SOQL queries** with indexed fields.\n- Implement **lazy loading** for expensive operations.\n- Use **asynchronous processing** for long-running operations.\n- Monitor with **Debug Logs** and **Event Monitoring**.\n- Use **ApexGuru** and **Scale Center** for performance insights.\n\n### Platform Cache\n\n- Use **Platform Cache** to store frequently accessed data and reduce SOQL queries.\n- `Cache.OrgPartition` - Shared across all users and sessions in the org.\n- `Cache.SessionPartition` - Specific to a user's session.\n- Implement proper cache invalidation strategies.\n- Handle cache misses gracefully with fallback to database queries.\n\n```apex\n// Good Example - Using Org Cache\npublic class AccountCacheService {\n    private static final String CACHE_PARTITION = 'local.AccountCache';\n    private static final Integer TTL_SECONDS = 3600; // 1 hour\n\n    public static Account getAccount(Id accountId) {\n        Cache.OrgPartition orgPart = Cache.Org.getPartition(CACHE_PARTITION);\n        String cacheKey = 'Account_' + accountId;\n\n        // Try to get from cache\n        Account acc = (Account) orgPart.get(cacheKey);\n\n        if (acc == null) {\n            // Cache miss - query database\n            acc = [\n                SELECT Id, Name, Industry, AnnualRevenue\n                FROM Account\n                WHERE Id = :accountId\n                LIMIT 1\n            ];\n\n            // Store in cache with TTL\n            orgPart.put(cacheKey, acc, TTL_SECONDS);\n        }\n\n        return acc;\n    }\n\n    public static void invalidateCache(Id accountId) {\n        Cache.OrgPartition orgPart = Cache.Org.getPartition(CACHE_PARTITION);\n        String cacheKey = 'Account_' + accountId;\n        orgPart.remove(cacheKey);\n    }\n}\n\n// Good Example - Using Session Cache\npublic class UserPreferenceCache {\n    private static final String CACHE_PARTITION = 'local.UserPrefs';\n\n    public static Map\u003cString, Object\u003e getUserPreferences() {\n        Cache.SessionPartition sessionPart = Cache.Session.getPartition(CACHE_PARTITION);\n        String cacheKey = 'UserPrefs_' + UserInfo.getUserId();\n\n        Map\u003cString, Object\u003e prefs = (Map\u003cString, Object\u003e) sessionPart.get(cacheKey);\n\n        if (prefs == null) {\n            // Load preferences from database or custom settings\n            prefs = new Map\u003cString, Object\u003e{\n                'theme' =\u003e 'dark',\n                'language' =\u003e 'en_US'\n            };\n            sessionPart.put(cacheKey, prefs);\n        }\n\n        return prefs;\n    }\n}\n```\n\n## Build and Verification\n\n- After adding or modifying code, verify the project continues to build successfully.\n- Run all relevant Apex test classes to ensure no regressions.\n- Use Salesforce CLI: `sf apex run test --test-level RunLocalTests`\n- Ensure code coverage meets the minimum 75% requirement (aim for 100%).\n- Use Salesforce Code Analyzer to check for code quality issues: `sf code-analyzer run --severity-threshold 2`\n- Review violations and address them before deployment.\n","description":"Guidelines and best practices for Apex development on the Salesforce Platform","import":{"commit_sha":"541b7819d8c3545c6df122491af4fa1eae415779","imported_at":"2026-05-18T20:05:35Z","license_text":"MIT License\n\nCopyright GitHub, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","owner":"github","repo":"github/awesome-copilot","source_url":"https://github.com/github/awesome-copilot/blob/541b7819d8c3545c6df122491af4fa1eae415779/instructions/apex.instructions.md"},"manifest":{}},"content_hash":[203,101,25,153,228,104,32,208,31,102,248,166,129,100,60,168,44,73,91,183,33,97,47,232,134,37,61,231,64,17,119,149],"trust_level":"unsigned","yanked":false}
