Apex ã§ã®ãã¡ã€ã³ã¬ã€ã€ãŒã®ååã®é©çš
åŠç¿ã®ç®ç
ãã®åå ãå®äºãããšã次ã®ããšãã§ããããã«ãªããŸãã
- ãã¡ã€ã³ Apex ã¯ã©ã¹ãäœæããã
- ãã¡ã€ã³ã¯ã©ã¹ã«ããã©ã«ãèšå®ããã³æ€èšŒã³ãŒããåæ ããã
- ãã¡ã€ã³ã¯ã©ã¹ã®ã¡ãœããã Apex ããªã¬ãŒã€ãã³ãã«å¯Ÿå¿ä»ããã
- å®è¡æã«ã»ãã¥ãªãã£é©çšã®ã¢ããªã±ãŒã·ã§ã³ãå¶åŸ¡ããã
äžç·ã«ãã¬ã€ã«ãé²ã¿ãŸããã
ãšãã¹ããŒãã®èª¬æãèŠãªãããã®ã¹ããããå®è¡ãããå Žåã¯ã 次ã®åç»ãã芧ãã ãããããã¯ãTrail Togetherã(äžç·ã«ãã¬ã€ã«) ã·ãªãŒãºã®äžéšã§ãã
(ãã®åç»ã¯ 17:30 ã®æç¹ããå§ãŸããŸããæ»ããŠæé ã®æåããèŠçŽãå Žåã¯ã泚æãã ããã)
åç §ã³ãŒã
ãã®ã¢ãžã¥ãŒã«ã§ã¯ãFFLIB Apex Common Samplecode ãããžã§ã¯ãã®æ¬¡ã® Apex ã¯ã©ã¹ãåç §ããŸããå§ããåã«éããŠããããšããå§ãããŸãã
ãã¡ã€ã³ã¯ã©ã¹ã®äœæ
åã®åå ã®ããªã¬ãŒã³ãŒãã§äœ¿çšãããŠãã fflib_SObjectDomain ã¯ã©ã¹ã¯ãããªã¬ãŒãã³ãã©ãŒããµããŒãããåºæ¬ã¯ã©ã¹ãæ¡åŒµãããªããžã§ã¯ãã»ãã¥ãªãã£ãªã©ã®æçãªæ©èœãæäŸããŸãã

ãã®åºæ¬ã¯ã©ã¹ã¯ããã³ãã¬ãŒãã¡ãœãããã¿ãŒã³ã䜿çšããŠãonValidate() ã¡ãœããã«ããã¬ã³ãŒãæ€èšŒãš onApplyDefaults() ã¡ãœããã«ããé
ç®å€ã®ããã©ã«ãèšå®ãè¡ãå
±éã®ãã¡ã€ã³ããžãã¯ãå®è£
ããããã®æšæºããã¯ãæäŸããŸãã
ããã«ãç¹å®ã® Apex ããªã¬ãŒã€ãã³ãã«é¢é£ããããžãã¯ãé
眮ããããã®ã¡ãœããããããŸããæåŸã«ãã³ã³ã¹ãã©ã¯ã¿ãŒ (ãã®ããã« fflib_SObjectDomain ã¯ã©ã¹ãæ¡åŒµãããã¹ãŠã®ã¯ã©ã¹ãå
¬éããå¿
èŠããããŸã) ããåã®åå
ã§èª¬æããäžæ¬åŠçåã®èšèšç®æšã«æ²¿ã£ãŠ sObject ã®ãªã¹ããååŸããŸãã
以äžã¯ãOpportunities ãã¡ã€ã³ã¯ã©ã¹ã®åºæ¬çãªå®è£ ã§ãã
public class Opportunities extends fflib_SObjectDomain {
public Opportunities(List<Opportunity> sObjectList) {
super(sObjectList);
}
public class Constructor implements fflib_SObjectDomain.IConstructable {
public fflib_SObjectDomain construct(List<SObject> sObjectList) {
return new Opportunities(sObjectList);
}
}
}Constructor å
éšã¯ã©ã¹ã«ãã£ãŠãåã®åå
ã® Apex ããªã¬ãŒãµã³ãã«ã§äœ¿çšãããŠããåºæ¬ã¯ã©ã¹ã¡ãœãã fflib_SObjectDomain.triggerHandler ãããã¡ã€ã³ã¯ã©ã¹ã®ããªã¬ãŒãã³ãã©ãŒããžãã¯ã®æ°ããã€ã³ã¹ã¿ã³ã¹ãäœæã㊠sObject ãªã¹ã (Trigger.new ãªã©) ã§æž¡ããããã«ãªã£ãŠããŸã ã
é ç®ã®ããã©ã«ãèšå®ããžãã¯ã®å®è£
é
ç®ã®ããã©ã«ãèšå®ããžãã¯ã®å ŽæãæäŸããããã«ãfflib_SObjectDomain åºæ¬ã¯ã©ã¹ã¯ onApplyDefaults() ã¡ãœãããå
¬éããŸãããã®ã¡ãœããã¯ãããªã¬ãŒã®åŒã³åºãæã« fflib_SObjectDomain åºæ¬ã¯ã©ã¹ã® handleBeforeInsert() ã¡ãœããããã³ãŒã«ãããŸãã
ããã«ããžãã¯ãé 眮ããããšã§ãã¬ã³ãŒãã远å ããããšãã«ã¢ããªã±ãŒã·ã§ã³å šäœã§äžè²«ããããã©ã«ãã䜿çšãããŸããå¿ èŠã«å¿ããŠããµãŒãã¹ããæç€ºçã«ã³ãŒã«ããããšãã§ããVisualforce ããŒãžãŸã㯠Lightning ã³ã³ããŒãã³ãçµç±ã§ã«ã¹ã¿ã UI ã«ã¢ã¯ã»ã¹ããŠãããŠãŒã¶ãŒã«ããã©ã«ãã¬ã³ãŒãå€ãæç€ºããå Žåãªã©ã«åœ¹ç«ã¡ãŸãã
ãã®åºæ¬ã¯ã©ã¹ã¯ãã³ã³ã¹ãã©ã¯ã¿ãŒã³ãŒã«ã§æäŸããã sObject ãªã¹ãã records ããããã£ãä»ããŠãã¹ãŠã®ã¡ãœããã«å
¬éããŸããããã¯å³å¯ã«ã¯ããªã¬ãŒã·ããªãªã§ã¯ãããŸããããåã®åå
ã®ãã¡ã€ã³èšèšã®ç®æšã«åŸã£ãŠãäžæ¬åŠçåãèæ
®ããããšã匷ããå§ãããŸãã
public override void onApplyDefaults() {
// Apply defaults to Opportunities
for(Opportunity opportunity : (List<Opportunity>) Records) {
if(opportunity.DiscountType__c == null) {
opportunity.DiscountType__c = OpportunitySettings__c.getInstance().DiscountType__c;
}
}
}æ€èšŒããžãã¯ã®å®è£
äžèšã®ããªã¬ãŒã¡ãœãããäžæžãããŠæ€èšŒããžãã¯ãå®è£
ã§ããŸããããã¹ããã©ã¯ãã£ã¹ãšããŠããã㯠Apex ããªã¬ãŒåŒã³åºãã® after ãã§ãŒãºã§ã®ã¿è¡ããŸããfflib_SObjectDomain åºæ¬ã¯ã©ã¹ã® 2 ã€ã® onValidate() ã¡ãœããã®ãããããäžæžãããããšã§ãæç¢ºã«å®çŸ©ãããå Žæã«ãã®ããžãã¯ãå®è£
ã§ããŸãã
public override void onValidate() {
// Validate Opportunities
for(Opportunity opp : (List<Opportunity>) this.records) {
if(opp.Type.startsWith('Existing') && opp.AccountId == null) {
opp.AccountId.addError('You must provide an Account when ' +
'creating Opportunities for existing Customers.');
}
}
}äžèšã® onValidate() ã¡ãœããã¯ãã¬ã³ãŒãããªããžã§ã¯ãã«æ¿å
¥ããããšåºæ¬ã¯ã©ã¹ããã³ãŒã«ãããŸããã¬ã³ãŒãæŽæ°æã®ããŒã¿å€æŽã«åå¿ããæ€èšŒããžãã¯ãå¿
èŠãªå Žåãæ¬¡ã®ããªã¢ã³ããäžæžãã§ããŸãã
public override void onValidate(Map<Id,SObject> existingRecords) {
// Validate changes to Opportunities
for(Opportunity opp : (List<Opportunity>) Records) {
Opportunity existingOpp = (Opportunity) existingRecords.get(opp.Id);
if(opp.Type != existingOpp.Type) {
opp.Type.addError('You cannot change the Opportunity type once it has been created');
}
}
}</Opportunity></Id,SObject>åºæ¬ã¯ã©ã¹ã¡ãœãã handleAfterInsert() ããã³ handleAfterUpdate() ã®ã³ãŒãã§ã¯ãApex ããªã¬ãŒã® after éšå (ãã®ãªããžã§ã¯ãã«å¯Ÿãããã¹ãŠã® Apex ããªã¬ãŒãå®äºããåŸ) ã§ã®ã¿ããã®ã¡ãœãããã³ãŒã«ããããšã§ãã»ãã¥ãªãã£ãã¹ããã©ã¯ãã£ã¹ãé©çšãããŸãããã®åäœã¯ãAgentExchange ããã±ãŒãžéçºè
ã«ãšã£ãŠããããŠéèŠã§ã (ããªãœãŒã¹ãã»ã¯ã·ã§ã³ãåç
§)ã
Apex ããªã¬ãŒããžãã¯ã®å®è£
å®è£ ãããã¡ã€ã³ããžãã¯ãå¿ ãäžèšã®ã¡ãœããã«åœãŠã¯ãŸããšã¯éããŸãããå®éãé¢å¿ã®åé¢ã¬ã€ãã©ã€ã³ã§ã¯ããããã®ã¡ãœããã«ãã¹ãŠã®ããã©ã«ãèšå®ãŸãã¯æ€èšŒããžãã¯ãå®è£ ããããšã¯å³æ ŒãªèŠä»¶ã§ã¯ãããŸãããããã¯åãªãèæ ®äºé ã§ããå¿ èŠã§ããã°ãäžèšã®ã¡ãœããã®ãã¹ãŠã«å ããããšãã§ããŸãã
ä»ã®ãã¡ã€ã³ãªããžã§ã¯ããä»ããŠåäœãåŒã³åºã Apex ããªã¬ãŒé¢é£ã®ã³ãŒããå®è£
ããããã«ã次ã®äŸã§ã¯å°ãäžèªç¶ã§ãããonAfterInsert() ã¡ãœãããäžæžãããŠãæ°ãã Opportunities ãæ¿å
¥ããããåžžã«é¢é£ãã Account ã® Description é
ç®ãæŽæ°ããŸãã
public override void onAfterInsert() {
// Related Accounts
List<Id> accountIds = new List<Id>();
for(Opportunity opp : (List<Opportunity>) Records) {
if(opp.AccountId!=null) {
accountIds.add(opp.AccountId);
}
}
// Update last Opportunity activity on related Accounts via the Accounts domain class
fflib_SObjectUnitOfWork uow =
new fflib_SObjectUnitOfWork(
new Schema.SObjectType[] { Account.SObjectType });
Accounts accounts = new Accounts([select Id from Account
where id in :accountIds]);
accounts.updateOpportunityActivity(uow);
uow.commitWork();
}</Opportunity></Id></Id>äžèšã®äŸã§ã¯æ¬¡ã®ç¹ã«çæããŠãã ããã
- Accounts ãã¡ã€ã³ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãã€ã³ã©ã€ã³ SOQL ã¯ãšãªã䜿çšããŠåæåãããŸãããã®ã¢ãžã¥ãŒã«ã®æ¬¡ã®åå
ã§ã¯ãã¯ãšãªããžãã¯ãã«ãã»ã«åããŠããã¡ã€ã³ã¯ã©ã¹ããžãã¯ã«ãšã£ãŠéèŠãªåºåããŒã¿ã®åå©çšæ§ãšäžè²«æ§ãé«ããã®ã«åœ¹ç«ã€ãã¿ãŒã³ã玹ä»ããŸãã
- ãSOCãã¢ãžã¥ãŒã«ã«ãããšã
fflib_SObjectUnitOfWorkã€ã³ã¹ã¿ã³ã¹ã¯ããµãŒãã¹ã³ã³ããã¹ãããã Apex ããªã¬ãŒã³ã³ããã¹ãã§äœ¿çšãããŸãããã®ã±ãŒã¹ã§ã¯ããã®éçšç¯å²ã¯ããªã¬ãŒã€ãã³ããŸãã¯ã¡ãœããã§ãããããã®ã¡ãœããã¯ããµãŒãã¹ã¬ã€ã€ãŒã§ã¯ãªããã¿ãŒã³ããçŽæ¥ã³ãŒã«ãããŸãããã®ãããäœæ¥åäœãäœæãã㊠Accounts ã¡ãœããã«æäŸãããAccounts ã¡ãœãããæŽæ°ã Account ã¬ã³ãŒãã«ç»é²ã§ããããã«ãªããŸããããã«ã¯å«ãŸããŠããŸããããéåžžã¯ã1 ãæã§äœæ¥åäœãåæåããŠéè€ãåé¿ããããšããå§ãããŸãã
- Accounts ã«åºã¥ãæŽæ°ã¢ã¯ãã£ããã£ã¯ãOpportunity ãšãããã Account ãªããžã§ã¯ãã®åäœã§ãããããããã§ Accounts ãã¡ã€ã³ã¯ã©ã¹ã«å§ããããšã¯åŠ¥åœã§ãããã¡ã€ã³ã¯ã©ã¹éã§ã®ãã®çš®ã® SSC ã«ã€ããŠã¯ã次ã®ã»ã¯ã·ã§ã³ã§ã説æããŸãã
åèãŸã§ã«ã以äžã Accounts.updateOpportunityActivity ã¡ãœããã§ãã
public class Accounts extends fflib_SObjectDomain {
public Accounts(List<Account> sObjectList) {
super(sObjectList);
}
public void updateOpportunityActivity(fflib_SObjectUnitOfWork uow) {
for(Account account : (List<Account>) Records) {
account.Description = 'Last Opportunity Raised ' + System.today();
uow.registerDirty(account);
}
}
}ã«ã¹ã¿ã ããžãã¯ã®å®è£
åºæ¬ã¯ã©ã¹ããäžæžãå¯èœãªã¡ãœããã®å®è£ ã®ã¿ã«å¶éãããŠããããã§ã¯ãããŸãããåã®åå ã®ä¿®æ£ããããµãŒãã¹ã¬ã€ã€ãŒãæãåºããŠãã ããã
public static void applyDiscounts(Set<Id> opportunityIds, Decimal discountPercentage) {
// Unit of Work
// ...
// Validate parameters
// ...
// Construct Opportunities domain class
Opportunities opportunities = new Opportunities( ... );
// Apply discount via domain class behavior
opportunities.applyDiscount(discountPercentage, uow);
// Commit updates to opportunities
uow.commitWork();
}</Id>ãã®ã³ãŒãã¯ãå²åŒã Opportunity ã«é©çšã§ãããã¡ã€ã³ã¯ã©ã¹ã¡ãœããã䜿çšãããã®ããžãã¯ããã¡ã€ã³ãªããžã§ã¯ãã«é¢é£ä»ããããå Žæã«ããã«ã«ãã»ã«åããŸãã
å¿
èŠã«å¿ããŠããã®ã³ãŒã㯠OpportunityLineItems ãã¡ã€ã³ã¯ã©ã¹ã«è¡ã¬ãã«ã®å²åŒã®é©çšãå§ããŸãã説æäžãååã©ã€ã³ãå©çšããåè«ã§ã¯ããžãã¯ãç°ãªããšæ³å®ããŠãã ããã

OpportunityLineItems ãã¡ã€ã³ã¯ã©ã¹ã®ã³ãŒãã¯ãã¡ãã§ç¢ºèªã§ããŸãã
fflib_ISObjectUnitOfWork ã€ã³ã¹ã¿ã³ã¹ã¯åŒæ°ãšããŠåãããŸããããããããšã§ã³ãŒã«å
(ãã®å Žå㯠OpportunitiesService.applyDiscount ã¡ãœãã) ãããããã¡ã€ã³ã³ãŒãå
ã§æž¡ããŠãããã«å¯Ÿããäœæ¥ãç»é²ãããã®åŸãOpportunityLineItems ãã¡ã€ã³ã¯ã©ã¹ã® applyDiscount() ã¡ãœããã«ãæž¡ããããã«ãªããŸãã
ãã¡ã€ã³ã¯ã©ã¹ãšãµãŒãã¹ã¯ã©ã¹ã®ããžãã¹ããžãã¯ã®æ¯èŒ
ã©ãã«ã³ãŒããé 眮ãã¹ããããããªããªãããšããããŸããSOC ååã«ç«ã¡è¿ã£ãŠããµãŒãã¹ã¬ã€ã€ãŒãšãã¡ã€ã³ã¬ã€ã€ãŒã®é¢å¿ãäœã«ããããèããŠã¿ãŸãããã
ã¢ããªã±ãŒã·ã§ã³ã®é¢å¿ã®çš®é¡ |
ãµãŒãã¹ãŸãã¯ãã¡ã€ã³ |
äŸ |
|---|---|---|
ã¬ã³ãŒãããŒã¿ãæäœãããããäžè²«ããŠé ç®ãæ€èšŒãããããã©ã«ãå€ãèšå®ãããããã«ããã |
ãã¡ã€ã³ |
ååã远å ããããããã©ã«ãã®å²åŒããªã·ãŒãé©çšããã |
è€æ°ã®æ å ±ã®äžæ¬ååŸãŸãã¯è€æ°ã®ãªããžã§ã¯ãã®æŽæ°ãå«ãŸãããŠãŒã¶ãŒãŸãã¯ã·ã¹ãã ã¢ã¯ã·ã§ã³ã«åå¿ãããã»ãšãã©ã®å Žåã¯ãã¬ã³ãŒãã®ã³ã¬ã¯ã·ã§ã³ã«å¯ŸããŠçºçå¯èœãªã¢ã¯ã·ã§ã³ãæäŸãããã®ã¢ã¯ã·ã§ã³ãå®äºããã®ã«å¿ èŠãªãã¹ãŠã調æŽããŸã (ä»ã®æ¯æŽãµãŒãã¹ãšé£æºããå¯èœæ§ããããŸã)ã |
ãµãŒãã¹ |
äœæ¥æç€ºããè«æ±æžãäœæããŠèšç®ãããäŸ¡æ Œè¡šæ å ±ãååŸããå ŽåããããŸãã |
ä»ã®é¢é£ã¬ã³ãŒãã®å€æŽã®äžéšãšããŠããŸãã¯ãŠãŒã¶ãŒãŸãã¯ã·ã¹ãã ã¢ã¯ã·ã§ã³ã®å®è¡ã«ãã£ãŠãã¢ããªã±ãŒã·ã§ã³ã§çºçããã¬ã³ãŒããžã®å€æŽãåŠçãããããšãã°ãå¿ èŠã«å¿ããŠããã©ã«ãå€ãèšå®ããŸããããé ç®ã®å€æŽã«ãã£ãŠåœ±é¿ãåããå¥ã®é ç®ãæŽæ°ãããŸãã |
ãã¡ã€ã³ |
Opportunity ãäœæããããšãã« Account ãªããžã§ã¯ããã©ãåå¿ãããããŸã㯠Opportunity å²åŒããã»ã¹ã®å®è¡æã« Discount ãã©ãé©çšãããããã¡ã¢: ãã®çš®ã®ããžãã¯ã¯ãµãŒãã¹ã¬ã€ã€ãŒã§éå§ããããšããããŸããããµãŒãã¹ã¡ãœãããµã€ãºã®ãµã€ãºãšè€éãã管çããããåå©çšãæ¹åãããããå Žåã¯ããã¡ã€ã³ã¬ã€ã€ãŒã§ããé©åã«æ©èœããŸãã |
è€æ°ã®ç°ãªããªããžã§ã¯ãã«å¯ŸããŠé©çšãããå ±éã®åäœãåŠçããã |
ãã¡ã€ã³ |
åè«ååãŸãã¯äœæ¥æç€ºååã©ã€ã³ã®äŸ¡æ Œãèšç®ãããã¡ã¢: ãããå
±æãã¡ã€ã³åºæ¬ã¯ã©ã¹ã«é
眮ããŠã |
ã»ãã¥ãªãã£é©çšã®å¶åŸ¡
ããã©ã«ãã§ã¯ãfflib_SObjectDomain åºæ¬ã¯ã©ã¹ã¯ Salesforce ãªããžã§ã¯ãã« CRUD ã»ãã¥ãªãã£ãé©çšããŸãããã ããã³ã³ãããŒã©ãŒãŸãã¯ãµãŒãã¹ã®ã©ã¡ãã䜿çšããå Žåã§ããããã¯ãªããžã§ã¯ããžã®ããããçš®å¥ã®ã¢ã¯ã»ã¹ã«å¯ŸããŠåŒã³åºãããŸãããµãŒãã¹ããžãã¯ã§ã¯ããªããžã§ã¯ããžã®æš©éãèŠæ±ããã«ãŠãŒã¶ãŒã«ä»£ãã£ãŠãªããžã§ã¯ãã«ã¢ã¯ã»ã¹ããå ŽåããããããããŸããã
ãã®ããã©ã«ãã®åäœãç¡å¹ã«ããŠç¬èªã®ãµãŒãã¹ã³ãŒãã§ã»ãã¥ãªãã£ãé©çšããå Žåãåºæ¬ã¯ã©ã¹ã®èšå®æ©èœã䜿çšã§ããŸããæ¬¡ã®äŸã¯ãåã³ã³ã¹ãã©ã¯ã¿ãŒã§ãããè¡ãæ¹æ³ã瀺ããŠããŸããä»ã«ãããã®ã³ãŒããå«ãç¬èªã®åºæ¬ã¯ã©ã¹ãäœæãããã¹ãŠã®ãã¡ã€ã³ã¯ã©ã¹ã«å¯ŸããŠãã®ã¯ã©ã¹ãæ¡åŒµãããšããæ¹æ³ããããŸãã
public Opportunities(List<Opportunity> sObjectList) {
super(sObjectList);
// Disable default Object Security checking
Configuration.disableTriggerCRUDSecurity();
}ãã¡ã€ã³ã¯ã©ã¹ã®ãã¹ã
ããå°ãããããå€ãã®ã«ãã»ã«åããããã£ã³ã¯ã«ããžãã¯ãåé¢ããããšã¯ããã¹ãäž»å°åéçº (TDD) ã«ãšã£ãŠã¡ãªããããããŸãããã¹ãã§ãã¡ã€ã³ã¯ã©ã¹ãæ§ç¯ããã¡ãœãããçŽæ¥åŒã³åºãããšã容æã«ãªãããã§ãããµãŒãã¹ã¬ã€ã€ãŒã®ãã¹ããäžèŠã«ãªãèš³ã§ã¯ãããŸããããããæŒžé²çãªãã¹ã-éçºã¢ãããŒããé©çšã§ããŸãã
ãã³ãºãªã³ Challenge ã®æºåããã
ãã® Challenge ãå®è¡ããã«ã¯ããApex ãšã³ã¿ãŒãã©ã€ãºãã¿ãŒã³: ãµãŒãã¹ã¬ã€ã€ãŒãã¢ãžã¥ãŒã«ã§äœ¿çšãã Trailhead Playground ãèµ·åããŸãããã§ã«ã€ã³ã¹ããŒã«ãããªãŒãã³ãœãŒã¹ã©ã€ãã©ãªãå¿ èŠã«ãªããŸããå¥ã® Trailhead Playground ã䜿çšããŠããå Žåã¯ãèµ·åããŠãããäžã® [Deploy to Salesforce (Salesforce ã«ãªãªãŒã¹)] ãªã³ã¯ã䜿çšããŠããŸã ApexMocks ã©ã€ãã©ãªã次㫠Apex Commons ã©ã€ãã©ãª ãã€ã³ã¹ããŒã«ããŠãã ããããããã®ã©ã€ãã©ãªãšããããã®ãªãŒãã³ãœãŒã¹äœ¿çšèš±è«Ÿå¥çŽã«ã€ããŠã®è©³çްã¯ãåãªããžããªãåç §ããŠãã ããã
-
ApexMocks ãªãŒãã³ãœãŒã¹ã©ã€ãã©ãªã®ãªãªãŒã¹
-
Apex Common ãªãŒãã³ãœãŒã¹ã©ã€ãã©ãªã®ãªãªãŒã¹
ãªãœãŒã¹
- GitHub: Apex Enterprise Patterns (Apex ãšã³ã¿ãŒãã©ã€ãºãã¿ãŒã³)
- Wikipedia: é¢å¿ã®åé¢
- Blog æçš¿:Where to Place Validation Code in an Apex Trigger (Apex ããªã¬ãŒã®ã©ãã«æ€èšŒã³ãŒããé 眮ããã)
- Blog æçš¿: Unit Testing, Apex Enterprise Patterns and Apex Mocks â Part 1 (åäœãã¹ããApex ãšã³ã¿ãŒãã©ã€ãºãã¿ãŒã³ãš Apex Mocks â ããŒã 1)
- Blog æçš¿: Unit Testing, Apex Enterprise Patterns and Apex Mocks â Part 2 (åäœãã¹ããApex ãšã³ã¿ãŒãã©ã€ãºãã¿ãŒã³ãš Apex Mocks â ããŒã 2)
- Blog æçš¿: Martin Fowler: Catalog of Patterns of Enterprise Application Architecture (ãšã³ã¿ãŒãã©ã€ãºã¢ããªã±ãŒã·ã§ã³ã¢ãŒããã¯ãã£ã®ãã¿ãŒã³ã®ã«ã¿ãã°)
