Saturday, February 26, 2022

My Opinions of learning Flow

I recently saw a very complicated screen flow that looks like a subway map in some big city, and different comments about it. As a fan of flow, I want to give my 2 cents here.

For a process with user interactions, Screen Flow could be a very good option. Because it covers the front and back end together, and the famous MVC is done at one time. The development is usually fast, which is very important in today's rapidly changing world. Especially it can build a POC and demo to the client for what can be done in a vivid way. I once built a Screen flow in the first meeting with the client, and it was a pretty awesome experience.

Automatic flow does not have an overwhelming advantage (other than not writing code), but a few disadvantages: low efficiency, no mandatory unit test, more limitations (such as the 2000 elements). But customers still want to use it, I also recommend them to do so, why? Because Flow is the tool matching the idea of "no-code, low-code", which the Salesforce platform has been advocated for many years. It's easier to build, and empower more citizen developers. Of cause, great power brings great responsibility, so an improperly built flow can break exiting functions. That's why I think everyone in the Salesforce ecosystem should learn some flow skills.

Is Flow a flash in the pan? I think at least from the Salesforce roadmap perspective it is not, so if you want a career related to the technical side of Salesforce, you must learn to flow well. Is Salesforce itself a flash in the pan? At least in the past 20 years, it's been a great success. In the next 20 years? Who knows, but I personally think it still is a quite good career choice in the near future. All of the original DJI (founded in 1896) stocks have been either removed or delisted, so good times do not last long. It's unlikely that a business will keep prosperity for hundred years. However, our life span as human beings does not require us to consider that long either. 

The focus of learning Flow is to know the best practices, good patterns, and in my opinion most importantly boundaries. What Flow can do, and what it can't do what it can. Flow is not a panacea, nor is Apex. There are always applicable scenarios for different tools, which is why that all-purpose saying "It depends" appears so often. What distinguishes the different skill levels is the ability to fill in the phrase of what it really depends on. 

Finally, to take a step back, if you really think that Salesforce will not last long enough for your career, there is no harm in learning Flow, because it is the same basic concepts of programming. Regardless of what tools or language you use, at the end of the day it is always about loop and control flow. If you want to deepen your knowledge, learn design patterns, that is the higher level of guidance, Flow, Apex or Java, is only a tool. However, it's necessary to have some foundation to learn the patterns, and Flow is a very friendly starting point.

Tuesday, February 15, 2022

Interesting DML Error in Salesforce Flows

 I recently saw an interesting error in one of the projects:

This error occurred: DUPLICATE_VALUE: Maximum number of duplicate updates in one batch (12 allowed). Attempt to update Id more than once in this Api call: record Id.

It came from a flow that has been running smoothly for a long time. The documentation https://help.salesforce.com/s/articleView?id=000314518&type=1 doesn't really explain my issue, because I don't have any scheduled actions or a wait element.

After some digging, I realize that if you try to update the same record multiple times in one transaction, then you may face this issue. In my case, I have flow automation on the child object that updates the corresponding parent object. When the parent has many children records (more than 12) and the values to be updated on the parent are different, I see this error. For example, the parent has 20 children namely: 1, 2, 3 ... 20, and each child is updating a text field on the parent using their own name, so the same transaction can end up assigning 1, 2, 3 ... 20 to the parent record's text field, and triggering the above error. If they update the parent in the same way (assigning the same value for the field), then there won't be any error, and that's what I missed in the past without knowing this potential issue.

Once the root cause has been determined, I can start to figure out a fix. The goal is quite simple, to avoid this recursive automation. So depending on the use case we need to add a decision element to check that field to update in the flow. For example, I want to save the maximum number then I need to compare the existing value and the target value in this decision node, if the existing value is greater than or equal to the target value, then the flow ends instead of continuing to update the parent record.

Interestingly I tried to replace the original logic with a trigger (without the decision part) using the code below, there is no error at all. 

trigger triggerContactName on Contact (after insert, after update) {

    List<Id> ids = new List<Id>();

    for (contact con: trigger.new){

        ids.add(con.accountId);

    }

    

    Map<Id, Account> accs = new Map<Id, Account>([Select Id, site From Account Where Id in: ids]);

    for (contact con: trigger.new){

        accs.get(con.accountId).site = con.lastName;      

    }

    update accs.values();

}

My understanding is that behind the scenes Salesforce isn't really bulkifying flows in the same way of using maps in my trigger. It may just list the record multiple times and update once, hence the maximum number of 12. 

This error reminds me of another error I faced a while ago, which is worth mentioning as well.

System.TypeException: Cannot have more than 10 chunks in a single operation. Please rearrange the data to reduce chunking.

This one is also interesting because the chunk is essentially a list of records of the same object, but as indicated in the error message, the sequence matters. So we should try to keep the records of the same object together to avoid this issue. For example, the following 2 snippets are doing the same thing, but the 1st one will trigger the error, and the 2nd one works fine.

Mixed pattern:

list<sObject> records = new list<sObject>();

for (integer i=0; i<20; i++) {

    Account acc = new Account (name = 'Test' + i);

    Contact con = new Contact(lastname = 'Test' +i);

    records.add(acc);

    records.add(con);

}

insert records;

Sorted pattern:

list<sObject> records = new list<sObject>();

for (integer i=0; i<20; i++) {

    Account acc = new Account (name = 'Test' + i);

    records.add(acc);

}


for (integer i=0; i<20; i++) {

    Contact con = new Contact(lastname = 'Test' +i);

    records.add(con);

}

insert records;

Flows are great, but we need to be careful about these little traps. As I recently learned, error handling is an absolute must everywhere, because the automation will fail, it's never a question of if it fails, but when it fails :)

Tips for Salesforce Certified Strategy Designer Exam

A little late to the party, but I just passed the latest Strategy Designer exam. Since it's a really new one (about one week old), there...