function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
scottm_pscottm_p 

best practice for controllers

Would be interested on thoughts or links to articles on best practice for apex controllers. My feeling is that they should be as lightweight as possible delegating the functionality to a set of business objects they call. 

sfdcfoxsfdcfox

I don't have any documentation, but I would assert that this is a reasonable design model. A page should only include the necessary logic to render the UI. Logic that directly affects records should be contained in triggers, if possible. For example, if you have a page that allows you to edit opportunity line items, you would probably want to have any calculation methods (such as calculating a custom total) as a trigger.

Bhup_IndoreBhup_Indore

find the best Practices here

 

http://wiki.developerforce.com/page/Apex_Code_Best_Practices

 

 

Thanks,

Bhup

 

 

scottm_pscottm_p

Thanks for this. I am aware of these but they mostly relate to governor limits. There seems to be relatively little out there about how to structure apps in Salesforce. Much of the code I see is quite basic with little in the way of a proper set of business objects. To me the Salesforce objects are really data objects, I think there should be a proper business layer on top so like this 

 

Salesforce objects (native and custom)

 

Business Objects 

 

Controllers

 

Visualforce pages

crop1645crop1645

One convention I use is to create wrapper classes for all my SFDC SObjects that need some sort of APEX. This way, I can give each SObject custom methods. I also use a Gateway class to collect all related SObjects before executing 1x1 validations/derivations on a trigger list - this avoids too many SOQL call governor issues

 

Here is a trivial example:

public without sharing class AccountWrapper {

	//	--------------------------------------------------------------------
	//	Wraps the Account object so we can have methods on it 
	//	--------------------------------------------------------------------
	
	//	------------------------------------------------
	//	Properties
	//	------------------------------------------------
	public 	Account					a {get; set;}
	private	Account					aOld;
	private Boolean					isValid		= true;					// passed validation checks?

	
	//	-------------------------------------------
	//	Constructor
	//	-------------------------------------------
	public AccountWrapper(Account a) {
		this.a 		= a;
		this.aOld	= null;
	}
	
	public AccountWrapper(Account a, Account aOld) {
		this.a 		= a;
		this.aOld	= aOld;
	}
	//	---------------------------------------------------------------------
	//	debug 
	//	---------------------------------------------------------------------
	public String debug() {
		return 	'\nName                     : ' + this.a.name  +
			'\nBillingCountry           : ' + this.a.billingCountry
			;
	}
	//	-------------------------------------------
	//	derive:			Field derivations
	//	-------------------------------------------
	public void derive(AccountGateway aGw) {  // AccountGateway is another class where all related records have been collected (Account's Contacts, for example)
		if (!this.isValid) {}
		else {
			// do derivations here
		}
	}	
	
	//	---------------------------------------
	//	prepareForClone:	Get clone source ready - used by VF controller - when overriding clone button 
	//	---------------------------------------	
	public void prepareForClone() {

		
		//	1.	get list of attachments to possibly clone at user's option
		this.attachIdToAttachMap	= new Map<ID,Attachment> ([select id, name, Description 					
											from Attachment where parentId = :this.a.id]);									
		//	2.	Clear fields that can't be cloned 
		
		
	}	
	//	-------------------------------------------
	//	validate:		Does Validations undoable by Force.com Validation Rules; sets instance Vbl isValid
	//	-------------------------------------------
	public void validate(AccountGateway aGw) {
		// do validations here, set this.isValid true or false
		}
	} 


}