Compreender o contexto de execução
Objetivos de aprendizagem
Após concluir esta unidade, você estará apto a:
- Saber quais métodos usar para invocar o Apex
- Escrever um acionador para um Salesforce Object
- Observar como o contexto de execução funciona executando código no Console do desenvolvedor
- Compreender como o administrador limita os padrões de design do impacto
- Compreender a importância de trabalhar com operações em massa
Acompanhar com o Trail Together
Deseja acompanhar um especialista enquanto trabalha nesta etapa? Veja este vídeo que faz parte da série Trail Together.
(Este clipe começa na marca dos 16:36 minutos, caso você queira retroceder e ver o início da etapa novamente.)
O que é o contexto de execução?
Nos aplicativos ASP.NET, o código é executado no contexto do domínio de um aplicativo. No universo da plataforma do Lightning, o código é executado dentro de um contexto de execução. Em poucas palavras, esse contexto representa o tempo transcorrido entre o momento em que o código é executado e o momento em que ele termina. É importante entender que o código do Apex que você escreve nem sempre é o único código a ser executado.
Para entender como isso funciona, é preciso conhecer todas as formas como o código do Apex pode ser executado na plataforma.
Métodos para invocar o Apex
Método |
Descrição |
---|---|
Acionador do banco de dados |
Invocado para um evento específico em um objeto padrão ou personalizado. |
Apex anônimo |
Trechos de código executados dinamicamente no Developer Console e em outras ferramentas. |
Apex assíncrono |
Ocorre ao executar um Apex futuro ou que permite a execução em fila, ao executar um trabalho em lote ou agendar a execução do Apex num intervalo especificado. |
Serviços da web |
Código a ser exposto pelos serviços da Web de entrada ou saída SOAP ou REST. |
Serviços de email |
Código configurado para processar emails recebidos ou enviados. |
Páginas do Lightning ou Visualforce |
Os controladores do Visualforce e os componentes do Lightning podem executar código do Apex automaticamente ou quando um usuário iniciar determinada ação, como clicar em um botão. Os componentes do Lightning também podem ser executados por processos e fluxos do Lightning. |
Além de invocar o código do Apex, as ações (como criar uma nova tarefa, enviar um email, realizar uma atualização de campo ou enviar uma mensagem de saída) podem ser acionadas por um dos recursos da plataforma declarativa. Essas ações também são realizadas dentro de um contexto de execução.
Outra consideração importante é o contexto do usuário que executa o código do Apex. Por padrão, o Apex é executado no contexto do sistema. O código do Apex tem acesso a todos os objetos e campos. As permissões de objeto, a segurança em nível de campo e as regras de compartilhamento não são aplicadas ao usuário atual. Você pode usar a palavra-chave with sharing para especificar que as regras de compartilhamento do usuário atual devem ser consideradas para determinada classe. Esse tópico é importante, ou seja, confira Usar as palavras-chave com compartilhamento e sem compartilhamento.
Fundamentos dos acionadores
Antes de aprender mais sobre o contexto de execução, vamos voltar um pouco atrás para apresentar a você o universo dos acionadores do banco de dados. De modo semelhante aos acionadores do SQL Server, os acionadores do banco de dados do Apex executam a lógica de programação antes ou depois de eventos nos registros do Salesforce. Ao definir o acionador, você pode especificar mais de um dos eventos a seguir:
- before insert
- before update
- before delete
- after insert
- after update
- after delete
- after undelete
A sintaxe básica de um acionador é assim:
trigger TriggerName on ObjectName (trigger_events) { // code_block }
Agora, sabemos o quanto os desenvolvedores .NET adoram resolver problemas com código, mas vamos dar uma megadica de produtividade para você. Só recorra ao uso do acionador quando tiver certeza absoluta de que não é possível alcançar o mesmo efeito com uma das nossas ferramentas de automação “apontar e clicar”.
Para facilitar sua vida, a Salesforce Platform inclui uma ferramenta de automação poderosa, o Flow Builder, para administrar a lógica de negócios sem ter que codificar. Na maioria dos casos, tarefas que antes só podiam ser realizadas com um acionador são agora mais adequadas para uma das ferramentas de automação.
Marcar o contexto de execução
Para entender melhor o contexto de execução, vamos criar juntos um acionador do banco de dados do Apex que gera uma oportunidade sempre que uma nova conta é inserida. Esse acionador chama um método de uma classe de manipulador; então, precisamos criar essa classe primeiro.
- Em Configuração, selecione Seu nome > Developer Console para abrir o Developer Console.
- No Developer Console, selecione File (Arquivo) > New (Nova) > Apex Class (Classe do Apex).
- Digite AccountHandler como nome da classe e clique em OK.
- Exclua o código existente e insira o seguinte trecho:
public with sharing class AccountHandler { public static void CreateNewOpportunity(List<Account> accts) { for (Account a : accts) { Opportunity opp = new Opportunity(); opp.Name = a.Name + ' Opportunity'; opp.AccountId = a.Id; opp.StageName = 'Prospecting'; opp.CloseDate = System.Today().addMonths(1); insert opp; } } }
- Pressione Ctrl+S para salvar sua classe.
Agora que temos a classe de manipulador, criaremos o acionador de conta.
- No Developer Console, selecione File (Arquivo) > New (Novo) > Apex Trigger (Acionador do Apex).
- Digite AccountTrigger como nome e selecione Account como sObject.
- Clique em Submit (Enviar).
- Exclua o código existente e insira o seguinte trecho:
trigger AccountTrigger on Account (before insert, before update, before delete, after insert, after update, after delete, after undelete) { if (Trigger.isAfter && Trigger.isInsert) { AccountHandler.CreateNewOpportunity(Trigger.New); } }
- Pressione Ctrl+S para salvar seu acionador.
Para concluir o guia passo a passo, executamos um código anônimo para simular que o usuário está inserindo uma nova conta usando a interface do Salesforce. Lembre-se: o código do Apex pode ser executado de várias formas diferentes.
- Em Configuração, selecione Seu nome > Developer Console para abrir o Developer Console.
- Selecione Debug (Depurar) > Open Execute Anonymous Window (Abrir janela Executar no modo anônimo).
- Exclua o código existente e insira o seguinte trecho:
Account acct = new Account( Name='Test Account 2', Phone='(415)555-8989', NumberOfEmployees=50, BillingCity='San Francisco'); insert acct;
- Verifique se a opção Open Log está selecionada e clique em Execute. Uma nova guia mostra o registro de execução. Mantenha-a aberta para poder examiná-la com atenção.
Examinar o registro de execução
Observe que a primeira linha do registro de execução marca o evento EXECUTION_STARTED e que a última linha é o evento EXECUTION_FINISHED. Tudo que está entre essas linhas é o contexto de execução.
Vamos ver o que acontece mais de perto. O evento CODE_UNIT_STARTED marca o momento em que o código da janela Execute Anonymous foi desencadeado. Essa linha está destacada em vermelho na imagem abaixo.
A segunda linha destacada, CODE_UNIT_STARTED, representa quando o código do evento BeforeInsert foi executado.
Não é possível ver na imagem, mas, se estiver acompanhando com a sua própria instância do Console do desenvolvedor, role mais para baixo nos resultados, na tela, e procure outras instâncias de CODE_UNIT_STARTED. Você verá, pelo menos, mais uma instância representando o momento em que o código do evento AfterInsert foi executado. Se você criou regras de fluxo de trabalho desencadeadas quando uma nova conta foi criada, essas regras também devem aparecer no registro de execução. Esse código inteiro funciona dentro do mesmo contexto de execução e, portanto, está sujeito ao mesmo conjunto de limites do administrador.
Você deve estar se perguntando: por que é tão importante entender isso? Bem, como o Salesforce é um ambiente multilocatário, os limites do administrador são essenciais para evitar que cada instância de uma organização do Salesforce consuma demasiados recursos. Isso basicamente evita que o sistema inteiro entre em colapso.
Trabalhando com limites
Isso nos traz de volta ao trabalho com limites. Provavelmente, os dois limites mais preocupantes estão relacionados com o número de consultas SOQL e de demonstrativos DML. Esses limites tendem a dar trabalho para os desenvolvedores novos na plataforma; então, queremos dedicar um tempo extra para falar sobre como evitá-los.
Trabalhando em massa
Muitos desenvolvedores caem na armadilha de desenvolver um código que funciona com um único registro. Eles aprendem bem rápido que isso pode ser um engano gravíssimo na plataforma do Lightning.
Os acionadores do Apex podem receber até 200 registros de uma vez. Atualmente, o limite síncrono para o número total de consultas SOQL é 100 e 150 para o número total de instruções DML emitidas. Portanto, se você tiver um acionador que executa uma consulta SOQL ou uma instrução DML dentro de um loop e esse acionador foi disparado para uma operação em massa, adivinhe?
BOOM!!!
Isso mesmo, você verá um erro de limites. É possível que o código seja implantado e execute bem durante algum tempo antes que o limite seja descoberto. Mas depois disso, o desenvolvedor precisa retornar e descobrir como “massificar” o código. Não é raro que essa segunda tentativa seja mais demorada do que o projeto inicial. Para evitar essa situação, desenvolva seu código do Apex para manipular operações em massa desde o início. Descubra como fazer isso no módulo Acionadores do Apex em massa.
Talvez você tenha percebido, talvez não tenha, mas o código do manipulador do acionador que criamos antes não usou um padrão em massa e, portanto, está propenso a erros de limites. Só para recordar, veja abaixo como era o código original.
public with sharing class AccountHandler { public static void CreateNewOpportunity(List<Account> accts) { for (Account a : accts) { Opportunity opp = new Opportunity(); opp.Name = a.Name + ' Opportunity'; opp.AccountId = a.Id; opp.StageName = 'Prospecting'; opp.CloseDate = System.Today().addMonths(1); insert opp; } } }
Repare que a operação insert DML está dentro do loop for. Isso é muito, muito ruim, algo a ser evitado a todo custo.
Felizmente, podemos alterar esse código para consertá-lo, fazendo com que ele escreva em uma variável de lista dentro do loop e, depois, insira o conteúdo da lista em uma única etapa.
- Em Configuração, selecione Seu nome > Developer Console para abrir o Developer Console.
- No Developer Console, selecione File (Arquivo) > Open (Abrir).
- Selecione Classes como tipo de entidade. Selecione AccountHandler como entidade.
- Clique em Open (Abrir).
- Exclua o código existente e insira o seguinte trecho:
public with sharing class AccountHandler { public static void CreateNewOpportunity(List<Account> accts) { List<Opportunity> opps = new List<Opportunity>(); for (Account a : accts) { Opportunity opp = new Opportunity(); opp.Name = a.Name + ' Opportunity'; opp.AccountId = a.Id; opp.StageName = 'Prospecting'; opp.CloseDate = System.Today().addMonths(1); opps.add(opp); } if (opps.size() > 0) { insert opps; } } }
- Pressione Ctrl+S para salvar sua classe.
Agora que consertamos o código do manipulador do acionador, vamos testá-lo para verificar se o acionador pode lidar com uma carga de 200 registros. Como você certamente já sabe, escrever testes de unidade para garantir que o código funciona é uma melhor prática.
- No Developer Console, selecione File (Arquivo) > New (Nova) > Apex Class (Classe do Apex).
- Digite AccountTrigger_Test como nome da classe e clique em OK.
- Exclua o código existente e insira o seguinte trecho:
@isTest private class AccountTrigger_Test { @isTest static void TestCreateNewAccountInBulk() { // Test Setup data // Create 200 new Accounts List<Account> accts = new List<Account>(); for(Integer i=0; i < 200; i++) { Account acct = new Account(Name='Test Account ' + i); accts.add(acct); } // Perform Test Test.startTest(); insert accts; Test.stopTest(); // Verify that 200 new Accounts were inserted List<Account> verifyAccts = [SELECT Id FROM Account]; System.assertEquals(200, verifyAccts.size()); // Also verify that 200 new Opportunities were inserted List<Opportunity> verifyOpps = [SELECT Id FROM Opportunity]; System.assertEquals(200, verifyOpps.size()); } }
- Pressione Ctrl+S para salvar sua classe.
- Selecione Test (Teste) > New Run (Nova execução).
- Selecione AccountTrigger_Test como TestClass e TestCreateNewAccountInBulk como método de teste.
- Clique em Run (Executar).
- Selecione a guia Testes e verifique se o teste é executado até o fim sem falhas, o que é indicado pelo sinal de visto verde na coluna Status.
Quero saber mais
O Apex usa o conhecido bloco try-catch-finally para lidar com as exceções. Mas o demonstrativo catch e o possível rollback podem mudar conforme o ponto em que o código do Apex é executado. Confira o link em Resources sobre as melhores práticas ao lidar com try, catch e rollback no Apex.
Não existe variável de aplicativo ou sessão na plataforma do Lightning. Se você precisar que os dados persistam entre as classes, use variáveis estáticas, mas lembre-se de que as variáveis estáticas na plataforma do Lightning não funcionam do mesmo jeito que no .NET. No universo da plataforma do Lightning, uma variável estática só pode preservar informações dentro de um contexto de execução única, embora haja outras opções disponíveis para manter os dados entre as invocações do acionador. Confira os links sobre o Apex avançado nos Resources, na Internet, para saber mais.
Ao trabalhar com limites, é preciso considerar vários dilemas, principalmente no caso dos desenvolvedores de pacotes gerenciados. A propósito, os parceiros do Salesforce costumam usar pacotes gerenciados para distribuir e vender aplicativos. Neste módulo, falamos bem superficialmente do que você precisa saber. Caso queira estudar o desenvolvimento em Apex a sério, confira os links sobre o Apex avançado nos Resources, na Internet.
Recursos
-
Como invocar Apex no Guia do desenvolvedor do código do Apex
-
Introdução aos acionadores do Apex na trilha do Desenvolvedor iniciante
-
Administradores e limites de execução
-
Como testar acionadores na trilha do Desenvolvedor iniciante