apex enterprise patterns: building strong foundations
DESCRIPTION
Any structure expected to stand the test of time and change needs a strong foundation! Software is no exception. Engineering your code to grow in a stable and effective way is critical to your ability to rapidly meet the growing demands of users, new features, technologies, and platform capabilities. Join us to obtain architect-level design patterns for use in your Apex code to keep it well factored, easy to maintain, and in line with platform best practices. You'll follow a Force.com interpretation of Martin Fowler's Enterprise Architecture Application patterns, and the practice of Separation of Concerns.TRANSCRIPT
![Page 1: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/1.jpg)
Building Strong FoundationsApex Enterprise Patterns
Andrew Fawcett, FinancialForce.com, CTO@andyinthecloud
![Page 2: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/2.jpg)
All about FinancialForce.comRevolutionizing the Back Office#1 Accounting, Billing and PSA Apps on the Salesforce platform
▪ Native apps
▪ San Francisco HQ, 595 Market St
▪ R&D in San Francisco, Harrogate UK, and Granada ES
▪ We are hiring! Meet us at Rehab!
![Page 3: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/3.jpg)
What's wrong with this picture?
![Page 4: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/4.jpg)
What's wrong with this picture?public with sharing class MyController {
public String theId;
public MyController(ApexPages.StandardController standardController){
theId = (String) ApexPages.currentPage().getParameters().get('id');}
public PageReference actionCheckInvoices(){
// Read the Account recordAccount accountRecord = [select Id, Name from Account where Id = :theId];// Do some processing on the Account record ... then update itupdate accountRecord;return null;
}}
Developer “A” writes an Apex Controller first
Developer “B” writes an Apex Batch job later.
public with sharing class MyBatchJob implements Database.Batchable<SObject> {
public void execute(Database.batchableContext info, List<Account> accounts){
for(Account account : accounts){
MyController myController = new MyController(new ApexPages.StandardController(account));myController.actionCheckInvoices();
}}
public Database.QueryLocator start(Database.BatchableContext info) { ... }
public void finish(Database.batchableContext info) { ... } }
![Page 5: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/5.jpg)
So what was wrong with that picture?
Developer “A”
Developer “B”
MyControllerMyController IssueUse of ApexPages.currentPage() Unnecessary and fragile, utilize instead
stdController.getId() methodError handling No try/catch error handling on controller
method
MyBatchJob IssueUse of ApexPages.currentPage() Is not available in a Batch Apex context, the constructor
code will give an exception.SOQL Query and DML Governors Calling the controller method in a loop will cause a SOQL
query and DML governor issues.Error Handling No try/catch error handling in the the execute methodSeparation of Concerns Developer A did not originally develop the controller logic
expecting or anticipating Developer B’s would in the future try to reuse it from a Batch Context as well.
They did not consider correct Separation of Concerns…
![Page 6: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/6.jpg)
Pattern ChecklistSeparation of Concerns ☐
Service Layer ☐
Domain Layer ☐
Selector Layer ☐
![Page 7: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/7.jpg)
So what is “Separation of Concerns” then?
“The goal is to design systems so that functions can be optimized independently of other functions, so that failure of one function does not cause other functions to fail, and in general to make it easier to understand, design and manage complex interdependent systems”Wikipedia, “Separation of Concerns”
![Page 8: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/8.jpg)
So what is “DRY” then?
Don’t Repeat Yourself“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.”Wikipedia, “Don’t repeat yourself (DRY)”
![Page 9: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/9.jpg)
Design Patterns for SOC & Force.com Best PracticeService LayerDomain Layer
▪ Yet another Wrapper / Trigger pattern!
Selector LayerReference Martin Fowler
▪ http://martinfowler.com/eaaCatalog/▪ Author of “Patterns of Enterprise
Application Architecture”
Reference ▪ http://wiki.developerforce.com/page/Apex_Enterprise_Patterns_-_Separation_of_Concerns
![Page 10: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/10.jpg)
Demo! “takeaway” a Sample Force.com Application!
GitHub: financialforcedev/fflib-apex-common-samplecode
![Page 11: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/11.jpg)
Sample Application, what’s on the menu?
Platform Feature Patterns UsedCustom Buttons Building UI logic and calling Service Layer code
from ControllersBatch Apex Reusing Service and Selector Layer code from
with a Batch contextIntegration API Exposing an Integration API via Service Layer
using Apex and RESTApex Triggers Factoring your Apex Trigger logic via the Domain
Layer (wrappers)VisualForce Remoting Exposing Service Layer code to HTML5 /
JavaScript libraries such as JQuery
GitHub: financialforcedev/fflib-apex-common-samplecode
![Page 12: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/12.jpg)
Pattern ChecklistSeparation of Concerns ☑
Service Layer ☐
Domain Layer ☐
Selector Layer ☐
![Page 13: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/13.jpg)
Introducing the Service Layer
![Page 14: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/14.jpg)
Introducing the Service LayerNaming Convention
▪ Suffix with ‘Service’, e.g. OpportunitiesService▪ Methods named by purpose not usage, e.g. applyDiscounts
![Page 15: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/15.jpg)
Introducing the Service LayerClear Code Factoring
▪ Encapsulates Processes / Tasks▪ Caller Context Agnostic
![Page 16: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/16.jpg)
Introducing the Service LayerDefined Responsibilities
▪ Supports Bulkifcation▪ Transaction management
![Page 17: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/17.jpg)
Developing and calling a Service Layer
Service Contract
public with sharing class AccountService{
public static void checkOutstandingInvoices(Set<Id> accountIds){
// Read the Account recordsList<Account> accountRecords = [select Id, Name from Account where Id in :accountIds];// Do some processing on the Account and Invoice records ... then update them.update accountRecords;
}}
AccountService.cls
Developer “A” follows Service Layer pattern.
public PageReference actionCheckInvoices(){ try { // Process the Account record AccountService.checkOutstandingInvoices(new Set<Id> { theId }); } catch (Exception e) { ApexPage.addMessages(e); } return null;}
MyController.cls
Developer “A” writes Controller code to consume the Service.
public void execute(Database.batchableContext info, List<Account> accounts){ try {
// Process Account recordsSet<Id> accountIds = new Map<Id, Account>(accounts).keySet();AccountService.checkOutstandingInvoices(accountIds);
} catch (Exception e) { emailError(e); }}
MyBatch.cls
Developer “B” then reuses the Developer “A” code safely.
![Page 18: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/18.jpg)
Code Walkthrough : Sample ServicesManaging DML and Transactions
▪ Unit of Work Pattern
Classes
OpportunitiesService.cls
![Page 19: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/19.jpg)
Code Walkthrough : Custom ButtonsCustom Buttons
▪ Detail and List View▪ Calling Visualforce Controller Code
Visualforce Controllers and Pages▪ Error Handling▪ Interacts with Service Layer
• Utilize bulkified methods • Assume transaction containment• Catch exceptions and display them on the page
Classes and Pages
OpportunityApplyDiscountController.cls• opportunityapplydiscount.page• opportunityapplydiscounts.pageOpportunityCreateInvoiceController.cls• opportunitycreateinvoice.page• opportunitycreateinvoices.page
![Page 20: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/20.jpg)
Code Walkthrough : Batch ApexClasses
CreatesInvoicesJob.cls
▪ Error Handling▪ Interacts with Service Layer
• Utilize bulkified methods • Assume transaction containment• Catch exceptions and logs them for later notificaiton
![Page 21: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/21.jpg)
Code Walkthrough : Exposing an Integration APIClasses
OpportunitiesResource.clsOpportunitiesService.cls
▪ Error Handling• Pass business logic exceptions to caller to handle• Assume transaction containment
▪ Exposing the API• To Apex Developers > Mark Service class and methods as global!
– Package to apply Apex versioning of the API
• To Web / Mobile Developers > Create RESTful API around Service layer
![Page 22: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/22.jpg)
Code Walkthrough : Visualforce RemotingAn “Opportunities Discount Console”
▪ Developer uses a Rich HTML5 Client Library, such as JQuery• Is not using traditional Visualforce markup or action functions on the controller
▪ Utilizing static “remote” methods on the controller (stateless controller)• Able to consume the Service layer functions also!• Assumes transactional integrity• Assumes the caller (JavaScript client) to handle exceptions
Classes
OpportunityConsoleController.cls
![Page 23: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/23.jpg)
Pattern ChecklistSeparation of Concerns ☑
Service Layer ☑
Domain Layer ☐
Selector Layer ☐
![Page 24: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/24.jpg)
Introducing the Domain Layer
![Page 25: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/25.jpg)
Introducing the Domain LayerNaming Convention
▪ Name uses plural name of object, e.g. Opportunities
![Page 26: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/26.jpg)
Introducing the Domain LayerClear Code Factoring
▪ Encapsulates Validation / Defaulting of Fields
▪ Wraps Apex Trigger Logic in Apex Class (Trigger/Wrapper Pattern)
![Page 27: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/27.jpg)
Introducing the Domain LayerDefined Responsibilities
▪ Enforces Bulkifcation for logic▪ Platform security best practice
(honors Users profile)▪ Encapsulates ALL logic / behavior
for each object• e.g. onValidate, onBeforeInsert and
applyDiscount
![Page 28: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/28.jpg)
Introducing the Domain Layer : Apex Trigger Flow
![Page 29: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/29.jpg)
Code Walkthrough : Domain Layer : Apex TriggersWhat no code?!? ☺ Triggers
OpportunitiesTrigger.triggerOpportunityLineItemsTrigger.trigger
![Page 30: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/30.jpg)
Code Walkthrough : Domain Layer : Domain ClassesBulkified Wrappers
▪ Base class fflib_SObjectDomain▪ Apex Trigger Callers▪ Support for DML Free Testing ▪ Able to apply Object Orientated Programming
Apex Classes
Opportunities.clsOpportunityLineItems.clsAccounts.cls
![Page 31: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/31.jpg)
Code Walkthrough : Domain Layer : Service CallersApex Service Callers
▪ Create Domain Instances▪ Bulkified Calls
Apex Classes
OpportunitiesService.cls
![Page 32: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/32.jpg)
Code Walkthrough : Domain : Extends vs Interfaces
Extending Apex Domain Classes▪ Extend or adjust existing behavior of classes of a similar nature
• Base class Chargeable ensures cost is recalculated on insert and update• DeveloperWorkItems Domain Class extends to provide its own calc logic
Implementing Apex Domain Interfaces▪ Good for applying behavior to different types of classes
• Interface InvoiceService.ISupportInvoicing• Implemented by Opportunities Domain Class
![Page 33: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/33.jpg)
Code Walkthrough : Domain Class ExtensionChargeable Base Class
▪ Apply to Custom Objects recording Work▪ Require hours and cost calculations▪ Performs recalculation on insert and update
![Page 34: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/34.jpg)
Pattern ChecklistSeparation of Concerns ☑
Service Layer ☑
Domain Layer ☑
Selector Layer ☐
![Page 35: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/35.jpg)
Introducing the Selector Layer
![Page 36: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/36.jpg)
Introducing the Selector LayerNaming Convention
▪ Plural object name suffixed by Selector• e.g. OpportunitiesSelector
![Page 37: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/37.jpg)
Introducing the Selector LayerClear Code Factoring
▪ Encapsulates Query Logic
![Page 38: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/38.jpg)
Introducing the Selector LayerDefined Responsibilities
▪ Consistency over queried fields▪ Platform security best practice▪ Encapsulates ALL query logic
![Page 39: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/39.jpg)
Code Walkthrough : Selector LayerEncapsulate Query Fields and Logic
▪ Base class fflib_SObjectSelector▪ Defines Common Fields▪ Default SOQL Helpers, FieldSet Support
Apex Classes
OpportunitiesSelector.clsOpportunityLineItemsSelector.clsProductsSelector.clsPricebooksSelector.clsPricebookEntriesSelector.cls
![Page 40: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/40.jpg)
Code Walkthrough : Selector Layer : CallersService Layer Logic : OpportunitiesSelector.selectByIdWithProducts
Domain Layer Logic : AccountsSelector.selectByOpportunity
Apex ClassOpportunitiesService.cls
Apex ClassOpportunities.cls
![Page 41: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/41.jpg)
Code Walkthrough : Selector Layer : CallersBatch Apex : OpportunitiesSelector.queryLocatorReadyToInvoice
Apex ClassCreatesInvoicesJob.cls
![Page 42: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/42.jpg)
Pattern ChecklistSeparation of Concerns ☑
Service Layer ☑
Domain Layer ☑
Selector Layer ☑
![Page 43: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/43.jpg)
Summary
![Page 44: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/44.jpg)
Summary
![Page 45: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/45.jpg)
When is SOC / DRY appropriate (a rough guide)?Solution / Code Base Size
Developers Requirements Scope Number of Client Types and Interactions
SOC/DRY Appropriate?
Small 1 to 2 • Well known and unlikely to change
• One off solutions• Limited number of objects
• Standard UI• Simple VF / Triggers• No Batch Mode• No API• No Mobile
Typically not
Small to Medium 1 to 6 • Well known but may need to evolve rapidly
• Growing number objects and processes interacting
• Product deliverable or larger duration projects
• Standard UI• Advanced VF / JQuery• Batch Mode• API (on roadmap)• Mobile (on roadmap)
Worth considering
Large > 6 • Scope driven by multiple customers and user types
• Large number of objects• Generic product or solution
aimed at Mid to Enterprise market with Customer or Partner Integrations.
• Growing development team!
• Standard UI • Advanced VF / JQuery• Batch Mode• Developer / Partner API • Mobile Clients• New Platform Feature
Ready, Chatter Actions!
Definite benifits
![Page 46: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/46.jpg)
Other Design Patterns Helping with SOC/DRY
Alternative Domain Layer Patterns▪ ‘Apex Trigger Pattern’ (Tony Scott)
• http://developer.force.com/cookbook/recipe/trigger-pattern-for-tidy-streamlined-bulkified-triggers
▪ ‘Salesforce Apex Wrapper Class’ (Mike Leach)• http://www.embracingthecloud.com/2013/09/06/SalesforceApexWrapperClass.aspx
▪ ‘Trigger Architecture Framework’ (Hari Krishnan)• http://krishhari.wordpress.com/category/technology/salesforce/apex-triggers/
![Page 47: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/47.jpg)
Andrew Fawcett
CTO,@andyinthecloud
![Page 48: Apex Enterprise Patterns: Building Strong Foundations](https://reader034.vdocument.in/reader034/viewer/2022042422/554eeaa0b4c905911d8b51fd/html5/thumbnails/48.jpg)