Aprender sobre reutilização de código e controladores do Apex

Objetivos de aprendizagem

Após concluir esta unidade, você estará apto a:
  • Descrever a diferença entre herança e composição para a reutilização de código.
  • Descrever as diferenças sintáticas e de arquitetura entre os controladores do Apex do Visualforce e dos componentes do Aura.

Herança vs. Composição

Embora pudéssemos facilmente passar uma semana neste tópico, em um seminário intensivo de design de software, pretendemos ser breves.

Os componentes do Aura podem herdar de seus componentes pais, e a herança é um estilo importante da arquitetura de código reutilizável. Porém:

Prefira a composição à herança.

Há um motivo para ser a “estrutura de componente do Lightning”. A composição é o modelo fundamental para a reutilização de seu código.

Aqui estão dois motivos concretos para você adotar este mantra.

  1. Na implementação da estrutura, a herança tem algumas desvantagens de desempenho significativas. Os detalhes estão sujeitos a mudança, mas você descobrirá que usar a herança consome mais memória e recursos do processador do que você esperaria.
  2. A herança em componentes do Aura não funciona exatamente como no Apex ou em Java. É...diferente. Por exemplo, um componente filho pode se estender a partir de um componente pai. E o componente filho tem acesso, por exemplo, aos manipuladores de ação e às funções auxiliares definidas do pai. E o componente filho pode substituir essas funções e manipuladores pelos seus. Mas o componente filho não pode estender essas funções ou manipuladores. Ou seja, o método auxiliar filho não pode chamar o super.aHelperFunction() de dentro de sua implementação de aHelperFunction() e então incluir lógica adicional. Ou você usa a função pai como implementada ou você a substitui por completo. Esta restrição impõe um obstáculo à reutilização. Há uma abordagem alternativa que envolve algum contorcionismo usando o <aura:method>. Ele é suportado e poderoso, mas se seu caso de uso for simples, ele parece um pouco elaborado demais.

A forma como a herança é implementada nos componentes do Aura é, como dissemos, peculiar. E a implementação está sujeita a mudanças. Evite hierarquias de herança complexas, assim você pode adaptar-se ao passo que a estrutura se altera.

Controladores do Apex

Vamos ver um controlador muito simples do lado do servidor e conversar sobre alguns pontos.
public with sharing class SimpleServerSideController {
    @AuraEnabled
    public static String serverEcho(String echoString) {
        return ('Hello from the server, ' + echoString);
    }
}

Há algumas coisas a serem notadas aqui, incluindo um número de diferenças específicas em relação a um controlador do Visualforce.

  • A mais óbvia das novidades é a anotação @AuraEnabled. Se você já trabalhou com JavaScript Remoting no Visualforce, é bem parecido com a anotação @RemoteAction que você usa para esses métodos.
  • A semelhança com o JavaScript Remoting continua com a assinatura do método. Os métodos do controlador do lado do servidor dos componentes do Aura devem ser static e public ou global.
  • A consequência dos métodos do controlador do lado do servidor serem static é que você não pode armazenar qualquer estado de componente no lado do servidor. Mantenha o estado do componente em seus atributos do lado do cliente, conforme descrito anteriormente.
  • As ações no lado do servidor retornam dados. Elas não retornam (não podem retornar) uma PageReference. Implemente sua lógica de navegação no lado do cliente, não no lado do servidor.
  • Deslizador! Algo que pode não ser óbvio, mas que causará muita dor de cabeça caso você esqueça, é que os nomes de parâmetros usados na declaração de método do Apex devem coincidir com os nomes de parâmetros usados ao criar a ação no lado do cliente.
  • Deslizador! Mais uma restrição não óbvia: Não dê a um método de controlador do lado do servidor o mesmo nome que o de uma função de manipulador de ação do lado do cliente. Isto seria algo… bizarro. Você deve adotar uma convenção de nomenclatura para seus métodos no lado do cliente e no lado do servidor, que faça uma distinção clara, e torne impossível colisões de nomes.

Vamos repetir estes dois últimos pontos. Os nomes de parâmetros devem coincidir ao passarem entre o código do lado do servidor e do lado do cliente. Porém, os nomes dos métodos não devem coincidir.

Apex vs. Componentes do Aura

Com qualquer componente do Aura que tenha Apex no lado do servidor, os dados trafegam entre o código JavaScript do componente do Aura e o código do Apex do lado do servidor. A maioria das conversões de parâmetros e de resultados entre os dois formatos de dados funciona automaticamente. Mas há algumas poucas limitações que podem afetar o projeto de seu software.

Apex não é JavaScript

Deslizador! Isso pode parecer óbvio, mas vale a pena destacar que quando você trafega os objetos entre os códigos no lado do cliente e do servidor, eles passam por transformações. Um objeto Apex, que pode incluir propriedades com lógica complexa, quando retornado em dados de resposta, se torna um objeto JavaScript simples, apenas com pares nome:valor. Variáveis de instâncias públicas são passadas e métodos de instância de getter público no objeto Apex são chamados e resolvidos para valores estáticos antes de o objeto ser serializado e retornado. E assim por diante.

Escada! Embora o processo seja determinístico, e compreensível, geralmente vale a pena criar classes especiais e simplificadas no Apex apenas para fins de empacotar e retornar os dados aos componentes do Aura. Use tais classes para transferência de dados, em vez de usar suas classes de processamento.

Parece trabalho extra (código). E é mesmo. Mas isto elimina parte da complexidade do nebuloso processo de transformação-serialização-transmissão-deserialização que acontece quando são retornados os dados do Apex para o JavaScript. Remover esta complexidade pode simplificar a depuração.

sObjects

Você pode criar novos sObjects em código JavaScript, incluindo objetos personalizados. Isto inclui um pouco mais de sintaxe, mas é simples. Estes sObjects podem ser enviadas como parâmetros em solicitações ao Apex do lado do servidor. Você pode retornar sObjects em uma resposta do Apex e a estrutura cuida da transformação.

Classes personalizadas

Escada! De forma prática, não é possível transmitir uma classe Apex personalizada como um parâmetro do JavaScript do lado do cliente para o Apex do lado do servidor. Em vez disso, use um objeto JavaScript simples para encapsular os dados estruturados do parâmetro. Analise o objeto conforme necessário em seu código Apex, por exemplo, no construtor para uma classe do Apex.

É possível retornar uma classe do Apex personalizada na resposta de seu controlador do lado do servidor para o JavaScript do lado do cliente. Porém, ela será serializada e deserializada como parte do processo, e o resultado pode não ser exatamente o que você esperava. Escada! Geralmente, é melhor retornar um mapa com os elementos dos dados que você quer incluir ou o JSON criado por você mesmo.

Classes internas

Deslizador! Você não pode usar classes internas do Apex no código dos componentes do Aura. O código do Apex do lado do servidor pode usá-las ao processar uma solicitação, mas a resposta retornada ao cliente não pode ser uma instância de uma classe interna.

Herança

Deslizador! Não é permitido usar herança com as classes do Apex personalizadas que você pretende retornar em resposta aos componentes do Aura.

Tratamento de erros do lado do servidor

Escada! Se seu código do Apex encontra um erro, você pode criar e lançar uma AuraHandledException. Capturar outras exceções, como uma exceção de DML, e relançá-las como uma AuraHandledException também resulta em uma experiência muito melhor no lado do cliente.