Custom Settings Naming Conventions

A quick post to share some thoughts on the standardisation of naming conventions applied to Custom Settings. With Custom Objects it is an obvious best practice to mirror exactly the conventions applied by the Standard Objects, there are no reasons not to adhere to this approach, none. With Custom Settings however there is no comparable reference and as such a great deal of variation exists in the naming conventions applied. For many, this matters little, however I’d make the usual arguments about maintenance, readability, build quality through predictable convention and so forth. There’s also merit in clearly distinguishing Hierarchy from List types and ensuring a meaningful naming for the latter, which can be utilised across many declarative build elements.

I use the naming conventions defined below, for simplicity and clarity reasons. All that really matters is that a standardised approach is taken.

1. Custom Setting Label – Pluralised in all cases (e.g. Data Sources). No “Setting[s]” suffix.

2. API Name – List Settings
– [Data entity that each list entry represents]ListSetting__c

Each record represents an individual entry and as such singular naming is applied, as per objects.

Examples – List
e.g. Analytic Views – AnalyticViewListSetting__c
e.g. Data Sources – DataSourceListSetting__c

3. API Name – Hierarchy Settings
– [Function of the settings]Settings__c

Each record represents the same set of settings applied at different levels. In concept this differs from objects and list settings, the plural naming reflects this.

Examples – Hierarchy
e.g. Org Behaviour Settings – OrgBehaviourSettings__c
e.g. My App Settings – MyApplicationSettings__c

As a further best practice, it is important that any requisite logic applied to the population of the Name field is described in the Custom Setting Description field. If the population is immaterial then simply state as such. Given the inability to relate settings at the attribute level, it can be the case that the Name field plays some role in grouping related settings.

Finally, where possible always retrieve Custom Settings data via the Custom Settings Methods – not via SOQL query. In the latter case the Application Cache is bypassed and the query counts against the limits context within the Apex transaction.

Any-org Design Considerations

The concept of any-org development is an interesting one. The strict definition, to my mind, being the development of a set of components (perhaps packaged) that are designed and coded specifically to install and function in any Salesforce org. This is typically an ISV concern, where testing and maintaining a single-code base can be highly desirable over managing a base package plus multiple extension packages, or in the worse case multiple independent packages. Either way an ISV needs to maximise the addressable market for a product whilst minimising the ongoing effort to do so. The same drivers do not apply in the single-org case, where a consultancy and/or in-house team are delivering technical components to be installed into a known Salesforce org (or multi-org estate). In the single-org case it is common practice to see technical components designed and coded for the current state of the target org(s), with no consideration to how the org(s) may evolve over time. This can often result in situations where costly technical work is required simply to activate an optional product feature, or to provide user access in another locale. In such cases the situation can often be compounded by the fact that the original development team are no longer available.

In short, in my view some degree of future-proofing should be considered in designing for the single-org model, using the techniques applied by ISVs in the any-org model.

    Any-org Design Considerations

  1. Optional Features
  2. Examples; Person Accounts, Quotes

    There are a multitude of optional product features which can be enabled directly in the Salesforce web application UI or via Salesforce support. In the majority of cases such feature activations irreversibly add new objects and fields to the Salesforce instance. From the perspective of keeping simple orgs uncluttered by objects related to unused features this makes perfect sense. From the perspective of designing for the any-org model, this approach poses a few challenges. The main challenge being that Apex code won’t compile where a static reference exists to an object (or field) that doesn’t exist in the org. There is no simple answer to this, instead a selective approach should be taken where optional features that may already be active (or could in the future be activated), that have some impact on your code are accommodated. The approach to achieving this for any-org Apex code basically involves replacing static references with Dynamic SOQL and Dynamic Apex (see coding techniques below).

  3. Multi-currency
  4. The default currency mode of a Salesforce org is single currency, the majority stay this way. It is however common to have multi-currency and perhaps advanced currency management (ACM) activated in orgs where business operations are international. Activation of multi-currency often occurs once the Salesforce org has become established, perhaps in a single region. This can be problematic where technical customisations have been added that aren’t currency aware.

    In the any-org case, all Apex code should be multi-currency aware and use Dynamic SOQL to add the CurrencyIsoCode field to all object queries involving currency fields. Additionally, currency aware logic should include checks to ensure that related transactions are the same currency, and that custom analytics are presenting data in the corporate currency (default and therefore expected behaviour for the native reporting functions). Note, the behaviour of aggregate functions involving currency fields must also be handled.

  5. Editions Support
  6. A key design decision for ISVs is the Salesforce editions to be supported by their managed package. This one has less relevance to the single-org model, unless the multi-org estate includes different editions.

    It is possible to group editions into two distinct groups;
    1. Group (or Team) Edition and Professional Edition
    2. Enterprise Edition and Unlimited Edition

    In the case of group 1 assume that standard objects such as Product, Pricebook2, PricebookEntry, RecordType do not exist and ensure no static references exist in the code. The OrganizationType field on the Organization object tells us which edition the code is executing within.

    public static Boolean isTeamOrProEdition(){
    		
    	if (isTeamOrProEdition==null){		
    		List<Organization> orgs = [select OrganizationType from Organization where Id=:UserInfo.getOrganizationId() limit 1];
    		if (orgs.size()>0)				
    			isTeamOrProEdition=(orgs[0].OrganizationType=='Team Edition' || orgs[0].OrganizationType=='Professional Edition');
    	}
    	return isTeamOrProEdition;
    }
    
  7. Internationalisation
  8. Whether an international user base is anticipated or not it is general software development best practice to externalise string literals into resource files. In the Salesforce context this means Custom Labels. A best practice here is to apply strict categorisation and a meaningful naming convention. Also ensure all literals are externalised not just labels in the UI, for example trigger error messages.

    Another consideration for i18n is the use of currency and date formatting helpers. Where UI components do not apply default formatting for an SObject field you need to handle this in code. An i18nHelper class which translates ISO locale and currency codes to date format strings and currency format strings plus symbols respectively can be very helpful.

    Useful abbreviations:
    i18n – internationalisation; development practice enabling support for localisation.
    l11n – localisation; act of localising an internationalised software product for a specific locale.

  9. Profile Permissions
  10. Visualforce pages are preprocessed for components directly bound to SObject fields where the user profile does not have CRUD or FLS permissions. In such cases the fields are not displayed or are made read-only, depending on visibility state. This comes as a surprise for many developers who assume that User Profile permissions are entirely ignored on Visualforce pages.

    reference: Enforcing_CRUD_and_FLS

    In the any-org model, where direct SObject field binding is being used in a Visualforce page, this may require a manual check during initialisation to protect the functional integrity of the page. For example, a custom page with no fields displayed and no explanation is not a great user experience, instead the page should simply inform the user they don’t have sufficient permissions, they can then take this up with their Administrators.

    private Boolean hasRequiredFLS(){    	
        // rule 1: all custom fields must be accessible.
        // rule 2: check isUpdateable on all fields where inline editing offered.
        	
        Schema.DescribeFieldResult d;
        	
        Map<String, Schema.SObjectField> siFieldNameToToken=Schema.SObjectType.SalesInvoice__c.fields.getMap();
        	
        for (Schema.SObjectField f : siFieldNameToToken.values()){    		
        	d = f.getDescribe();
        		
        	if (!d.isCustom()) continue;
        	if (!d.isAccessible()) return false;
        }
    
        d = siFieldNameToToken.get('InvoiceDate__c').getDescribe();
        if (!d.isUpdateable()) 
        	this.isInlineEditable=false;
        else {
        	d = siFieldNameToToken.get('DueDate__c').getDescribe();
        	if (!d.isUpdateable()) 
        	    	this.isInlineEditable=false;
        	else this.isInlineEditable=true;
        }	
        return true;
    }
    
    Coding Techniques

  1. Dynamic SOQL
  2. Do not statically reference objects or fields that may not exist in the org. Instead compose Dynamic SOQL queries and execute via Database.query(). With this approach, you can build the required query using flags which indicate the presence of optional feature fields such as RecordTypeId, CurrencyIsoCode etc. The Apex Language Reference provides good coverage of Dynamic SOQL. Be very careful to ensure that your composed string does not include user supplied text input – this would open up a vulnerability to SOQL injection security vectors.

    public static Id getStandardPricebookId(){
    	if (standardPricebookId==null){			
    		String q='select Id, isActive from Pricebook2 where IsStandard=true';
    		SObject p = Database.query(q);
    	
    		if (!(Boolean)p.get('IsActive')){
    			p.put('IsActive',true);
    			update p;
    		}
    		standardPricebookId=(String)p.get('Id');
    	}
    	return standardPricebookId;
    }
    
    public SalesInvoice__c retrieveSalesInvoice(String siId){
        try{
            //& Using dynamic Apex to retrieve fields from the fieldset to create a soql query that returns all fields required by the view.
            String q='select Id,Name,OwnerId';
            q+=',TotalGross__c';
    
            for(Schema.FieldSetMember f : SObjectType.SalesInvoice__c.FieldSets.invoices__Additional_Information.getFields()){
                if (!q.contains(f.getFieldPath())) q+=','+f.getFieldPath();
            }   
                
            if (UserInfo.isMultiCurrencyOrganization()) q+=',CurrencyIsoCode';			
            if (AppHelper.isPersonAccountsEnabled()) q+=',PersonEmail,PersonContactId';  
                
        	q+=',(select Id,Description__c,Quantity__c from SalesInvoiceLineItems__r order by CreatedDate asc)';     		
            q+=' from SalesInvoice__c';
            q+=' where Id=\''+siId+'\'';
                
            return Database.query(q);
        } catch (Exception e){
            throw e;
        }
    }
    
  3. Dynamic Apex
  4. Do not statically reference objects or fields that may not exist in the org. Instead use Dynamic Apex techniques such as global describes and field describes. Where a new SObject is required, use the newSObject() method as shown below, this is particularly useful for unit test data creation. The Apex Language Reference provides good coverage of Dynamic Apex, every developer should be familiar with this topic.

    public static List<SObject> createPBE(Id pricebookId, List<SObject> products){
    	SObject pbe;
    	List<SObject> entries = new List<SObject>();		
    		
    	Schema.SObjectType targetType = Schema.getGlobalDescribe().get('PricebookEntry');
    	if (targetType==null) return null;
    				
    	for (SObject p : products){
    		pbe = targetType.newSObject();
    			
    		pbe.put('Pricebook2Id',pricebookId);
    		pbe.put('Product2Id',p.Id);
    		pbe.put('UseStandardPrice',false);
    		pbe.put('UnitPrice',100);	
    		pbe.put('IsActive',true);
    		entries.add(pbe);
    	}	
    	if (entries.size()>0) insert entries;	
    	return entries;
    }
    
  5. UserInfo Methods
  6. The UserInfo standard class provides some highly useful methods for any-org coding such as;
    isMultiCurrencyOrganization(), getDefaultCurrency(), getLocale() and getTimezone(). The isMultiCurrencyOrganization() method will be frequently used to branch code specific to multi-currency orgs.

    public static String getCorporateCurrency(){			
    	if (corporateCurrencyIsoCode==null){			
    		corporateCurrencyIsoCode=UserInfo.getDefaultCurrency();
    		
    		if (UserInfo.isMultiCurrencyOrganization()){
    			String q='select IsoCode, ConversionRate from CurrencyType where IsActive=true and IsCorporate=true';
    			List<SObject> currencies = Database.query(q);
    			if (currencies.size()>0)
    				corporateCurrencyIsoCode=(String)currencies[0].get('ISOCode');				
    		}
    		return corporateCurrencyIsoCode;
    	}
    }
    
    Challenges

  1. Unit Test Data
  2. In the any-org model the creation of unit test data can be a challenge due to the potential existence of mandatory custom fields and/or validation rules. To mitigate the former, Dynamic Apex can be used to identify mandatory fields and their data type such that test data can be added (via a factory pattern of some sort). In the latter case there is no way to reliably detect a validation rule condition and as such for ISVs it is a blessing that unit tests do not actual have to pass in a subscriber org (wrong as this may be in principle). In the single-org case we can improve on this (and we have to), by adding a global Validation Rule switch-off flag in a Org Behaviour Custom Setting (see previous post) – this approach is helpful in many areas but for unit test data creation it can isolate test code from Validation Rules added post-deployment. There’s a tradeoff here between protecting unit tests versus the risk of using test data that may not adhere to the current set of Validation Rules.

  3. Unit Test Code Coverage
  4. The addition of multiple conditional code paths, i.e. branching, for the any-org case makes it challenging to achieve a high code coverage percentage in orgs which do not have the accommodated features activated. For example, unit tests executing in a single currency org, will not be run code specific to multi-currency, and therefore the code coverage drops accordingly. To mitigate this, consider adding OR conditions to IF branches which include unit test flags and perhaps Test.isRunningTest() to cover as much code as possible before leaving the branch. During coding always strive to absolutely minimise the feature-specific code – this approach will help greatly in respect to unit test coverage.

  5. QA
  6. In the any-org model, it is imperative to test your code in an org with the accommodated features activated. This will require multiple QA orgs and can increase the overall testing overhead considerably. Also, factor in the lead time required to have features activated by Salesforce support, such as multi-currency and Person Accounts.

  7. Security
  8. Dynamic SOQL queries open up the possibility of SOQL-injection attacks where user-supplied text values are concatentated into an executed SOQL query string. Always sanitise and escape data values where such code behaviour is necessary.

  9. Governor Limits
  10. The any-org model is highly contingent upon the use of limited resources such as Apex Describes. As a best practice employ a helper class pattern with cached values.

    One Approach – Future Proofing Single-org Developments

    Optional Features – selective
    Multi-currency – yes
    Editions Support – no
    i18n – yes
    Unit Test Data – yes
    Profile Permissions – yes

    The list above is my default position on the approach to take on single-org developments, this can change significantly depending on the current state of the org in terms of configuration and customisation, plus the client perspective on the evolution of their Salesforce org and attitude toward investing in future-proofing/extensibility. In the single-org, consultancy project case it’s advisable to be completely open and let the client decide if the additional X% cost is worth the value. I think the real point here is that the conversation takes place and the client has the opportunity to make an informed decision.

Salesforce Query Optimisation

Understanding how the Salesforce Query Optimiser (SQO) works is fundamental to delivering performance at the data layer. Good practice in this regard, as part of an optimised physical data model implementation, is key to delivering efficient data access at the application layer.

In short, certain fields are indexed by default, custom indexes can be added via External Id and unique field attributes or by Salesforce support. For composite indexes the latter is required. The SQO utilises an index statistics table which records the distribution of data in each index. When processing a query, a pre-query is made to the statistics table to determine whether a candidate index is useful or not, in terms of selectivity thresholds etc.

The Query & Search Optimization Cheat Sheet provides a very useful reference in terms of the logic applied by the SQO, plus the fields indexed by default. Bookmark as a guide next time you’re writing a complex SOQL query or designing a data model. In the latter case performance of data retrieval is an often overlooked design consideration.

Salesforce Summer 13 – Checkpoints

My first post on this blog back in March 2012 related to Simulated Breakpoints, a developer console feature enabling a head dump to be captured when code execution hit a specified line(s) of Apex script. Whilst not comparable to the power of breakpoints in debugging with other languages, Simulated Breakpoints was a definitely step forward for Force.com development, but I suspect this still remains an unused feature, with System.debug() statements being used instead. I don’t believe too many developers are juggling the Force.com IDE and Developer Console, which is unfortunate as the latter provides features and metrics not supported by the IDE.

Checkpoints.
In Summer ’13 Simulated Breakpoints are now termed Checkpoints and can be set on lines of Apex script in the same way using the code editor (now with syntax highlighting) within the Developer Console. In addition to capturing a heap dump, Apex script or SOQL query Execution Actions can be added which run when code execution hits the Checkpoint. Very useful in determining state of the execution context and in particularly in debugging data related issues.

In the screenshot below we can see the new Developer Console UI for Summer 13, the Checkpoints tab and the definition of an example SOQL query Execution Action which will run when the Checkpoint is hit.

3.Checkpoint create

In the screenshot below we can see the result, when the Heap Dump log statement is double-clicked a Checkpoint tab is revealed with subtabs that show the Heap Dump itself, plus the result of defined Execution Actions. Note, I was unable to open the Checkpoint results where an Apex Execution Action was defined, from the log activity it does appear to run as an Execute Anonymous block, but it isn’t clear if the user context is the debugging user or the running user.

4.Checkpoint result

Patterns of Construction

I’m a big advocate of setting out the key elements of the development process succinctly but unambiguously at the start of a software development project, particularly in cases where I have no prior history of working with the development team. Such process elements typically cover environments, coding standards, technical design and review requirements, source-code control strategy etc. Perhaps the most valuable area to cover are the basic patterns of construction (or Design Patterns), without this developers are left to their own devices in naming technical components and structuring code, which can be a serious issue with maintainability and standardisation. It is incredibly time expensive and de-motivating to address this after the fact. Instead a clear picture provided upfront can provide the development team with a strong reference covering 80% of the cases, the remainder can be addressed individually during technical design. The example below provides an example of a basic construction pattern which covers naming conventions and structural concerns. Following such a pattern makes the technical implementation predictable and should improve maintainability, the latter being a obligation to take seriously on consulting projects. My rule of thumb is to try and leave the org in a state a future me would consider acceptable.

New Advanced Apex Programming Book

Interesting new book covering advanced Apex topics such as execution context, asynchronous programming, robust design patterns and so on.. Excellent addition to the Force.com Developer’s arsenal!

Advanced Apex Programming – Author: Dan Appleman
Table of Contents

Update (2012-09-10)
I now have my hands on this book and have to say I’m really impressed. So often I work on projects where the principles of Thinking in Apex have been overlooked and basic mistakes made – now there’s an alternative to having to infer the right mindset to bring to Force.com development from the technical documentation. Well documented design patterns that address real world concerns can only help raise the quality bar.

SOQL Record Locking

There may be cases where a pessimistic locking strategy makes sense within your custom Apex script, for example the available inventory statistic on a Stock record may need to be locked while your code works out the correct value to decrement.

The interesting, but rarely used SOQL keyword “FOR UPDATE” can be applied to SOQL query statements to lock the returned records such that only the current call context can modify the records via DML operations.

Account a = [select Id, Name from Account where City='Edinburgh' LIMIT 1 FOR UPDATE];

Results are automatically ordered by ID, a preferred ORDER BY clause is not supported. When applying custom locking, remember to order locks from parent to child and always, always follow the same sequence in all cases, otherwise you open up the possibility of introducing deadlocks.

Remember each Apex call context is an implicit transaction with auto-commit, i.e. committed or rolled-back atomically. For finer, conditional transaction control within a call context use savepoints (Database.setSavePoint()).

Reflection in Apex

For experienced developers, the lack of reflection capabilities in the Apex language can be a limitation in the type of patterns that can be ported from other languages (Java, C# etc.). With Summer 12, the Type class now supports the newInstance method, enabling instantiation via the class name as a string. Sounds simple, but this method opens the door to a number of typical reflection use cases. Excellent news.

This developer force post provides an excellent intro.

FieldSets in Apex

As of the Summer ’12 release FieldSets can be accessed through Dynamic Apex (or Apex Describe). Remember, FieldSets are admin configured arbitrary groupings of fields, added on the object detail page within setup. With the upcoming release, controller code can now dynamically build a soql query that retrieves the data for the fields in the FieldSet, which in turn can then provide data for Visualforce dynamic bindings. Previously the binding was possible, but there was no way to retrieve the fields to construct the soql query – a serious limitation.

Why is this interesting? Well, consider you’re developing a custom app comprised of Visualforce pages, wouldn’t it be great if new custom fields added later could simply just render in the UI (in a logical position) without modifying the page definition or controller code? Or perhaps that obsolete field you no longer wish to display just disappears..

Admin configurable custom pages (and apps) is a good thing. If you’re building custom pages give some thought to FieldSets and dynamic field rendering, this could save you time and your customer money down the line.

Same principle as Custom Labels, you need to rule the dynamic field rendering requirement out, not in.

for(Schema.FieldSetMember f : SObjectType.Player__c.FieldSets.Dimensions.getFields()){
  q+=f.getFieldPath()+',';
}

Visualforce User Agent Detection

The code below provides an example of a page action method used to detect a mobile user-agent and perform redirection. Alternatively the same approach could be used with dynamic Visualforce components to switch between mobile/web optimised page composition.

	public PageReference redirectDevice(){
		String userAgent = ApexPages.currentPage().getHeaders().get('USER-AGENT');
		
		//& some devices use custom headers for the user-agent.
		if (userAgent==null || userAgent.length()==0){
			userAgent = ApexPages.currentPage().getHeaders().get('HTTP_X_OPERAMINI_PHONE_UA');
		}		
		if (userAgent==null || userAgent.length()==0){
			userAgent = ApexPages.currentPage().getHeaders().get('HTTP_X_SKYFIRE_PHONE');
		}
		 		
  		//& replace with custom setting - using (?i) case insensitive mode.		
		String deviceReg = '(?i)(iphone|ipod|ipad|blackberry|android|palm|windows\\s+ce)';
		String desktopReg = '(?i)(windows|linux|os\\s+[x9]|solaris|bsd)';
		String botReg = '(?i)(spider|crawl|slurp|bot)';
		
		Boolean isDevice=false, isDesktop=false, isBot=false;
		
		Matcher m = Pattern.compile(deviceReg).matcher(userAgent);
		if (m.find()){
			isDevice = true;
		} else {
			//& don't compile the patterns unless required.
			m = Pattern.compile(desktopReg).matcher(userAgent);
			if (m.find()) isDesktop = true;
			
			m = Pattern.compile(botReg).matcher(userAgent);
			if (m.find()) isBot = true;
		}
		//& Default is mobile - unless a desktop or bot user-agent identified.					
		if (!isDevice && (isDesktop || isBot)) return null; //& no redirect.						
		return new PageReference('/apex/MobileIndex'); //& redirect.
	}