Oh my god. It's full of code!

Organizing Your Salesforce Apex Codebase

Hey all,
So this is a topic that is constantly on my mind. I am a little bit OCD and I am always looking for the cleanest, fastest, overall best way to store and organize things. It’s borderline obsessive.

When I first started coding in Apex, I had no idea how you were supposed to structure things. I wrote a trigger and a class for every single task I wanted to do (if I wrote a class at all, often I would just jam everything in a trigger). It was an awful mess, but I was also a total n00b so I didn’t know any better. I couldn’t really find any suggestions on how to organize your code base, or what best practice were for triggers, classes and the ever popular unit tests.

I eventually started to realize you can in fact have multiple actions in one trigger, have multiple methods in your classes, reference classes from each other, and some of of those other things that seem so very obvious now. So after about 3 or 4 years, here are some suggestions for you newbies, or those who still don’t really know how they want to set things up. This is just my approach and it’s totally ‘home brewed’. I have no idea these ideas are best practice or not, but they seem to work really well for me.

1) One trigger file for every object type that needs Apex logic

When you first start, you may think it is good to be super modular and have a sepearte trigger file for every action (I thought that was a pretty slick idea at first too). And honestly, functionally it’s fine. However it does lead to a very cluttered code base, and it’s hard to turn individual triggers on and off. It’s also hard to see all the logic attached to an object. That is why I suggest making ONE trigger that has some if statements that control which logic gets fired when. Here, I’ll show you what I mean. We have an object in our org called a respondent (they basically power our whole org, and there is a hell of a lot of logic attached to them).

trigger RespondentTriggers on Respondent__c (after delete, after insert, after undelete, 
after update, before delete, before insert, before update) 
{
    
    Respondent__c[] respondents = Trigger.new;
    Respondent__c[] oldRespondents = Trigger.old;
    //This set of triggers is responsible for all actions related to respondent__c objects.
    
    //Before execution Triggers
    if(Trigger.isBefore)
    {
        if(Trigger.isInsert)
        {
            respondentClasses.populateRespondentData(respondents);
            respondentClasses.checkDupeHouseholdContacts(respondents,respondents);
            
        }
        else if(Trigger.isUpdate)
        {
            respondentClasses.populateRespondentData(respondents);
            respondentClasses.checkDupeHouseholdContacts(respondents,oldRespondents);
            
        }
    
        else if(Trigger.isDelete)
        {
            
        }
    
        else if(Trigger.isUnDelete)
        {
            
        }    
    }

    //After execution Triggers
    else if(Trigger.isAfter)
    {
        if(Trigger.isInsert)
        {
            respondentClasses.checkChildCampaignSpotsAvailable(respondents);
            respondentClasses.createPayments(respondents);
            respondentClasses.updateCounters(respondents);
            respondentClasses.flagRecentlyTested(respondents);
            respondentClasses.updateCampaignMembers(respondents);
            respondentClasses.setFirstRecruitDate(respondents);
            
        }
        else if(Trigger.isUpdate)
        {
            respondentClasses.updateCounters(respondents);
            respondentClasses.updateCampaignMembers(respondents);
            respondentClasses.flagRecentlyTested(respondents);
            respondentClasses.setFirstRecruitDate(respondents);
            respondentClasses.updateRelatedPayment(respondents);
            respondentClasses.clearPastParticipationOnCancel(respondents);
            
        }
    
        else if(Trigger.isDelete)
        {
            respondentClasses.updateCounters(oldRespondents);
        }
    
        else if(Trigger.isUnDelete)
        {
            respondentClasses.updateCounters(respondents);
        }    
    }            
}

Here you can easily see ALL the logic attached to my object (thanks in part to descriptive method names). You can also see it is very easy to control the order of execution of my triggers (which I have no idea how to do if you have separate trigger files), and you can easily turn off chunks by commenting out one line. It makes for a very clean setup in my opinion.

2) Group all logic for objects in one class if possible

Just like how I want all my trigger logic for each object in its own file, it is nice to keep all my methods for an object in it’s own class file. I know sometimes methods will be shared between objects (in that case I recommend trying to abstract them and put them in their own utilities class) but in general you can keep things pretty straight forward if you group similar methods into one class. Some methods will touch multiple types of objects, in that case I generally just put the method in the class for the object which triggers the method to fire. Example if I have a method that updates accounts and contacts, you might not be sure where to put it, but if you are updating all contacts as a result of an account update, but that method in your account methods class.

3) Use standardized naming

As programmers we all know the importance of descriptive variable and method names. However beyond just description I think it is important to be standardized. I want to look at a method or class and be able to know what it does, and what I can expect it to contain by looking at the name. For me, my classes fall into two categories generally.

A) Classes that contain logic for triggers
B) Classes that contain logic for custom visualforce pages

I have taken to using the simple naming convention of either [object]Classes or [pageName]Controller. Example my class with methods for my account trigggers is called accountClasses, while my class with methods for my online scheduling software is called schedulingController. It’s maybe not perfect, but it’s helpful and it looks nice when I look at the list of files in Eclipse 😛

4) Create a utilities class

There are some methods that are handy to have all over the place. Don’t recreate them in every class, simple create a single utilities class and reference its methods when you need. For example my utilities file has methods for reading an XML attribute from an XML string, breaking an serialized string (sent from an html form, serialized with jQuery) into a map, generating a random string of a given length, converting a sObject into JSON (though this won’t be needed after winter 12), and doing simple encryption/description. These methods don’t really belong to any particular object, they are just helpers that are handy to have.

5) Put your unit tests in the class they are testing

Unit tests have been a sticking point for me since day one. At first I didn’t understand them, then I didn’t find them useful, then I couldn’t figure out how I wanted to organize them, now I just… hate them. Anyway, I went through a lot of refactoring before I came up with a way of doing unit tests I liked. Like most people I started out putting the unit tests direction in the class. Querying for data I needed, maybe creating it right there whatever. Then I realized, wait I am creating a ton of the same testing data in every stupid class. What if I made one class, broke each class I am testing into it’s own method and just shared the data among the tests. Now I don’t need to make so much testing data and all my tests are compacted into one file. Genius! Or so I thought. Turns out this is an aweful idea. It is the opposite of modular and can make it very hard to deploy code if your sandbox and prod get too badly out of sync (too many schema or code changes). Don’t do this.

Instead, do what I am in the progress of migrating to. Create a class that only creates test data. Make a method in it for creating some of each kind of object you might want. Then put your testing code in each class, and simple call out to your data generating class to make the data you need for testing.

For example lets say I need an account to manipulate for my unit test. In my testDataGenerator class I have this method.

    
global class testDataGenerator 
{
    private static Account testAccount; 
    public static Account createTestAccount()   
    {
        if(testAccount == null)
        {
            //make an account so we can attach a contact to it
            Account localTestAccount = new Account(name='My Test Account', Tax_ID__c='99-9999999');
            insert localTestAccount;
            return localTestAccount;
        }
        else
        {
            return testAccount;
        }   
    }
}

It will make account on it’s first invocation, and simply return the existing account on any subsequent invocations, making it faster. Now if I need an account in my unit test I can just say

Account thisTestAccount = testDataGenerator.createTestAccount();

Boom, now I have an account I can use without having to write a ton of code, and it keeps my actual unit test clean. Of course this also means that since all my unit tests are using this class I only have to update the testDataGenerator if a new field becomes required on the account object, or some other such change is needed.

Anyway, those are just some things I learned from the school of hard knocks. I hope this helps some of you devs out there get your code organized. Till next time!

4 responses

  1. Matthew Mitchener

    I’ve just started writing Apex code and love these tips! Never thought of consolidating all trigger code in one file.

    November 14, 2013 at 5:01 pm

  2. Anonymous

    Thanks, although ideas are not new in programming, but was very useful to apply them to SF.

    January 23, 2014 at 3:54 pm

  3. Anonymous

    Thanks for the helpful tips + suggestions!

    September 4, 2014 at 9:06 pm

  4. Anonymous

    Thanks for sharing.

    June 28, 2016 at 1:13 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s