Domain-Driven-Design principles are largely adopted in companies embracing microservice architecture and one of the key ideas is to separate the data model of the persistence layer from the business layer and the one of the business layer from the API layer, so that the business layer can be exposed to the outside world in a simplified way and its complexities can be hidden from external clients. Because the Salesforce development model and the primitives offered by the Lightning Platform do not map to any of other technologies, these principles can be interpreted in various ways.
Interpretation 1: Lightning components and any external integration must not depend on the SObject schema of the org (and therefore tags such as force:recordData can't be used). One key benefit is that you can refactor the underlying model without refactoring the UI or the external clients, and also support multiple versions of the API. The key drawback is that you need to write custom controllers or Apex Rest Endpoints for each interaction.
Interpretation 2: It is not possible to isolate in Salesforce the persistence from the business logic, because validation rules, workflow rules, triggers and other development primitives are coupled with the SObject model, and therefore even providing a separate API model brings limited benefits which might not be worth the overhead.
Interperetation 3: Lightning components are not external to the domain and they are part of the same release cycle of the other metadata on the org, so they are already coupled with everything else and you won't be able to relax this coupling. It is perfectly fine for them to depend on SObject schemas:
- custom controllers needs to be used only when you need to read or write (transactionally) multiple or different sobjects
- rest endpoints still remain useful to provide an API which abstracts away the SObject model and can be invoked from the outside (external systems)
Interpretation 4: Building on top of interpretation 3, is it possible to avoid writing controllers at all when you have to deal with read operations or non transactional write operations and invokes the SObject rest api, avoiding the cumbersome development model for Apex Server Side controllers?
Conclusion: Are there other interpretations, are there benefits or drawbacks we didn't capture in our analysis, and what is the SFDC developers community experience with those principles?
We are currently evaluating different strategies to interact with Salesforce inside Lightning Components:
- Write a controller, which guarantees you can provide transactional guarantees within a single backend call even when performing multiple CRUD operations
- Write a controller but never return SObjects, since SObject belongs to the persistence layer and we would like to have the freedom to change the persistence without changing the UI. (Does it even apply? Is the metadata / the org a monolith anyways?)
- Find a way to invoke API so you do not need to write controllers which go through the Metadata release process, which might be cumbersome
What are the experience of the SFDC developers community, and is the third even a possibility?