Code Contribution Guidelines
Firstly, thank you for your support in contributing to DLRS!
Here are some simple guidelines we ask you to follow
- Be familiar with the Git and submit all changes via PR’s, after submitting your PR check its status as we run some automation against all changes.
- Be familiar with the general layout and style of code and separation of concerns
- Ensure all modified or new Apex code you contribute has associated Apex tests
- Ensure all code passes X style guide rules
- Visualforce pages are lowercase in filename with no underscores
Code Overview
Q: Is there a class diagram for the code base?
This diagram shows the core service class described below being reused from various controllers, scheduled jobs and even a flow action! More detailed descriptions of these classes and others are included below.
[TODO - Need to install ApexUML package into a scratchorg]
Q: What are the main groupings of functionality and related files?
Feature | Related Objects, Classes, LWC’s etc |
---|---|
Core Engine - the core logic of the tool - its beating heart! | ObjectsLookupRollupSummary__c Original store for rollup definitions LookupRollupSummary2__c New store for rollup definitions LookupRollupCalculateJob__c Used to avoid overlapping scheduled job execution LookupRollupSummaryLog__c Used to record failed rollups stemming from scheduled updates, records get automatically cleared on successful reruns LookupRollupSummaryScheduleItems__c When a rollup definition is defined as scheduled, this object records a list of parent records that need to be recalculated next time the RollupJob class is executed by a schedule LookupChild__c and LookupParent__c Only used by Apex test classes Classes LREngine.cls See below RollupService.cls See below RollupSummary.cls See below RollupSummariesSelector.cls See below RollupJob.cls The incremental schedule recalc job, typically scheduled manually under Setup Apex Classes and reads instructions from LookupRollupScheduleItems__c .RollupCalculateJob.cls Specific to one rollup, uses criteria based on SOQL where clause to update parent records based on selected child records. RollupCalculateScheduableJob.cls Specific to one rollup, is an Apex scheduler for the above job, so it can be run on a recurring basis not just once. |
Core UI - from the welcome page, to the main editing UI to managing rollup schedules and view schedules. | Visualforce Pageswelcome.page and welcometab.page The main welcome tab page! managerollupsummaries.page The main page for editing rollup definitions managerollupsummaries_New.page A brand new pilot UI for the tool with more advanced UI features managetrigger.page Used by RollupController.cls to deploy Apex Triggers dynamically, uses a JavaScript library via static resources to zip stuff up. managetriggermdt.page Same as above, but tweaked to work with Custom Metadata stored rollup definitions vs Custom Object. rollupcalculate.page See RollupCalculateJob.cls aboverollupcalculatemdt.page See RollupCalculateJob.cls aboverollupschedulecalculate.page See RollupCalculateScheduableJob.cls aboverollupsummaryenhanced.page An older pilot UI based on the Custom Objects rollups (do not edit) rolluplogdelete.page See RollupSummaryLogDeleteController.cls belowrollupsummaryview.page See RollupSummaryLogDeleteController.cls belowApex Controllers WelcomeController.cls The main welcome page (default tab for DLRS app) ManageLookupRollupSummariesController.cls The main controller for editing rollup definitions RollupController.cls The main controller for deploying Apex Triggers dynamically! ManageLookupRollupSummariesNewController New pilot UI for the tool with more advanced UI features RollupCalculateController.cls See RollupCalculateJob.cls aboveRollupScheduledCalculateController.cls See RollupCalculateScheduableJob.cls aboveRollupSummaryViewController.cls The main controller to view full recalc scheduled rollups in one place RollupSummaryLogDeleteController.cls Simple controller to make deleting LookupRollupSummaryLog__c records easier for the user (so long as they know its safe to do so)RollupSummaryEnhancedController.cls An older pilot UI based on the Custom Objects rollups (do not edit) |
Optimizer UI - relatively new UI for the tool - to help keep implementations healthy and running smoothly! Designed to be extensible easily. | FlexipageLookupRollupSummariesGome.flexipage This is actually the Lookup Rollup Summaries Tools page and includes one component, the optimizer.cmp below.Aura Components optimizer.cmp Linked with the Flexipage above, dynamically renders itself based on registered optimization components and their output. optimizerNotification.cmp Generic component used by the optimization components (see below) to communicate to the user. Classes OptimizerComponentController.cls Calls methods on the OptimizerService to render recommended optimizations to the user for the tool OptimizerService.cls Internally extensible class that allows developers to write inner classes that perform various health checks by updating the NotificationReference enum and adding a corresponding inner class. See inner classes LookupRollupSummaryLogsExist and LookupRollupSummaryScheduleItemsFieldDeletion for examples. Also see further information in this blog. |
Others - Flow integration and other misc files. | RollupActionCalculate.cls Implement invocable Action to allow the rollup engine to be invoked from Flow and other declarative builders. |
Q: Where do I put SOQL logic?
If it relates to rollup definition information you want to query, please refer to the information above on the RollupSelector
class. If it is more general, other system objects for example, please use the Selector pattern for this, see below.
Q: I see the tool uses fflib
, what parts of it does it use?
It is used only to provide support for the Enterprise Architecture Patterns Selector concept, more about this can be found on the internet and in Trailhead itself.
Q: Where do I put new classes?
If its a new library class (from another open source library) please try to put thus under the /lib
folder. Otherwise you can put new classes, including test classes directly in the /src
folder.
Q: What other files do I need to consider when making changes?
The tool has its own permission sets that get upgraded when user install the latest package version. Thus if you add new tabs, objects, fields etc you will want to consider if they need exposing via one or both of the two packaged permission sets.
Q: Where are rollup definitions stored?
Historically the tool only used Custom Objects and went through many public releases with this approach. Custom Metadata arrived on the platform and provided a better way to store and access rollup definitions - which are essentially metadata. In order to maintain backwards compatibility - with those who installed the package prior - an abstraction layer was implemented within the code - to check both locations when looking for rollups. Users installing the tool for the first time are directed to the Manage Rollup Summaries tab which only reads and writes rollup configurations to Custom Metadata objects. The old Declarative Rollup Summaries tab for the Custom Object is still available but not added to the app by default.
Q: Tell me more about this abstraction layer for access rollup definitions?
The RollupSummariesSelector
class is the single place in which the DLRS code base reads rollup definitions. It uses another class RollupSummary
to represent a rollup definition instead of the usual __c
or __mdt
types.
This is because the selector class encapsulates both reading from the custom object and custom metadata locations where rollup definitions can exist in both places for some older customers. This encapsulation also makes it the perfect place to implement changes in the data model (new fields, defaults etc) without incurring widespread changes to the rest of the code.
Additionally the selector class uses two inner selector classes to separate the concerns of reading from two different locations, these inner classes are CustomMetadataSelector
and CustomObjectSelector
. The RollupSummariesSelector
class exposes several public methods that represent requests the rest of the code makes for rollup information. These methods delegate to methods in the inner classes mentioned above. One to query for custom object based rollups and one for custom metadata based rollups. The results from both of these delegations are aggregated together before returning to the caller - so it appears as one result set and thus the storage and access patterns complexity is invisible to the caller.
Q: Why does the tool mostly use Visualforce page?
The main UI of the tool is the Manage Rollup Summaries tab although it uses the Lightning styles, it is a Visualforce page. As mentioned above the tool primarily uses Custom Metadata objects to store configuration - these objects are not supported by traditional Apex DML. Although Apex now supports Custom Metadata Operations natively, it does not support delete operations. For this reason Apex HTTP callouts to the Salesforce SOAP Metadata API are used to implement the read, update and delete actions when managing rollup definitions. This API requires a Session ID from the users current session with the correct privileges, at present this is only obtained from a Visualforce Apex Controller execution context. Other parts of the tools UI, such as the Tools tab use Lightning Web Components and no Visualforce.
Q: Where is the main entry point for the tools engine?
The methods marked as global on the RollupService class are used to perform the core operations of the tool, including scheduling of work and responding to scheduled invocations. Of course its primary entry point is RollupService.triggerHandler
, which is a generic entry point capable of determining the context (which objects) the trigger is being fired from and scanning for one or more rollup definitions to execute. This class has gotten quite large over the years and is also supported by many test classes RollupServiceTestX
.
Additionally, the LREngine
class was the historic origin of the tools birth and performs much of the actual rollup work and results in set of parent records to update. This class is only ever used by the RollupService
class and can be considered an implementation detail of it. Given that the LREEngine
class is no longer it seems maintained by its original author, and given the overhead in maintaining it as such within DLRS, it is worth considering merging it as part of a future refactor of RollupService
class should that happen.