Criar uma Exception personalizada no Magento 2



Contextualizando



O que é uma Exception?

É um mecanismo que sinaliza um evento excepcional, significa algo que não é comum. A exceção ocorre quando acontece algo fora da regra de negócio prevista.
O tratamento de exceção é o mecanismo responsável pelo tratamento da ocorrência de condições que alteram o fluxo normal da execução de programas de computadores.
Exceção são usadas para fazer tratamentos no código, ou seja, podemos fazer um controle de exceção em determinada parte de um código fonte para saber qual foi o erro que levou ao problema.
Uma exceção pode ser lançada através da palavra reservada throw quando o trecho de código estiver envolvido na palavra reservada try, e capturada através da palavra reservada catch. Cada bloco try precisa ter ao menos um catch ou finally correspondente.
Uma classe de exceção definida pelo usuário pode ser criada herdando a classe Exception, consequentemente, o objeto lançado precisa ser uma instância da classe Exception ou uma subclasse de Exception. Tentar lançar um objeto sem essa ascendência resultará em um erro fatal. Para saber mais, consulte a documentação oficial do PHP sobre as exceptions.



Código para criar uma Exception

Este tipo de arquivo deve seguir a estruturas de pastas VendorModuleExceptionNameException.php. Cada arquivo de Exception deve estender a classe MagentoFrameworkExceptionLocalizedException.

<?php

namespace VendorModuleException;

use MagentoFrameworkExceptionLocalizedException;
use MagentoFrameworkPhrase;

class NameException extends LocalizedException

    public function __construct(
        Phrase $phrase = null,
        Exception $cause = null,
        array $params = [],
        $code = 0
    ) 
        parent::__construct($phrase, $cause, $params, $code);
    

A classe MagentoFrameworkExceptionLocalizedException estende da classe Exception do PHP e é estendida por um conjunto de classes que o próprio Magento já disponibiliza para o uso, estas classes de excessão estão disponíveis no caminho MagentoFrameworkException.



Disparando uma excessão

Ao disparar uma excessão, o código será interrompido e será “capturado” pelo primeiro catch que envolverá o código (podendo ser de outra função ou método. Para disparar uma excessão personalizada no Magento, é igual a lançar qualquer outra excessão.

throw new VendorModuleExceptionNameException(
    __('Message exception')
);



Finalização

Valores entre chaves (test) devem ser alterados na implementação do código.



Habilitando as alterações

Execute o comando PHP para limpar todos os caches de armazenamento em cache do processos.

php bin/magento cache:clean
php bin/magento flush



Diretórios e Arquivos

Segue a a lista de diretórios e arquivos que devem ser criados.

- app/
  - code/
    - Vendor/
      - Module/
        - etc/
          - module.xml
        - Exception/
          - NameException.php
        - registration.php
        - composer.json

Source link

Caso de uso: RegEx

Podemos identificar padrões em uma cadeia de caracteres usando Expressões Regulares (Regular Expression ou RegEx).

Para validar o formato de um CPF, por exemplo, é necessário que esteja no seguinte padrão:

  • xxx.xxx.xxx-xx (cada x corresponde à um dígito decimal)

Então através de uma RegEx conseguimos identificar se esse padrão foi seguido ou não.



Introdução

Usando a linguagem de programação Python, importa-se o módulo re que fornece operações de expressões regulares.

import re

Cria-se uma função validar a qual recebe uma string cpf, ela retorna válido ou inválido.

def validar(cpf):
    validador = expressao.match(cpf)
    if validador:
        return 'válido'
    return 'inválido'



Primeiro caso

Usando a função re.match, compara-se o cpf com a expressão regular compilada expressao, ela retorna um Match Object caso combine, do contrário retorna None, o valor é atribuído à variável validador.

A expressão escrita a seguir contém alguns símbolos com significado especial, são eles:

  • ^ sinaliza o início de uma linha ou string
  • $ sinaliza o fim de uma linha ou string
  • d corresponde aos dígitos decimais de 0 a 9

Um detalhe importante, o uso de . também possui um significado especial e para retirar esse significado usa-se a antes do caracter, assim ele se torna o . (ponto literal).

expressao = re.compile(r'^ddd.ddd.ddd-dd$')

Essa expressão é escrita de uma forma simples, repetindo os caracteres no formato esperado.



Evitando repetição de elementos

Podemos reescrevê-la usando mais recursos implementados no módulo re, usando o conceito de repetição de elementos da RegEx representados por chaves , aplicando-o ao conjunto de dígitos d que é repetido um certo número de vezes, obtem-se:

expressao = re.compile(r'^d3.d3.d3-d2$')



Evitando repetição de trechos

Outra forma de expressar a RegEx é usando o conceito de grupos. Nesse caso podemos agrupar um trecho do formato que se repete, fazendo um grupo de 3 dígitos e um . (ponto literal), que devem ser repetidos duas vezes.

expressao = re.compile(r'^(d3.)2d3-d2$')



Exemplos de execução

Usaremos três exemplos para testar a validação do CPF:

a = '111.222.333-44'
b = '1234.123.789-88'
c = '123.12.789-88'
d = 'abs.ert.yui.lk'

print(f'''
    O CPF: a é validar(a)
    O CPF: b é validar(b)
    O CPF: c é validar(c)
    O CPF: d é validar(d)
    ''')

Analisando a saída obtida, notamos que:

  • O exemplo a está no formato correto.
  • O exemplo b contém mais dígitos do que o esperado no primeiro trecho.
  • O exemplo c contém menos dígitos do que o esperado no segundo trecho.
  • O exemplo d apresenta caracteres não-dígitos, sendo inválido.
    O CPF: 111.222.333-44 é válido
    O CPF: 1234.123.789-88 é inválido
    O CPF: 1234.12.789-88 é inválido
    O CPF: abs.ert.yui.lk é inválido



Considerações

Vimos que uma RegEx pode ser escrita de várias formas para validar o mesmo padrão e ainda existem diversas outras maneiras, podendo levar em conta a legibilidade ou complexidade da escrita para fazer sua escolha.

Aprendendo mais sobre os recursos do módulo re do Python.

Estudando mais sobre expressões regulares.

Se escreve caracter/caráter/caracteres?

Enjoy!


Source link

Melhorando seus Testes com GRAMÁTICA



Prólogo

Há tempos eu venho fazendo code reviews em repositórios dos meus viewers, que pedem esse CR em live etc e eu fico muito atento as boas práticas mas eu vejo que algo muito comum entre essas amostras é como falta alguns entendimentos para nomes de métodos ou até mesmo as classes.

Como entender o que o método handle faz no AppRepository? Ou o que o teste test_user_fails faz na suite UserCommandsTest? Muitas vezes falta descrição ou objetividade no que é escrito te faz perder muito tempo tentando entender como funciona ou qual deveria ser o comportamento correto daquele bloco de código.

Há muito tempo essa prática de não ser auto descritivo vem sendo sustentada pelos desenvolvedores do mundo a fora e você pode entender que quando uma empresa te pede para corrigir esse tipo de coisa, para ser mais assertivo em como deixar uma função legível, é porquê essa empresa se preocupa mais com a QUALIDADE do código entregue do que com qualquer outra coisa.

Existem muitos pontos que dizem se um código é limpo ou não, mas um deles certamente é a clareza de como você escreve seus métodos ou documentação.



Suites de Testes

O cenário mais comum onde devs vem pecando cada vez mais em descrições que não descrevem nada é no PIOR LUGAR pra isso acontecer: SUITES DE FUCKING TESTES!

Cara, você ter uma suíte com 103782183129 testes que não são auto descritivos é um tiro no pé IMENSO do ponto de vista de quem vai dar manutenção nisso no futuro. Testes devem cobrir cenários especificos, porém, se você não CONTAR ou especificar os comportamentos no nome da função, já não vai servir de muita coisa. Vamos pra um exemplo:

Peguei um código pra revisar onde o método deveria checar se uma transação estava sendo feita para o mesmo usuário e estava sendo escrito assim:

public function test_payer_and_payee_equals();

it("payer and payee equals");

Quando eu li isso, inicialmente eu fiquei confuso porquê pra mim na primeira interpretação até ler o código, deveria ser pra checar se os usuários são iguais porém no código eles NÃO deveriam ser iguais.

Agora vamos entender algumas palavrinhas que podem de fato ajudar a ter um melhor entendimento para a criação de sentenças de testes:

  • Can = Usado quando o usuário DEVE ter aquele comportamento e é um teste não tem exceções (fluxo de como deveria funcionar)
  • Should = Usado quando o usuário DEVERIA ter aquele comportamento e é um teste que vai cair em alguma exceção (fluxo de como deveria chegar na exceção)
  • Should NOT = Usado quando o usuário não deveria ter algum comportamento e é um teste que vai cair em alguma exceção (fluxo de como deveria chegar na exceção)

Se eu fosse reescrever o nome da função pra ser algo mais claro, ficaria assim:

public function test_payer_and_payee_should_not_be_the_same();

it("payer and payee should not be the same");

ou

public function test_user_should_not_send_money_to_his_own_account();

it("user should not send money to his own account");

Ficou bem mais descritivo né? O esperado de um teste é que o nome da função seja a descrição do que deve acontecer ali dentro. Agora vamos pro segundo exemplo:

public function test_value_is_greather_than_zero();

it("value is greather than zero");

Esse aqui ficou bem confuso… O nome da suite é TransactionControllerTest então você consegue assumir algumas coisas vendo o nome desse teste, porém, você assumir algo quer dizer que o teste não diz o que faz e isso é um problema se você tiver de refatorar ele lá na frente.

  • O que eu interpretei: o valor (que eu não sei do que exatamente) tem/deve que ser é maior que zero.
  • O que deveria ser: o valor da transação deve ser maior que zero.

Agora reescrevendo essa função temos as possibilidades:

public function test_user_should_transfer_an_amount_greather_than_zero();

it("user should transfer an amount greather than zero");

ou

public function test_transaction_amount_should_be_greather_than_zero();

it("transaction amount should be greather than zero");

Esses cenários até o momento não envolveram a palavra “should” e “not” que especificam que os cenários deverão cair em exceções.

Agora vamos para um cenário positivo onde nada daria erro contemplando a mesma suíte de testes:

public function test_balance_payee_is_ok_after_transaction();

it("balance payee is ok after transaction");

Eu vi que é o único teste que retorna 201, então eu já entendi que ele vai pelo lado certo da coisa. Porém, ainda não achei o nome do teste descritivo ao ponto de saber o que tá rolando.

Você citar um comportamento do TESTE no nome não fica tão legal, afinal, o seu teste precisa garantir que o valor da carteira do pagador vai estar OK, certo?! Isso é pra dentro do código, não pro nome.

O que poderia fazer para melhorar esse cenário:

public function test_user_can_create_a_new_deposit();
public function test_user_can_create_a_new_withdraw();
public function test_user_can_create_a_new_transaction();

it("User can create a new deposit");
it("User can create a new withdraw");
it("User can create a new transaction");

Mais assertivo que isso eu creio que seja impossível. Usando o can nós estamos AFIRMANDO que o retorno tem que ser algo positivo, já que o usuário PODE fazer aquela ação.

Espero que você tenha gostado da ideia proposta no post, não esqueça de deixar de compartilhar nas redes sociais e deixar o like aqui na plataforma!


Source link

🤔 False, true, "Falsy" & "Truthy" 👀



🤔 False, true, “Falsy” & “Truthy” 👀



⚙️ Entendendo um pouco do contexto Geral.

Na computação temos um Tipo chamado: “Booleano”. O que é: Booleano?

Aqui estamos falando tipo primitivo do TypeScript: “Boolean”. (⊙.☉)7

Ser do tipo (Booleano) significa que algum valor, isto é, alguma variável, constante ou qualquer coisa que possuí em si um valor desse tipo pode ser:

  • Verdadeiro (Isto é, true) 👍
  • Falso (Isto é, false) 👎

O nome “Booleano” (Boolean em TypeScript) faz uma homenagem ao Matemático & Filósofo George Boole, ele “construiu” a base algébrica necessária para a criação Lógica Algébrica que podemos usar para: Operações lógicas (em booleanos) como conjunção (||), disjunção (&&), disjunção exclusiva ((p && !q) || (!p && q)), equivalência lógica (==) e negação (!), que correspondem a algumas das operações da álgebra booliana (É a parte da do conceito da Matemática Discreta).



Fornecendo um exemplo básico ԅ(≖‿≖ԅ):

/** Vamos iniciar uma constante "Booleana" verdadeira */
const constanteVerdadeira: Boolean = true;
/** Vamos iniciar uma constante "Booleana" falsa através da inversão do seu valor boleano com o operador "!" */
const constanteFalsa: Boolean = !constanteVerdadeira;

if(constanteFalsa && constanteVerdadeira ) 
    console.log("Ambas as constantes são verdadeiras. ヽ(´▽`)/")
 else if (constanteFalsa || constanteVerdadeira) 
    console.log("Ao menos uma das constantes são falsas ( ಠ ʖ̯ ಠ )")
 else 
    console.warn("Nenhuma constante é verdadeira (҂◡_◡)")



🤔 Por que existe: “Falsy” ou “Truthy”?

Na lógica, afirmações diferentes são logicamente equivalentes se tiverem o mesmo conteúdo lógico. Isto é, se elas tiverem o mesmo valor de verdade em todos os modelos. Também conhecido por “Tautologia”, isto é, algo que é correspondente em termos lógicos.



👎 O que é o “Falsy” ou _Errôneo/_Falseáveis ?

***➡️ Falsy é um *”_pseudo tipo*_” **logicamente equivalente ao **Valor Primitivo *false para o JavaSript.



Os valores que seriam aceitos como false seriam:

  • 0 – (O valor numérico Zero).
  • 0n – (Um inteiro de GIGANTE cujo valor numérico é zero – um bigInt).
  • null – (O tipo primitivo Nulo).
  • undefined – (Algo que não possui valor atribuído, isto é, indefinido).
  • NaN (Not-a-Number** -** algo que não é um número pertencente ao conjuntos dos reais)
  • “” ou ” ** (Uma cadeia de **caracteres vazia)



Segue a prova do supracitado (☞゚ヮ゚)☞

const inteiroDeValorNumericoZero: number = 0;
const floatDeValorNumericoZero: number = 0.0;
const inteiroGrandeComValorNumericoZero: bigint = BigInt(0);
const nulo: null = null;
let indefinido;
const naoNumero: number = Number.NaN; //Sim, o tipo de NaN é "numero" ¯_(ツ)_/¯
const cadeiaDeCaracteresVazia = '';

let valoresInexatos: unknown[] = [
    inteiroDeValorNumericoZero,
    floatDeValorNumericoZero,
    inteiroGrandeComValorNumericoZero,
    nulo,
    indefinido,
    naoNumero,
    cadeiaDeCaracteresVazia
]

valoresInexatos.forEach((valor) => console.log(valor ? "Verídico" : "Errôneo/Falseáveis"));



O que é “Truthy” ou Verídico?

Truthy é um pseudo tipo” *logicamente equivalente ao **Valor Primitivo *true* para o JavaSript.*



Os valores que seriam aceitos como true seriam:

  • ‘0’ ou “0” – (Uma cadeia de caracteres com o Valor numérico zero dentro dela).
  • ‘false’ ou “false” (…) – (Uma cadeira de caracteres com a palavra “false”).
  • []_ – (Um** vetor (“**_array” **vazio), isto é, **sem elementos presentes dentro dele)
  • – (Um objeto sem nenhuma propriedade.)
  • ()=> – (Uma definição de função anônima ou não.



Segue a prova do supracitado (☞゚ヮ゚)☞

const cadeiaDeCaracteresComZero: string = '0';
const cadeiaDeCarcteresComAPalavraFalse: string = 'false';
const vetorVazio: number[] = [];
const funcaoNomeada: Function = () => 
    //vazia


let valoresVeridicos: unknown[] = [
    cadeiaDeCaracteresComZero,
    cadeiaDeCarcteresComAPalavraFalse,
    vetorVazio,
    funcaoNomeada,
    () => 
]

valoresVeridicos.forEach((valor) => console.log(valor ? "Verídico" : "Errôneo/Falseado"));

Source link

Três conceitos para um Código Limpo



Prólogo

A pergunta mais constante entre os desenvolvedores que estão querendo sair do nível Júnior para Pleno é “será que meu código tá uma merda?” ou “beleza isso funciona, mas como melhorar esse lixo?” e se questionar sobre a qualidade do produto que você está entregando é um sinal de que você está (digi)evoluindo.

Na minha jornada como desenvolvedor eu venho cada vez entendendo que no final das contas o importante é a engenharia e não a ferramenta, até porquê você sabe que um CRUD é uma sequencia X que pode ser replicada em TODAS as linguagens, certo? Logo, se você sabe a teoria/engenharia, a pratica só precisa da ferramenta/linguagem.

Agora, vamos entender sobre conceitos/padrões que podem estar ligados diretamente à qualidade do código entregue, onde nós deveriamos nos preocupar muito mais do que sobre “qual framework usar”.



O que vamos aprender?

Nesse post, quero dar exemplos de conceitos e métodologias para que possamos melhorar nosso código. Sendo eles:

  • DRY (Don’t Repeat Yourself)
  • Early Return (Anti Hadouken)
  • KISS (Keep it Simple Stupid)



1. Dont Repeat Yourself (DRY)

O tal do DRY é algo bem visto quando o assunto é abstração. A ideia do principio é você não repetir coisas que podem ser abstraidas pra blocos de códigos únicos. Se você está fazendo o mesmo bloco de código duas vezes, ele é refatorável pra uma função com argumentos.

Não entendeu? Se liga aqui então:

class UserRepository 

    public function createUser(array $payload): bool
    
        $query = $this->pdo->prepare('SELECT * FROM users WHERE email = :email');
        $query->bindParam(':email', $payload['email'], PDO::PARAM_STR);
        $query->execute();

        if ($query->count()) 
            throw new Exception('E-mail já cadastrado');
        

        $query = $query->prepare('INSERT INTO users values (null,:name,:email, :password)');

        return $query->execute();
    

    public function getUser(string $email): ?array
    
        $query = $this->pdo->prepare('SELECT * FROM users WHERE email = :email');
        $query->bindParam(':email', $email, PDO::PARAM_STR);
        $query->execute();

        if (!$query->count()) 
            throw new Exception('Usuário inexistente.');
        

        return $query->fetch(PDO::FETCH_ASSOC);
    



Nesse exemplo feito em menos de 5 minutos podemos ver que há uma duplicidade de código quando fazemos a query do createUser e a query do getUser e não há necessidade de duplicar isso caso haja uma função pra lidar com esse comportamento.

Se liga:

class UserRepository 

    public function createUser(array $payload): bool
    
        $query = $this->getUserByEmail($payload['email']);

        if (count($query)) 
            throw new Exception('E-mail já cadastrado');
        

        $query = $query->prepare('INSERT INTO users values (null,:name,:email, :password)');

        return $query->execute();
    

    public function getUser(string $email): ?array
    
        $query = $this->getUserByEmail($email);

        if (! count($query)) 
            throw new Exception('Usuário inexistente.');
        

        return $query->fetch(PDO::FETCH_ASSOC);
    

    public function getUserByEmail(string $email): array
    
        $query = $this->pdo->prepare('SELECT * FROM users WHERE email = :email');
        $query->bindParam(':email', $email, PDO::PARAM_STR);
        $query->execute();

        return $query->fetch(PDO::FETCH_ASSOC);
    



Isolamos uma abstração em uma única função e usamos ela em 2 lugares e o código ainda ficou um pouco mais legível (desde que você dê um nome bacana pra sua função abstraida). Bacana né? Se a galera juninha prestasse atenção nesse tipo de coisa desde o dia zero já teriamos carros voadores :p



2. Early Return Statement

Beleza, agora vamos falar de complexidade de código: tá ligado aquele código que tem um monte de if/else um dentro do outro parecendo um hadouken? Então, isso ai é um PORRE pra gente que vai dar manutenção no futuro e muitas vezes perdemos uns minutos refatorando o negócio. Então, se ensinarmos a rapaziada como não criar esse tipo de código vai ser a maior vitória pros devs que mexem com legado (eu incluso).

Você não sabe o que é um código hadouken? É isso aqui ó:


class AuthRepository
{
    public function adminAuthenticate(array $credentials): bool
    
        if ($user = User::where('email', $credentials['email'])) 
            $password = Hash::verify($user->password, $credentials['password']);
            if($password) 
                if ($user->isAdmin) 
                    Auth::login($user);
                    return true;
                else 
                    throw new UnauthorizedException('vc n é um admin seu merda');
                
             else 
                throw new UnauthorizedException('senha errada seu otário');
            
         else 
            throw new UnauthorizedException('ce nem existe no meu banco wtf');
        
    
}

Acho que nesse exemplo deu pra entender o conceito de hadouken, né? Encadeamos tantos ifs e elses que não fez o menor sentido e só aumentou a complexidade do código. Agora, se entendermos a lógica do Early Return a coisa fica um pouco mais bonita.

O que é: fazer com que o else seja sempre a condição principal e dar o retorno da função o quanto antes. Ou seja: negar a função e retornar em caso de erro. Não entendeu? Vamos pra prática então:


class AuthRepository

    public function adminAuthenticate(array $credentials): bool
    
        $user = User::where('email', $credentials['email'])
        if (!$user) 
            throw new UnauthorizedException('ce nem existe no meu banco wtf');
        

        $password = Hash::verify($user->password, $credentials['password']);
        if (!$password) 
            throw new UnauthorizedException('senha errada seu otário');
        

        if (!$user->isAdmin) 
            throw new UnauthorizedException('vc n é um admin seu merda');
        

        Auth::login($user);
        return true;
    

Negamos todas as condicionais pra fazer com que elas retornassem o quanto antes e garantimos uma melhor legibilidade pro código. O Early Return vem sendo cada vez mais citados por devs e empresas como algo obrigatório pra criar um código bacana e saber isso com certeza vai te deixar a frente de uma galera.

Mas Daniel, não devo usar o else? Bom, isso fica inteiramente pra você. Eu não gosto, mas tem vezes que não dá pra fugir. Fica ai a reflexão :p



3. Keep it Simple Stupid (KISS)

Cara, é bem legal implementar lógicas ao seu software e tudo mais porém chega numa hora que a própria linguagem já tem aquele método ali que você fez pronto, e com toda certeza mais otimizado. Então, pra quê?! As vezes manter as coisas simples são mais vantajosas a longo prazo e isso visto de um lado mais dev da vida onde temos gambiarras pra todo lado, é um puta ponto positivo.

Vamos um exemplo de um bloco de código zoado e uma versão desse mesmo bloco porém simples:

// Jeito zoado
function getOAuthProvider(string $providerId) 
    switch($providerId) 
        case 0:
            return 'twitch';
        case 1:
            return 'discord';
        case 2:
            return 'twitter';
        case 3: 
            return 'google';
        case 4: 
            return 'facebook';
    


// Jeito simples
function getOAuthProvider(string $providerId) 
    $providers = ['twitch', 'discord', 'twitter', 'google', 'facebook'];
    return $providers[$providerId];


Adicionar um switch case num bloco de código que era só retornar um array não parece engenharia demais? Sempre que você ver algo extremamente complexo, ou ficando grande, tente refatorar pra ficar o mais simples possível.

Gostou desse post? Clica no coraçãozinho e me siga nas redes sociais!


Source link

Como sobrescrever arquivos no Magento 2 através de preferences



Contextualizando



Magento 2 e a injeção de dependência

Para entender melhor a injeção de dependência é importante o conhecimento do 5º princípio do SOLID, a Inversão de Dependência (Dependency Inversion Principle).

É chamada de dependência cada instância de objeto dentro de uma determinada classe, porque a classe fica dependente da instância do objeto para ser executada. Para a injeção desta instância, é recomendado, que seja realizado através do DIP (Inversão de dependência).

A Injeção de dependência é um padrão de projeto (design pattern) que permite uma classe mantenha um baixo nível de acoplamento entre diferentes módulos do sistema, ou seja, permite que uma classe não seja responsável por criar os objetos dos quais depende.



Object Manager

O Object Manager é uma classe de serviço do Magento que instancia objetos no início do processo de bootstrap, gerando e injetando as classes declaradas no arquivo di.xml como dependências nos construtores das classes instanciadas.

Como o Object Manager fornece seu serviço indiretamente, a classe não deve depender do próprio Object Manager. As únicas exceções são factories personalizadas com lógica complexa e integrações de testes que necessitam das configurações de ambiente.

O Magento utiliza sua ferramenta de compilação de código para coletar todas as informações das dependências das classes e as armazena em arquivos. Durante o processo de criação das classes, o Object Manager utiliza essas informações de criação para criar objetos concretos na aplicação.

Classes de serviço que não existem no código base, como proxies, factories e interceptors que são declarados no código ou nas configurações, são gerados com a ajuda do compilador.



O que são as preferências?

As preferências (preferences) são utilizadas para indicar a implementação padrão das interfaces através do Object Manager, caso a interface injetada no construtor de uma classe não tenha sido mapeada com um preference, ao instanciar a classe será exibido um erro. Para a que o Object Manager faça o mapeamento da interface para a classe, deve-se utilizar o nó <preference> no arquivo di.xml, indicando no atributo for qual a interface e no atributo type qual a classe que deverá ser sobrescrita e implementar os métodos determinados pela interface.

A preference não precisa ser utilizada apenas com interfaces, é possível sobrescrever uma classe de outro módulo, definindo a nova classe globalmente. Para que o Object Manager faça o mapeamento da classe que deve ser sobrescrita, deve-se utilizar o nó <preference> no arquivo di.xml, indicando no atributo for qual a classe que será sobrescrita e no atributo type qual a classe que deverá ser sobrescrever, e nesta sobrepor o método com a mesma assinatura (desde que ele seja do publico ou protegido).



Código para sobrescrever arquivos



di.xml

O Object Manager usa a implementação através da abstração mapeando quando a assinatura do construtor de uma classe solicita um objeto por sua interface. O Object Manager utiliza esse mapeamento para determinar qual é a implementação padrão para a classe de um escopo específico. Estes tipo de funcionalidade deve ser implementada dentro do arquivo di.xml, seguindo a estruturas de pastas VendorModuleetcareadi.xml.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <!-- Override a custom Interface -->
    <preference for="VendorModuleApiDataEntityNameInterface" type="VendorModuleModelEntityName" />

    <!-- Override a Magento Class -->
    <preference for="VendorModuleDirectoryClassToReplace" type="VendorModuleDirectoryClassReplaced" />
</config>



Interface

O código a seguir se refere a interface de uma entidade que deverá receber uma sobrescrição.

<?php

namespace VendorModuleApiData;

interface EntityNameInterface

    public const ATTR_NAME = 'attribute_name';

    public function getMethod(): type;

    public function setMethod(): self;



Model da Interface

O código a seguir se refere a implementação dos métodos de uma interface.

<?php

namespace VendorModuleModel;

use VendorModuleApiDataEntityNameInterface;
use VendorModuleModelResourceModelResourceModelName;

class EntityName implements EntityNameInterface

    public function getMethod(): type
    
        return $this->getData(self::ATTR_NAME);
    

    public function setMethod(string $attrName): self
    
        return $this->setData(self::ATTR_NAME, $attrName);
    



Classe a substituir

O código a seguir se refere a sobrescrição do método de uma classe, podendo ser uma classe de qualquer tipo (Block, Controller, Data Provider, Model, Ui Component, Service, etc).

<?php

namespace VendorModuleDirectory;

class ClassToReplace

    public function methodName(): type
    
        // Old code here
    



Classe substituída

O código a seguir se refere a extensão do(s) método(s) de uma classe.

<?php

namespace VendorModuleDirectory;

use VendorModuleDirectoryClassToReplace;

class ClassReplaced extends ClassToReplace

    public function methodName(): type
    
        // New code here
    



Finalizando

Valores entre chaves (test) devem ser alterados na implementação do código.



Habilitando as alterações

Comando para gerar a configuração das injeções de dependência e todas as classes ausentes que precisam ser geradas (proxys, interceptors, etc).

php bin/magento setup:di:compile



Diretórios e Arquivos

Segue a a lista de diretórios e arquivos que devem ser criados.

- app/
  - code/
    - Vendor/
        - Module/
          - Api/
            - Data/
              - EntityNameInterface.php
          - etc/
            - di.xml
            - module.xml
          - Directory/
            - ClassReplaced.php
          - Model/
            - EntityName.php
          - registration.php
          - composer.json

Source link

Tipos de deploy e como isso impacta a vida de uma aplicação

Na squad onde estava alocada, por ser a minha primeira aplicação em produção, resolvi acompanhar e aprender mais sobre esse universo chamado devops, infra, enfim… toda a parte que não está envolvida com o código em si, mas com a estrutura de como isso vai rodar para o usuário.

Nesse meio tempo de trabalho e estudos, conheci o CharlesCD que trabalha com o conceito de deploy em círculos, bom… aqui começa a minha jornada de aprendizado sobre deploy, começa que existem tipos de deploy e eu sequer sabia disso, a seguir um compilado de artigo que encontrei sobre o tema.



Primeiramente, o que é um tipo deploy ou estratégia de deploy?

Em algumas literaturas e empresas, chamamos de tipo de deploy ou estratégia de deploy a forma na qual a aplicação será colocada a disposição do usuário final.

Uma estratégia de deploy é uma forma de alterar ou atualização uma aplicação. O objetivo é fazer a mudança sem afetar a aplicação de forma que o usuário mal note as mudanças

Fonte: OpenShift – RedHat, tradução livre



Alguns tipos de deploys utilizados



Canary

O deploy do tipo Canary visa reduzir o risco de disponibilizar uma atualização de uma única vez para todos os usuários, dessa forma, a atualização é disponibiliza para apenas um grupo seleto de usuários antes de ir para o público geral.

Em Canary, o ambiente antigo segue ativo simultaneamente ao novo ambiente. Por isso, pode-se liberar uma parcela dos usuários para acessar o novo ambiente e ver como ele se comporta com usuários reais. Assim é possível identificar se vão existir problemas no dia a dia.

Fonte: Locaweb

Entretanto, essa estratégia não propõe nenhuma estratégia de escolha de usuários para a expansão. Por esse motivo, torna-se mais difícil gerenciar as versões existentes do sistema, o que contribui para que não haja tanto versionamento.



Blue-Green

O tipo blue-green trabalha com o conceito de espelhamento, ou seja, a instância da versão antiga e a instância da versão mais recente rodam em paralelo em produção e o SRE utiliza um load balancer para ir direcionando o tráfego da versão antiga para a versão mais recente.

O principal benefício desta técnica é que o downtime é zero, trazendo mais segurança para a transição. Apesar disso, o custo para o blue-green deployment é bastante elevado, já que demanda o dobro de infraestrutura para ser executado.



Círculos

A ideia consiste que se crie círculos de implementação, e disponibilize para cada circulo a versão de software que melhor convém para o usuário e para a regra de negócio.

Círculos são grupos de usuários criados a partir de características específicas dentro de um mesmo ambiente. Dessa forma, o desenvolvedor pode segmentar os usuários de acordo com as regras que mais fizerem sentido para testar aquela release.

Fonte: CharlesCD – ZupInnovation

Por exemplo, é possível criar um círculo de engenheiros da região Norte do Brasil, outro de engenheiros do sudeste e um terceiro contendo todos os engenheiros brasileiros. Baseado nessa segmentação de clientes, pode-se elaborar diversas lógicas de deploy.



Conclusão de uma desenvolvedora

Claramente que não há a melhor estratégia aqui, tudo vai depender da necessidade da empresa/instituição que vai implementar a aplicação e nível de conhecimento do SRE, por exemplo, para escolher qual será utilizada.

Na minha concepção, tendo a vivência de atuar na área comercial e de negócios e agora atuando como desenvolvedora, faz muito sentido utilizar o deploy em círculo para testar hipóteses desde de alterações na UX para o cliente (será que ele prefere um botão aqui ou ali? Isso aqui está mais legível para ele ou não? Esse pop-up é mais inclusivo para a terceira idade ou não?) até implementação de novas regras de negócio (precisamos aumentar a conversão de clientes nessa área do e-commerce, será que se expormos a oferta dessa forma funcionará? temos esse bug na rotina, mas será que é bug mesmo? Nosso público-alvo são os estudantes do sudeste, será que eles são os maiores usuários da nossa ferramenta?).

Por experiência minha, eu sofria demais com as demandas que clientes me passavam de mudanças que eles gostariam, mas nunca acontecia ou então demorava meses para “subir”, com a ideia de deploy em círculos esse cenário muda drasticamente.

E você, o que acha desses conceitos? Algum faz mais sentido para você, assim como o deploy em círculos faz mais sentido para mim?

Compartilha aqui comigo!


Source link

Testes de Software: quais os tipos e por que implementar?

Testes de software focam na investigação ou validação de funcionalidades que comprovam a qualidade do software ou produto que está sendo testado, para os envolvidos no projeto. Aprenda mais sobre este processo essencial para garantia a qualidade de um software 👇
Quais são os tipos de testes de software?

Geralmente existem dois tipos de testes:

Funcionais:

  • Unit Testing
  • Integration Testing
  • System Testing
  • Sanity Testing
  • Smoke Testing
  • Interface Testing
  • Regression Testing
  • Beta/Acceptance Testing

Performance:

  • Load Testing
  • Stress Testing
  • Volume Testing
  • Security Testing
  • Compatibility Testing
  • Install Testing
  • Recovery Testing
  • Reliability Testing
  • Usability Testing
  • Compliance Testing
  • Localization Testing

Como definir quais testes devem ser implementados?

Para definir os testes de um sistema, é importante se perguntar quais são as funcionalidades que o sistema tem, e o que ele precisa para funcionar. Depois de se fazer estas perguntas, é muito mais fácil identificar quais pontos os testes cabem. Inclusive se você é iniciante no mundo de testes e qualidade de software, pode ser uma maneira mais rápida de encontrar o teste que precisa, antes de se familiarizar mais profundamente com os nomes e categorias de cada um.

A Implementação de testes varia por projeto e pelas tecnologias sendo usadas. Sistemas muito grandes geralmente precisam de testes de performance, pois tem um volume de usuários muito alto. Os demais podem se beneficiar muito de testes de regressão, testando o sistema por completo. Mas os mais comuns são os testes funcionais, pois são mais assertivos, e requerem um acompanhamento eficiente com a documentação, e tarefas bem descritas. Ajudando na organização do projeto e na detecção de erros antes de chegar ao cliente.

É importante documentar os testes. Descrevendo qual o resultado esperado, o que está sendo testado, e caso necessário alguma instrução mais específica para seu time. Manter um bom controle de quais testes existem, e de detalhes de cada um previne a divergência de coordenação entre os desenvolvedores do projeto. Um time organizado pode chegar aos cenários de teste sendo estudados juntos, anotando também os requisitos funcionais, de database, especificações técnicas, entre outros.

Comunicação é crucial para a criação de testes que trazem valor para o projeto. Faça reuniões com seus colegas, identifique os pontos mais fracos do sistema e use os testes para fortalecer esses pontos.

Lembre-se que testes também podem melhorar a qualidade do código no seu projeto. Algumas ferramentas como PHP-cs-fixer, PHP Mess Detector, eslint, etc. Ajudaram a manter uma qualidade de código dentro do projeto com todos os desenvolvedores.
Qual o impacto de testes contínuos em software para empresas?

Fazer testes contínuos é o único jeito de garantir a qualidade de software. Então são essenciais, se adaptando aos requerimentos do projeto. O maior impacto, além de manter a qualidade, é garantir que o sistema continue funcionando como esperado e ajudando os desenvolvedores a encontrar erros antes de liberar o acesso para os clientes.

Mais importante que prevenir erros de sistema ou uma experiência de usuário ruim, são os impactos financeiros e legais. Um sistema sem testes, é mais vulnerável a ter vulnerabilidades de segurança, usar pacotes desatualizados, ou ter Bugs que podem ser usados de maneira maliciosa por terceiros. Horrível não!? Então não se esqueça de implementar testes no seu software/sistema, e caso você não saiba por onde começar entre em contato conosco!


Aprenda mais nos nossos canais digitais!
Site: https://fireworkweb.com.br
Youtube:https://bit.ly/2GwqNU1
Insta: @fireworkweb
Face: @fireworkweb
Linkedin: Firework Web & Mobile


Source link