JavaScript - Aplicação em Camadas
JavaScript - Aplicação em Camadas
Introdução
Aplicação em camadas – Uma aplicação em camadas é aquela em que o código da
aplicação é dividido em arquivos diferentes. Esses arquivos são chamados de camadas e
o tipo de camada é determinado com base no seu contexto. Para entender isso mais
facilmente vamos utilizar um exemplo mostrando a diferença entre uma aplicação
tradicional e uma aplicação em camadas. Nossa aplicação de exemplo é um conversor de
temperatura de Fahrenheit para Celsius.
console.log(converteParaCelsius(fahrenheit));
Veja que nessa versão temos apenas um arquivo e todo código da nossa aplicação está
nele. Como vimos, a aplicação em camadas tem seu código dividido em múltiplos
arquivos. Veja os exemplos abaixo:
Camada de conversão de temperatura
Arquivo conversor.js
function converteParaCelsius(fahrenheit)
{
let celsius = (fahrenheit – 32) / 1.8;
return celsius;
}
console.log(converteParaCelsius(fahrenheit));
Veja que o código ainda é o mesmo, porém, agora ele está dividido em dois arquivos
diferentes. Essa divisão resultou em duas camadas para a nossa aplicação.
Agora que vimos o que é uma aplicação em camadas, vamos entender por que é útil.
A principal utilidade de uma aplicação em camadas é facilitar a manutenção do código. As
aplicações estão sempre recebendo atualizações e novidades, e com isso, o código
aumenta constantemente. Quanto maior o código mais complexo é a sua manutenção e
sem a divisão de camadas, todos os contextos da aplicação ficam em um só lugar. Por
exemplo: se o desenvolvedor precisasse alterar o conteúdo dos dados armazenados, ele
teria que percorrer todo o código para encontrar essa informação. A divisão em camadas
facilita esse processo, pois o desenvolvedor pode ir direto ao ponto em que precisa fazer a
alteração. Além de facilitar a manutenção, a separação em camadas também deixa o
código mais organizado e fácil de entender. Vamos a um exemplo:
function efetuaCalculoArea(raio)
{
const valorPi = 3.14;
let retornaArea = valorPi * (raio * raio);
return retornaArea;
}
retornoArea = efetuaCalculoArea(raio);
console.log(“Area: “ + retornoArea);
Repare que o nosso código possui duas variáveis com nomes bem semelhantes. Uma
situação como essa pode facilmente confundir o desenvolvedor e a alteração da variável
incorreta pode causar um erro na aplicação. Por exemplo, se no momento da
implementação tivéssemos utilizado a variável retornaArea no lugar de retornoArea, a
aplicação retornaria um erro. Por isso, dividir a aplicação em camadas nos ajuda a resolver
esse problema.
index.js
import efetuaCalculoArea from ‘./calculo.js’;
retornoArea = efetuaCalculoArea(raio);
console.log(“Area: “ + retornoArea);
calculo.js
function efetuaCalculoArea(raio)
{
const valorPi = 3.14;
let retornaArea = valorPi * (raio * raio);
return retornaArea;
}
Veja que as variáveis foram separadas em arquivos diferentes, resolvendo o problema dos
nomes semelhantes no mesmo arquivo.
Refatoração
Agora que você já sabe o que são e para que servem as aplicações em camadas, vamos
conhecer um conceito muito importante no processo de divisão de camadas: a refatoração.
Conceito: Na programação, refatorar significa melhorar, reorganizar um código sem alterar
seu objetivo. Para entender melhor, vamos a um exemplo:
Essa é uma aplicação que converte Celsius para Fahrenheit
let celsius = 25;
let fahrenheit;
console.log(fahrenheit + ‘ºF’);
function converteCelsiusParaFahrenheit(celsius)
{
let fahrenheit;
fahrenheit = (celsius * 1.8) + 32;
return fahrenheit;
function retornaStatusTemperaturaFahrenheit(celsius)
{
let status;
return status;
}
let celsius = 25;
console.log(resultado + ‘ºF’);
console.log(statusResultado);
Ciclo de refatoração
Um código pode ser refatorado várias vezes, de acordo com a necessidade do
programador.
console.log(resultado + ‘ºF’);
console.log(statusResultado);
retornaDadosTemperatura.js
function converteCelsiusParaFahrenheit(celsius)
{
let fahrenheit;
fahrenheit = (celsius * 1.8) + 32;
return fahrenheit;
function retornaStatusTemperaturaFahrenheit(celsius)
{
let status;
index.js
import {converteCelsiusParaFahrenheit, retornaStatusTemperaturaFahrenheit} from
‘./retornaDadosTemperatura.js’;
console.log(resultado + ‘ºF’);
console.log(statusResultado);
converteTemperatura.js
function converteCelsiusParaFahrenheit(celsius)
{
let fahrenheit;
fahrenheit = (celsius * 1.8) + 32;
return fahrenheit;
}
statusTemperatura.js
function retornaStatusTemperaturaFahrenheit(celsius)
{
let status;
Na versão com 2 arquivos as funções são tratadas como um único contexto: O contexto
de temperatura.
A técnica de refatoração será essencial não apenas na divisão de camadas, mas também
durante toda sua carreira como programador. Um código organizado demonstra
profissionalismo e é através da refatoração que a organização do código é alcançada. E
lembre-se: a refatoração é um ciclo e você deve sempre buscar melhorar o código da sua
aplicação.
Contextos da aplicação
O contexto de uma aplicação é a separação do seu conteúdo em grupos menores com
base em suas semelhanças. Veja um exemplo:
Contexto do cálculo da área
let base = 16;
let altura = 8;
contexto de exibição
console.log(“A área do triângulo é “ + area);
console.log(“IMC: “ + resultado);
Agora é só analisar o código e identificar seus contextos. Observando o código podemos
ver dois contextos: Contexto do cálculo de IMC e o contexto de exibição. O contexto do
cálculo de IMC é representado pela função calculaIMC, pois o único objetivo dela é esse.
Já o restante do código assume o contexto de exibição, pois seu objetivo em conjunto é
retornar resultado do cálculo de IMC para o usuário.
Como fizemos alterações no nosso código, será necessário observá-lo novamente para
identificar os contextos. A função retornaStatusIMC é utilizada para retornar o status do
usuário com base no cálculo do IMC e por esse motivo ela está no contexto do cálculo
IMC.
if(peso > 0)
{
pesoValido = true;
}
return pesoValido;
}
validaAltura
function validaAltura(altura)
{
let alturaValida = false;
if(altura > 0)
{
alturaValida = true;
}
return alturaValida;
}
Nesta parte do código as duas funções são utilizadas para checar os valores de peso e
altura e determinar o que dever ser feito.
let verificaPesoAltura = validaPeso(peso);
let verificaAlturaValida = validaAltura(altura);
Hierarquia de camadas
Vamos usar o exemplo da calculadora de IMC, onde vimos a camada exibição consumir
funções da camada de serviço IMC. Agora nós conheceremos as subcamadas, que são
camadas menores que auxiliam direta ou indiretamente uma camada de hierarquia maior.
Uma camada pode ter infinitos níveis de subcamadas, o limite é a necessidade da
aplicação. Para entender melhor essa ideia, considere o seguinte exemplo:
Uma empresa quer fazer uma reforma no escritório e para isso ela contrata um arquiteto. A
relação entre a camada empresa e a camada arquiteto se dá em uma hierarquia de grau 1,
pois os dois são de hierarquias maiores e estão no mesmo nível. O arquiteto será
responsável pela obra, mas não é ele quem vai fazer a obra. O arquiteto não vai pintar as
paredes ou colocar os pisos. Para isso, o arquiteto contrata um mestre de obras. Observe
que o mestre de obras está em uma hierarquia de grau 2, pois está 1 grau abaixo do
arquiteto. O mestre de obras por sua vez, contrata uma equipe de operários, que
executam as tarefas e se reportam a ele. Os operários estão em uma hierarquia de grau 3,
pois estão separados do arquiteto por duas hierarquias.
Agora que entendemos a hierarquia, vamos ver o que cada parte desse exemplo
representa. O arquiteto é como a camada de serviço. É uma camada de hierarquia maior
que para cumprir a sua missão consome camadas de hierarquia menor. O mestre de
obras e os operários são as subcamadas que fornecem dados para o arquiteto direta e
indiretamente. O arquiteto se informa do estado da obra com o mestre de obras, que por
sua vez, busca informações com os operários para levar ao arquiteto. No nosso exemplo
a empresa se comunica com o arquiteto e ele fala com o mestre de obras. A empresa
nunca fala diretamente com o mestre de obras. Isso acontece, pois, empresa e arquiteto
estão no mesmo grau de hierarquia. A hierarquia deve ser respeitada na comunicação
entre as camadas.
console.log(mensagem);
return imc;
}
Subcamada de serviço
Vamos ver como a aplicação muda quando adicionamos uma nova camada a ela.
O que queremos fazer aqui é adicionar o seguinte código à nossa aplicação.
function formataIMC(imc)
{
return imc.toFixed(2);
}
Esse código tem como objetivo formatar o valor do IMC em duas casas decimais. Perceba
que a função formataIMC não se encaixa em nenhum contexto existente da nossa
calculadora de IMC. A função formataIMC não está diretamente relacionada ao cálculo do
IMC e também não é associada diretamente a exibição dos dados. Ela é uma função de
apoio para a camada de serviço IMC. Por esse motivo foi necessário criar uma nova
camada. Uma nova camada é criada quando existe um novo contexto. Agora qie
entendemos porque precisamos de uma nova camada, vamos adicioná=la à nossa
calculadora. Para isso, criaremos um novo arquivo chamado formatacaoDados.js, que será
responsável por formatar o resultado do IMC.
function formataIMC(imc)
{
return imc.toFixed(2);
}
Subcamada de exibição
Perfeito, vimos a nossa primeira subcamada, e agora vamos ver como diferentes camadas
podem ter subcamadas.
As subcamadas não são adicionadas apenas à camada de serviço, qualquer camada pode
ter uma subcamada. Para demonstrar isso, vamos adicionar uma subcamada à nossa
camada de exibição. Para isso, criamos um novo arquivo: pesoAlturaValidacao.js
function validaPeso(peso)...
}
function validaAltura(altura)...
}
Contextos
import {converteParaReal, converteParaEuro} from './converteMoedas.js';
import {formataReal, formataEuro, formataDolar} from './formataMoedasConvertidas.js';
if(conversor == 'real')
{
valor_convertido = converteParaReal(dolar);
valor_convertido = formataReal(valor_convertido);
}
else if(conversor == 'euro')
{
valor_convertido = converteParaEuro(dolar);
valor_convertido = formataEuro(valor_convertido);
}
function converteParaReal(dolar)
{
let taxa_conversao = 5.07;
let real = dolar * taxa_conversao;
return real;
}
function converteParaEuro(dolar)
{
let taxa_conversao = 0.83;
let euro = dolar * taxa_conversao;
return euro;
}
function formataDolar(dolar)
{
let valor_formatado = '$ '+dolar;
return valor_formatado;
}
function formataReal(real)
{
let valor_formatado = 'R$ '+real;
return valor_formatado;
}
function formataEuro(euro)
{
let valor_formatado = ' € '+euro;
return valor_formatado;
}
O objetivo principal da aplicação é mostrar em que dia da semana vai cair cada feriado
retornado.
let numeroFeriados = 3;
function retornaProximosFeriados(numeroFeriados)
{
// Para conseguir filtrar os dados a função filtraFeriados precisa do array dos feriados e
do número de feriados a ser retornado.
let feriadosFiltro = filtraFeriados (feriadosNacionais, numeroFeriados);
feriadosFiltro.forEach(feriado => {
const dataFeriado = feriado.data;
let diaSemana = formataDiaSemana(dataFeriado);
const dataFeriadoFormatada = formataDataFeriado(diaFeriado);
feriadosFiltroFormatados.push({
nome: feriado.nome,
diaSemana: diaSemana,
data: dataFeriadoFormatada
});
});
return feriadosFiltroFormatados;
}
A camada de serviço feriados não sabe como a filtragem ocorre ou como a formatação é
feita. Ela apenas se preocupa em retornar os próximos feriados. A função
retornaProximosFeriados recebe como parâmetro o número de feriados que queremos
retornar. Em seguida, esse valor é passado para a função filtraFeriados que recebe também
um array contendo todos os feriados da camada de dados. O retorno do filtro é então
‘varrido’ e retornamos o dia da semana em que o feriado vai cair e a data do feriado formata
no padrão dia/mês/ano. Resultado é adicionado ao array feriadosFiltroFormatadoss que
passa a ter o nome, o dia da semana e a data formatada do feriado. Por fim, a função
retorna o array com os dados formatados para que ele possa ser consumido pela camada
de exibição. Veja que a camada de serviço feriados possui chamadas para outras funções
que o auxiliam. Essas funções fazem parte das camadas de apoio de serviço.
Outra camada de apoio é a camada de filtragem dos feriados. Seu objetivo é filtrar os
próximos feriados e retornar para a camada de serviço feriados. O processo de filtragem
dos feriados começa ‘varrendo’ o array de feriados e adicionando o ano as datas
correspondentes. Fazemos isso adicionando o ano atual em todas as datas de feriados e
comparando-as com a data atual. Se a data do feriado já tiver passado colocamos ela para
o próximo ano. Exemplo:
Hoje = 24/12/2023
Natal = 25/12/2023
Ano novo = 01/01/2023 => 01/01/2024
Veja que como 01/01/2023 já passou, seu ano foi alterado para 2024
Com as datas definidas criamos um novo array com o mesmo conteúdo, mas dessa vez
com a data completa e no formato Date do JS. Por fim usamos a função nativa sort para
ordenar nosso array por data e depois retornamos dele apenas o número de feriados que
queremos com o slice. No código do nosso exemplo retornaremos apenas os 3 próximos
feriados. Com os dados filtrados, precisamos formata-los e é exatamente o que veremos
como fazer.
filtros.js
// Define a função filtraFeriados que recebe dois parâmetros: feriados e numeroFeriados
function filtraFeriados(feriados, numeroFeriados)
{
// Obtém a data atual
const dataAtual = new Date();
// Obtém o ano atual da data atual
const anoAtual = dataAtual.getFullYear();
A última camada de apoio é a camada de formatação dos feriados. Seu objetivo é retornar
a data e o dia da semana formatados corretamente.
formataDataFeriado.js
function formataDiaSemana(dataFeriado) {
let diasDaSemana = [
"Domingo", "Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira",
"Sábado"
];
return diasDaSemana[dataFeriado.getDay()];
}
function formataDataFeriado(dataFeriado)
{
const diaFeriado = dataFeriado.getDate();
const mesFeriado = dataFeriado.getMonth() + 1;
const anoFeriado = dataFeriado.getFullYear();
return dataExibicao;
}