Continuing my previous thoughts on the proper usage of before and after triggers, I'll share with you a problem that may arise if you choose to architect your trigger in an unorganized way.
For those of you that want the TL;DR version, skip the next 3 or 4 paragraphs of background info.
We have tree-like relationships between some of our data for an internal project management Force.com app that look like this (I haven't used UMLs in awhile, so don't read it thinking it's UML):
(Now, I realize that the pro SFers who are reading this may see that I am missing some killer functionality that Salesforce offers, but please don't share your suggestions to improve this data model, because I am leaving out the details for the sake of simplifying the explanation.)
When a time entry is inserted or updated, it tells its task to update itself because it has fields that summarize how much time has been entered on it. When a task updates, it will sum its child time entries and update some of its field values. Because the project also keeps track of the time entered on its tasks, the task forces its project to update itself.
When a time entry, task, or project moved, I was seeing a "Too many SOQL queries: 101" error because of all the recalculation that had to take place. This was a common error that I knew how to solve, but solving it, I discovered, required re-structuring and organizing the triggers on time entry and task.
Like most other developers, I slowly added features to this app as they were requested, placing each new feature in its own trigger. After seeing that I had 7 triggers on task, 4 triggers on time entry, and 4 triggers on project, I decided that it was time to get these under control by using a Master Trigger pattern, arriving at a variation of the pattern described by this blogger.
After moving the trigger logic into methods of a static helper class called by a single master trigger, I discovered that I was updating the parent task twice! Once in a before trigger and once in an after trigger! It took some more refactoring, but I was able to remove the update call from the before trigger and fix the problem.
Learn from my mistakes! Separate the duties of the before and after trigger! The before trigger is used to make the record fix itself, the after trigger for fixing others records.
Having learned my lesson, I have since always used the master trigger pattern to organize my code, and always consult Mr. Before and Uncle After when deciding where to put logic in a trigger.
Why use the Master Trigger pattern?
Tuesday, April 26, 2011
Labels:
Salesforce
Friday, April 22, 2011
(I give you permission to skip the first 3 paragraphs if you are a TL;DR kinda person)
As a Force.com developer, I find Salesforce triggers to be very powerful, because of their simplicity and ease-of-use. It's a simple concept, very much like 'events' in other languages, triggers are called when a record is CRUDed to or from the database. Do you desire functionality that is so complex that a formula field can't handle it? Add a regular field to the object and populate it on a before trigger. Do you want to update a child record when a field or fields on its parent record are modified? Add code to the after update trigger on the parent object to check for field modifications and then update the appropriate child record.
Now, I'm not here today to teach you the 101, 102, and 103 classes on Force.com triggers, I'm here to warn you of the unorganized mess that your triggers and its code will become as it grows in size. Like slowly warming the water in a crustacean's tub to keep it from noticing that it is, in fact, being cooked, triggers and classes will slowly start growing in your org. After you return from you week-long vacation in Maui, you will sit down, refreshed, grab the next thing in your to-do list, and start searching for a good place for this addition, or worse, bug-fix. Panic will strike you and you will be overcome by regret, regret for not reading this blog post earlier and realizing that you should get your steaming pile of code organized.
So, how do you get your steaming pile of code organized, you ask? Well, you can start by using triggers for their intended purpose. Not all triggers are created the same, you see. There are plainly visible limitations on some triggers, such as the Id, CreatedById, and LastModifiedDate standard fields having no value in a before insert trigger, or that all records in trigger.new are null in an after delete trigger. Then there are the invisible characteristics of triggers. What characteristics are those, you ask? Allow me to anthropomorphize them for you.
Triggers are divided into two categories: before and after. I'm sure you know what the difference is, but do you know how their differences feel?
The code in a 'before' trigger will run before the transaction occurs, so this should only be used for either validation or for populating its own too-complex-to-be-a-formula fields. This is where any decisions about the incoming data should be made, like forcing it to update its Club Card membership before entering the party, or bouncing the data, because it wasn't on your list. This all must occur *before* the data has been committed to the database - before it's entered the party. It's a perfect match. (Yes, Mr. Before is a bouncer at a club.) The one thing that you should restrain yourself from doing is using DML statements here. I suggest that these are better left for its sibling, the 'after' trigger.
The code in an 'after' trigger will run *after* the data has been committed to the database. The record received the all-clear and you gave it a flower for its lapel, and you allowed it to enter the party. This is where you tell other people that the record has entered the building. Do some SOQLs here to find the BFF object, and tell the BFF object to suit up, because it's game-time. Query for the DJ object and have it pull out the records that our new member enjoys. Give an update to each compatible female that our new member will encounter, telling them how awesome he is. Yes, Uncle After is the club owner, and he directs the rest of the objects to ensure that all club members are in-the-know about the current state of the club and its new member.
Anthropomorphized, signed, and sealed. Keep YOUR club organized and informed and YOU will be happy.
Labels:
Salesforce
Subscribe to:
Posts (Atom)