3

We have been trying to explore the enterprise pattern, having it implemented in our experiments.

We totally understand the benefits of having Service layer - Code reusability, easy maintenance.

However, while understanding the Selector layer I couldn't see why having this layer will be an added advantage. Referring to this book, we always end up creating a new instance for every new query we will be needing. So if mistakenly, I don't reuse the instance that was previously created for the same requirement and create a new instance to perform the query again, I would end up doing an additional SOQL query anyway.

Am I missing any important concept here of Selector layer - Can Selector layer (or, together with Service Layer) return us the exact same set of result that was previously already queried without performing another SOQL query again? Maybe, something similar to caching - i.e. if the same set of data is again requested and if it is already queried, then return it from the 'cache' (maybe data stored in static maps, list etc). Or, does this layer is just for serving the purpose of separation of concern - Making code more readable and presentable?

Also, how feasible/ideal it is to have our own lite version of this pattern? We can see that fflib might get little complicated to understand, implement and put in to practice - So is it okay to have our own Service layer and Selector layer (maybe a little less complicated query factory which can be utilized by Service layer)? Has anyone ever tried it out?

1
  • 1
    as an all-in adopter of fflib in many orgs, the sfdcfox answer is spot-on. My own experience is that adopting all of fflib - service, selector, domain, and uow is the way to go -- but you can start by applying it to a single sobject to get your feet wet. The fflib documentation in blogs and books (which you will refer to to get started) presumes all 4 layers. fflib also is well-integrated with apexmocks which supports unit testing without all the DML setup. If you search stackexchange for fflib, you'll see there is a fair amount of support here for the pattern
    – cropredy
    Commented May 7, 2021 at 0:43

1 Answer 1

6

The main point of a Selector layer is to standardize queries. In most applications, the same queries tend to be used in various places, so it makes sense to centralize them; you can easily update all similar queries in one place if a requirement changes. For example, maybe you decide to split an object in "half" by record types, and now you need all the original queries to use one record type, and you need new queries to handle the new record type. The Selector layer makes this change relatively trivial.

If you want a caching layer, you certainly can. I've implemented a simple cache without a service layer just to save on SOQLs; in one extreme example, a project I was working on required up to 98 SOQL to save a record, and I was able to cut it down to approximately 48, if I recall. But you can do Caching independently from a Selector layer, or you can combine the two for a powerful solution to drastically reduce SOQL usage, improving performance and reducing the likelihood of blowing up governor limits.

Of course, the Selector also does help with code presentation, but it's primary purpose is to consolidate common queries within an application; a good Salesforce implementation compartmentalizes various objects (mostly) to specific applications, helping the entire platform run efficiently, and a Selector design encourages this design pattern. Of course, many CRM objects (Account, Lead, Contact, Case, and Opportunity, mostly) will likely end up being part of several applications, but by separating logic out into Selectors and Services, you can minimize the amount of trigger processing that needs to happen for each application.

Another benefit can be unit tests. You can "fake" queries to retrieve objects that need not have been really saved in the database, potentially shaving many minutes off your unit tests. This can bring deployments down from hours to minutes in many cases.

Fflib is a finely tuned library that works well for most serious implementations, but you're right, it can be a bit overwhelming to deal with Units of Work, Selectors, Services, and everything else. It's definitely a "Swiss Army Knife" style library, but that also suggests it's functionally complete. Since it's open source, you can certainly cherry-pick which parts you'd like to use, or even be inspired by. If you don't think you'll ever get to the complexity that fflib is designed to handle, you don't need to use it.

3
  • 3
    Another benefit is the ability to mock the results, e.g. using SObjectFabricator, as long as you have dependency injection for getting hold of your Selector implementation. This is a nice way to make your unit tests faster by actually avoiding committing and querying data, where possible.
    – Phil W
    Commented May 6, 2021 at 16:54
  • 2
    @PhilW Indeed, with Dependency Injection, you can save governor limits and CPU time drastically in some cases. You still need end-to-end tests to validate governor limit usage though, but not for every test.
    – sfdcfox
    Commented May 6, 2021 at 17:15
  • @sfdcfox Hi. Would you mind explaining why everybody uses dynamic soql in fflib selectors? There is a point about mocks, but can't you use mocks without using dynamic query? It is just weird to see people using query factory where it is not needed. The common fields in selector sounds good, but in reality you do not want to query every field all the time.
    – Mr Smith
    Commented Jan 23 at 15:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .