Skip to content

Commit

Permalink
Minlopro: Code Conventions (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
awesomeandrey authored Nov 29, 2024
2 parents 4219569 + 6a19ee0 commit 156bfd0
Show file tree
Hide file tree
Showing 17 changed files with 245 additions and 38 deletions.
175 changes: 175 additions & 0 deletions CODECONVENTIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Code Conventions

- [Introduction](#introduction)
- [General Best Practices](#general-best-practices)
- [Code Conventions](#code-conventions)
- [Apex Classes](#apex-classes)
- [Naming Conventions](#naming-conventions)
- [Critical Coding Standards](#critical-coding-standards)
- [Class Design](#class-design)
- [Unit Tests](#unit-tests)
- [LWC (Lightning Web Components)](#lwc-lightning-web-components)
- [Naming Conventions](#naming-conventions-1)
- [Critical Coding Standards](#critical-coding-standards-1)
- [Aura Components](#aura-components)
- [Naming Conventions](#naming-conventions-2)
- [Critical Coding Standards](#critical-coding-standards-2)

## Introduction

This guide serves as a comprehensive reference for Salesforce developers, covering best practices and conventions to ensure consistency, maintainability, and scalability across projects.

---

## General Best Practices

- Every declarative metadata component (flow, custom object, custom field etc.) must have clear & meaningful description provided.
- Configure/wWrite polite, user-friendly error messages.
- Example: Prefer “Please provide a value for the Status field” over “Missing required field.”
- Avoid hardcoding sensitive data like IDs or credentials.
- Design your logic to handle large data sets and avoid hitting Salesforce's governor limits.

---

## Code Conventions

### Apex Classes

#### Naming Conventions

1. **Classes**:
- Use PascalCase (e.g., `AccountTriggerHandler`).
- Test classes should append `Test` to the name (e.g., `AccountServiceTest`).
2. **Variables**:
- Use camelCase (e.g., `recordIndex`).
- Avoid single-character variables except in loop counters.
3. **Methods**:
- Start with a lowercase letter and use camelCase (e.g., `fetchCustomerRecords`).
4. **Constants**:
- Use uppercase with underscores (e.g., `MAX_LIMIT`).

#### Critical Coding Standards

1. Use **PascalCase** for class names and **camelCase** for method and variable names.
2. Write one trigger per object and delegate logic to handler classes.
3. Always bulkify your code to handle collections of records efficiently.
4. Avoid SOQL or DML operations inside loops.
5. Use `Queueable` Apex for asynchronous processing when logic doesn’t need to run immediately.
6. Never hardcode IDs, user names, or sensitive data in your code.
7. Always check for **CRUD** and **FLS** permissions before performing DML or SOQL operations.
8. Use `try-catch` blocks for error handling, and throw custom exceptions for clarity.
9. Use `addError()` in triggers to provide user-friendly validation error messages.
10. Avoid SOQL queries without `WHERE` clauses or `LIMIT` to prevent retrieving excessive records.
11. Use `RecordType.DeveloperName` instead of `RecordType.Name` for better locale-independent queries.
12. Write descriptive comments for methods, classes, and complex logic to improve readability.
13. Use **Separation of Concerns**: divide logic into service, controller, and utility classes.
14. Mock data and external calls in unit tests to avoid dependency on dynamic data.
15. Avoid HTTP callouts within loops; batch them or use Asynchronous Apex.

#### Class Design

Follow the separation of concerns (SoC) principle:

- **Controller Classes**: Handle UI-related logic.
- **Service Classes**: Contain business logic.
- **Selector Classes**: Perform SOQL queries.

Example Class Structure:

```apex
public with sharing class AccountService {
public void processAccounts(List<Account> accounts) {
// Business logic
}
}
```

#### Unit Tests

1. Ensure every test method has clear, descriptive names that indicate the purpose of the test.
2. Aim for **100% code coverage**, with at least **85% coverage** as the minimum standard.
3. Write unit tests for both **positive** and **negative** scenarios to cover all use cases.
4. Use `Test.startTest()` and `Test.stopTest()` to reset governor limits and isolate test execution.
5. Create all necessary test data programmatically within the test method using utility classes or static methods.
6. Never rely on existing data in the database for tests - avoid `@SeeAllData=true` annotation.
7. Use mocking frameworks like **ApexMocks** to mock data, external services, and dependent methods.
8. Avoid using real DML operations in tests where possible; use mock objects to test business logic.
9. Test **bulk operations** by inserting or updating 200 records to simulate real-world scenarios.
10. Include meaningful **assertions** to validate expected outcomes.
11. Test for exceptions explicitly using `Assert.fail` or `try-catch` blocks.
12. Avoid hardcoding IDs, record names, or other sensitive data in test methods.
13. Verify CRUD and FLS permissions in tests to simulate different user profiles and permissions.
14. Use test classes to validate that SOQL and DML operations respect governor limits and query performance.

---

### LWC (Lightning Web Components)

#### Naming Conventions

1. Use **camelCase** for JavaScript variables and methods (e.g., `handleButtonClick`).
2. Use descriptive names for public properties and annotate them with `@api` (e.g., `@api accountId`).
3. Use meaningful event names prefixed by the component name (e.g., `accountSelected`).
4. Use PascalCase for class names in JavaScript (e.g., `AccountOverview`).
5. Prefer [SLDS](https://www.lightningdesignsystem.com) CSS classes over custom ones for styling purposes.
6. For reusable components, append `-util` or `-helper` to the name (e.g., `date-picker-util`).
7. Use `handle<EventName>` for event handler names (e.g., `handleSaveClick`).
8. Define constant values in uppercase with underscores (e.g., `MAX_ITEMS`).
9. Use `camelCase` for HTML template bindings and JavaScript properties (e.g., `isVisible`).
10. Avoid abbreviations in names unless widely recognized (e.g., use `calculateTotal`, not `calcTotal`).
11. Use singular or plural naming based on the context (e.g., `product` for a single item, `products` for lists).

#### Critical Coding Standards

1. Always use `@api` to define public properties and methods explicitly.
2. Avoid hardcoding object or field names; use dynamic binding or Lightning Data Service (LDS).
3. Use two-way data binding (`getter` and `setter`) for calculated or reactive properties.
4. Avoid business logic in components; delegate to Apex or utility classes for maintainability.
5. Do not manipulate the DOM directly; rely on framework methods and lifecycle hooks.
6. Use `template.querySelector` only when necessary, and avoid global selectors.
7. Always clean up resources like intervals, event listeners, or timers in the `disconnectedCallback`.
8. Follow HTML structure conventions: slot attributes first, system properties next, and event handlers last.
9. Use `import` for sharing JavaScript utilities across components (e.g., `import { calculateTax } from 'c/utils'`).
10. Leverage CSS custom properties for theming instead of inline styles.
11. Use `lightning` components wherever possible instead of custom implementations (e.g., `lightning-input`).
12. Avoid circular dependencies by properly structuring imports and exports.
13. Use the `wired` decorator (`@wire`) to connect to Salesforce data and cache results for efficiency.
14. Validate user input at both the component level and in the backend (Apex).
15. Ensure every event dispatched uses `CustomEvent` and bubbles only when necessary.

---

### Aura Components

#### Naming Conventions

1. Use **camelCase** for attribute names (e.g., `recordId`).
2. Use **PascalCase** for component names (e.g., `AccountDetails`).
3. Use a descriptive name for component events with an appropriate suffix (e.g., `onAccountSelect`).
4. Prefer [SLDS](https://www.lightningdesignsystem.com) CSS classes over custom ones for styling purposes.
5. Name application events descriptively and append `Evt` (e.g., `AccountSelectedEvt`).
6. Append `Container` to the name of wrapper components (e.g., `AccountContainer`).
7. Prefix custom CSS classes with the component name to avoid global conflicts (e.g., `accountDetails__header`).
8. Use the same name for event and handler where applicable (e.g., `saveButtonClick` for `onSaveButtonClick`).
9. Use `handle<EventName>` for JavaScript handler functions (e.g., `handleAccountSave`).
10. Constants in JavaScript should be named in uppercase with underscores (e.g., `MAX_RECORDS`).
11. Avoid abbreviations in names unless they are widely recognized (e.g., use `Component` instead of `Cmp`).
12. Use singular or plural naming based on the purpose (e.g., `account` for one record, `accounts` for collections).

#### Critical Coding Standards

1. Always use **attributes** with proper `type` definitions (e.g., `type="String"`).
2. Define default values for attributes where applicable using the `default` attribute.
3. Minimize business logic in the controller; delegate logic to helper methods.
4. Use `event.getParam()` and avoid directly accessing event parameters for flexibility.
5. Avoid hardcoding field and object names; use dynamic references or design patterns.
6. Use `action.setParams()` and avoid passing too many parameters in Apex methods.
7. Validate data at both the client and server-side for security and consistency.
8. Use `aura:if` sparingly; prefer dynamic expressions in `aura:iteration`.
9. Always handle `callback` responses from server-side controllers to manage state or errors.
10. Dispatch meaningful and user-friendly error messages to the UI on server-side errors.
11. Avoid deep nesting of components; aim for flatter hierarchies for better readability.
12. Cache frequently used data in component-level attributes to reduce server calls.
13. Use descriptive comments for each function, especially helper methods and server calls.

---
48 changes: 26 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@
<span>[![Release](https://github.com/awesomeandrey/minlopro-dx/actions/workflows/release_workflow.yml/badge.svg?branch=main)](https://github.com/awesomeandrey/minlopro-dx/actions/workflows/release_workflow.yml)</span>
<span>[![Reset Destructive Manifests](https://github.com/awesomeandrey/minlopro-dx/actions/workflows/reset_destructive_manifests.yml/badge.svg)](https://github.com/awesomeandrey/minlopro-dx/actions/workflows/reset_destructive_manifests.yml)</span>

- [About](#about)
- [Prerequisites](#prerequisites)
- [Branches](#branches)
- [Release Branch Preparation](#release-branch-preparation)
- [Managing Environment Variables](#managing-environment-variables)
- [Scripts in `package.json`](#scripts-in-packagejson)
- [Useful Commands](#useful-commands)
- [Code Convention](#code-convention)

## About

<span style="display: inline-flex; align-items: center;">
<img src="assets/images/MinloproAppLogoMin.png" alt="Minlopro" width="50" style="margin-right: 8px;">
This is a blueprint repository for a typical Salesforce org-based project which is accompanied with CI/CD automations.
</span>
<img src="assets/images/MinloproAppLogoMin.png" alt="Minlopro" width="50">

This is a blueprint repository for a typical Salesforce org-based project which is accompanied with CI/CD automations.

## Prerequisites

Expand All @@ -24,7 +32,7 @@ for configuring `$JAVA_HOME` environment variable.

Additionally install utility tools as follows: [`jq`](https://www.baeldung.com/linux/jq-command-json), [`xmllint`](https://www.baeldung.com/linux/xmllint), [`xmlstarlet`](https://xmlstar.sourceforge.net).

Run `bash ./scripts/deploy/build.sh` in order to load project dependencies.
Run `bash ./scripts/deploy/build.sh` in order to load project dependencies (including [Salesforce CLI](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_unified.htm)).

Look through the pre-configured GitHub Workflows/Actions located in `.github/workflows/` folder.

Expand Down Expand Up @@ -82,20 +90,6 @@ Follow the steps below:
This process ensures a structured flow of features into releases, maintaining stability and predictability in release
management.

## Useful Commands

_Deploy Codebase_

```
npm run sf:manifest:create && npm run src:deploy:full
```

_Publish Community_

```
sf community publish --name "DigEx" --target-org "$SCRATCH_ORG_ALIAS"
```

## Managing Environment Variables

Environment variables are useful for deploying metadata components with secrets or org-specific settings (e.g.
Expand All @@ -122,6 +116,16 @@ E.g. you can execute particular script passing in ORG alias:
npm run src:push -- -o "$SCRATCH_ORG_ALIAS"
```

Please, refer
to [Salesforce CLI](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_unified.htm)
for more information.
## Useful Commands

_Deploy Codebase_

```
npm run sf:manifest:create && npm run src:deploy:full
```

_Publish Community_

```
sf community publish --name "DigEx" --target-org "$SCRATCH_ORG_ALIAS"
```
5 changes: 0 additions & 5 deletions manifests/destructiveChangesPost.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>Minlopro_App_Logo</members>
<members>Minlopro_App_Logo_min</members>
<name>ContentAsset</name>
</types>
<version>61.0</version>
</Package>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<CustomPermission xmlns="http://soap.sforce.com/2006/04/metadata">
<isLicensed>false</isLicensed>
<label>View Logs</label>
</CustomPermission>
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<enabled>true</enabled>
<name>LoggerSettings__c</name>
</customSettingAccesses>
<customPermissions>
<enabled>true</enabled>
<name>ViewLogs</name>
</customPermissions>
<description>Grants access to logger module features. This PS should be primarily used by developer(s).</description>
<fieldPermissions>
<editable>false</editable>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"ActionColor" : "#2574A9",
"BorderColor" : "rgb(216, 221, 230)",
"CardBackgroundColor" : "rgba(255, 255, 255, 0)",
"CompanyLogo" : "/file-asset/MinloproAppLogoMin?v=1&amp;height=300&amp;width=300",
"CompanyLogo" : "/file-asset/MinloproAppLogo?v=1&amp;height=300&amp;width=300",
"DetailTextColor" : "rgb(84, 105, 141)",
"ErrorFontColor" : "#ff9e9e",
"HeaderFonts" : "Montserrat",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"id" : "51933273-2f0e-489b-8704-2634bf18c891",
"label" : "Car Detail",
"objectApiName" : "Car__c",
"routeType" : "detail-a0B",
"routeType" : "detail-a07",
"type" : "route",
"urlPrefix" : "car"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"id" : "883da7e1-0418-4f44-9bd2-4660bc3e6250",
"label" : "Car List",
"objectApiName" : "Car__c",
"routeType" : "list-a0B",
"routeType" : "list-a07",
"type" : "route",
"urlPrefix" : "car"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"id" : "250ff930-16dc-476c-ab11-1a8f96b26b53",
"label" : "Car Related List",
"objectApiName" : "Car__c",
"routeType" : "relatedlist-a0B",
"routeType" : "relatedlist-a07",
"type" : "route",
"urlPrefix" : "car"
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@
} ],
"themeLayoutType" : "BIGuMbINxUUPKhG01SUcMMJNvZRHRb",
"type" : "view",
"viewType" : "detail-a0B"
"viewType" : "detail-a07"
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@
} ],
"themeLayoutType" : "BIGuMbINxUUPKhG01SUcMMJNvZRHRb",
"type" : "view",
"viewType" : "list-a0B"
"viewType" : "list-a07"
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@
} ],
"themeLayoutType" : "BIGuMbINxUUPKhG01SUcMMJNvZRHRb",
"type" : "view",
"viewType" : "relatedlist-a0B"
"viewType" : "relatedlist-a07"
}
4 changes: 2 additions & 2 deletions src/minlopro/main/applications/MinloproConsole.app-meta.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
experimentation.</description
>
<formFactors>Large</formFactors>
<isNavAutoTempTabsDisabled>false</isNavAutoTempTabsDisabled>
<isNavPersonalizationDisabled>false</isNavPersonalizationDisabled>
<isNavAutoTempTabsDisabled>true</isNavAutoTempTabsDisabled>
<isNavPersonalizationDisabled>true</isNavPersonalizationDisabled>
<isNavTabPersistenceDisabled>true</isNavTabPersistenceDisabled>
<isOmniPinnedViewEnabled>false</isOmniPinnedViewEnabled>
<label>Minlopro Console</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ global class MinloproContactsConnection extends DataSource.Connection {
columns.add(
DataSource.Column.get(
'SalesforceOwnerId',
'Salesforce Owner Id',
'Salesforce Owner ID',
'',
true,
true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@
<isIntrospectAllTokens>false</isIntrospectAllTokens>
<isNamedUserJwtEnabled>false</isNamedUserJwtEnabled>
<isPkceRequired>false</isPkceRequired>
<isRefreshTokenRotationEnabled>false</isRefreshTokenRotationEnabled>
<isSecretRequiredForRefreshToken>false</isSecretRequiredForRefreshToken>
<isSecretRequiredForTokenExchange>false</isSecretRequiredForTokenExchange>
<isTokenExchangeEnabled>false</isTokenExchangeEnabled>
<oauthClientCredentialUser>@SF_USERNAME</oauthClientCredentialUser>
<scopes>Full</scopes>
<scopes>RefreshToken</scopes>
</oauthConfig>
<oauthPolicy>
<ipRelaxation>BYPASS</ipRelaxation>
<isTokenExchangeFlowEnabled>false</isTokenExchangeFlowEnabled>
<refreshTokenPolicy>specific_lifetime:1:HOURS</refreshTokenPolicy>
</oauthPolicy>
<permissionSetName>Minlopro - Custom Auth. Provider &amp; NC</permissionSetName>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<isFilteringDisabled>false</isFilteringDisabled>
<isNameField>false</isNameField>
<isSortingDisabled>false</isSortingDisabled>
<label>Salesforce Owner Id</label>
<label>Salesforce Owner ID</label>
<length>18</length>
<referenceTargetField>User.ExternalId__c</referenceTargetField>
<referenceTo>User</referenceTo>
Expand Down
Loading

0 comments on commit 156bfd0

Please sign in to comment.