Read more at jamessimone.net, or return to the homepage





Building A Better Singleton

In the last post on Picklist Validation, I touched briefly on my disappointment in being unable to bring to fruition a better pattern for creating singletons — the perfect way to access constant values like those in a picklist:

I hate writing singleton property accessors, and have spent more hours than I'd care to admit trying to "solve" that problem through a variety of abstract class hacks ... none of which has borne any fruit. That's the nature of progression, though — failure is a part of the process.

In the ensuing weeks, I spent a considerable portion of time simply spent bulleting out thoughts about the "problem" that I had first introduced in the Idiomatic Apex post:

Last night, while winding down, the situation finally resolved itself in a burst of inspiration. Messily implemented first in my notebook (my handwritten braces get progressively worse), I finally figured out how to resolve the static nature of singletons with an object-oriented approach:

classes/Singleton.cls
1linkpublic abstract class Singleton {

2link private static final Map<Type, Singleton> typeToSingleton

3link = new Map<Type, Singleton>();

4link

5link public static Singleton getSingleton(Type type) {

6link if(typeToSingleton.containsKey(type) == false) {

7link typeToSingleton.put(type, (Singleton)type.newInstance());

8link }

9link return typeToSingleton.get(type);

10link }

11link}

Going back to the Picklist class from the previous post, now the base class just needed to extend Singleton so that subclasses could make use of the type:

1linkpublic abstract class Picklist extends Singleton {

2link //...etc

3link}

4link

5linkpublic class AccountIndustries extends Picklist {

6link public AccountIndustries() {

7link super(Account.Industry);

8link }

9link

10link //the newer invocation

11link //note that because there isn't a "set"

12link //method, if I wasn't going for mobile

13link //friendly code, this could be reduced to a single line

14link public static AccountIndustries Current {

15link get {

16link return (AccountIndustries)Singleton.getSingleton(AccountIndustries.class);

17link }

18link }

19link

20link //the more idiomatic singleton, for testing purposes

21link public static AccountIndustries Instance {

22link get {

23link if(Instance == null) {

24link Instance = new AccountIndustries();

25link }

26link return Instance;

27link }

28link private set;

29link }

30link

31link public String AGRICULTURE { get { return this.getValue('Agriculture'); }}

32link public String APPAREL { get { return this.getValue('Apparel'); }}

33link}

Of course, it's not enough to simply have code that compiles — is it performant? Let's do some simple iteration to stress test this new Singleton pattern:

classes/SingletonStressTests.cls
1link@isTest

2linkprivate class SingletonStressTests {

3link @isTest

4link static void it_should_establish_a_baseline_iteration_time() {

5link runTest(null);

6link }

7link

8link @isTest

9link static void it_should_use_idiomatic_singleton() {

10link runTest(new TestIdiomaticSingleton());

11link }

12link

13link @isTest

14link static void it_should_use_new_singleton() {

15link runTest(new TestNewSingleton());

16link }

17link

18link static void runTest(TestFunction function) {

19link for(Integer index = 0; index < 10000; index++) {

20link if(function != null) {

21link function.call();

22link }

23link }

24link }

25link

26link private abstract class TestFunction {

27link public abstract void call();

28link }

29link

30link private class TestIdiomaticSingleton extends TestFunction {

31link public override void call() {

32link System.debug(AccountIndustries.Instance.AGRICULTURE);

33link }

34link }

35link

36link private class TestNewSingleton extends TestFunction {

37link public override void call() {

38link System.debug(AccountIndustries.Current.AGRICULTURE);

39link }

40link }

41link}

Woof. Initial results were not promising:

TEST NAMEOUTCOMERUNTIME (MS)
SingletonStressTests.itShouldEstablishABaselineIterationTimePass23
SingletonStressTests.itShouldUseIdiomaticSingletonPass240
SingletonStressTests.itShouldUseNewSingletonPass1160

At first, I wondered if perhaps the dynamic Type.newInstance, or perhaps even the usage of the internal Map within the Singleton class was responsible for the slowdown. I would expect that there would be some slowdown, some overhead, in the usage of this more complicated setup ... however, I did not expect that the new method would be six times slower. Of course, in actual usage, such slowdown might not matter for your application ... but that's not the Joys Of Apex way. While I was ecstatic at the notion of saving 8 lines of code through the use of this new singleton one-liner, I wasn't about to recommend that to my clients if it meant taking such a big performance hit.

I tried eliminating the map. I tried passing an actual instance of the class to the getSingleton function (in this case, using new AccountIndustries) instead of dynamically spinning an instance up. Nothing. No changes reduced the runtime appreciably.

Then it hit me — the property Current itself was not being cached. Just for kicks, let's switch to the more idiomatic method for instantiating singletons to see if that made up any ground in terms of performance:

classes/AccountIndustries.cls
1linkpublic static AccountIndustries Current {

2link get {

3link if(Current == null) {

4link Current = (AccountIndustries)Singleton.getSingleton(AccountIndustries.class);

5link }

6link return Current;

7link }

8link private set;

9link}

The results were fascinating:

TEST NAMEOUTCOMERUNTIME (MS)
SingletonStressTests.itShouldEstablishABaselineIterationTimePass27
SingletonStressTests.itShouldUseIdiomaticSingletonPass109
SingletonStressTests.itShouldUseNewSingletonPass85

OK, so the pattern was not itself responsible for the performance slowdown. That was great news. It wasn't great news that it still took 9 lines of code to retrieve a singleton instance. Apex does feature static constructors, but those are no good; was there any way to ensure that the property was only initialized once without all the boilerplate?

Perhaps you see where this is headed now. There is, of course, one last trick up our sleeves — the final keyword. Traditionally used to ensure an object's dependencies are set only in the constructor, final is also compatible with static variables and ensures that they are only ever initialized once.

That makes the AccountIndustries object look pretty svelte indeed:

classes/AccountIndustries.cls
1linkpublic class AccountIndustries extends Picklist {

2link public AccountIndustries() {

3link super(Account.Industry);

4link }

5link

6link public static final AccountIndustries Current = (AccountIndustries)Singleton.getSingleton(AccountIndustries.class);

7link

8link //only keeping this property now to re-run the tests

9link public static final AccountIndustries Instance = new AccountIndustries();

10link

11link public String AGRICULTURE { get { return this.getValue('Agriculture'); }}

12link public String APPAREL { get { return this.getValue('Apparel'); }}

13link //etc, adding constants as is necessary to

14link //represent your picklists values in code

15link //with minimal usage of "magic" strings

16link //and the added benefit of intellisense

17link}

Running the tests again:

TEST NAMEOUTCOMERUNTIME (MS)
SingletonStressTests.itShouldEstablishABaselineIterationTimePass23
SingletonStressTests.itShouldUseIdiomaticSingletonPass98
SingletonStressTests.itShouldUseNewSingletonPass90

Easy peasy. I ran the tests dozens of times — for whatever reason, the newer method was always a few milliseconds faster than simply caching the instance. One can only surmise that there exists some fairly interesting tail-end optimizations in how the compiler assembles the Type.newInstance code which gives it a slight edge over the use of the new keyword.

linkSingleton Pattern Conclusion

Lessons learned in building a better singleton:

One thing that should be noted with the usage of Type.newInstance() — it requires the usage of a public zero-argument constructor. That shouldn't come as a surprise for those of you following along from the Factory post. It does however, fly in the face of the more classic singleton pattern (which makes the constructor private in order to force invocation through the public static variable). That's definitely something to consider when making your object design choices. The limitations of the Type class in Apex have frequently proven less-than-ideal in testing, as well, since it requires elevating test classes to public that shouldn't have to have elevated visibility. As always, food for thought.

I hope that this post proved educational for you. The usage of singletons is fairly common, and knowing that you have some tricks up your sleeve when you need to implement one is always a good thing. Till next time!

The original version of Building A Better Singleton can be read on my blog.

Singleton Pattern Conclusion

Home Apex Logging Service Apex Object-Oriented Basics Batchable And Queueable Apex Building A Better Singleton Continuous Integration With SFDX Dependency Injection & Factory Pattern Enum Apex Class Gotchas Extendable Apis Future Methods, Callouts & Callbacks Idiomatic Salesforce Apex Introduction & Testing Philosophy Lazy Iterators Lightweight Trigger Handler LWC Composable Modal LWC Composable Pagination LWC Custom Lead Path Mocking DML React Versus Lightning Web Components Refactoring Tips & Tricks Repository Pattern setTimeout & Implementing Delays Sorting And Performance In Apex Test Driven Development Example Testing Custom Permissions Writing Performant Apex Tests



Read more tech articles