AUTOMATISERING · 10 min lezen

Wanneer Apex en wanneer Flow?

De meeste organisaties kiezen hier nooit bewust. Er komen een paar flows bij, later een trigger, en drie jaar verder durft niemand er nog iets weg te halen. Dit artikel geeft de volgorde waarin je de keuze hoort te maken.

De vraag komt bijna altijd te laat

Apex of Flow is zelden de eerste vraag. Er is meestal al iets gebouwd, er zit al gedrag in de org, en de vraag komt pas boven zodra iets stukgaat of traag wordt. Dan gaat het gesprek over de tool, terwijl het over de volgorde zou moeten gaan.

Die volgorde is: eerst kijken of je het helemaal niet hoeft te bouwen, dan of configuratie het afvangt, dan Flow, en pas daarna Apex. Elke stap naar beneden kost je onderhoud, kennis in huis en een releaseproces. Dat is geen principekwestie maar een rekensom. Wat een beheerder morgen zelf kan aanpassen, hoef je niet in te plannen.

Begin onder Flow, niet erin

Voordat je de Flow Builder opent, is de vraag of standaardfunctionaliteit het al oplost. In veel orgs staat een record-triggered flow die precies doet wat een formuleveld gratis had gedaan, inclusief de opslag, de herberekening en de foutmail die erbij hoort.

Vaak overgeslagen

  • ✓Formulevelden: altijd actueel, geen opslag, geen automatisering die kan falen.
  • ✓Roll-up summary velden op master-detail: tellen en optellen zonder één regel logica.
  • ✓Validatieregels: houden foute data tegen in plaats van hem achteraf te repareren.
  • ✓Approval-processen: goedkeuring met stappen, delegatie en historie, out of the box.
  • ✓Custom Metadata: waarden die per omgeving of periode verschillen, zodat ze niet in je logica vastgeklonken zitten.

Pas als geen van deze het afvangt, begint de keuze tussen Flow en Apex echt.

Wat Flow inmiddels wel kan

Het beeld van Flow als het simpele broertje van code is een paar jaar achterhaald. Workflow Rules en Process Builder zijn uitgefaseerd, dus alles wat declaratief is loopt nu door Flow. Twee dingen bepalen wat een flow je kost.

Before-save of after-save

Een before-save record-triggered flow past velden aan op het record dat toch al wordt weggeschreven. Geen extra DML, geen tweede save. Een after-save flow die hetzelfde veld zet, doet daar een volledige update overheen en trapt de save-cyclus opnieuw af. Dat verschil is ordegroottes, niet procenten. Het is ook de meest gemaakte fout in orgs die klagen dat Flow traag is.

Flow is wel degelijk gebulkificeerd

De hardnekkigste misvatting is dat Flow niet tegen volume kan. Get Records en Update Records werken op collecties: tweehonderd records in één transactie leveren één query en één DML op. Wat wel omvalt, is een Get of Update binnen een loop. Dat is geen tekortkoming van Flow, het is dezelfde fout die in Apex net zo fataal is. Alleen zie je hem in de Flow Builder makkelijker over het hoofd.

Wat daarna overblijft aan echte grenzen is een korte lijst. En die is een stuk specifieker dan "complexe logica".

Waar Flow tegen een muur loopt

Vijf grenzen waar geen ontwerp omheen komt. Kom je er één tegen, dan is de keuze gemaakt.

  1. 1

    Foutafhandeling

    Faalt een record-triggered flow, dan rolt de hele transactie terug en krijgt de eigenaar van de flow een mail met een stacktrace. De gebruiker ziet een melding waar hij niets mee kan. Je kunt niet één record laten falen en de rest doorlaten, en je kunt een fout niet netjes afvangen en doorgaan.

  2. 2

    Transactiecontrole

    Geen savepoints, geen gedeeltelijke commits, geen bewuste keuze om vijf van de tien records te verwerken. In Apex regel je dat met een savepoint en Database.update met partial success. In Flow is het alles of niets.

  3. 3

    Externe koppelingen

    Een callout kan niet vanuit een before-save flow, en niet na een DML in dezelfde transactie zonder asynchrone omweg. Wil je een response parsen, een timeout opvangen of opnieuw proberen, dan zit je hoe dan ook in Apex.

  4. 4

    Volume boven één transactie

    Zodra je meer moet verwerken dan er in één transactie past, heb je Batch of Queueable Apex nodig. Scheduled flows verwerken records ook in batches, maar je hebt geen grip op de chunkgrootte, geen herstart en geen bruikbare foutlog.

  5. 5

    Testen en samenwerken

    Apex dwingt testdekking af voordat je naar productie mag. Flow Tests bestaan, maar alleen voor record-triggered flows en zonder de assertiekracht van een Apex-test. Daar komt bij dat een flow XML is die je niet zinnig kunt mergen: twee mensen die tegelijk aan dezelfde flow werken, overschrijven elkaar.

En wat Apex je kost

Deze kant blijft in dit soort vergelijkingen meestal onderbelicht, terwijl juist die bepaalt of code de goedkopere keuze is.

  • Elke wijziging gaat via een deployment. Een zin in een e-mailtekst aanpassen duurt dan geen twee minuten maar een release.
  • Minimaal 75 procent testdekking over de hele org voordat je naar productie mag. Iemand schrijft die tests, en iemand onderhoudt ze.
  • De beheerder die het proces het beste begrijpt, kan er niets meer aan veranderen. Elke aanpassing loopt via een ontwikkelaar.
  • Vertrekt de bouwer, dan moet een ander de code kunnen lezen. Een flow is in elk geval nog te volgen door iemand die geen ontwikkelaar is.

De eerlijke vuistregel is daarom niet dat code beter is. Kies code waar het je iets oplevert dat Flow niet kan, en niet omdat het netter voelt.

Governor limits gelden voor allebei

Flow en Apex delen dezelfde limieten binnen één transactie. Een flow die naar Apex uitwijkt, krijgt geen nieuw budget. Wie deze getallen kent, ziet aan een ontwerp al waar het gaat knellen.

LimietPer transactieWaar het misgaat
SOQL-queries100Elke Get Records telt mee, ook die in een subflow of in een trigger die je flow afvuurt
DML-statements150Elke Create, Update en Delete, inclusief de saves die je automatisering zelf veroorzaakt
Records per DML10.000Geldt over de hele transactie, niet per element
CPU-tijd10 sec. synchroon, 60 sec. asynchroonFlow-elementen zijn in de regel duurder in CPU dan dezelfde logica in Apex
Callouts100, samen max. 120 sec.Niet toegestaan na een DML in dezelfde transactie zonder asynchrone stap
Heap6 MB synchroon, 12 MB asynchroonEen grote collectie in een flow telt net zo hard mee als in Apex

De praktische conclusie: komt je ontwerp in de buurt van deze getallen, dan is de vraag niet meer Flow of Apex, maar synchroon of asynchroon.

De beslisboom

Vijf vragen, in deze volgorde. Stop bij de eerste waar je ja op zegt.

  1. 1

    Kan het zonder automatisering?

    Formuleveld, roll-up summary, validatieregel of approval-proces. Zo ja: bouw niets. Dit is de goedkoopste automatisering die er bestaat.

  2. 2

    Moet een gebruiker er stap voor stap doorheen?

    Screen Flow. Zit er zware of vertakte rekenlogica in, laat de flow dan een invocable Apex-class aanroepen en houd het scherm zelf leeg.

  3. 3

    Zet je alleen velden op het record dat net is opgeslagen?

    Before-save record-triggered flow. Geen trigger, geen after-save flow, geen extra DML.

  4. 4

    Is er een callout, transactiecontrole, verwerking over meerdere transacties of foutafhandeling per record nodig?

    Apex. Invocable, Queueable of Batch, afhankelijk van het volume en het moment waarop het moet draaien.

  5. 5

    Blijft alles op nee staan?

    Dan is het een after-save record-triggered flow. Dat is de standaardkeuze, niet het vangnet.

Screen (Start)

Gebruiker voert gegevens in

Get Records

Data ophalen voor de flow

Apex Action

Zwaardere logica uitvoeren

Screen (Resultaat)

Toont uitkomst aan gebruiker

Update Records

Gegevens bijwerken

Een screen flow die het rekenwerk uitbesteedt aan Apex: de beheerder houdt het scherm, de ontwikkelaar de logica.

Drie situaties uit de praktijk

Dezelfde vraag, drie verschillende uitkomsten.

Welkomstproces bij een nieuwe klant

Situatie
Een dienstverlener wil dat er bij een nieuwe klant automatisch een welkomstmail uitgaat en dat de accountmanager na zeven dagen een taak krijgt om na te bellen.
Keuze
After-save record-triggered flow op Account, met een scheduled path voor de taak.
Waarom
Er worden andere records aangemaakt, dus before-save valt af. De logica is één beslissing, en de tekst van de mail verandert een paar keer per jaar. Dat wil je door de marketingmanager laten doen, niet door een release.
Wat je hier fout ziet gaan
Dezelfde logica in een Apex-trigger, waarna elke tekstwijziging drie weken duurt.

Offerte met een rekenmodel

Situatie
Een installatiebedrijf laat de binnendienst een aantal waarden invullen en berekent daaruit de verwachte opbrengst en de prijs. Het model bestaat uit staffels, correctiefactoren en uitzonderingen, en wijzigt per seizoen.
Keuze
Screen Flow voor de invoer, invocable Apex-class voor de berekening, staffels in Custom Metadata.
Waarom
De flow is de plek waar de beheerder schermen en velden aanpast. De berekening hoort niet in beslisblokken en formulevariabelen: die is te vertakt om te blijven volgen en te belangrijk om niet te testen. In een Apex-class is hij leesbaar, versiebeheerd en met echte testgevallen af te dekken. De staffels zelf horen in Custom Metadata, zodat een tariefwijziging geen deployment kost.
Wat je hier fout ziet gaan
Het rekenmodel in de flow zelf. Na twee seizoenen staat er een flow van veertig elementen die niemand meer durft aan te raken.

Nachtelijke synchronisatie met het ERP

Situatie
Een groothandel krijgt elke nacht duizenden voorraad- en statusupdates uit een extern systeem. Records die niet te matchen zijn, moeten worden vastgelegd en niet stilzwijgend overgeslagen.
Keuze
Batch Apex vanuit een scheduled job, met een custom object als foutlog.
Waarom
Het volume past niet in één transactie, er is een koppeling met een extern systeem, en de eis dat één slecht record de rest niet blokkeert is precies wat Flow niet kan. Database.update met partial success plus een eigen logregel per fout geeft de beheerder 's ochtends een lijst om mee te werken, in plaats van een mailbox vol systeemmeldingen.
Wat je hier fout ziet gaan
Een scheduled flow haalt dit bij duizend records misschien nog wel, maar valt om zodra het volume groeit. En dan zonder bruikbaar spoor van wat er precies misging.

De twee orgs waar je niet wilt eindigen

Alles in Flow

Elf record-triggered flows op Account, allemaal after-save, in een volgorde die niemand kan voorspellen. Een veldupdate in de ene flow triggert de andere. De org loopt tegen de CPU-limiet aan bij een import van driehonderd records. Niemand haalt er iets weg, omdat onduidelijk is wat eraan hangt.

Alles in Apex

Elke automatisering zit in triggers en handler-classes. Op papier keurig. In de praktijk staat de beheerder bij elke tekstwijziging in de rij bij een ontwikkelaar en is de doorlooptijd van een kleine wijziging drie weken. De business bouwt er ondertussen een eigen spreadsheet naast.

Beide orgs hebben hetzelfde probleem: er is één keer een tool gekozen en daarna is er niet meer gekozen.

Wie meerdere automatiseringen op hetzelfde object heeft staan, doet er goed aan te weten in welke volgorde Salesforce ze uitvoert. Lees hoe de order of execution werkt.

Kort samengevat

SituatieKies
Veldupdate op het record dat net is opgeslagenBefore-save record-triggered flow
Vervolgacties: taak, mail, gerelateerd record aanmakenAfter-save record-triggered flow
Gebruiker moet stappen doorlopenScreen Flow
Zware of vertakte rekenlogica in een schermprocesScreen Flow met invocable Apex
Koppeling met een extern systeemApex, asynchroon
Meer records dan er in één transactie passenBatch of Queueable Apex
Fouten per record vastleggen zonder de rest te blokkerenApex
Waarden die per omgeving of periode verschillenCustom Metadata, niet hardcoderen

Veelgestelde vragen

Per element wel, maar daar gaat het zelden op stuk. Een before-save flow die één veld zet, is sneller dan een after-save trigger die hetzelfde doet met een extra DML erbij. Prestatieproblemen komen vrijwel altijd door de opzet: queries in een loop, stapels flows op hetzelfde object, of after-save waar before-save had gekund.

Binnen één transactie ja, want de elementen werken op collecties. Waar het misgaat is een Get of Update binnen een loop, en bij volumes die niet in één transactie passen. Voor dat laatste heb je Batch Apex nodig.

Ja, Salesforce heeft beide uitgefaseerd en levert er een migratietool bij. Behandel het alleen niet als een een-op-een-conversie. Het is het moment om te bekijken wat er nog nodig is, wat naar een before-save flow kan en wat gewoon weg mag.

Technisch is er geen harde grens, praktisch houd je er één per object per timing aan: één before-save en één after-save, met de logica daarbinnen geordend. Je kunt sinds Spring '22 met de flow trigger order een volgorde afdwingen, maar dat is een pleister. Het lost niet op dat je logica dan over meerdere flows verspreid staat.

Ja. Een Apex-methode met de annotatie @InvocableMethod verschijnt als actie in de Flow Builder. Dat is de hybride vorm en meestal de beste uitkomst: de beheerder houdt de flow, de ontwikkelaar houdt de logica.

Weet je of je automatisering nog de juiste kant op staat?

Plan een Quick Scan: dertig minuten via screenshare, waarin we samen door je org lopen. Hoe je automatisering erbij staat, waar het lastig te beheren wordt en welke keuzes je later gaan opbreken. Een gesprek, geen rapport.