[SalesForce] How to best structure code so it can be run synchronously and in Batch

This question is somewhat related to my other open question on the asynch/synch topic.

Assume I would have an algorithm that could tell me that for a given customer org (data volumes and other factors) my function A will run into limits. How would I have to implement it that it can be easily be called synchronously and asynchronously?

Please also assume that just calling my method as a @future would not suffice. I really need it as a Batch.

Am I thinking to complicated or is there a pattern or best practice on how to structure my code for those cases.

FYI: I changed those question back to unanswered as one important
aspect is not yet answered. How to structure setup/state
initialisation code that in Batch classes goes into the constructor or
the start method. Where would that go if the functionality is called
synchronuously?

Best Answer

I follow a pattern known as the Service Layer. If you can elaborate on your 'function a' signature and needs I can provide some more specific examples for you, but this should give the general idea.

Service Layer, “Defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation.” Martin Fowler / Randy Stafford, EAA Patterns

In an Apex world it essentially encapsulates all your applications process logic in single layer that is agnostic of the callers, be they Batch Apex, Future, Apex Triggers, VF Controllers etc.... If you follow this practice closely you can even turn such things into a public Apex or REST API for your application quite easily.

enter image description here

This is an example of such a service method.

public class OpportunityService
{
    public static void applyDiscounts(Set<ID> opportunityIds, Decimal discountPercentage)

This is then consumed by a VF controller like so...

public PageReference applyDiscounts()
{
    try
    {
        // Apply discount entered to the selected Opportunities
        OpportunitiesService.applyDiscounts(
           new Map<Id,SObject>(standardSetController.getSelected()).keyValues(),
           DiscountPercentage);
    }
    catch (Exception e)
    {
        ApexPages.addMessages(e);
    }          
    return ApexPages.hasMessages() ? null : standardController.view();               
}

Or a Batch Apex class like so...

public with sharing class DiscountOpportunities
    implements Database.Batchable<sObject>
{
    public Decimal DiscountPercentage {get;set;}

    public Database.QueryLocator start(Database.BatchableContext BC) { ... }

    public void execute(Database.BatchableContext BC, List<sObject> scope)
    {
        try
        {
            OpportunitiesService.applyDiscounts(
                new Map<Id,SObject>(scope).keyValues(),DiscountPercentage);
        }
        catch (Exception e)
        {
            // Email error, log error, chatter error etc..
        }
    }

    public void finish(Database.BatchableContext BC) { ... }
}

There are a few other examples in the article linked below.

Designing a Service Layer. In either case the transactional scope and containment of the logic is managed entirely by the service layer, the callers responsibility is only to pass in the correct information, interpret responses and handle any Apex exceptions accordingly. Note also that service methods take bulkified parameters to match most callers needs and to better enforce bulkifcaiton within the service logic itself.

Further Reading. You can read more about this sample code, the guidelines and and other Apex Enterprise Patterns link within here. I'd be keen to know more about the signature of function A so I can perhaps taylor this answer a bit further for you.

Hope this helps!

Related Topic