0

When creating async apex classes (e.g. Batcheable, Queueable), especially classes associated with specific SObjects, what might be the best practice for where these async classes should be housed. Specifically, what solutions would best adhere to SOLID design principles and other concepts like Separation of Concerns.

Possible solutions I've been able to come up with thus far are as follows:

  1. House the async class as its own class with a name prefix associating it with other related classes

    Example: AccountSpecificPurposeQueueable, which can easily be found alongside other classes like AccountService, AccountSelector, and AccountTriggerHandler.

    Benefits: Seems to have stronger adherence to Separation of Concerns and single responsibility principle.

    Drawbacks: Can lead to a glut of classes for a single object

  2. House the async class as part of the service class

    Example: AccountService class has a sub class AccountSpecificPurposeQueueable.

    Benefits: Smaller number of classes, all functionality limited to service class

    Drawbacks: Increased reasons to change service class, and more likelihood of merge conflicts due to multiple developers modifying the same service class.

My inclination is that solution one is most likely the most appropriate. I'm curious if this is correct, or if there are other and more suited solutions not listed here.

2 Answers 2

2

This is more an opinion questions so what I share here is an opinion, which may or may not work for you/others.

We came to realize that in Salesforce due to nature of platform, smaller classes are better for maintenance, testing and collaboration (less-conflicts). Hence in clients we consult, we always advised to err on the side of smaller classes. In some places, we have put in a informal rule of max 1000 lines per class.

With that said, we have adopted this pattern.

AccountService => Houses primary account related core functionality
AccountDto => Houses various Data Transfer Objects (wrapper classes)
AccountTriggerHandler => Trigger Handler for account, which calls service as required
AccountUpdaterJob => Any queueable classes related to account
AccountCleanupBatch => Any batch classes related to account
AccountRestApi => If we have to expose some account related apex rest apis

Here replace Account with your business entity name like Contact or Proposal etc.,

Along with we aggressively build bunch of Utility classes that all others share to reduce the amount code we need to write. Some of utility classes are,

Utils
HttpClient
HttpMock
ObjectMock
Settings
ApiBase
TriggerHandler
...
1

My practice which is not bullet-proof and subject to better alternatives.

If it is a Schedulable class with no call to a batchable (or calls a configurable batchable)

  • xxxSchedulable

If it is a Schedulable class with a paired Batchable

  • xxxSchedulable that implements System.Schedulable and Database.Batchable

If it is a batchable that stands on its own, perhaps called from other service classes

  • xxxBatchable

If it is a service class with a lightweight/trivial queueable application need

  • xxxService with an inner class xxxYYYQueueable

If it is a fairly beefy queueable ..

  • xxxServiceQueueable or sometimes, xxxServiceAsync

I like to make xxx reference the primary SObject of the business function performed by the class. This way they sort nicely in the IDE. This isn't always possible but works most of the time. Also applies to xxxYYYInvocable so it is easy to find apex usable by Flows.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .