API simples utilizando workerman(assincrono) usando TDD, DDD e boas praticas para escalonamento horizontal.

Overview

Motivos para usar workerman

Além de mais rápido que o swoole, não necessita de libs externas, porém o ponto negativo é não possuir corrotinas, sendo necessária fazer uma chamada para outra thread(no repositório tem um exemplo usando o envio de emails) para fazer um serviço de forma assincrona.

Endpoints disponíveis

/register (post)

  • necessário user_name, email, password e confirm_password.
  • caso o usuário seja registrado corretamente, uma mensagem com status 201 deve retornar.
  • o usuário criado vem com padrão inativo e recebe um activation_hash para ativação.

/activate?activation_code=xxxxxxxxxxx (get)

  • o activation_hash de um usuário.

/login (post)

  • necessário email e password de um usuário.
  • o retorno é um jwt token valido pelo tempo determinado no .env.

/users/logout (post)

  • apaga a sessão atual do usuário.

/users/delete (delete)

  • deleta o usuário (desde que seja o usuário da sessao ativa no momento e o token esteja correto).

/users/update/user_name, /users/update/email, /users/update/password

  • são auto explicativos, fazem update dos dados do usuário, cada um com seu input específico.

/admin/update/user_name, /admin/update/email, /admin/update/activate, /admin/update/access_level

  • praticamente os mesmos endpoints dos usuários, porém pode fazer update de dados de outros usuários.
  • pode ativar outros usuários.
  • pode alterar o nivel de acesso de outros usuários(desde que abaixo do próprio nivel de acesso).

Método de instalação

requisitos necessários

  • PHP 7.4
  • composer
  • redis
  • mariadb/mysql
  • Configurar o .env

configurações importantes do .env

SERVER_PROCESS_COUNT= numero de processos(geralmente o dobro de nucleos do processador)

MAIL_PROCESS_COUNT= numero de processos para o servidor de email, pode ser somente 1, caso haja muita carga pode dividir a quantidade de processos com o server_process_count

Para instalar o sistema rodar o comando composer install.

Para adicionar as tabelas ao banco de dados rodar o comando vendor/bin/phinx migrate.

Para executar os testes é só rodar o comando vendor/bin/phpunit na pasta raiz.

Para verificar todas as mensagens da API traduzidas deixar o APP_DEBUG=false no .env

Como iniciar o projeto

php start.php start

o código é atualizado automaticamente pelo reloader, logo mesmo ficando armazenado na memória você não precisa parar o processo e iniciar novamente a cada mudança no código.

para parar o processo você pode apertar as teclas crtl+c no terminal ou enviar o comando php start.php stop em outro terminal.

Resumo do escalonamento horizontal

Ao usar um sistema assincrono com o PHP temos uma quantidade de requisições que chega mais próxima a linguagens compiladas como o Go/rust. Porém em frameworks fullStack esse aumento de velocidade é grandemente reduzido e se torna inviável.

exemplos: Ao utilizar um microframework temos a opção de fazer o acesso a session estar presente no redis. podendo a longo prazo separar os servidores, redis e sql completamente.

Um serviço que funciona em uma thread a parte é o de envio de emails que está aberto via websocket e também pode ser desacoplado sem grandes problemas do serviço principal.

Resumo do DDD utilizado no projeto

Administradores e usuários são parecidos, porém NÃO SÃO IGUAIS

  • Logo, não existem motivos para estarem na mesma entidade. Isso cria uma maior complexidade inicial, porém a longo prazo permite que os métodos não precisem de verificações constantes ou que as regras de negócio se tornem mais complexas devido a essas verificações.

Você não deve utilizar uma entidade baseada em uma ORM

  • Ao utilizar entidades baseadas em ORM, além da perda de desempenho já comprovada (https://www.youtube.com/watch?v=3TJfR1Ta4GU).
  • Você não conseguirá desacoplar esse código no futuro, caso queira trocar para um banco de dados diferente(seja ele sql ou noSql) sua entidade deveria permitir esse tipo de troca. já que a responsabilidade de salvar/modificar/deletar qualquer dado é responsabilidade do repositório.
  • Você não poderá desacoplar suas regras de negócio do framework que utiliza, deixando todo o projeto preso em uma "facilidade" inicial.

Suas entidades não devem ser pobres/anemicas!!!

  • As entidades não podem estar vazias, as regras de negócio devem estar dentro delas, não de outras entidades.
  • As entidades não podem simplesmente ser getters/setters para regras contidas em outros lugares.

Alguns códigos irão se repetir porém isso será necessário

  • Um usuário e um administrador tem as mesmas opções para fazer update em certos dados, porém, a entidade usuário faz um tipo de update em seu escopo, e a entidade do administrador a faz em um escopo diferente. Nesse exemplo(e em outros) o DDD ultrapassa o SOLID para manter o sistema com uma forma mais dinâmica e organizada.
  • A longo prazo isso irá economizar validações desnecessárias, tais como verificar se um usuário é um administrador antes de fazer alguma modificação, ou se o nível de acesso está correto.

O desenvolvedor não pode ser obcecado por tipos primitivos

  • Um email não é uma string, uma senha ou um nome de usuário também não são simples strings. esses objetos de valor deveriam estar criados com erros(exceptions) e validações próprias para cada tipo de dado.

Entenda a raiz de diretórios utilizando DDD

  • Todo projeto a nivel de domínio está dentro da pasta src
  • Regras complexas devem estar em pastas separadas(no caso users), pense nela como tendo toda complexidade em volta dos usuários

Pasta src/Users/Application

  • O arquivo presente aqui (userServices.php) diz respeito a diferentes tipos de ações que o usuário pode tomar dentro do sistema ex:
    • Login
    • Register
    • Activate
    • Delete
  • Todas elas são ações que a entidade pode tomar(entidade usuário) que sejam como "ações do usuário". porém não alteram os valores da própria entidade, esses métodos devem ficar dentro da mesma.

Pasta src/Users/Domain

  • Os arquivos na pasta de domínio são divididos entre:
  • Uma pasta para as exceptions presentes tanto nas entidades quanto nos value objects
  • Uma pasta para os value objects(evitando o uso constante de tipos primitivos)
  • As regras utilizadas como no banco de dados devem estar presentes aqui na forma de uma interface, que deve ser implementada para TODOS os tipos de bancos de dados que venham a ser utilizados no sistema, não fazendo necessária a alteração na entidade de usuários(por exemplo)
  • O arquivo handler(e outros que venham a aparecer) contem os métodos que a entidade usuário pode usar para "se representar" dentro do sistema.

Pasta src/Users/Infrastructure

  • Aqui ficam todas as partes implementadas pelas interfaces dentro do sistema.
  • No caso, para o repository(alterações no banco de dados) usamos o Illuminate(por isso RepositoryIlluminate)
  • O JWT tem sua interface levemente mais complexa, por isso tem uma pasta separada para configurações.
  • O PHPMailer(também implementado no domínio) utilizado no sistema, também poderia ser substituido por qualquer outro mail sender que pudesse ser implementado na mesma interface.

Pasta src/Users/Presentation

  • Os templates de email(de emails para os usuários) ficam aqui dentro também, já que pertencem exclusivamente a esse domínio.
  • O authentication e administration são uma forma de interface do sistema(no caso acesso via http como uma API), e sua unica função é direcionar os dados para o domínio que, pode ser acessado via CLI também.

Por se tratar de um assunto extremamente complexo e longo, os domínios aplicados aqui podem servir para consulta, mas não como guia para a sua aplicação, a única intenção desse repositório é despertar sua curiosidade sobre a importância do DDD

Entrando no TDD

  • Seu sistema deve poder ser utilizado via CLI ou qualquer outro tipo de saida/entrada de dados e ser completamente independente da interface utilizada. (a interface web é apenas um dos possíveis métodos de utilização).

Entenda como funciona o TDD

Ao desenvolver utilizando TDD algumas regras sempre devem ser levadas em consideração:

  • O sistema precisa ser completamente testável(seja via postman com uma API para testes de endpoint) sejam menores partes do código e a validação dos value objects.
  • Você deve desenvolver a nova implementação criando primeiro os testes para a mesma, assim pensará sempre nas regras envolvidas na nova implementação e estará menos suscetível a falhas.

Entenda o object calisthenics:

  • Only One Level Of Indentation Per Method (Apenas um nível de identação por método)
    • Você deve manter seu código simples, se ele precisa de mais um nível de identação, provavelmente você poderia por uma parte desse código dentro de um método diferente(dificilmente métodos com mais de um nivel de identação(no máximo 2) seguem as regras do SOLID).
  • Don’t Use The ELSE Keyword (não use else)
  • Wrap All Primitives And Strings (envolva todos os tipos primitivos e strings)
    • Essa regra já é utilizada dentro do DDD, você deve encapsular valores dentro de objetos de valor dentro do seu domínio, um exemplo disso são cpf, email, senha, todos são valores específicos que enriquecem seus domínios e não devem ser tratados como tipos primitívos.
  • First Class Collections (coleções de primeira classe)
    • Objetos de coleção(iteráveis) devem ter uma classe iterável a parte, e não devem ser tratadas como arrays/objetos avulsos.
  • One Dot Per Line (um ponto por linha)
    • Essa regra diz que você não deve encadear métodos, a não ser que esteja usando o padrão Method Chaining Pattern.
  • Don’t Abbreviate (não abrevie)
    • Não abrevie nomes de métodos/classes ou objetos, novamente: se o nome de um método(por exemplo) é muito grande, provavelmente ele não está seguindo o SOLID e está fazendo mais de uma função dentro da classe.
  • Keep All Entities Small (mantenha todas as entidades pequenas)
    • Outra regra que segue os princípios do DDD, se uma classe tem muitos métodos, provavelmente ela poderia ser dividida em outras classes menores e mais coesas com seu próprios contextos.
  • No Classes With More Than Two Instance Variables (sem classes com mais de duas variáveis de instância)
    • Mais uma regra que segue os princípios do SOLID e do DDD, se suas classes tem muitas variáveis de instância, provavelmente ela está fazendo mais do que deveria. aumentando a complexidade do código e dificultando a manutenção.
  • No Getters/Setters/Properties (sem getters/setters)
    • Você não deve alterar as propriedades da sua classe simplesmente setando outros valores a ela sem motivo, logo as propriedades de set devem ser pensadas para continuarem dando coerencia e funcionalidade a classe, sem ferir os princípios do SOLID.
    • Basicamente: você não deve poder alterar os valores de sua classe sem motivo, apesar de "fácil" esse é um dos principais motivos das entidades estarem anêmicas a longo prazo.

Este projeto é um exemplo e estará em constante crescimento. a qualquer dúvida/sugestão/melhoria, sinta-se livre para abrir uma issue/PR

You might also like...
The fastest pure PHP database framework with a powerful static code generator, supports horizontal scale up, designed for PHP7
The fastest pure PHP database framework with a powerful static code generator, supports horizontal scale up, designed for PHP7

Maghead 4.0.x IS CURRENTLY UNDER HEAVY DEVELOPMENT, API IS NOT STABLE Maghead is an open-source Object-Relational Mapping (ORM) designed for PHP7. Mag

Plugin simples de máquinas para pocketmine-mp
Plugin simples de máquinas para pocketmine-mp

Plugin simples de máquina para aqueles que estão aprendendo PocketMine-MP Principais funções do plugin ✔️ Simples de aprender ✔️ Pocketmine 3 ✔️ SQLit

Um simples pacote para facilitar a integração com a proxypay

PROXYPAY SDK UM SIMPLES PACOTE EM PHP PARA GERAR PAGAMENTOS UTILIZANDO A PROXYPAY INSTALAÇÃO Se deseja instalar este pacote execute o comando abaixo:

📁 As Sessões são uma forma simples de armazenar dados para usuários, ficando mais confiável em manipular dados importantes

📁 As Sessões são uma forma simples de armazenar dados para usuários, ficando mais confiável em manipular dados importantes

Simples endpoints para recurso
Simples endpoints para recurso "Pessoa"

Simples endpoints para recurso "Pessoa" Endpoints para "Pessoa" utilizando segregação de interfaces e desacoplamento com o framwork Laravel v8.75. POS

Planner semanal simples e intuitivo para melhor organização das tarefas semanais.

Planner semanal simples e intuitivo para melhor organização das tarefas semanais. Simple and intuitive weekly planner for better organization of your tasks.

CRUD utilizando laravel, sendo um site para criação de eventos e festivais.

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Creamos un inicio de sesión desde Facebook para nuestra aplicación web utilizando la librería de Socialite

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Real-world Project to learning about Unit Testing/TDD with Laravel for everybody

KivaNote - a Laravel TDD Sample Project Let me introduce you to KivaNote, a simple real-world application using Laravel to show you how the TDD & Unit

Game of life developed in PHP with TDD approach

What is Game of Life: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life Project structure: Engine is in App\Services\LifeEngine.php Tests are in T

Essa é uma aplicação RESTFul API e também uma aplicação MVC usando Blade construída com Laravel 8.

MVC - API - CRUD - REVENDA DE CARROS Essa é uma aplicação RESTFul API e também uma aplicação MVC usando Blade construída com Laravel 8. Neste projeto

Proyecto Start-Basic sobre Login y crud de usuarios, mediante Api Rest, usando la plantilla AdminLte 3.1 y manejo de roles y permisos con spatie y autenticacion JWT
Proyecto Start-Basic sobre Login y crud de usuarios, mediante Api Rest, usando la plantilla AdminLte 3.1 y manejo de roles y permisos con spatie y autenticacion JWT

Proyecto Start-Basic sobre Login y crud de usuarios, mediante Api Rest, usando la plantilla AdminLte 3.1 y manejo de roles y permisos con spatie y autenticacion JWT

Aplicación de chat usando HTML, CSS, PHP, JS and MySQL.

SYSTEMSGT Codigo fuente de aplicación CHAT - SYSTEMSGT Lenguajes HTML CSS PHP JS MySQL Pre-requisitos 📋 Para poder utilizar esta aplicación necesitas

Definindo e usando variáveis ​​de ambiente dentro do PHP

Variáveis ambientes PHP Definindo e usando variáveis de ambiente dentro do PHP A primeira coisa a fazer é criar o arquivo composer.json na pasta raiz

Aprenda a construir um CRUD simples, fácil e rápido

CRUD PHP MYSQL Aprenda a construir um CRUD simples, fácil e rápido CRUD pastas: /config/ = pasta onde será armazenado toda a lógica de configuração da

 CRUD SIMPLES E INTUITIVO FEITO EM PHP+REST
CRUD SIMPLES E INTUITIVO FEITO EM PHP+REST

crudrest 🚧 CRUD SIMPLES E INTUITIVO FEITO EM PHP+REST 🚀 Em construção... 🚧 Descrição do Projeto Exemplo de um CRUD feito em PHP utilizando do REST

Versão 2 do System Storage, com melhorias e com a principal mudança, usando Laravel, um Framework do PHP.
Versão 2 do System Storage, com melhorias e com a principal mudança, usando Laravel, um Framework do PHP.

Versão 2 do System Storage, com melhorias e com a principal mudança, usando Laravel, um Framework do PHP.

Repositorio del tutorial CRUD Laravel 9 y Vue 3 usando Vite

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Owner
Andre
An old Tibia server programmer who fell in love with software development
Andre
A sample RESTful API in Laravel with PHPunit test.

Laravel PHP Framework URL | URI | Action |

Fasil 9 Jul 11, 2020
To run time/IO related unit tests (e.g., sleep function calls, database queries, API calls, etc) faster using Swoole.

To run time/IO related unit tests (e.g., sleep function calls, database queries, API calls, etc) faster using Swoole.

Demin Yin 11 Sep 9, 2022
A video course for laravel artisan to learn creating API using testing

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Bitfumes 16 Oct 6, 2022
Very simple mock HTTP Server for testing Restful API, running via Docker.

httpdock Very simple mock HTTP Server for testing Restful API, running via Docker. Start Server Starting this server via command: docker run -ti -d -p

Vo Duy Tuan 4 Dec 24, 2021
Projeto utilizado para prática de TDD usando PHP com a equipe de desenvolvimento.

?? TDD com PHP ?? Detalhamento do projeto Projeto desenvolvido durante um DOJO que organizei com os colegas de equipe da GAM Distribuidora. A proposta

Felipe Fernandes 3 Sep 11, 2021
¡BACKEND OVER APP! API REST IMPLEMENTANDO CONCEPTOS DE ARQUITECTURA HEXAGONAL, DDD, TDD Y SOLID. HECHO EN LARAVEL & PHP

¡BACKEND OVER APP! API REST IMPLEMENTANDO CONCEPTOS DE ARQUITECTURA HEXAGONAL, DDD, TDD Y SOLID. HECHO EN LARAVEL & PHP

Cristian Camilo Vasquez 17 Dec 27, 2022
💫 Vega is a CLI mode HTTP web framework written in PHP support Swoole, WorkerMan / Vega 是一个用 PHP 编写的 CLI 模式 HTTP 网络框架,支持 Swoole、WorkerMan

Mix Vega 中文 | English Vega is a CLI mode HTTP web framework written in PHP support Swoole, WorkerMan Vega 是一个用 PHP 编写的 CLI 模式 HTTP 网络框架,支持 Swoole、Work

Mix PHP 46 Apr 28, 2022
Um modelo de loja virtual utilizando HTML, CSS, JS, Bootstrap e PHP, utilizando ferramentas de edição de texto (VS Code), Edição de imagens (Adobe photoshop) e de vetorização (Adobe Illustrator).

Loja virtual fictícia Um modelo de loja virtual utilizando HTML, CSS, JS, Bootstrap e PHP, utilizando ferramentas de edição de texto (VS Code), Edição

Emily Leme 2 Sep 8, 2021
Uma solucão simples para integrar sua aplicação Laravel a API PIX do Banco Central do Brasil

Uma solução simples para integrar a sua aplicação Laravel com a API PIX do Banco Central do Brasil Instalação Publicando os assets Publicando o arquiv

Mateus Junges 74 Dec 19, 2022