Salesforce 开发实践探索

  在Salesforce项目实施过程中,对项目代码的维护可以说占据极大的精力,无论是因为项目的迭代,还是需求的变更,甚至是项目组成员的变动,都不可避免的需要维护之前的老代码,而事实上,几乎没有任何一个项目的整个周期中,维护人员都是最初的开发人员,所以,合适的编码规范能极大的改善代码的可读性,方便其他开发者,甚至你自己在一段时间之后来阅读,维护你的代码

  首先最重要的是包括对象,字段,进程生成器,工作流,class类,触发器,函数,变量在内的所有API的命名应该是“望文生义”的,也即是说,通过你的API就能推测你的函数功能  

类型

规范

示例

对象API

对象名称单词用下划线连接

WeChat_Account__c

字段API

字段名称单词用下划线连接

WeChat_Account_ID__c

Class

单词连写,首字母大写

OrderItem

Trigger

Trigger名称=对象名+Trigger

AccountTrigger

Handler

Trigger的实现类 = Trigger名+Handler

AccountTriggerHandler

Visualforce页面

页面功能描述

OrderTracking

Vf页面控制类

VF页面的名+Controller

OrderTrackingController

WebService Class

类功能描述+WS

CalculationPriceWS

Batch Class

功能描述+Batch

AutoUpdateAccountStatusBatch

Schedule Class

功能描述+Sch

AutoUpdateAccountStatusSch

测试类

Test_+Class名或Trigger名

Test_OrderItem

常量

全大写,单词与单词之间下划线隔开

PAGE_SIZE

变量

驼峰命名法,尽可能避免单字符

userName

方法名

每个方法前必须加说明包括:参数说明、返回值说明、异常说明。如果方法名实在是太长可以对变量名缩写,但是必须添加相应的说明

checkStatus

上表是一些推荐的命名规范,仅供参考.

  在开发的过称中,需要尽可能的减少if,for循环的嵌套,下面是一段嵌套很深的代码节选

public void updateOppInsAccShare(List<Opportunity> list_opp,Map<Id,Opportunity> map_oldOpp){
    Set<Id> set_opp = new Set<Id>();
    for(Opportunity op : list_opp){
        Opportunity old = map_oldOpp.get(op.Id);
        if(op.OwnerId != null && op.OwnerId != old.OwnerId){
            set_opp.add(op.Id);
        }
    }
    if(!set_opp.isEmpty()){
        List<Opportunity> list_op = [select Id,OwnerId,AccountId,Account.OwnerId from Opportunity where Id in: set_opp];
        List<AccountShare> list_share = new List<AccountShare>();
        for(Opportunity op : list_op){
            if(op.AccountId != null && op.Account.OwnerId != null){
                
                for(Opportunity p : list_opp){
                    if(p.Id == op.Id){
                        //新的所有人不等于客户所有人,则创建共享
                        if(p.OwnerId != op.Account.OwnerId){
                            System.debug('============op.AccountId===' + op.AccountId + '---p.OwnerId--' + p.OwnerId + '----op.Account.OwnerId-----' + op.Account.OwnerId);
                            AccountShare share = new AccountShare();
                            share.AccountId = op.AccountId;
                            share.UserOrGroupId = p.OwnerId;
                            share.AccountAccessLevel='Edit';
                            share.OpportunityAccessLevel='Edit';
                            share.RowCause='Manual';
                            list_share.add(share);
                            break;
                        }
                    }
                }                                        
            }
        }
        if(!list_share.isEmpty()){
            insert list_share;
        }
    }
}

上面的代码可以看到多层逻辑嵌套,读起来不是那么的容易理解其核心逻辑,我们可以这样改写

 1 //业务机会所有人变更,共享该业务机会对应客户的读写权限给新所有人
 2 public void updateOppInsAccShare(List<Opportunity> list_opp,Map<Id,Opportunity> map_oldOpp){
 3     Set<Id> set_opp = new Set<Id>();
 4     for(Opportunity op : list_opp){
 5         if(op.OwnerId == map_oldOpp.get(op.Id).OwnerId){
 6             continue;
 7         }
 8         set_opp.add(op.Id);
 9     }
10     if(set_opp.isEmpty()){
11         continue;
12     }
13     
14     List<Opportunity> list_op = [select Id,OwnerId,AccountId,Account.OwnerId from Opportunity where Id in: set_opp];
15     List<AccountShare> list_share = new List<AccountShare>();
16     
17     for(Opportunity op : list_op){
18         if(op.AccountId == null){
19             continue;
20         }            
21         for(Opportunity p : list_opp){
22             if(p.Id != op.Id && p.OwnerId == op.Account.OwnerId){
23                 continue;
24             }            
25             System.debug('============所有人变更的业务机会对应客户id===' + op.AccountId 
26                          + '---业务机会所有人id--' + p.OwnerId 
27                          + '----所有人变更的业务机会对应的客户所有人-----' + op.Account.OwnerId);                         
28             AccountShare share = new AccountShare();
29             share.AccountId = op.AccountId;
30             share.UserOrGroupId = p.OwnerId;
31             share.AccountAccessLevel='Edit';
32             share.OpportunityAccessLevel='Edit';
33             share.RowCause='Manual';
34             list_share.add(share);
35             break;            
36         }                                        
37     }
38     if(!list_share.isEmpty()){
39         insert list_share;
40     }
41 }    

在原有基础上的修改如上,实质上对于权限共享的应该还包括删除原所有人的权限以及处理因所有人变更引起的业务机会读写权限缺失问题,可以参考我的博客:Salesforce 开发整理(三)权限共享

同样需要注意的一点是,避免在循环中使用SOQL查询语句以及DML操作。

Salesforce系统限制一次请求不允许超过100个SOQL查询语句,150个DML操作。下面是一个将查询和更新语句放在for循环中的操作

1 trigger ContactTrigger on Contact(after insert){
2     for(Contact c:trigger.new){
3         Account acc = [select id,Name from Account where id=:c.AccountId];
4         acc.Name = c.FirstName;
5         update acc;
6     }
7 }

如果一次执行的数据超过200条,那么就超出了Salesforce的限制,所以我们修改为批量的方法

 1 trigger ContactTrigger on Contact(after insert){
 2     //联系人关联客户id
 3     Set<Id> accIds = new Set<Id>();
 4     for(Contact c : trigger.new){
 5         if(c.AccountId != null){
 6             accIds.add(c.AccountId);
 7         }
 8     }
 9 
10     if(accids.size() > 0){
11         map<Id,Account> accountMap = new map<Id,Account>([select name from Account where id IN:accids]);
12         for(Contact c : trigger.new){
13             if(!accountMap.containskey(c.AccountId)){
14                 continue;
15             }
16             accountMap.get(c.AccountId).Name = c.LastName;
17         }
18     }
19     
20     if(accountMap.size() > 0) update accountMap.values();
21 }

同样的,在使用SOQL语句查询时,需要那些字段就查询那些字段,以提高性能。

最后是代码的注释部分

在类和Trigger的头部添加作者、创建时间、功能描述,如果此类需要修改,那么要记录修改时间,修改人,修改内容简介

/********
    *
    *  作者:Ricardo
    *  创建时间:2018-05-31  
    *  功能描述:
    *         function1() ...
    *         function2() ...
    *  修改人:updatePerson
  * 修改时间:updateTime
* 修改内容:description * ***** public class PrintQuote{
////// code.... }

方法注释应该有适当的说明,位于方法声明之前,包括:说明,参数说明、异常说明、返回值说明和特别说明等

 1 /*******
 2    *
 3    *  描述:单个发送邮件
 4    *  参数:address:邮件地址
 5    *  参数:text:邮件正文
 6    *  返回值:发送结果
 7    *
 8    ****/
 9 public String SendChatter(String address,String text){    
10     //  code....
11 }

针对一些关键的代码逻辑,特殊的变量都应该标记上代码注释,但是需要避免的是写太多无用的代码注释,否则跟不写注释的效果不没有太大的差异

最后是关于在开发中使用RecordTypeId,UserId,记录ID以及角色名称,用户名称等硬码,如果确定有特殊需要,可以使用自定义设置进行配置

开发时适当的遵循编码规范,可以写出简洁,易读,扩展性强,结构好的代码,既有助于自己编码习惯的养成,也能有效降低开发维护的难度,可以说是很有必要的。

以上如有错漏,欢迎指正,如有疑问,欢迎评论区留言探讨

推荐一些Salesforce编码最佳实践的网站

Force.com Apex Code Best Practices

VF页面最佳实践

SOQL(Salesforce Object Query Language)查询

SOOSL(Salesforce Object Search Language)查询

ApexCode最佳实践

Visualforce最佳实践

Force.com集成设计模式与最佳实践

Force.com大数据最佳实践

posted @ 2018-06-01 00:06  Ricardo.M.Lu  阅读(879)  评论(0编辑  收藏  举报