Why do you think we can / can't replace SOQL Builders with User Mode SOQL?
I will answer your first question because I have more experience with Selectors which gives me a better view of why we need them.
First of all
WITH USER_MODE applies an FLS + Sharing rules to the SOQL:
The object permissions, field-level security, and sharing rules of the current user are enforced.
Of course, it's a good practice to do it, but we do not live in a perfect world, a lot of projects have bad design.
What if I would like to respect FLS, but get records
without sharing to meet business requirements?
WITH USER_MODE is not always a solution.
WITH USER_MODE covers a tiny fraction (FLS, sharing rules*) of what Selectors can do.
There are a lot of benefits that the Selector layer can provide:
- Additional level of abstraction - The selector layer is an additional level of abstraction that gives you the possibility to control the execution of SQOL. It's a quite generic statement, but that level is a source of other benefits.
- Mocking - Selector classes give a possibility to mock return values in unit tests.
- Mock external objects (__x) - External objects cannot be inserted in unit tests. You need to mock all SOQLs, of course, there is
if (Test. isRunningTest()), but not an elegant and clean solution.
- Mock custom metadata - Custom metadata cannot be inserted in unit tests unless the developer uses the Metadata API. Mocking can be a solution.
- Control field-level security - The best practice is to execute SOQLs
WITH USER_MODE to enforce field-level security and object permissions of the running user. The selector layer can apply
WITH USER_MODE by default to all of the queries, so the developer does not need to care about it. Developers can also add
WITH SYSTEM_MODE to all SOQLs from a specific selector. I believe selectors make FLS control easier.
- Control sharings rules - The selector allows to execution of different SQOLs within the same class in different sharing modes (
- Avoid duplicates - Generic SQOLs like
getByRecordType can be stored in the selector class. It makes developers' lives easier when you have predefined/tested methods.
- Default configuration - The selector class can provide default SOQL configuration like default fields, FLS settings, and sharing rules. I was on a project were sharing rules were screwed up and each SOQL needed a default condition
OwnerId = :UserInfo.getUserId(), it was quite simple to achieve with Selectors by adding a default condition to all of the SOQL.
- Cache - The selector can have additional logic to save SOQL results. That approach can be beneficial in places where we need to save SOQL limits.