4

We have had quite intensive discussions regarding the same topic in the programmer's communities. The two main view points are

  1. As close to the first use - To limit scope and improve performance
  2. Together in the code - To improve readability

I think the compiler design is also an important consideration in this regard. So in salesforce where do you think is the best place to declare the variables? Does declaring them together affect the performance considerably? Please let me know your thoughts.

PS : My apologies if the question sounds too abstract. Wanted to know the feedback of the SFSE community on this topic.

8

Primary issues at play:

  • Declaration vs. Instantiation
  • Comprehension
  • Variable scope
  • Use of final
  • Access level

Declaration vs. Instantiation

Declaration and Instantiation are very different questions. Declaration of a variable should have a negligible effect on performance at any point in the system. My instinct is to say put it wherever best aids your comprehension, though variable scope is a concern. Instantiation is another question entirely.

Instantiation should be deferred until you know you need data. Where best to declare variables is more rooted in opinion. The differences can be well illustrated by an Execute Anonymous script:

static Blob getContent(Integer rows)
{
    String content = '';
    for (Integer i = 0; i < rows; i++)
        content += i + '\n';
    return Blob.valueOf(content);
}

Blob bigCsv; // declaration = nbd
//bigCsv = getContent(1000000000); // will cause CPU Timeout

Comprehension

The topic of where to declare variables to best aid comprehension is deeply rooted in opinion and will depend on your style and personality. It will, of course, vary greatly from programmer to programmer. Usually I try to group things together by type, visibility, etc. and keep my constructor close to the top of my file. I try to keep inner class definitions towards the bottom to minimize clutter.

In regards to properties, I find that if it is a vanilla { get; private set; } it's fine to put before my constructor, but if there is custom logic, it's better put after the constructor. Before or after method declarations? You can debate which ordering is most clear until the cows come home. Having a consistent system is probably the best policy.

But that's just, like, my opinion man. Rough outline:

public class ComprehensionExample
{
    public static final String CONSTANT1 = 'Cannot be modified!';
    public static final String CONSTANT2 = 'BOOM!';
    public static final Integer INT1 = 1;
    public static final Integer INT2 = 2;
    public static final Integer INT3 = 3;

    public String property { get; private set; }

    final String initVariable;
    final List<SObject> collectionVariable;
    public ComprehensionExample(String input, List<SObject> collection)
    {
        this.initVariable = input;
        this.collectionVariable = collection;
    }

    public void publicMethod() { }
    void privateMethod() { }

    public List<SObject> complexProperty
    {
        get
        {
            if (complexProperty == null)
            {
                // lazy load pattern
                complexProperty = [/*someQuery*/];
            }
        }
        private set;
    }

    public class InnerClassDefinition
    {
        Integer classProperty;
        public InnerClassDefinition() { /*constructor*/ }
    }
}

Variable Scope

Reading Material: Static and Instance Methods, Variables, and Initialization Code

You should declare your variable in such a way that it can only be accessed within the context where it is necessary. Method parameters will only be accessible within the method itself. Instance variables are not accessible from static methods.

public class ScopeExample
{
    // The below variable can be accessed by other classes (public)
    // The below variable can be accessed by other methods within the class (static)
    public static Integer methodCalls = 0;

    //The below variable cannot be accessed from static methods
    public String notAccessibleFromStaticMethods = 'Can\'t touch this';

    public static Integer add(Integer input)
    {
        // Methods can access static variables
        methodCalls++;

        // The below variable cannot be accessed elsewhere in the class
        // but it can be accessed again within the method
        Integer meaningOfLife = 42;


        // Variables declared within a block are not visible outside of it
        // regardless of the type of block
        for (Integer i = 0; i < 10; i++) { Integer invisibleSquare = 100; }
        if (true) { Integer invisibleSquare = 64; }
        else { Integer invisibleSquare = 36; }
        try
        {
            Integer invisibleSquare = 16;
            throw new DmlException();
        }
        catch (DmlException dmx)
        {
            Integer invisibleSquare = 4;
        }

            // to uncomment would cause compile fail:
            // system.debug(invisibleSquare);
        return input + methodCalls + meaningOfLife;
    }
}

Use of final

Reading Material: Using the final Keyword

This keyword makes you pay more attention if you want to declare and instantiate in separate locations. You can only instantiate once, and it has to be either at declaration or within a constructor or initialization block.

public class FinalExample
{
    // I find declaring constants at the top of my file improves readability
    // Constants should be declared outside of any method or inner class
    public static final String CONSTANT = 'Cannot be modified';

    // One useful pattern to manage stateful information is to make it final
    // This guarantees the information won't change
    // And you can make sure your collections are non-nillable
    final String initializationValue;
    final List<String> nonNullCollection;
    public FinalExample(String input)
    {
        this.initializationValue = input;
    }
}

Access Level

Reading Material: Access Modifiers

I try to be as restrictive on visibility and scope as possible. Hence, I use private whenever it is feasible to do so, unless I find a good reason to make something public. Note that you can still test the values of private variables by marking them with the @TestVisible annotation.

You mostly don't have to worry about global or protected unless you're working with managed packages. One particular pet peeve of mine is that when you are declaring a property, you should use private set unless you actually want the property writeable, which I find surprisingly often. Queried records are a great example.

public Account readOnly { get; private set; } // use when only you should set data
public String readWrite { get; set; } // use for page inputs
public String writeOnly { private get; set; } // rarely used in my experience

  • How do you think it will differ for instantiation, am assuming that there will be performance impacts higher than declaration. So in salesforce, will instantiation of non primitive types cause considerable performance degradation - when done earlier than required? – Prajith May 4 '16 at 18:50
  • @Stygon Your primary concern is using up heap that you don't need to use, but depending on your instantiation mechanism, it could use up a lot of cpu time too. – Adrian Larson May 4 '16 at 18:52
  • Yeah. CPU time also comes into play once we consider instantiation. Good point. – Prajith May 4 '16 at 18:53
  • 1
    @Stygon Added a more illustrative example. – Adrian Larson May 4 '16 at 18:58
  • another helpful tip: @TestVisible is helpful on private variables/methods so testmethods can set/manipulate/reference "constants" ; test in one place private methods that might have complex logic and where mocked sobjects are useful, etc.. – cropredy May 5 '16 at 22:56
3

I'd say option 0: declare and initialize at first use. This minimises the scope (the number of lines where the variable could be referenced so makes the code easier to understand) and reduces the chance of using a variable that has an invalid (or null) value.

For example:

// Compiler won't allow "a" to be referenced here

for (Account a : [
        select Name
        from Account
        limit 10
        ]) {
    // Do something with "a"
}

// Compiler won't allow "a" to be referenced here

Only use class fields (properties) where they are really necessary: local variables defined in a method have at most the scope of a method whereas class fields could be referenced in any method.

On this minimising scope theme, private is a huge help because it means a field or method can only be referenced within the class.

  • @AdrianLarson I'll leave that one to you... – Keith C May 4 '16 at 20:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.