apex-enterprise-patterns / fflib-apex-common

Common Apex Library supporting Apex Enterprise Patterns and much more!
BSD 3-Clause "New" or "Revised" License
903 stars 514 forks source link

Is it right to have multiple fflib apps in my project? #370

Closed AllanOricil closed 2 years ago

AllanOricil commented 2 years ago

At the moment Im working on a feature which I could have used, for instance, a Selector that was already being used by another FFlib App, but I decided to create my own selector for this new FFLIb App. And that fews reasonable to me. What it does not few that obvious is what to do when working with Triggers (.trigger files). If I have two FFLIB Apps using the same object, should I declare two trigger handlers on the trigger, like this

trigger ObjectTrigger on Object__c(
    after insert
) {
    fflib_SObjectDomain.triggerHandler(
        APP1_ObjectTriggerHandler.class
    );

    fflib_SObjectDomain.triggerHandler(
        APP2_ObjectTriggerHandler.class
    );
}

or should I have two Triggers for the same object????

trigger APP1ObjectTrigger on Object__c(
    after insert
) {
    fflib_SObjectDomain.triggerHandler(
        APP1_ObjectTriggerHandler.class
    );
}
trigger APP2ObjectTrigger on Object__c(
    after insert
) {
    fflib_SObjectDomain.triggerHandler(
        APP2_ObjectTriggerHandler.class
    );
}
ImJohnMDaniel commented 2 years ago

G'day @AllanOricil

The preference would be to have a single trigger. This way you can ensure consistent execution order of all of the various domain processes working on it.

I am curious why you are asking? Is it because your apps are in separate packages or is it something else?

Hope this helps.

AllanOricil commented 2 years ago

I'm asking it because our project is kind brand new and we want to have a solid base before going to prod.

In this project im developing an App to control when Platform Events are dispatched. This app I built using fflib sample code to guide me. And because we are already using fflib for common code, I was wondering if it was a good decision to create separste resources to my app, instead of sharing things that were already built. For instance, the common app already had a ContactsSelector, and my app also needed one, so I created one to my App. I kept doing this for all the resources my app needed. Then I arrived in the Trigger and this question came to my mind. What should I do in case one day two different fflib apps need to use the same Object? And then I ended up here on github to ask someone who is expert on fflib @ImJohnMDaniel So, can you confirm it to me. If one day two apps share the same object, the best thing to do is the code below:

trigger ObjectTrigger on Object__c(
    after insert
) {
    fflib_SObjectDomain.triggerHandler(
        APP1_ObjectTriggerHandler.class
    );

    fflib_SObjectDomain.triggerHandler(
        APP2_ObjectTriggerHandler.class
    );
}

We are not developing any managed or unlocked package. All the Metadata is kept on a single repository.

ImJohnMDaniel commented 2 years ago

@AllanOricil, when you say that you are developing "multiple apps" but "all the metadata is kept in a single repo", is that repo setup in the sfdx-project.json file with multiple package directories similar to the following?

{
  "packageDirectories": [
    {
      "path": "sfdx-source/APP1",
      "default": false
    },
    {
      "path": "sfdx-source/APP2",
      "default": false
    }
  ],
  "sfdcLoginUrl": "https://login.salesforce.com",
  "sourceApiVersion": "52.0",
}

If that is the situation, where do APP1_ObjectTriggerHandler and APP2_ObjectTriggerHandler exist?

ImJohnMDaniel commented 2 years ago

@AllanOricil -- follow up question. Does FFLIB and the "common code" also exist in this single repo?

AllanOricil commented 2 years ago

Yes, and the common code uses FFLIB as well

AllanOricil commented 2 years ago

Like this

image

image

AllanOricil commented 2 years ago

My little app is called Document Signing Process. At the moment both apps don't share any triggers for the same object, so we are fine. But what would happen if both have a trigger handler for the Contact object, would I do something like this?

trigger ContactTrigger on Contact(
    before insert, 
    before update, 
    before delete, 
    after insert, 
    after update, 
    after delete, 
    after undelete
) {
    fflib_SObjectDomain.triggerHandler(
        APP1_ContactTriggerHandler.class
    );

    fflib_SObjectDomain.triggerHandler(
        APP2_ContactTriggerHandler.class
    );
}
ImJohnMDaniel commented 2 years ago

So, as long as you have all of the code under a single "package directory" specified in the sfdx-project.json file, you should have no issues. You will be able to add all of the various trigger handlers to a single trigger.

I will caution you though. Going this direction will "blur the architectural boundaries" of the various apps over time. This is fine as long as you have no intention of using unlocked packaging. But if you eventually want to go to unlocked packaging, then you will be faced with "untangling the org" into proper layers and have a lot of new concerns to think about.

If you have not already done so, I would suggest watching this talk from VirtualDreamin20 -- Architectural Considerations to Implementing DX and 2nd Generation Packaging. It will give you a good overview about the extra items that you will need to consider if you ever need to go the route of packaging. It also explains the purpose behind the Force-DI ](https://github.com/apex-enterprise-patterns/force-di) and AT4DX frameworks working in concert with FFLIB. DF18 -- Advanced Techniques To Adopt Salesforce DX Unlocked Packages is another webinar that gives you a practical "How-To" for AT4DX, if that interests you.

Hope this helps. Let me know if you have more questions.

Cheers!

AllanOricil commented 2 years ago

Thanks @ImJohnMDaniel I will watch the video to learn more about it.