<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Luiz Schons]]></title><description><![CDATA[Luiz Schons]]></description><link>https://luizschons.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1751542390893/109fe88b-8199-4a11-865d-468b7a6f07a3.png</url><title>Luiz Schons</title><link>https://luizschons.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 12:02:10 GMT</lastBuildDate><atom:link href="https://luizschons.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Microservices são débitos técnicos?]]></title><description><![CDATA[Desenvolver software nunca esteve tão complexo e ao mesmo tempo tão simples. A complexidade está na quantidade de tecnologias, frameworks, linguagens e padrões que temos disponíveis para desenvolver software. A simplicidade está na facilidade de aces...]]></description><link>https://luizschons.com/microservices-sao-debitos-tecnicos</link><guid isPermaLink="true">https://luizschons.com/microservices-sao-debitos-tecnicos</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Fri, 06 Dec 2024 00:57:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733446569479/2802990b-09f4-4598-8607-aa3ce0a9a8b0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Desenvolver software nunca esteve tão complexo e ao mesmo tempo tão simples. A complexidade está na quantidade de tecnologias, frameworks, linguagens e padrões que temos disponíveis para desenvolver software. A simplicidade está na facilidade de acesso a essas tecnologias e na facilidade de desenvolver software.</p>
<p>Com a facilidade de desenvolver software, muitas vezes, não nos preocupamos com a qualidade do software que estamos desenvolvendo. A qualidade do software é um fator muito importante para o sucesso de um projeto. É ela que garante que o software seja fácil de manter, fácil de evoluir e fácil de corrigir.</p>
<p>Muitas vezes focamos os nossos estudos e nosso tempo para o aprendizado de novas tecnologias e frameworks, mas esquecemos de estudar e aprender sobre arquitetura de software e isso é um grande erro. A arquitetura de software é o que garante a a manutenibilidade, a evolução e a correção do software.</p>
<p>Decidir qual arquitetura utilizar em um projeto é uma tarefa muito importante e que deve ser feita com muito cuidado. Uma escolha não muito acertada pode trazer muitos problemas para o projeto e para a equipe de desenvolvimento, e grande problema é que esses efeitos colaterais podem não ser percebidos no início do projeto, mas sim ao longo do tempo.</p>
<p>Alguns dos principais problemas que podem ser causados por uma arquitetura de software não muito acertada são grande acoplamento entre os módulos do software, baixa coesão entre os módulos, dificuldade em escalar, problemas de performance, dificuldade em testar entre outros.</p>
<p>Imagine o seguinte cenário: o tempo foi passando, você e sua equipe foram notando que o software está ficando cada vez mais complexo, parece que a cada nova funcionalidade que é implementada, o software fica mais instável, mais difícil de manter, mais difícil de evoluir e mais difícil de corrigir. E agora? O que fazer?</p>
<p>Eis que surge do nada a palavra mágica: <strong>Microservices</strong>. Microservices é a solução para todos os problemas de arquitetura de software. Microservices é a solução para todos os problemas de acoplamento, coesão, escalabilidade, performance e testes.</p>
<p>Eu concordo que micro-serviços são uma excelente solução para muitos problemas de arquitetura de software, mas não são a solução para todos os problemas.</p>
<p>Você já pensou em refatorar seu código antes de tentar uma solução mais complexa como micro-serviços?</p>
<p>Pensou em estudar e aprender sobre arquitetura de software antes de tentar uma solução baseada puramente em tendências do momento ou em soluções que funcionaram para outras empresas?</p>
<p>A <code>Netflix</code>, <code>Amazon</code>, <code>Google</code> tem soluções ótimas para os problemas de arquitetura de software dela, mas será que essas soluções funcionam para o seu projeto?</p>
<p>Será que está na hora de você e sua equipe pararem de tentar soluções mágicas e começarem a estudar e aprender sobre qualidade e arquitetura de software?</p>
<p>Você não acha que usar micro-serviços para resolver problemas de arquitetura de software é um débito técnico?</p>
<p>Não vou dar resposta para essas perguntas, mas acho que você deveria pensar sobre isso.</p>
<p>Não acho que você nunca deve usar micro-serviços, mas acho que você deve pensar muito antes de usar.</p>
<p>Existem sim casos onde essa arquitetura faz todo sentido, mas existe uma grande quantidade de casos onde essa arquitetura só esta sendo usada para resolver débitos técnicos deixados por uma decisão errada tomada no início do projeto.</p>
<p>Não abomine microservices, mas não os use como solução para todos os problemas.</p>
<p>Estude, aprenda, e tome decisões baseadas em fatos e não em tendências.</p>
<p>Manter um software de qualidade é um trabalho árduo e que exige muito estudo e dedicação, mas é um trabalho que vale a pena.</p>
<p>E você, o que acha? Microservices são débitos técnicos?</p>
]]></content:encoded></item><item><title><![CDATA[Acoplamento estático e dinâmico em Microservices]]></title><description><![CDATA[Aplicações monolíticas são aquelas que possuem um único código fonte, um único executável e um único processo. Muitas vezes, essas aplicações são construídas em uma única linguagem de programação e são implantadas em um único servidor.
Quando começam...]]></description><link>https://luizschons.com/acoplamento-estatico-e-dinamico-em-microservices</link><guid isPermaLink="true">https://luizschons.com/acoplamento-estatico-e-dinamico-em-microservices</guid><category><![CDATA[Microservices]]></category><category><![CDATA[Developer]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[distributed system]]></category><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Fri, 11 Oct 2024 20:02:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728676878819/bf2aea65-50ce-4c88-b1fe-681ef7ff8c11.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Aplicações monolíticas são aquelas que possuem um único código fonte, um único executável e um único processo. Muitas vezes, essas aplicações são construídas em uma única linguagem de programação e são implantadas em um único servidor.</p>
<p>Quando começamos a desenvolver, monolitos são a nossa primeira experiência na maioria das vezes. Eles são fáceis de desenvolver, testar e implantar. No entanto, à medida que a aplicação cresce, o monolito começa a se tornar um problema.</p>
<p>A escalabilidade de um software é a uma das coisas mais importantes a serem consideradas hoje. Saber lidar de forma dinâmica com o crescimento de usuários e dados é essencial para o sucesso de um software.</p>
<p>Sistemas monolíticos são difíceis de escalar. Eles são construídos como um único bloco de código, o que significa que, para escalar a aplicação, você precisa replicar todo o código ou escalar verticalmente o servidor. Isso pode ser caro e ineficiente.</p>
<blockquote>
<p><strong>Escalabilidade vertical</strong> é a capacidade de aumentar a capacidade de um servidor, adicionando mais recursos, como CPU, RAM e disco. Isso é feito para melhorar o desempenho de um servidor.</p>
<p><strong>Escalabilidade horizontal</strong> é a capacidade de aumentar a capacidade de um sistema, adicionando mais instâncias do sistema. Isso é feito para melhorar a disponibilidade e a confiabilidade de um sistema.</p>
</blockquote>
<p>Microservices é uma arquitetura de software que resolve esse problema (mas cria outros). Em vez de construir uma única aplicação monolítica, você constrói várias aplicações pequenas e independentes, chamadas de micro-serviços. Cada microservice é responsável por uma parte específica da aplicação e se comunica com outras aplicações.</p>
<p>Embora, em teoria, os micro-serviços pareçam oferecer uma solução ideal para problemas de escalabilidade, eles apresentam desafios próprios na prática. Um dos principais desafios é o gerenciamento do acoplamento entre eles.</p>
<p>No mundo ideal, microservices devem ser independentes e desacoplados. Isso significa que uma aplicação deve ser capaz de funcionar sem depender de outra. No entanto, principalmente em migrações de sistemas monolíticos para microservices, é comum que dependam uns dos outros e chamamos isso de acoplamento.</p>
<p>Existem dois tipos de acoplamento em microservices: acoplamento estático e acoplamento dinâmico, e é sobre eles que vamos falar hoje.</p>
<hr />
<h2 id="heading-exemplo-de-arquitetura-de-microservices"><strong>Exemplo de arquitetura de microservices</strong></h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728676759014/bb9c5c1b-8245-4a17-9691-a5a166d7539f.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-componentes"><strong>Componentes:</strong></h3>
<ol>
<li><p><strong>API Gateway</strong>:</p>
<ul>
<li><p>Atua como o ponto de entrada para todas as solicitações externas ao sistema.</p>
</li>
<li><p>Recebe requisições HTTP dos clientes e as encaminha para os serviços internos apropriados (como ProductCatalogService, OrderService, e UserService).</p>
</li>
<li><p>Manter o controle de acesso, autenticação, roteamento de requisições, e agregação de respostas.</p>
</li>
</ul>
</li>
<li><p><strong>ProductCatalogService</strong>:</p>
<ul>
<li><p>Gerencia informações sobre produtos à venda, como descrições, preços e disponibilidade.</p>
</li>
<li><p>Pode consultar um serviço de descoberta como o Consul para localizar outros serviços necessários.</p>
</li>
</ul>
</li>
<li><p><strong>OrderService</strong>:</p>
<ul>
<li><p>Gera pedidos de compra.</p>
</li>
<li><p>Interage com outros serviços para obter informações do produto (via ProductCatalogService) e detalhes do usuário (via UserService).</p>
</li>
<li><p>Manipula pedidos no banco de dados MongoDB e publica eventos de pedidos para o RabbitMQ, permitindo comunicação assíncrona com outros serviços.</p>
</li>
</ul>
</li>
<li><p><strong>UserService</strong>:</p>
<ul>
<li><p>Administra informações de usuários, como perfis, preferências e histórico de compras.</p>
</li>
<li><p>Permite que outros serviços venham a consultar informações do usuário de forma segura.</p>
</li>
</ul>
</li>
<li><p><strong>PaymentService</strong>:</p>
<ul>
<li><p>Responsável pelo processamento de transações de pagamento.</p>
</li>
<li><p>Interage com o banco de dados MongoDB para armazenar informações sobre transações financeiras.</p>
</li>
<li><p>Publica eventos de transação no RabbitMQ para permitir que outros serviços (como o NotificationService) sejam notificados sobre ocorrências financeiras.</p>
</li>
</ul>
</li>
<li><p><strong>RabbitMQ</strong>:</p>
<ul>
<li><p>Permite a mensageria assíncrona entre serviços, facilitando a comunicação desacoplada.</p>
</li>
<li><p>Transmite eventos de pedidos e transações para partes interessadas.</p>
</li>
</ul>
</li>
<li><p><strong>NotificationService</strong>:</p>
<ul>
<li>Envia notificações para os usuários com base em eventos recebidos através do RabbitMQ, como atualizações de status de pedidos ou mensagens de confirmação de pagamento.</li>
</ul>
</li>
<li><p><strong>MongoDB</strong>:</p>
<ul>
<li><p>Armazena dados críticos para o sistema, como informações de pedidos, usuários e transações.</p>
</li>
<li><p>Um banco de dados NoSQL, como o MongoDB, é bem adequado para sistemas que exigem flexibilidade de esquema e manuseio eficiente de dados não estruturados.</p>
</li>
</ul>
</li>
<li><p><strong>Consul</strong>:</p>
<ul>
<li><p>Serviço utilizado para descoberta, configuração e gerenciamento de serviços.</p>
</li>
<li><p>Permite que microservices descubram dinamicamente a localização de outros serviços, facilitando uma arquitetura altamente flexível e resiliente.</p>
</li>
</ul>
</li>
<li><p><strong>Nginx</strong>:</p>
<ul>
<li>Pode representar um servidor web reverso ou balançador de carga que distribui requisições entre várias instâncias do API Gateway, melhorando a capacidade e a disponibilidade.</li>
</ul>
</li>
</ol>
<hr />
<h2 id="heading-acoplamento-estatico"><strong>Acoplamento estático</strong></h2>
<p>Os componentes em verde representam acoplamento estático.</p>
<p>O acoplamento estático ocorre quando um microservice depende de outro microservice em tempo de compilação ou configuração inicial do sistema.</p>
<p>Na maioria das vezes, acoplamentos estáticos são fáceis de identificar. Os mais comuns são:</p>
<ol>
<li><p><strong>Dependência de código</strong>: um microservice chama diretamente outro através de uma chamada de função ou API.</p>
</li>
<li><p><strong>Dependência de banco de dados</strong>: um microservice acessa diretamente o banco de dados de outra aplicação.</p>
</li>
<li><p><strong>Dependência de configuração</strong>: um micro-serviço depende de configurações específicas de outro microservice.</p>
</li>
</ol>
<p>Outra forma de acoplamento estático é quando um microservice depende de um contrato específico de outro. Por exemplo, um microservice espera que outro serviço retorne um objeto JSON específico. Se o contrato mudar, o microservice que depende dele pode quebrar, então é preciso atualizar a aplicação que depende do contrato.</p>
<hr />
<h2 id="heading-acoplamento-dinamico"><strong>Acoplamento dinâmico</strong></h2>
<p>Os componentes em azul representam acoplamento dinâmico.</p>
<p>O acoplamento dinâmico ocorre quando um microservice depende de outro em tempo de execução.</p>
<p>Na maioria das vezes, acoplamentos dinâmicos são mais difíceis de identificar. Os mais comuns são:</p>
<ol>
<li><p><strong>Dependência de mensageria</strong>: um microservice envia uma mensagem para um barramento de mensagens e espera que outro serviço responda.</p>
</li>
<li><p><strong>Dependência de descoberta de serviço</strong>: um microservice consulta um serviço de descoberta para localizar outro.</p>
</li>
</ol>
<p>O interessante do acoplamento dinâmico é que ele permite que microservices sejam mais independentes e desacoplados. Se um microservice não estiver disponível, o que depende dele pode continuar funcionando, mesmo que de forma limitada.</p>
<hr />
<h2 id="heading-conclusao"><strong>Conclusão</strong></h2>
<p>Na hora de projetar microservices, é importante considerar o acoplamento entre eles. Acoplamento estático e acoplamento dinâmico são duas formas de acoplamento que podem ser usadas em sistemas distribuídos.</p>
<p>Não existe uma regra rígida sobre qual tipo de acoplamento é melhor. Na verdade, a maioria dos sistemas de microservices terá uma combinação de acoplamento estático e acoplamento dinâmico.</p>
<p>Você como arquiteto precisa decidir qual tipo de acoplamento faz mais sentido para o problema que você está resolvendo no momento. Em alguns casos, acoplamento estático pode ser mais simples e eficiente. Em outros casos, acoplamento dinâmico pode ser mais flexível e resiliente.</p>
<p>O importante é entender as diferenças entre acoplamento estático e acoplamento dinâmico e saber quando usar cada um deles.</p>
<hr />
<h2 id="heading-referencias"><strong>Referências</strong></h2>
<ul>
<li><a target="_blank" href="https://www.amazon.com.br/Arquitetura-Software-Trade-off-Arquiteturas-Distribu%C3%ADdas/dp/8550819840">Arquitetura de Software: as Partes Difíceis: Análises Modernas de Trade-off Para Arquiteturas Distribuídas</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Event-driven Architecture (EDA)]]></title><description><![CDATA[Arquitetura de Software é um grande Trade-off no mundo da tecnologia, muitas vezes a escolha de uma arquitetura errada pode levar a um grande retrabalho e atraso no projeto. Sabendo disso, sempre é bom conhecer as arquiteturas mais utilizadas e enten...]]></description><link>https://luizschons.com/event-driven-architecture-eda-2775822e52cf</link><guid isPermaLink="true">https://luizschons.com/event-driven-architecture-eda-2775822e52cf</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Sat, 03 Aug 2024 19:22:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586221446/b934fd77-1b05-4aac-a06f-9b84e14f3fc4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Arquitetura de Software é um grande Trade-off no mundo da tecnologia, muitas vezes a escolha de uma arquitetura errada pode levar a um grande retrabalho e atraso no projeto. Sabendo disso, sempre é bom conhecer as arquiteturas mais utilizadas e entender o que cada uma tem de melhor para dessa forma escolher a que vai causar menos problemas no futuro, e esse é o grande segredo de uma boa arquitetura, prever o futuro.</p>
<p>Neste artigo vamos falar sobre a Arquitetura Orientada a Eventos (Event-driven Architecture — EDA), uma arquitetura que tem como principal característica a comunicação entre os serviços através de eventos.</p>
<h3 id="heading-o-que-e-eda">O que é EDA?</h3>
<p>A Arquitetura Orientada a Eventos (Event-driven Architecture — EDA) é um estilo de arquitetura de software que promove a produção, detecção, consumo e reação a eventos. Um evento pode ser qualquer coisa que seja notável ou significativa para o sistema, como alterações de estado, uma ação do usuário, um erro, uma mensagem recebida, entre outros.</p>
<p>Os eventos são mensagens assíncronas que são geradas por um produtor e consumidas por um ou mais consumidores. O produtor não precisa saber quem são os consumidores, e os consumidores não precisam saber quem são os produtores. Isso permite que os sistemas sejam desacoplados, escaláveis e flexíveis.</p>
<p>No nosso exemplo de hoje vamos simular o seguinte cenário:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586215514/fc4eed68-02f7-4b90-9ff9-8eb40d9c2fd0.png" alt /></p>
<h3 id="heading-exemplo-pratico">Exemplo prático</h3>
<p>O sistema é composto por 4 serviços:</p>
<h4 id="heading-ecommerce-frontend"><strong>ecommerce-frontend:</strong></h4>
<ul>
<li>Frontend de um e-commerce que permite ao usuário adicionar produtos ao carrinho.</li>
<li>Usa React para criar a interface do usuário.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586217058/735c553b-591e-4b72-92dc-a186c441bae4.png" alt /></p>
<h4 id="heading-stock-service"><strong>stock-service:</strong></h4>
<ul>
<li>Serviço que gerencia o estoque dos produtos.</li>
<li>Usa PHP para comuncição com o RabbitMQ.</li>
</ul>
<p>&lt;?php<br />require __DIR__ . '/vendor/autoload.php';  </p>
<p>use PhpAmqpLib\Connection\AMQPStreamConnection;<br />use PhpAmqpLib\Message\AMQPMessage;  </p>
<p>header("Access-Control-Allow-Origin: *");<br />header("Access-Control-Allow-Headers: *");<br />header("Access-Control-Allow-Methods: *");  </p>
<p>if ($_SERVER['REQUEST_METHOD'] === 'POST') {  </p>
<p>    $order = json_decode(file_get_contents('php://input'), true);  </p>
<p>    $success = true;   </p>
<p>    $connection = new AMQPStreamConnection('rabbitmq', 5672, 'guest', 'guest');<br />    $channel = $connection-&gt;channel();  </p>
<p>    $channel-&gt;queue_declare('stock_updated', false, false, false, false);  </p>
<p>    $msg = new AMQPMessage(json_encode([<br />        'order_id' =&gt; 1,<br />        'status' =&gt; 'updated'<br />    ]));  </p>
<p>    $channel-&gt;basic_publish($msg, '', 'stock_updated');  </p>
<p>    $channel-&gt;close();<br />    $connection-&gt;close();  </p>
<p>    header('Content-Type: application/json');<br />    echo json_encode(['success' =&gt; $success]);<br />}</p>
<blockquote>
<p>O código acima é somente um exemplo didático, não é um código funcional e nem seguro.</p>
</blockquote>
<h4 id="heading-payment-service">payment-service:</h4>
<ul>
<li>Serviço que os pagamentos dos pedidos.</li>
<li>Usa Python para comunicação com o RabbitMQ.</li>
</ul>
<p>import pika<br />import json<br />import time  </p>
<p>max_retries = 5<br />retry_delay = 5  </p>
<p>def establish_connection(max_retries, retry_delay):<br />    for i in range(max_retries):<br />        try:<br />            connection = pika.BlockingConnection(pika.ConnectionParameters('rabbitmq'))<br />            return connection<br />        except pika.exceptions.AMQPConnectionError:<br />            if i &lt; max_retries - 1:<br />                time.sleep(retry_delay)<br />            else:<br />                raise  </p>
<p>def process_payment(order):<br />    print(f"Processando pagamento para o pedido: {order['order_id']}")<br />    return True  </p>
<p>def callback(ch, method, properties, body):<br />    order = json.loads(body)<br />    success = process_payment(order)  </p>
<p>    payment_event = json.dumps({<br />        'order_id': order['order_id'],<br />        'status': 'processed' if success else 'failed'<br />    })  </p>
<p>    try:<br />        channel.basic_publish(exchange='', routing_key='payment_processed', body=payment_event)<br />        print(f"Pagamento {'sucesso' if success else 'falha'} para o pedido: {order['order_id']}")<br />    except pika.exceptions.AMQPError as e:<br />        print(f"Erro ao publicar mensagem: {str(e)}")  </p>
<p>def setup_channel(connection):<br />    channel = connection.channel()<br />    channel.queue_declare(queue='stock_updated')<br />    channel.queue_declare(queue='payment_processed')<br />    channel.basic_consume(queue='stock_updated', on_message_callback=callback, auto_ack=True)<br />    return channel  </p>
<p>if __name__ == "__main__":<br />    connection = establish_connection(max_retries, retry_delay)<br />    channel = setup_channel(connection)<br />    print('Aguardando eventos de atualização de estoque...')<br />    try:<br />        channel.start_consuming()<br />    except KeyboardInterrupt:<br />        print('Interrompido pelo usuário')<br />    finally:<br />        if connection:<br />            connection.close()</p>
<blockquote>
<p>O código acima é somente um exemplo didático, não é um código funcional e nem seguro.</p>
</blockquote>
<h4 id="heading-rabbitmq">rabbitmq:</h4>
<ul>
<li>Servidor de mensageria que permite a comunicação entre os serviços.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586219241/f89afcd2-0cc9-4390-837c-6fafa44d770a.png" alt /></p>
<p>O link para o repositório com o código completo está disponível <a target="_blank" href="https://github.com/sschonss/event-driver">aqui</a>.</p>
<h3 id="heading-fluxo-de-comunicacao">Fluxo de comunicação</h3>
<ol>
<li>O usuário acessa o frontend do e-commerce e adiciona um produto ao carrinho.</li>
<li>O frontend envia uma requisição para o serviço de estoque para realizar o checkout do produto.</li>
<li>O serviço de estoque verifica se o produto está disponível e envia um evento de atualização de estoque para o RabbitMQ.</li>
<li>O serviço de pagamento consome o evento de atualização de estoque e processa o pagamento do pedido.</li>
<li>O serviço de pagamento envia um evento de pagamento processado para o RabbitMQ.</li>
</ol>
<h3 id="heading-trade-offs">Trade-offs</h3>
<p>Esse fluxo de comunicação é um exemplo simples de como a Arquitetura Orientada a Eventos (EDA) pode ser utilizada para desacoplar os serviços e permitir que eles se comuniquem de forma assíncrona e sem a necessidade de saber quem são os produtores ou consumidores dos eventos, tanto que foi por isso que resolvi usar diferentes linguagens de programação para cada serviço.</p>
<p>Tudo isso permite que os serviços sejam escaláveis, flexíveis e resilientes, pois cada serviço é responsável por uma única tarefa e pode ser facilmente substituído ou atualizado sem afetar os outros serviços.</p>
<p>Mas nem tudo são flores, a Arquitetura Orientada a Eventos (EDA) também tem suas desvantagens, como a complexidade de implementação, a necessidade de garantir a ordem dos eventos, a dificuldade de depurar problemas e a necessidade de garantir a entrega dos eventos.</p>
<p>Por isso, é importante avaliar se a Arquitetura Orientada a Eventos (EDA) é a melhor escolha para o seu projeto e se você está disposto a lidar com as suas complexidades.</p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>Essa foi somente uma introdução à Arquitetura Orientada a Eventos (EDA), uma arquitetura que tem como principal característica o desacoplamento dos serviços através de eventos assíncronos.</p>
<p>Não existe uma arquitetura perfeita, cada uma tem suas vantagens e desvantagens, e cabe a você escolher a que melhor se adequa ao seu projeto e às suas necessidades.</p>
<p>Espero que esse artigo tenha te ajudado a entender um pouco mais sobre a Arquitetura Orientada a Eventos (EDA) e como ela pode ser utilizada para criar sistemas escaláveis, flexíveis e resilientes.</p>
<p>O link para o repositório com o código completo está disponível <a target="_blank" href="https://github.com/sschonss/event-driver">aqui</a>.</p>
<p>Se você tiver alguma dúvida ou sugestão, deixe nos comentários abaixo.</p>
]]></content:encoded></item><item><title><![CDATA[Algoritimo Dijkstra]]></title><description><![CDATA[Edsger W. Dijkstra foi um cientista da computação holandês que fez contribuições significativas para a ciência da computação. Ele é mais conhecido por desenvolver o algoritmo de Dijkstra, que resolve o problema do caminho menos custoso em um grafo di...]]></description><link>https://luizschons.com/algoritimo-dijkstra-0d73b29ab3e5</link><guid isPermaLink="true">https://luizschons.com/algoritimo-dijkstra-0d73b29ab3e5</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Mon, 29 Jul 2024 23:49:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586210788/4deec74c-6576-4022-b8f7-2c0cc9ef1e92.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Edsger W. Dijkstra foi um cientista da computação holandês que fez contribuições significativas para a ciência da computação. Ele é mais conhecido por desenvolver o algoritmo de Dijkstra, que resolve o problema do caminho menos custoso em um grafo direcionado ou não direcionado com arestas não negativas.</p>
<p>Mas antes de falar sobre o algoritmo de Dijkstra, vamos falar sobre o algoritmo de <code>Pesquisa em Largura</code>.</p>
<h3 id="heading-pesquisa-em-largura">Pesquisa em Largura</h3>
<p>Trabalhar com grafos é uma tarefa comum em computação. Um dos problemas mais comuns é encontrar o menor caminho entre dois vértices em um grafo. O algoritmo de <code>Pesquisa em Largura</code> mostra como encontrar o menor caminho em um grafo, como por exemplo, o caminho mais curto entre duas cidades em um mapa que tem cidades como vértices e estradas como arestas.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586193682/83906eab-e030-4187-ada0-a6fb599c5a92.png" alt /></p>
<p>Imagine que precisamos sair de A para chegar em G. O algoritmo de <code>Pesquisa em Largura</code> nos ajuda a encontrar o menor caminho. O algoritmo começa visitando o vértice de origem (A) e então explora todos os vértices vizinhos. Depois disso, explora os vértices que estão a dois passos de distância e assim por diante.</p>
<p>No nosso caso o menor caminho é <code>A -&gt; B -&gt; E -&gt; G</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586196340/21335b16-46e7-41d0-83ce-9616afcbc13c.png" alt /></p>
<p>Nesse caso, temos somente 3 <code>passos</code> para chegar em G.</p>
<h3 id="heading-algoritmo-de-dijkstra">Algoritmo de Dijkstra</h3>
<p>Mas e se as arestas tiverem pesos? O algoritmo de <code>Pesquisa em Largura</code> não funciona mais. O algoritmo de Dijkstra é um algoritmo que encontra o caminho mais <code>barato</code> em um grafo direcionado ou não direcionado, com arestas que possuem pesos. O algoritmo de Dijkstra mantém duas listas: uma lista de vértices visitados e uma lista de vértices não visitados. Ele seleciona o vértice não visitado mais próximo do vértice de origem, marca-o como visitado e atualiza os pesos dos vértices vizinhos.</p>
<p>Vamos adaptar o exemplo anterior para incluir pesos nas arestas.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586198835/e98599cc-e8c7-42f7-90fd-db6bc0585fe0.png" alt /></p>
<p>Agora temos pesos em cada aresta, e nosso desafio é encontrar o caminho em que a soma dos pesos seja menor.</p>
<p>Vamos aplicar o algoritmo de Dijkstra para encontrar o menor caminho de A para G.</p>
<ol>
<li>Começamos em A e visitamos todos os vértices vizinhos.</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586200913/c8fb16dd-c96c-46f1-9631-8cc994f9e8c8.png" alt /></p>
<p>2. O próximo vértice mais próximo de A é C. Então visitamos C e atualizamos as distâncias dos vértices vizinhos.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586202833/605433b6-8e50-4537-a177-c1622ea93383.png" alt /></p>
<p>3. O próximo vértice mais próximo de A é D. Então visitamos D e atualizamos as distâncias dos vértices vizinhos.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586204480/9501673c-afae-4064-8bbc-07d604383605.png" alt /></p>
<p>4. O próximo vértice mais próximo de A é E. Então visitamos E e atualizamos as distâncias dos vértices vizinhos.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586206680/0b1d5fc0-12a1-45e9-9da0-d87c7527efa4.png" alt /></p>
<p>O menor caminho de A para G é <code>A -&gt; C -&gt; D -&gt; E -&gt; G</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586209257/72e9e802-5834-479a-856d-0a9cb6649c96.png" alt /></p>
<h3 id="heading-aplicando-isso-com-php">Aplicando isso com PHP</h3>
<p>Vamos criar um exemplo prático em PHP para aplicar o algoritmo de Dijkstra.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
$graph = [
    <span class="hljs-string">'A'</span> =&gt; [<span class="hljs-string">'B'</span> =&gt; <span class="hljs-number">10</span>, <span class="hljs-string">'C'</span> =&gt; <span class="hljs-number">5</span>],
    <span class="hljs-string">'B'</span> =&gt; [<span class="hljs-string">'E'</span> =&gt; <span class="hljs-number">8</span>, <span class="hljs-string">'D'</span> =&gt; <span class="hljs-number">3</span>],
    <span class="hljs-string">'C'</span> =&gt; [<span class="hljs-string">'D'</span> =&gt; <span class="hljs-number">2</span>, <span class="hljs-string">'F'</span> =&gt; <span class="hljs-number">4</span>],
    <span class="hljs-string">'D'</span> =&gt; [<span class="hljs-string">'E'</span> =&gt; <span class="hljs-number">2</span>, <span class="hljs-string">'F'</span> =&gt; <span class="hljs-number">6</span>],
    <span class="hljs-string">'E'</span> =&gt; [<span class="hljs-string">'G'</span> =&gt; <span class="hljs-number">2</span>],
    <span class="hljs-string">'F'</span> =&gt; [<span class="hljs-string">'E'</span> =&gt; <span class="hljs-number">1</span>],
    <span class="hljs-string">'G'</span> =&gt; []
];

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dijkstra</span>(<span class="hljs-params">$graph, $source, $target</span>)
</span>{
    $dist = [];
    $prev = [];
    $queue = <span class="hljs-keyword">new</span> <span class="hljs-built_in">SplPriorityQueue</span>();

    <span class="hljs-keyword">foreach</span> ($graph <span class="hljs-keyword">as</span> $vertex =&gt; $adj) {
        $dist[$vertex] = INF;
        $prev[$vertex] = <span class="hljs-literal">null</span>;
        $queue-&gt;insert($vertex, $vertex === $source ? <span class="hljs-number">0</span> : INF);
    }

    $dist[$source] = <span class="hljs-number">0</span>;

    <span class="hljs-keyword">while</span> (!$queue-&gt;isEmpty()) {
        $u = $queue-&gt;extract();

        <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">empty</span>($graph[$u])) {
            <span class="hljs-keyword">foreach</span> ($graph[$u] <span class="hljs-keyword">as</span> $v =&gt; $cost) {
                $alt = $dist[$u] + $cost;
                <span class="hljs-keyword">if</span> ($alt &lt; $dist[$v]) {
                    $dist[$v] = $alt;
                    $prev[$v] = $u;
                    $queue-&gt;insert($v, $alt);
                }
            }
        }
    }

    $path = [];
    $u = $target;
    <span class="hljs-keyword">while</span> (<span class="hljs-keyword">isset</span>($prev[$u])) {
        array_unshift($path, $u);
        $u = $prev[$u];
    }
    array_unshift($path, $source);

    <span class="hljs-keyword">return</span> $path;
}

$path = dijkstra($graph, <span class="hljs-string">'A'</span>, <span class="hljs-string">'G'</span>);
<span class="hljs-keyword">echo</span> implode(<span class="hljs-string">' -&gt; '</span>, $path);
</code></pre>
<p>Segue o passo a passo da execução do algoritmo:</p>
<ul>
<li><p>1. Inicializamos as distâncias e a fila de prioridade.</p>
</li>
<li><p>2. Inicializamos a distância do vértice de origem como 0.</p>
</li>
<li><p>3. Enquanto a fila de prioridade não estiver vazia, extraímos o vértice com a menor distância.</p>
</li>
<li><p>4. Para cada vértice vizinho, calculamos a distância alternativa e atualizamos a distância se for menor.</p>
</li>
<li><p>5. Construímos o caminho percorrendo os vértices anteriores. 6. Retornamos o caminho.</p>
<h2 id="heading-conclusao">Conclusão</h2>
<p>  Com o aumento do uso de AI, Machine Learning e Big Data, o conceito de grafos se tornou cada vez mais importante. O algoritmo de Dijkstra é um dos algoritmos mais importantes para encontrar o menor caminho em um grafo. Espero que você tenha entendido como o algoritmo de Dijkstra funciona e como ele pode ser aplicado em um cenário do mundo real. Se você gostou desse artigo, deixe um comentário e compartilhe com seus amigos. Até a próxima!</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Arquitetura Hexagonal e Mensageria com PHP]]></title><description><![CDATA[Arquiteura Hexagonal (Ports and Adapters)
Link para o projeto: https://github.com/sschonss/microservices-hexagonal
Existem diversas formas de se organizar um projeto, e uma das formas mais conhecidas é a arquitetura hexagonal. A arquitetura hexagonal...]]></description><link>https://luizschons.com/arquitetura-hexagonal-e-mensageria-com-php-aa10a2148257</link><guid isPermaLink="true">https://luizschons.com/arquitetura-hexagonal-e-mensageria-com-php-aa10a2148257</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Thu, 04 Jul 2024 01:11:37 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-arquiteura-hexagonal-ports-and-adapters">Arquiteura Hexagonal (Ports and Adapters)</h3>
<p>Link para o projeto: <a target="_blank" href="https://github.com/sschonss/microservices-hexagonal">https://github.com/sschonss/microservices-hexagonal</a></p>
<p>Existem diversas formas de se organizar um projeto, e uma das formas mais conhecidas é a arquitetura hexagonal. A arquitetura hexagonal é uma forma de organizar o projeto de forma que ele seja independente de frameworks, banco de dados, UI, etc. O objetivo é que o projeto seja independente de qualquer tecnologia, e que possa ser facilmente substituído.</p>
<p>Neste projeto, a arquitetura hexagonal foi implementada utilizando a linguagem de programação PHP e o framework Laravel. A ideia é que o projeto seja independente do Laravel, e dessa maneira, usamos somente o Laravel para criar rotas e controladores, e o restante do projeto é independente do Laravel.</p>
<h3 id="heading-estrutura-do-projeto">Estrutura do projeto</h3>
<p>O projeto foi dividido em 3 camadas principais:</p>
<ul>
<li><p><strong>Laravel</strong>: Toda a infraestrutura do projeto, como rotas, controladores, etc.</p>
</li>
<li><p><strong>Adapters</strong>: Camada responsável por conter os adaptadores de entrada e saída do projeto.</p>
</li>
<li><p><strong>Core</strong>: Camada responsável por conter as regras de negócio do projeto. Dentro do core, iremos trabalhar com Domain Driven Design (DDD).</p>
</li>
</ul>
<h3 id="heading-adapters">Adapters</h3>
<p>Os adapters são responsáveis por adaptar as entradas e saídas do projeto. Mas o que isso significa?</p>
<p>Imagine que você tem um projeto que precisa se comunicar com um banco de dados. Se você não utilizar uma camada de adapter, você terá que utilizar o banco de dados diretamente no seu projeto. Isso significa que você terá que utilizar as classes do banco de dados diretamente no seu projeto, e isso fará com que seu projeto fique dependente do banco de dados.</p>
<p>Então um ORM (Object Relational Mapping) é um exemplo de adapter. O ORM é uma camada que adapta a comunicação com o banco de dados, e dessa maneira, o projeto não fica dependente do banco de dados.</p>
<p>Dentro do nosso projeto, temos os seguintes adapters:</p>
<ul>
<li><p><strong>EmailAdapter</strong>: Adapter responsável por enviar e-mails.</p>
</li>
<li><p><strong>RabbitMQAdapter</strong>: Adapter responsável por enviar mensagens para o RabbitMQ.</p>
</li>
</ul>
<p>Neles contém as classes que adaptam a comunicação com o serviço de e-mail e com o RabbitMQ.</p>
<p>Tudo isso somente usando PHP sem Laravel, para que o projeto seja independente e possa ser facilmente substituído.</p>
<h3 id="heading-core">Core</h3>
<p>O core é a camada responsável por conter as regras de negócio do projeto. Dentro do core, iremos trabalhar com Domain Driven Design (DDD).</p>
<h3 id="heading-o-que-e-ddd">O que é DDD?</h3>
<p>Domain Driven Design é uma forma de organizar o projeto de forma que ele seja separado por domínios. Cada domínio é uma parte do projeto que contém as regras de negócio. Dessa maneira, o projeto fica organizado e fácil de ser mantido.</p>
<p>Dentro do core, temos os seguintes domínios:</p>
<ul>
<li><p>Email: Domínio responsável por emails em geral da aplicação.</p>
</li>
<li><p>Connections: Domínio responsável por conexões com serviços externos, como RabbitMQ, Redis, etc.</p>
</li>
</ul>
<p>Dentro de cada domínio, teremos as camadas responsáveis por conter as regras de negócio para cada feature.</p>
<p>O mais importante é que o core não depende de nada. Ele é independente de qualquer framework, banco de dados, etc. Dessa maneira, podemos facilmente substituir o Laravel por outro framework, ou o MySQL por outro banco de dados.</p>
<p>O Core se comunica com serviços externos através dos adapters. Dessa maneira, o core não fica dependente de nenhum serviço externo, somente do adapter.</p>
<h3 id="heading-projeto">Projeto</h3>
<p>O projeto é um exemplo simples de como a arquitetura hexagonal pode ser implementada. O projeto é um sistema de cadastro de usuários, onde o usuário pode se cadastrar e receber um e-mail de boas-vindas.</p>
<p>O projeto foi dividido em 3 serviços:</p>
<ul>
<li><p>Main App: Serviço principal, onde o usuário se cadastra. Nele está a arquitetura hexagonal.</p>
</li>
<li><p>RabbitMQ: Serviço de mensageria, onde o Main App envia uma mensagem para o RabbitMQ.</p>
</li>
<li><p>Email App: Serviço de e-mail, onde lê as mensagens do RabbitMQ e envia um e-mail para o usuário.</p>
</li>
</ul>
<p>Dessa maneira, o Main App não fica dependente do RabbitMQ e do serviço de e-mail. Ele somente envia uma mensagem para o RabbitMQ, e o RabbitMQ envia a mensagem para o serviço de e-mail.</p>
<h3 id="heading-como-rodar-o-projeto">Como rodar o projeto</h3>
<p>Para rodar o projeto, você precisa ter o Composer, Docker e o Docker Compose instalados na sua máquina.</p>
<p>Após instalar o Docker e o Docker Compose, basta rodar o seguinte comando:</p>
<p><code>cd main-app   composer install   ./vendor/bin/sail up</code></p>
<p>Após rodar o comando, o projeto estará rodando na porta 80.</p>
<p>Já podemos criar um usuário através do endpoint <code>POST /api/user</code>, passando o seguinte JSON:</p>
<p><code>{   "name": "John Doe",   "email": "john@doe.com",   "password": "123456"   }</code></p>
<p>Após criar o usuário, será disparado um evento para o RabbitMQ, mas o serviço de e-mail ainda não está rodando. Para rodar o serviço de e-mail, basta rodar o seguinte comando:</p>
<p><code>cd email-app   docker-compose up --build --force-recreate</code></p>
<p>Após rodar o comando, o serviço de e-mail estará rodando e irá ler as mensagens do RabbitMQ e enviar um e-mail para o usuário.</p>
<h3 id="heading-acessar-o-rabbitmq">Acessar o RabbitMQ</h3>
<p>Para acessar o RabbitMQ, basta acessar o seguinte endereço:</p>
<p><code>http://localhost:15672</code></p>
<p>E fazer login com as seguintes credenciais:</p>
<p><code>Username: guest   Password: guest</code></p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>A arquitetura hexagonal é uma forma de organizar o projeto de forma que ele seja independente de qualquer tecnologia. Neste projeto, a arquitetura hexagonal foi implementada utilizando a linguagem de programação PHP e o framework Laravel. A ideia é que o projeto seja independente do Laravel, e dessa maneira, usamos somente o Laravel para criar rotas e controladores, e o restante do projeto é independente do Laravel.</p>
<p>O projeto é um exemplo simples de como a arquitetura hexagonal pode ser implementada. O projeto é um sistema de cadastro de usuários, onde o usuário pode se cadastrar e receber um e-mail de boas-vindas.</p>
<p>Também foi implementado um serviço de mensageria com RabbitMQ e um serviço de e-mail. Dessa maneira, o Main App não fica dependente do RabbitMQ e do serviço de e-mail. Ele somente envia uma mensagem para o RabbitMQ, e o RabbitMQ envia a mensagem para o serviço de e-mail.</p>
<p>Vimos como a mensageria ajuda a desacoplar os serviços, e como a arquitetura hexagonal ajuda a organizar o projeto de forma que ele seja independente de qualquer tecnologia.</p>
]]></content:encoded></item><item><title><![CDATA[Microservices e Mensageria com PHP, NodeJS, RabbitMQ e Docker]]></title><description><![CDATA[O desenvolvimento de microserviços é uma abordagem arquitetural que estrutura uma aplicação como um conjunto de serviços pequenos e independentes, que são executados em seu próprio processo e se comunicam por meio de protocolos leves, como HTTP, WebS...]]></description><link>https://luizschons.com/microservices-e-mensageria-com-php-nodejs-rabbitmq-e-docker-7266127c8489</link><guid isPermaLink="true">https://luizschons.com/microservices-e-mensageria-com-php-nodejs-rabbitmq-e-docker-7266127c8489</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Sat, 29 Jun 2024 15:05:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586225558/2aac07c7-f37b-4a91-bb14-5e4d7656ea8a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>O desenvolvimento de microserviços é uma abordagem arquitetural que estrutura uma aplicação como um conjunto de serviços pequenos e independentes, que são executados em seu próprio processo e se comunicam por meio de protocolos leves, como HTTP, WebSockets ou AMQP.</p>
<p>Neste artigo, vamos criar uma aplicação de microserviços com PHP, RabbitMQ e Docker. O RabbitMQ é um software de mensageria que implementa o protocolo AMQP (Advanced Message Queuing Protocol), que é um protocolo de mensagens assíncronas.</p>
<h3 id="heading-o-que-e-rabbitmq">O que é RabbitMQ?</h3>
<p>Vamos imaginar o seguinte cenário: você tem um sistema que precisa enviar e-mails para os usuários. Em vez de enviar os e-mails diretamente, você pode enviar uma mensagem para uma fila de mensagens, que será consumida por um serviço que envia os e-mails. Isso é o que o RabbitMQ faz: ele recebe mensagens de produtores e as envia para consumidores.</p>
<p>Dessa forma é possível desacoplar a produção de mensagens do consumo, o que permite escalar cada parte do sistema de forma independente. Além disso, o RabbitMQ garante que as mensagens sejam entregues na ordem correta e que não sejam perdidas.</p>
<h3 id="heading-arquitetura-da-aplicacao">Arquitetura da aplicação</h3>
<p>Nossa aplicação será composta por dois microserviços: um produtor e um consumidor. O produtor será responsável por enviar mensagens para uma fila de mensagens, e o consumidor será responsável por consumir as mensagens e exibi-las no terminal.</p>
<p>Nosso primeiro passo será criar o arquivo <code>docker-compose.yml</code> para definir os serviços da nossa aplicação:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">services:</span>
  <span class="hljs-attr">rabbitmq:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">"rabbitmq:3-management"</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">"rabbitmq"</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"15672:15672"</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"5672:5672"</span>

  <span class="hljs-attr">php-app:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">./php-app</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">rabbitmq</span>

  <span class="hljs-attr">node-app:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">./node-app</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">rabbitmq</span>
</code></pre>
<p>Neste arquivo, definimos três serviços: <code>rabbitmq</code>, <code>php-app</code> e <code>node-app</code>. O serviço <code>rabbitmq</code> é baseado na imagem <code>rabbitmq:3-management</code>, que inclui a interface de gerenciamento do RabbitMQ. Os serviços <code>php-app</code> e <code>node-app</code> são baseados em imagens customizadas que iremos criar.</p>
<h3 id="heading-criando-o-produtor-com-php">Criando o produtor com PHP</h3>
<p>Agora, vamos criar o diretório <code>php-app</code> e o arquivo <code>Dockerfile</code> dentro dele:</p>
<pre><code class="lang-bash">mkdir php-app &amp;&amp; touch php-app/Dockerfile
</code></pre>
<p>No arquivo <code>Dockerfile</code>, vamos definir a imagem base e copiar os arquivos da aplicação:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> php:<span class="hljs-number">7.4</span>-cli

<span class="hljs-keyword">RUN</span><span class="bash"> apt-get update &amp;&amp; apt-get install -y librabbitmq-dev libssl-dev git unzip wget curl</span>

<span class="hljs-keyword">RUN</span><span class="bash"> docker-php-ext-install sockets pdo pdo_mysql</span>
<span class="hljs-keyword">RUN</span><span class="bash"> pecl install amqp &amp;&amp; docker-php-ext-enable amqp</span>

<span class="hljs-keyword">COPY</span><span class="bash"> . /usr/src/myapp</span>
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /usr/src/myapp</span>

<span class="hljs-keyword">RUN</span><span class="bash"> curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/<span class="hljs-built_in">local</span>/bin --filename=composer</span>

<span class="hljs-keyword">RUN</span><span class="bash"> composer clear-cache</span>

<span class="hljs-keyword">RUN</span><span class="bash"> composer install</span>

<span class="hljs-keyword">CMD</span><span class="bash"> [<span class="hljs-string">"php"</span>, <span class="hljs-string">"./publisher.php"</span>]</span>
</code></pre>
<p>Neste arquivo, definimos a imagem base <code>php:7.4-cli</code> e instalamos as dependências necessárias para o RabbitMQ e o Composer. Em seguida, copiamos os arquivos da aplicação para o diretório <code>/usr/src/myapp</code>, instalamos as dependências do Composer e executamos o script <code>publisher.php</code>.</p>
<p>Agora, vamos criar o arquivo <code>publisher.php</code> na raiz do projeto:</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-keyword">require_once</span> <span class="hljs-keyword">__DIR__</span> . <span class="hljs-string">'/vendor/autoload.php'</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">PhpAmqpLib</span>\<span class="hljs-title">Connection</span>\<span class="hljs-title">AMQPStreamConnection</span>;
<span class="hljs-keyword">use</span> <span class="hljs-title">PhpAmqpLib</span>\<span class="hljs-title">Message</span>\<span class="hljs-title">AMQPMessage</span>;

$maxRetries = <span class="hljs-number">5</span>;
$retryDelay = <span class="hljs-number">5</span>;

<span class="hljs-keyword">for</span> ($attempt = <span class="hljs-number">0</span>; $attempt &lt; $maxRetries; $attempt++) {
    <span class="hljs-keyword">try</span> {
        $connection = <span class="hljs-keyword">new</span> AMQPStreamConnection(<span class="hljs-string">'rabbitmq'</span>, <span class="hljs-number">5672</span>, <span class="hljs-string">'guest'</span>, <span class="hljs-string">'guest'</span>);
        $channel = $connection-&gt;channel();
        <span class="hljs-keyword">break</span>;
    } <span class="hljs-keyword">catch</span> (<span class="hljs-built_in">Exception</span> $e) {
        <span class="hljs-keyword">echo</span> <span class="hljs-string">"Failed to connect to RabbitMQ. Retrying in <span class="hljs-subst">$retryDelay</span> seconds...\n"</span>;
        sleep($retryDelay);
    }    
}

<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">isset</span>($connection)) {
    <span class="hljs-keyword">echo</span> <span class="hljs-string">"Not possible to connect to RabbitMQ. Exiting...\n The application will be restarted by Docker\n"</span>;
    <span class="hljs-keyword">exit</span>(<span class="hljs-number">1</span>);
}

$channel-&gt;queue_declare(<span class="hljs-string">'hello'</span>, <span class="hljs-literal">false</span>, <span class="hljs-literal">false</span>, <span class="hljs-literal">false</span>, <span class="hljs-literal">false</span>);

$msg = <span class="hljs-keyword">new</span> AMQPMessage(<span class="hljs-string">'Hello, RabbitMQ! Now is '</span> . date(<span class="hljs-string">'Y-m-d H:i:s'</span>));
$channel-&gt;basic_publish($msg, <span class="hljs-string">''</span>, <span class="hljs-string">'hello'</span>);

<span class="hljs-keyword">echo</span> <span class="hljs-string">" [x] Sent 'Hello, RabbitMQ!'\n"</span>;

$channel-&gt;close();
$connection-&gt;close();
</code></pre>
<p>Neste arquivo, criamos uma conexão com o RabbitMQ, declaramos uma fila chamada `hello` e enviamos uma mensagem para essa fila. Em seguida, fechamos a conexão com o RabbitMQ. Perceba que estamos tentando conectar ao RabbitMQ várias vezes, com um intervalo de 5 segundos entre as tentativas.</p>
<p>Isso é importante para garantir que a aplicação consiga se conectar ao RabbitMQ mesmo que ele não esteja disponível imediatamente. Isso é uma prática comum em aplicações distribuídas, onde a disponibilidade dos serviços pode variar ao longo do tempo, pesquise mais sobre `circuit breaker` e `retry pattern`.</p>
<p>Mas para instalar as dependências do RabbitMQ e do Composer, precisamos criar o arquivo `composer.json` na raiz do projeto:</p>
<pre><code class="lang-json">{ <span class="hljs-attr">"require"</span>: { <span class="hljs-attr">"php-amqplib/php-amqplib"</span>: <span class="hljs-string">"^3.1"</span>, <span class="hljs-attr">"phpseclib/phpseclib"</span>: <span class="hljs-string">"^3.0"</span> } }
</code></pre>
<h2 id="heading-criando-o-consumidor-com-nodejs">Criando o consumidor com Node.js</h2>
<p>Agora, vamos criar o diretório `node-app` e o arquivo `Dockerfile` dentro dele:</p>
<pre><code class="lang-bash">mkdir node-app &amp;&amp; touch node-app/Dockerfile
</code></pre>
<p>No arquivo `Dockerfile`, vamos definir a imagem base e copiar os arquivos da aplicação:</p>
<pre><code class="lang-dockerfile"><span class="hljs-keyword">FROM</span> node:<span class="hljs-number">14</span> 
<span class="hljs-keyword">WORKDIR</span><span class="bash"> /usr/src/app </span>
<span class="hljs-keyword">COPY</span><span class="bash"> package\*.json ./ </span>
<span class="hljs-keyword">RUN</span><span class="bash"> npm install </span>
<span class="hljs-keyword">COPY</span><span class="bash"> . . </span>
<span class="hljs-keyword">CMD</span><span class="bash"> \[<span class="hljs-string">"node"</span>, <span class="hljs-string">"subscriber.js"</span>\]</span>
</code></pre>
<p>Neste arquivo, definimos a imagem base `node:14`, copiamos os arquivos da aplicação para o diretório `/usr/src/app`, instalamos as dependências do Node.js e executamos o script `subscriber.js`.</p>
<p>Agora, vamos criar o arquivo `subscriber.js` na raiz do projeto:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> amqp = <span class="hljs-built_in">require</span>(<span class="hljs-string">'amqplib'</span>);

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">connectWithRetry</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> maxRetries = <span class="hljs-number">5</span>;
    <span class="hljs-keyword">const</span> retryDelay = <span class="hljs-number">5000</span>;

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> attempt = <span class="hljs-number">1</span>; attempt &lt;= maxRetries; attempt++) {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> amqp.connect(<span class="hljs-string">'amqp://rabbitmq'</span>);
            <span class="hljs-keyword">return</span> connection;
        } <span class="hljs-keyword">catch</span> (err) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Not possible to connect to RabbitMQ. Retrying in <span class="hljs-subst">${retryDelay}</span>ms. Attempt <span class="hljs-subst">${attempt}</span> of <span class="hljs-subst">${maxRetries}</span>`</span>);
            <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, retryDelay));
        }
    }

    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Failed to connect to RabbitMQ after <span class="hljs-subst">${maxRetries}</span> attempts`</span>);
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">receiveMessages</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> connection = <span class="hljs-keyword">await</span> connectWithRetry();
        <span class="hljs-keyword">const</span> channel = <span class="hljs-keyword">await</span> connection.createChannel();
        <span class="hljs-keyword">const</span> queue = <span class="hljs-string">'hello'</span>;

        <span class="hljs-keyword">await</span> channel.assertQueue(queue, { <span class="hljs-attr">durable</span>: <span class="hljs-literal">false</span> });

        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">" [*] Waiting for messages in %s."</span>, queue);

        channel.consume(queue, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">msg</span>) </span>{
            <span class="hljs-built_in">console</span>.log(<span class="hljs-string">" [x] Received: %s"</span>, msg.content.toString());
        }, {
            <span class="hljs-attr">noAck</span>: <span class="hljs-literal">true</span>
        });

    } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-built_in">console</span>.error(err.message);
        process.exit(<span class="hljs-number">1</span>);
    }
}

receiveMessages();
</code></pre>
<p>Neste arquivo, criamos uma conexão com o RabbitMQ, declaramos uma fila chamada `hello` e consumimos as mensagens dessa fila.</p>
<p>Em seguida, exibimos as mensagens no terminal. Assim como no produtor, estamos tentando conectar ao RabbitMQ várias vezes, com um intervalo de 5 segundos entre as tentativas. Isso é importante para garantir que o consumidor consiga se conectar ao RabbitMQ mesmo que ele não esteja disponível imediatamente.</p>
<p>E para instalar as dependências do RabbitMQ, precisamos criar o arquivo `package.json` na raiz do projeto:</p>
<pre><code class="lang-json">{ <span class="hljs-attr">"name"</span>: <span class="hljs-string">"node-app"</span>, <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0.0"</span>, <span class="hljs-attr">"description"</span>: <span class="hljs-string">""</span>, <span class="hljs-attr">"main"</span>: <span class="hljs-string">"subscriber.js"</span>, <span class="hljs-attr">"dependencies"</span>: { <span class="hljs-attr">"amqplib"</span>: <span class="hljs-string">"^0.8.0"</span> }, <span class="hljs-attr">"author"</span>: <span class="hljs-string">""</span>, <span class="hljs-attr">"license"</span>: <span class="hljs-string">"ISC"</span> }
</code></pre>
<h2 id="heading-executando-a-aplicacao">Executando a aplicação</h2>
<p>Agora que criamos os serviços do RabbitMQ, do produtor e do consumidor, vamos executar a aplicação com o Docker Compose:</p>
<pre><code class="lang-bash">docker compose up --build
</code></pre>
<p>Isso irá criar os containers dos serviços e executar a aplicação. Você verá as mensagens enviadas pelo produtor sendo exibidas no terminal pelo consumidor.</p>
<p>O RabbitMQ também estará disponível na porta 15672, onde você pode acessar a interface de gerenciamento e visualizar as filas e as mensagens.</p>
<p>Com isso, criamos uma aplicação de microserviços com PHP, RabbitMQ e Docker. Essa abordagem arquitetural permite escalar cada parte do sistema de forma independente e garante a entrega das mensagens na ordem correta.</p>
<p>Espero que este artigo tenha sido útil e que você possa aplicar esses conceitos em seus projetos. Se tiver alguma dúvida ou sugestão, deixe nos comentários.</p>
<p>Qualquer dúvida, estou à disposição.</p>
<p>Link do Repositório: <a target="_blank" href="https://github.com/sschonss/ms-rabbitmq">Microservices e Mensageria com PHP, RabbitMQ e Docker</a></p>
]]></content:encoded></item><item><title><![CDATA[PHP — Streams Filters]]></title><description><![CDATA[Se você já trabalhou com arquivos em PHP, provavelmente já usou funções como fopen, fwrite, fread, fclose, entre outras. Streams são uma abstração muito poderosa e flexível para trabalhar com arquivos e outros recursos de I/O.
Streams são uma forma d...]]></description><link>https://luizschons.com/php-streams-filters-d2c681cbec6d</link><guid isPermaLink="true">https://luizschons.com/php-streams-filters-d2c681cbec6d</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Tue, 04 Jun 2024 01:11:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586299110/eaf9b102-5a29-4217-add6-f8104bd38836.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Se você já trabalhou com arquivos em PHP, provavelmente já usou funções como <code>fopen</code>, <code>fwrite</code>, <code>fread</code>, <code>fclose</code>, entre outras. Streams são uma abstração muito poderosa e flexível para trabalhar com arquivos e outros recursos de I/O.</p>
<p>Streams são uma forma de abstrair a manipulação de dados de entrada e saída, permitindo que você leia e escreva dados de e para diferentes fontes, como arquivos, strings, conexões de rede, etc.</p>
<p>Por exemplo, você pode usar streams para ler dados de um arquivo, processá-los e escrevê-los em outro arquivo, sem ter que se preocupar com a origem ou destino dos dados.</p>
<p>Ou então, você pode usar streams para ler dados de uma conexão de rede, processá-los e escrevê-los em um banco de dados. E assim por diante.</p>
<h3 id="heading-exemplo-basico">Exemplo básico</h3>
<p>$stream = fopen('data.txt', 'r');<br />while (!feof($stream)) {<br />    $line = fgets($stream);<br />    echo $line;<br />}<br />fclose($stream);</p>
<p>Neste exemplo, abrimos um arquivo chamado <code>data.txt</code> em modo de leitura (<code>'r'</code>). Em seguida, lemos o conteúdo do arquivo linha por linha até o final do arquivo (<code>feof($stream)</code>). Por fim, fechamos o arquivo com <code>fclose($stream)</code>.</p>
<p>Mas o que é um stream? Um stream é um recurso que representa uma fonte ou destino de dados. No exemplo acima, <code>$stream</code> é um stream que representa o arquivo <code>data.txt</code>.</p>
<p>Vamos ver um exemplo mais avançado.</p>
<h3 id="heading-exemplo-avancado">Exemplo avançado</h3>
<p>$context = stream_context_create([<br />    'http' =&gt; [<br />        'method' =&gt; 'POST',<br />        'header' =&gt; 'Content-Type: application/json',<br />        'content' =&gt; json_encode(['key' =&gt; 'value']),<br />    ],<br />]);  </p>
<p>$stream = fopen('http://example.com/data.csv', 'r', false, $context);<br />while (!feof($stream)) {<br />    $line = fgetcsv($stream);<br />    print_r($line);<br />}<br />fclose($stream);</p>
<p>Neste exemplo, criamos um contexto de stream com <code>stream_context_create</code>, que é um array associativo com opções de configuração para o stream. No caso, estamos configurando um stream HTTP com o método <code>POST</code>, o cabeçalho <code>Content-Type: application/json</code> e o corpo da requisição em formato JSON.</p>
<p>Em seguida, abrimos um stream para a URL <code>http://example.com/data.csv</code> em modo de leitura (<code>'r'</code>) com o contexto de stream que acabamos de criar.</p>
<p>Depois, lemos o conteúdo do stream linha por linha com <code>fgetcsv</code>, que lê uma linha do stream e a converte em um array de valores separados por vírgula.</p>
<p>Por fim, fechamos o stream com <code>fclose</code>.</p>
<h3 id="heading-mas-por-que-usar-streams">Mas por que usar streams?</h3>
<p>O PHP surgiu em uma época em que a manipulação de arquivos era a principal forma de interagir com o sistema de arquivos e outros recursos de I/O. Por isso, as funções de manipulação de arquivos do PHP são baseadas em operações de baixo nível, como abrir, ler, escrever e fechar arquivos, os famosos <code>fopen</code>, <code>fread</code>, <code>fwrite</code> e <code>fclose</code>.</p>
<p>Com o tempo, a necessidade de interagir com outros tipos de recursos de I/O, como conexões de rede, bancos de dados, etc., tornou-se cada vez mais comum. E foi aí que os streams entraram em cena.</p>
<p>Streams são essencialmente uma camada de abstração sobre diferentes tipos de recursos de I/O, permitindo que você leia e escreva dados de e para esses recursos de forma consistente, independente da origem ou destino dos dados.</p>
<p>Quando eu falo de recursos de I/O, estou me referindo a qualquer coisa que você possa ler ou escrever dados, como arquivos, strings, janelas de console, conexões de rede, sockets, pipes, etc.</p>
<p>E quando eu falei de não se preocupar com a origem ou destino dos dados, eu quis dizer que você não precisa saber se está lendo de um arquivo, de uma conexão de rede, de um banco de dados, etc. Você simplesmente lê os dados do stream e os processa da forma que desejar. Isso é muito poderoso e flexível.</p>
<h3 id="heading-e-como-eu-uso-streams">E como eu uso streams?</h3>
<p>Para usar streams em PHP, você precisa entender alguns conceitos básicos:</p>
<ul>
<li><strong>Resource</strong></li>
<li><strong>Context</strong></li>
<li><strong>Wrapper</strong></li>
<li><strong>Stream functions</strong></li>
<li><strong>Stream filters</strong></li>
</ul>
<blockquote>
<p><strong><em>Nota*</em></strong>: Este é apenas um resumo básico sobre streams em PHP. Para saber mais, consulte a<em> [</em>documentação oficial<em>](https://www.php.net/manual/en/book.stream.php)</em>.*</p>
</blockquote>
<h3 id="heading-resource">Resource</h3>
<p>Vamos nos aprofundar um pouco mais no conceito de recurso (resource) em PHP.</p>
<p>Um stream é representado por um recurso (resource) em PHP. Um recurso é uma variável especial que contém uma referência interna para um recurso externo, como um arquivo, uma conexão de rede, etc. Você pode criar um recurso com a função <code>fopen</code> e fechá-lo com a função <code>fclose</code>.</p>
<p>Um <code>resource</code> em PHP é indentificador interno para recursos externos, e a função <code>get_resource_type</code> pode ser usada para obter o tipo de recurso.</p>
<p>$stream = fopen('data.txt', 'r');<br />echo get_resource_type($stream);<br />fclose($stream);</p>
<p>No console, você verá algo como <code>stream</code>.</p>
<p>O <code>resource</code> sempre vai referenciar o arquivo aberto.</p>
<h3 id="heading-context">Context</h3>
<p>Um contexto de stream é um array associativo com opções de configuração para o stream. Você pode criar um contexto de stream com a função <code>stream_context_create</code> e passá-lo como argumento para funções que abrem streams, como <code>fopen</code>, <code>file_get_contents</code>, etc.</p>
<p>Quando você abre um stream com um contexto de stream, as opções de configuração do contexto são aplicadas ao stream. Por exemplo, você pode configurar um stream HTTP com o método <code>POST</code>, o cabeçalho <code>Content-Type: application/json</code>, etc.</p>
<p>$context = stream_context_create([<br />    'http' =&gt; [<br />        'method' =&gt; 'POST',<br />        'header' =&gt; 'Content-Type: application/json',<br />        'content' =&gt; json_encode(['key' =&gt; 'value']),<br />    ],<br />]);  </p>
<p>$stream = fopen('http://example.com/data.csv', 'r', false, $context);</p>
<p>Ou então, você pode usar um contexto de stream para configurar um stream FTP com o nome de usuário e senha.</p>
<p>$context = stream_context_create([<br />    'ftp' =&gt; [<br />        'username' =&gt; 'user',<br />        'password' =&gt; 'pass',<br />    ],<br />]);  </p>
<p>$stream = fopen('ftp://example.com/data.csv', 'r', false, $context);</p>
<h3 id="heading-wrapper">Wrapper</h3>
<p>Um wrapper é um esquema de URL que define como o PHP deve abrir um stream. Por exemplo, o wrapper <code>http</code> é usado para abrir streams HTTP, o wrapper <code>ftp</code> é usado para abrir streams FTP, etc.</p>
<p>Quando você abre um stream com <code>fopen</code>, o PHP usa o wrapper correspondente para abrir o stream. Por exemplo, se você abrir um stream <code>http://example.com/data.csv</code>, o PHP usará o wrapper <code>http</code> para abrir o stream.</p>
<p>Você também pode usar wrappers para abrir streams de outros tipos de recursos, como strings, variáveis de memória, etc.</p>
<p>$stream = fopen('data:text/plain;base64,SGVsbG8gV29ybGQ=', 'r');<br />echo stream_get_contents($stream);<br />fclose($stream);</p>
<p>Neste exemplo, estamos abrindo um stream de uma string codificada em base64 com o wrapper <code>data</code>. O conteúdo da string é <code>Hello World</code>.</p>
<p>$stream = fopen('php://memory', 'r+');</p>
<p>Neste exemplo, estamos abrindo um stream de uma variável de memória com o wrapper <code>php</code>. O stream é aberto em modo de leitura e escrita (<code>'r+'</code>).</p>
<p>$stream = fopen('ogg://temp', 'r+');</p>
<p>OGG é um wrapper que permite a manipulação de arquivos de áudio no formato OGG, isso é um exemplo de um wrapper personalizado.</p>
<p>Você pode criar seus próprios wrappers personalizados para abrir streams de outros tipos de recursos, como bancos de dados, APIs, etc.</p>
<p>Veja a <a target="_blank" href="https://www.php.net/manual/en/wrappers.php">documentação oficial</a> para mais informações sobre wrappers em PHP.</p>
<h3 id="heading-stream-functions">Stream functions</h3>
<p>O PHP fornece várias funções para trabalhar com streams, como <code>fopen</code>, <code>fclose</code>, <code>fread</code>, <code>fwrite</code>, <code>feof</code>, <code>fseek</code>, <code>ftell</code>, <code>fgetcsv</code>, <code>stream_get_contents</code>, etc.</p>
<p>Você pode usar essas funções para abrir, fechar, ler, escrever, posicionar, verificar o final, etc., de um stream.</p>
<p>Por exemplo, você pode usar <code>fopen</code> para abrir um stream, <code>fread</code> para ler dados do stream, <code>fwrite</code> para escrever dados no stream e <code>fclose</code> para fechar o stream.</p>
<p>$stream = fopen('data.txt', 'r');  </p>
<p>while (!feof($stream)) {<br />    $line = fgets($stream);<br />    echo $line;<br />}  </p>
<p>fwrite($stream, 'Hello World');  </p>
<p>fclose($stream);p</p>
<p>Neste exemplo, estamos abrindo um arquivo chamado <code>data.txt</code> em modo de leitura (<code>'r'</code>). Em seguida, lemos o conteúdo do arquivo linha por linha até o final do arquivo com <code>fgets</code>. Depois, escrevemos a string <code>Hello World</code> no arquivo com <code>fwrite</code>. Por fim, fechamos o arquivo com <code>fclose</code>.</p>
<p>Você pode usar essas funções para trabalhar com streams de diferentes tipos de recursos, como o curl, sockets, pipes, etc.</p>
<p>$url = 'http://example.com/data/page.html';  </p>
<p>$data = curl_init($url);  </p>
<p>curl_setopt($data, CURLOPT_RETURNTRANSFER, true);  </p>
<p>$response = curl_exec($data);  </p>
<p>curl_close($data);  </p>
<p>$stream = fopen('php://memory', 'r+');  </p>
<p>fwrite($stream, $response);  </p>
<p>rewind($stream);  </p>
<p>echo stream_get_contents($stream);  </p>
<p>fclose($stream);</p>
<p>Neste exemplo, estamos fazendo uma requisição HTTP com o curl para a URL <code>http://example.com/data/page.html</code>. Em seguida, abrimos um stream de uma variável de memória com o wrapper <code>php</code> em modo de leitura e escrita (<code>'r+'</code>). Depois, escrevemos a resposta da requisição no stream com <code>fwrite</code>. Por fim, exibimos o conteúdo do stream com <code>stream_get_contents</code> e fechamos o stream com <code>fclose</code>.</p>
<h3 id="heading-stream-filters">Stream filters</h3>
<p>Aqui chegamos a um dos recursos mais poderosos e flexíveis dos streams em PHP: os filtros de stream.</p>
<p>Imagine o seguinte cenário: você está lendo dados de um arquivo e precisa processar esses dados antes de exibi-los na tela. Com os filtros de stream, você pode criar um filtro que processa os dados conforme necessário e aplicá-lo ao stream de leitura, sem precisar modificar o código que lê os dados.</p>
<p>Por exemplo, você pode usar um filtro de stream para converter os dados de um arquivo de texto para letras maiúsculas antes de exibi-los na tela.</p>
<p>$stream = fopen('data.txt', 'r');  </p>
<p>stream_filter_append($stream, 'string.toupper');  </p>
<p>echo stream_get_contents($stream);  </p>
<p>fclose($stream);</p>
<p>Neste exemplo, estamos abrindo um arquivo chamado <code>data.txt</code> em modo de leitura (<code>'r'</code>). Em seguida, aplicamos o filtro <code>string.toupper</code> ao stream com <code>stream_filter_append</code>, que converte os dados para letras maiúsculas. Por fim, exibimos o conteúdo do stream com <code>stream_get_contents</code> e fechamos o arquivo com <code>fclose</code>.</p>
<p>Essa conversão é feita automaticamente pelo filtro de stream, ocorre durante a leitura dos dados e não afeta o arquivo original.</p>
<p>Você pode criar seus próprios filtros de stream para processar os dados de acordo com suas necessidades.</p>
<p>Veja a <a target="_blank" href="https://www.php.net/manual/en/filters.php">documentação oficial</a> para mais informações sobre filtros de stream em PHP.</p>
<h3 id="heading-filterphp">FilterPHP</h3>
<p>Mas eu preparei um exemplo para você entender melhor como funciona um filtro de stream.</p>
<p>No primeiro exemplo, vamos criar um filtro de stream que filtrará somente para linhas que contém a palavra “PHP”.</p>
<p>&lt;?php  </p>
<p>class FilterPHP extends php_user_filter<br />{<br />    public $stream;<br />    public string $filter;  </p>
<p>    public function onCreate(): bool {<br />        $this-&gt;stream = fopen('php://temp', 'w+');<br />        return $this-&gt;stream !== false;<br />    }  </p>
<p>    public function filter($in, $out, &amp;$consumed, $closing): int {<br />        $this-&gt;filter = 'PHP';<br />        $out_data = '';<br />        while ($bucket = stream_bucket_make_writeable($in)) {<br />            $line = explode("\n", $bucket-&gt;data);<br />            foreach ($line as $l) {<br />                if (str_contains($l, $this-&gt;filter)) {<br />                    $out_data .= $l . "\n";<br />                }<br />            }<br />        }  </p>
<p>        $bucket_out = stream_bucket_new($this-&gt;stream, $out_data);<br />        stream_bucket_append($out, $bucket_out);  </p>
<p>        return PSFS_PASS_ON;<br />    }<br />}</p>
<p>Vamos entender o que está acontecendo no código acima passo a passo.</p>
<ol>
<li>Criamos uma classe chamada <code>FilterPHP</code> que estende a classe <code>php_user_filter</code>. Esta classe é usada para criar um filtro de stream personalizado.</li>
</ol>
<p>Se você já trabalhou com classes em PHP, deve estar estranhando o fato de extender uma classe com um nome tão estranho. Isso acontece porque a classe <code>php_user_filter</code> é uma classe interna do PHP que não segue as convenções de nomenclatura de classes em PHP que foram estabelecidas pela comunidade ao longo dos anos.</p>
<ol>
<li>A classe <code>FilterPHP</code> possui duas propriedades: <code>$stream</code> e <code>$filter</code>. A propriedade <code>$stream</code> é usada para armazenar um stream temporário onde os dados filtrados serão escritos. A propriedade <code>$filter</code> é usada para armazenar o filtro que será aplicado aos dados.</li>
<li>O método <code>onCreate</code> é chamado quando o filtro é criado. Neste método, abrimos um stream temporário com <code>fopen('php://temp', 'w+')</code> e armazenamos o recurso do stream na propriedade <code>$stream</code>. Se o stream não puder ser aberto, retornamos <code>false</code>.</li>
</ol>
<blockquote>
<p>O método <code>onCreate</code> é um método obrigatório que deve ser implementado em todos os filtros de stream personalizados, funcionando como um construtor para o filtro.</p>
<p>Mas o que é <code>php://temp</code>? <code>php://temp</code> é um wrapper que permite a criação de streams temporários em PHP. Os streams temporários são armazenados na memória ou em um arquivo temporário, dependendo do tamanho dos dado</p>
</blockquote>
<p>3. O método <code>filter</code> é chamado para filtrar os dados do stream. Neste método, lemos os dados de entrada das seguintes variáveis:</p>
<ul>
<li><code>$in</code>: stream de entrada, onde os dados originais são lidos. Este stream é somente leitura, vem de <code>input</code> e é passado para o filtro.</li>
<li><code>$out</code>: stream de saída, onde os dados filtrados são escritos. Este stream é somente escrita, vem de <code>output</code> e é passado para o filtro.</li>
<li><code>&amp;$consumed</code>: quantidade de dados consumidos pelo filtro. Este valor é atualizado pelo filtro e passado de volta para o PHP.</li>
<li><code>$closing</code>: indica se o stream está sendo fechado. Se for <code>true</code>, o filtro deve liberar todos os recursos alocados.</li>
</ul>
<blockquote>
<p><strong><em>Nota*</em></strong>: O<em> `</em>&amp;<em>` </em>na frente de uma variável em PHP indica que a variável é passada por referência, ou seja, o valor da variável pode ser alterado dentro da função e refletido fora dela.*</p>
</blockquote>
<p>4. No método <code>filter</code>, lemos os dados de entrada do stream com <code>stream_bucket_make_writeable</code> e os armazenamos na variável <code>$out_data</code>. Em seguida, dividimos os dados em linhas com <code>explode("\n", $bucket-&gt;data)</code> e verificamos se cada linha contém a palavra "PHP" com <code>str_contains($l, $this-&gt;filter)</code>.</p>
<p>5. Se a linha contiver a palavra “PHP”, a linha é adicionada à variável <code>$out_data</code>. Em seguida, criamos um novo bucket de saída com <code>stream_bucket_new</code> e o adicionamos ao stream de saída com <code>stream_bucket_append</code>.</p>
<p>6. Por fim, retornamos <code>PSFS_PASS_ON</code> para indicar que o filtro deve continuar a passar os dados para o próximo filtro ou para o stream de saída.</p>
<p>Agora que criamos o filtro de stream, vamos aplicá-lo a um stream de entrada.</p>
<p>&lt;?php  </p>
<p>require_once './FilterPHP.php';  </p>
<p>$json = 'https://raw.githubusercontent.com/sschonss/stream-php/main/data.json';  </p>
<p>$fileContents = file_get_contents($json);  </p>
<p>if ($fileContents === false) {<br />    die('Failed to fetch data from the endpoint.');<br />}  </p>
<p>stream_filter_register('filterphp', 'FilterPHP') or die("Failed to register filter.");  </p>
<p>$tempStream = fopen('php://temp', 'r+');<br />fwrite($tempStream, $fileContents);<br />rewind($tempStream);  </p>
<p>$out_fp = fopen('php://stdout', 'w') or die("Failed to open output stream.");<br />stream_filter_append($tempStream, 'filterphp');  </p>
<p>while ($data = fread($tempStream, 1024)) {<br />    $data = str_replace('"name": ', '', $data);<br />    $data = str_replace('"description": ', '', $data);<br />    echo $data;<br />}  </p>
<p>fclose($tempStream);<br />fclose($out_fp);</p>
<p>Neste exemplo, estamos lendo um arquivo JSON de uma URL com <code>file_get_contents</code> e armazenando o conteúdo do arquivo em uma variável chamada <code>$fileContents</code>.</p>
<p>Em seguida, registramos o filtro de stream <code>FilterPHP</code> com <code>stream_filter_register</code>. O primeiro argumento é o nome do filtro, que será usado para aplicar o filtro ao stream de entrada. O segundo argumento é o nome da classe do filtro.</p>
<p>É importante registrar o filtro de stream antes de aplicá-lo ao stream de entrada, para que o PHP saiba como lidar com o filtro.</p>
<p>Depois, abrimos um stream temporário com <code>fopen('php://temp', 'r+')</code> e escrevemos o conteúdo do arquivo no stream com <code>fwrite</code>. Em seguida, rebobinamos o stream com <code>rewind</code>.</p>
<blockquote>
<p><strong><em>Nota*</em></strong>: O<em> `</em>rewind<em>` </em>é uma função que move o ponteiro interno do stream para o início do stream. Isso é necessário porque o ponteiro interno do stream é movido para o final do stream após a escrita.*</p>
<p><strong><em>Nota*</em></strong>: Ponteiro em PHP é como se fosse um cursor que aponta para a posição atual do stream.*</p>
</blockquote>
<p>Depois, abrimos um stream de saída com <code>fopen('php://stdout', 'w')</code> e aplicamos o filtro de stream <code>FilterPHP</code> ao stream temporário com <code>stream_filter_append</code>.</p>
<p>Por fim, lemos os dados do stream temporário com <code>fread</code> e exibimos os dados na tela com <code>echo</code>. Antes de exibir os dados, removemos as aspas duplas das chaves <code>name</code> e <code>description</code> com <code>str_replace</code>.</p>
<p>Por fim, fechamos o stream temporário e o stream de saída com <code>fclose</code>.</p>
<p>O retorno do código acima será algo como:</p>
<p>php-filter_1  |       "PHP",<br />php-filter_1  |        "PHP (Hypertext Preprocessor) é uma linguagem de script amplamente utilizada para desenvolvimento web e pode ser embutida em HTML."<br />php-filter_1  |        "Composer é um gerenciador de dependências para PHP, permitindo que você declare as bibliotecas que seu projeto depende e as instale."<br />php-filter_1  |        "Laravel é um framework web PHP, conhecido por sua sintaxe elegante e ferramentas robustas para desenvolvimento rápido de aplicativos."<br />php-filter_1  |        "Symfony é um conjunto de componentes PHP reutilizáveis e um framework web para criar aplicações e sites."<br />php-filter_1  |        "CodeIgniter é um framework PHP poderoso e simples de usar, construído para desenvolvedores que precisam de um toolkit elegante para criar aplicativos web completos."<br />php-filter_1  |       "CakePHP",<br />php-filter_1  |        "CakePHP é um framework PHP rápido de desenvolvimento que proporciona uma estrutura extensível para desenvolvedores criar aplicativos web."<br />php-filter_1  |        "Zend Framework é uma coleção de pacotes PHP profissionais com mais de 570 milhões de instalações."</p>
<p>Caso você queira testar o código acima, você pode clonar o repositório <a target="_blank" href="https://github.com/sschonss/stream-php">stream-php</a> e executar o comando <code>docker-compose up</code> para subir o container com o PHP e testar o código.</p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>Streams são uma abstração poderosa e flexível para trabalhar com arquivos e outros recursos de I/O em PHP. Com streams, você pode ler e escrever dados de e para diferentes fontes, como arquivos, strings, conexões de rede, etc., de forma consistente e independente da origem ou destino dos dados.</p>
<p>Além disso, você pode usar contextos de stream para configurar streams com opções específicas, wrappers para abrir streams de diferentes tipos de recursos, funções de stream para trabalhar com streams de forma eficiente e filtros de stream para processar os dados conforme necessário.</p>
<p>Espero que este guia tenha sido útil para você entender melhor como trabalhar com streams em PHP. Se tiver alguma dúvida, sugestão ou correção, fique à vontade para entrar em contato.</p>
<p>Até a próxima!</p>
]]></content:encoded></item><item><title><![CDATA[JIT (Just in Time) — PHP]]></title><description><![CDATA[Se você ainda não atualizou para o PHP 8.0 ou maior, está na hora de fazer isso. O PHP 8.0 foi lançado em 26 de novembro de 2020 e trouxe o JIT (Just In Time) e é sobre ele que vamos falar hoje.
Código OPC
Quando você executa um script PHP, o PHP o c...]]></description><link>https://luizschons.com/jit-just-in-time-php</link><guid isPermaLink="true">https://luizschons.com/jit-just-in-time-php</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Tue, 28 May 2024 00:27:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586230614/ae3ea9d2-4f1f-4d88-b1ec-0ce7573ba5e1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Se você ainda não atualizou para o PHP 8.0 ou maior, está na hora de fazer isso. O PHP 8.0 foi lançado em 26 de novembro de 2020 e trouxe o JIT (Just In Time) e é sobre ele que vamos falar hoje.</p>
<h3 id="heading-codigo-opc">Código OPC</h3>
<p>Quando você executa um script PHP, o PHP o compila para um código intermediário chamado de código OPC (PHP Opcode). O código OPC é então executado pela máquina virtual Zend.</p>
<p>Segue um exemplo de código PHP e seu código OPC:</p>
<p><strong>PHP:</strong></p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>
$a = M_PI;
$b = <span class="hljs-number">10</span> + sin($a);
<span class="hljs-keyword">echo</span> <span class="hljs-string">"Result: "</span>, $b;
</code></pre>
<p><strong>Código OPC:</strong></p>
<pre><code class="lang-c">Finding entry points
Branch analysis from position: <span class="hljs-number">0</span>
<span class="hljs-number">1</span> jumps found. (Code = <span class="hljs-number">62</span>) Position <span class="hljs-number">1</span> = <span class="hljs-number">-2</span>
filename:       /in/ceTlX
function name:  (null)
number of ops:  <span class="hljs-number">9</span>
compiled vars:  !<span class="hljs-number">0</span> = $a, !<span class="hljs-number">1</span> = $b
line      #* E I O op                           fetch          ext  <span class="hljs-keyword">return</span>  operands
-------------------------------------------------------------------------------------
    <span class="hljs-number">2</span>     <span class="hljs-number">0</span>  E &gt;   ASSIGN                                                   !<span class="hljs-number">0</span>, <span class="hljs-number">3.14159</span>
    <span class="hljs-number">3</span>     <span class="hljs-number">1</span>        INIT_FCALL                                               <span class="hljs-string">'sin'</span>
          <span class="hljs-number">2</span>        SEND_VAR                                                 !<span class="hljs-number">0</span>
          <span class="hljs-number">3</span>        DO_ICALL                                         $<span class="hljs-number">3</span>
          <span class="hljs-number">4</span>        ADD                                              ~<span class="hljs-number">4</span>      <span class="hljs-number">10</span>, $<span class="hljs-number">3</span>
          <span class="hljs-number">5</span>        ASSIGN                                                   !<span class="hljs-number">1</span>, ~<span class="hljs-number">4</span>
    <span class="hljs-number">4</span>     <span class="hljs-number">6</span>        ECHO                                                     <span class="hljs-string">'Result%3A+'</span>
          <span class="hljs-number">7</span>        ECHO                                                     !<span class="hljs-number">1</span>
    <span class="hljs-number">5</span>     <span class="hljs-number">8</span>      &gt; RETURN                                                   <span class="hljs-number">1</span>
</code></pre>
<p>Basicamente, o código OPC é uma sequência de instruções que a máquina virtual Zend executa.</p>
<h1 id="heading-jit"><strong>JIT</strong></h1>
<p>Mas onde o JIT entra nisso? O JIT é um compilador que compila o código OPC em código de máquina nativo. Isso significa que o JIT compila o código OPC em código de máquina que a CPU pode executar diretamente.</p>
<p>Dessa forma não usamos mais a máquina virtual Zend para executar o código OPC, mas sim o código de máquina nativo gerado pelo JIT.</p>
<h1 id="heading-habilitando-o-jit"><strong>Habilitando o JIT</strong></h1>
<p>O JIT não é habilitado por padrão. Para habilitá-lo, você precisa de alguns passos adicionais.</p>
<p>Primeiro, você precisa instalar a extensão <code>opcache</code>:</p>
<pre><code class="lang-bash">sudo apt-get install php8.0-opcache
</code></pre>
<p>Depois, você precisa habilitar o JIT no arquivo de configuração do PHP (<code>php.ini</code>):</p>
<pre><code class="lang-php">[opcache]
opcache.enable=<span class="hljs-number">1</span>
opcache.jit_buffer_size=<span class="hljs-number">100</span>M
opcache.jit=tracing
opcache.jit=<span class="hljs-number">1205</span>
opcache.enable_cli=<span class="hljs-number">1</span>
</code></pre>
<p>Aqui, estamos habilitando o JIT e definindo o tamanho do buffer JIT para 100 MB. O JIT pode operar em dois modos: <code>tracing</code> e <code>function</code>. O modo <code>tracing</code> é o modo padrão e é mais rápido, mas o modo <code>function</code> é mais preciso.</p>
<p>Para entender melhor a diferença entre os modos <code>tracing</code> e <code>function</code>, recomendo a leitura da <a target="_blank" href="https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit">documentação oficial</a>.</p>
<p>E depois habilitamos o JIT para a linha de comando (<code>opcache.enable_cli=1</code>).  </p>
<h2 id="heading-benchmark"><strong>Benchmark</strong></h2>
<p>Se você roda o PHP na Web, o JIT pode não fazer muita diferença. Mas se você roda scripts PHP na linha de comando, o JIT pode trazer um grande ganho de performance.</p>
<p>Pois então, vamos fazer um benchmark para comparar a performance do PHP 8.0 com e sem JIT.</p>
<p>No repositório <a target="_blank" href="https://github.com/sschonss/jit-php-doc">php-jit-doc</a> você encontra um script PHP que calcula um monte de coisa para deixar o processador bem ocupado.</p>
<blockquote>
<p><em>Não vamos entrar em detalhes de escrita e padrões deste script, pois o foco é o JIT.</em></p>
</blockquote>
<p>Vamos rodar o script sem JIT:</p>
<pre><code class="lang-bash">./start.sh
</code></pre>
<p>O resultado foi:</p>
<pre><code class="lang-bash">Execution time: 6.2343468666077 seconds
Encrypted: 46d37684d6032ef0167c00d29f3358d5a180438d3e8604e4c11728699d78fdb0a32284bfa8234ed59f69e7febd0d23bebab983211565582a98da8cb5c8800e42
</code></pre>
<p>Agora vamos habilitar o JIT e rodar o script novamente:</p>
<pre><code class="lang-bash">./start-jit.sh
</code></pre>
<p>O resultado foi:</p>
<pre><code class="lang-bash">Execution time: 3.292811870575 seconds
Encrypted: 46d37684d6032ef0167c00d29f3358d5a180438d3e8604e4c11728699d78fdb0a32284bfa8234ed59f69e7febd0d23bebab983211565582a98da8cb5c8800e42
</code></pre>
<p>Com o JIT habilitado, o script PHP rodou 3 segundos mais rápido. Isso é um ganho de performance muito considerável.</p>
<p>Mas lembre-se, o JIT não é uma bala de prata. Ele pode não fazer muita diferença para scripts PHP que rodam na Web. Mas para scripts PHP que rodam na linha de comando, o JIT pode trazer um grande ganho de performance.</p>
<h1 id="heading-conclusao"><strong>Conclusão</strong></h1>
<p>Esse foi um breve resumo sobre o JIT no PHP 8.0. Se você quiser saber mais sobre o JIT, recomendo a leitura da <a target="_blank" href="https://www.php.net/manual/en/intro.opcache.php">documentação oficial</a></p>
<p>Trouxe somente exemplos básicos e didáticos para que você entenda o que é o JIT e como habilitá-lo. Acho que era importante trazer esse conteúdo para o prefil para que possamos falar sobre assuntos mais complexos e avançados.</p>
<p>Se você gostou do conteúdo, deixe um comentário e compartilhe com seus amigos. Até a próxima!</p>
]]></content:encoded></item><item><title><![CDATA[Programação Paralela, e Assíncrona com PHP]]></title><description><![CDATA[Photo by Ben Griffiths on Unsplash
Introdução
PHP é uma linguagem de programação de propósito geral, amplamente utilizada para desenvolvimento web. No entanto, PHP também pode ser utilizado para desenvolvimento de aplicações desktop, scripts de autom...]]></description><link>https://luizschons.com/programac3a7c3a3o-paralela-e-assc3adncrona-com-php-5969c49d0bba</link><guid isPermaLink="true">https://luizschons.com/programac3a7c3a3o-paralela-e-assc3adncrona-com-php-5969c49d0bba</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Thu, 25 Apr 2024 00:20:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586238526/ea059127-9847-4d0f-87aa-f65a9a93723c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Photo by <a target="_blank" href="https://unsplash.com/@benofthenorth?utm_source=medium&amp;utm_medium=referral">Ben Griffiths</a> on <a target="_blank" href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></p>
<h3 id="heading-introducao">Introdução</h3>
<p>PHP é uma linguagem de programação de propósito geral, amplamente utilizada para desenvolvimento web. No entanto, PHP também pode ser utilizado para desenvolvimento de aplicações desktop, scripts de automação, entre outros. Neste artigo, vamos explorar o uso de PHP para programação paralela e assíncrona.</p>
<h3 id="heading-programacao-paralela">Programação Paralela</h3>
<p>Programação paralela é um paradigma de programação que consiste em dividir um problema em partes menores que podem ser executadas simultaneamente. Em PHP, a programação paralela pode ser feita utilizando a extensão <a target="_blank" href="https://www.php.net/manual/en/book.parallel.php">parallel</a> ou a extensão <a target="_blank" href="https://www.php.net/manual/en/book.pthreads.php">pthreads</a>, que permite a criação de threads em PHP.</p>
<h4 id="heading-mas-voce-sabe-o-que-e-uma-thread">Mas você sabe o que é uma thread?</h4>
<blockquote>
<p><em>Uma thread é uma unidade básica de processamento que pode ser executada de forma independente. Em um programa paralelo, várias threads podem ser executadas simultaneamente, o que pode resultar em um aumento significativo de desempenho.</em></p>
<p><em>Quando você compra um processador com múltiplos núcleos, você está comprando a capacidade de executar várias threads simultaneamente. No entanto, para aproveitar ao máximo essa capacidade, é necessário que o software seja desenvolvido de forma a utilizar esses recursos de forma eficiente.</em></p>
</blockquote>
<h4 id="heading-exemplo-de-programacao-paralela-em-php">Exemplo de Programação Paralela em PHP</h4>
<p>&lt;?php  </p>
<p>use function parallel\run;  </p>
<p>class DataProcessor<br />{<br />    public function process(array $data): array {<br />        $formattedData = $this-&gt;formatData($data);<br />        $excel_file = $this-&gt;generateExcel($formattedData);<br />        $this-&gt;sendEmail($excel_file, Auth::user()-&gt;email);<br />    }<br />}  </p>
<p>$data = range(1, 1000);  </p>
<p>$processor = new DataProcessor();  </p>
<p>$parallelResult1 = run(function () use ($processor, $data) {<br />    return $processor-&gt;process($data);<br />});  </p>
<p>$parallelResult2 = $processor-&gt;process($data);</p>
<p>No exemplo acima, estamos utilizando a extensão parallel para executar o método <code>process</code> da classe <code>DataProcessor</code> em paralelo. Isso significa que o método será executado em uma thread separada, o que pode resultar em um aumento de desempenho.</p>
<p>Isso não é bala de prata, e nem sempre é a melhor solução para todos os problemas. No entanto, em alguns casos, a programação paralela pode ser uma forma eficiente de melhorar o desempenho de uma aplicação.</p>
<p>O exemplo acima é bastante simplificado, mas ilustra como a programação paralela pode ser utilizada em PHP. Para obter mais informações sobre a extensão parallel, consulte a <a target="_blank" href="https://www.php.net/manual/en/book.parallel.php">documentação oficial</a>.</p>
<p>Aqui esta uma imagem de um exemplo de programação paralela em PHP:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586235019/e7563efd-e150-4fc2-a5d1-758f6bb59a65.png" alt /></p>
<p><em>Imagem ilustrativa de um exemplo de programação paralela retirada da internet.</em></p>
<p>Perceba que a programação paralela é diferente da programação assíncrona. Na programação paralela, várias threads são executadas simultaneamente, enquanto na programação assíncrona, várias tarefas podem ser executadas de forma concorrente, mas não necessariamente simultaneamente.</p>
<h3 id="heading-programacao-assincrona">Programação Assíncrona</h3>
<p>Programação assíncrona é um paradigma de programação que consiste em executar tarefas de forma concorrente, sem a necessidade de esperar que uma tarefa seja concluída para iniciar outra. Em PHP, a programação assíncrona pode ser feita utilizando a extensão <a target="_blank" href="https://www.swoole.co.uk/">swoole</a>, que permite a criação de servidores web assíncronos em PHP.</p>
<h4 id="heading-mas-voce-sabe-o-que-e-um-servidor-web-assincrono">Mas você sabe o que é um servidor web assíncrono?</h4>
<blockquote>
<p><em>Um servidor web assíncrono é um servidor que pode lidar com várias requisições simultaneamente, sem a necessidade de criar uma nova thread para cada requisição. Isso permite que o servidor seja mais eficiente e possa lidar com um grande número de requisições de forma concorrente.</em></p>
<p><em>Você pode achar o termo “servidor auto-contido” em alguns lugares, mas a ideia é a mesma: um servidor que pode lidar com várias requisições simultaneamente, sem a necessidade de criar uma nova thread para cada requisição.</em></p>
</blockquote>
<h4 id="heading-exemplo-de-programacao-assincrona-em-php">Exemplo de Programação Assíncrona em PHP</h4>
<p>use Swoole\Http\Server;  </p>
<p>$server = new Server("0.0.0.0", 9501);  </p>
<p>$server-&gt;on("start", function (Server $server) {<br />    echo "Server started at http://{$server-&gt;host}:{$server-&gt;port}\n";<br />});  </p>
<p>$server-&gt;on("request", function ($request, $response) {<br />    $data = $request-&gt;rawContent();<br />    $response-&gt;end("Received data: $data");<br />});  </p>
<p>$server-&gt;start();</p>
<p>No exemplo acima, estamos utilizando a extensão swoole para criar um servidor web assíncrono em PHP. O servidor irá escutar na porta 9501 e responder a todas as requisições com uma mensagem contendo os dados recebidos</p>
<p>Esse exemplo é bastante simplificado, mas ilustra como a programação assíncrona pode ser utilizada em PHP. Para obter mais informações sobre a extensão swoole, consulte a <a target="_blank" href="https://www.swoole.co.uk/">documentação oficial</a>.</p>
<p>Aqui esta uma imagem de um exemplo de programação assíncrona:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586236219/554adf54-7f19-4abf-bea2-aad9a2b23333.png" alt /></p>
<p>Imagem ilustrativa de um exemplo de programação assíncrona retirada da internet.</p>
<h3 id="heading-ciclo-de-vida-de-uma-requisicao-no-php-fpm">Ciclo de Vida de uma Requisição no PHP-FPM</h3>
<p>Quando uma requisição é feita a um servidor web PHP, como o PHP-FPM, o servidor passa por várias etapas para processar a requisição e retornar uma resposta ao cliente. O ciclo de vida de uma requisição no PHP-FPM pode ser dividido em várias etapas:</p>
<ol>
<li><strong>Recebimento da Requisição:</strong> O servidor web (Apache, Nginx, etc.) recebe a requisição do cliente e a encaminha para o PHP-FPM.</li>
<li><strong>Pool de Processos:</strong> O PHP-FPM mantém um pool de processos PHP pré-carregados para processar as requisições. Quando uma requisição é recebida, o PHP-FPM escolhe um processo disponível para processar a requisição.</li>
<li><strong>Autoload:</strong> O PHP-FPM carrega os arquivos necessários para processar a requisição, incluindo as classes e funções utilizadas no script PHP. As classes e funções são carregadas automaticamente pelo PHP, de acordo com as regras de autoload definidas no arquivo <code>composer.json</code>.</li>
<li><strong>Análise e Compilação:</strong> O PHP analisa o script PHP e compila o código em uma forma que pode ser executada pelo interpretador PHP.</li>
<li><strong>Execução do Script:</strong> O PHP executa o script PHP, processando as instruções e gerando a saída da requisição.</li>
<li><strong>Gerar Resposta:</strong> O PHP-FPM gera a resposta da requisição, incluindo o cabeçalho HTTP e o corpo da resposta.</li>
<li><strong>Envio da Resposta:</strong> O PHP-FPM envia a resposta ao servidor web, que a encaminha de volta ao cliente.</li>
<li><strong>Encerramento do Processo:</strong> Após enviar a resposta, o processo PHP é encerrado e retorna ao pool de processos disponíveis para processar novas requisições.</li>
</ol>
<p>O ciclo de vida de uma requisição no PHP-FPM pode variar dependendo da configuração do servidor web e do PHP-FPM. No entanto, essas etapas são comuns na maioria dos servidores web PHP.</p>
<h3 id="heading-ciclo-de-vida-de-uma-requisicao-no-swoole">Ciclo de Vida de uma Requisição no Swoole</h3>
<p>Quando uma requisição é feita a um servidor web assíncrono PHP, como o Swoole, o servidor passa por várias etapas para processar a requisição e retornar uma resposta ao cliente. O ciclo de vida de uma requisição no Swoole pode ser dividido em várias etapas:</p>
<p>O início do ciclo de vida de uma requisição no Swoole começa com a inicialização do servidor Swoole e a configuração do script PHP que será executado para processar as requisições. O servidor Swoole escuta em uma porta específica e aguarda a chegada de requisições.</p>
<p>Nesse ponto, o servidor já está com o autoload configurado, as classes e funções necessárias já estão carregadas e o script PHP está pronto para processar as requisições.</p>
<ol>
<li><strong>Recebimento da Requisição:</strong> Quando uma requisição é feita ao servidor Swoole, o servidor recebe a requisição e a encaminha para o script PHP configurado para processar a requisição.</li>
<li><strong>Processamento da Requisição:</strong> O script PHP processa a requisição, executando as instruções necessárias para gerar a resposta da requisição.</li>
<li><strong>Análise e Compilação:</strong> O PHP analisa o script PHP e compila o código em uma forma que pode ser executada pelo interpretador PHP.</li>
<li><strong>Execução do Script:</strong> O PHP executa o script PHP, processando as instruções e gerando a saída da requisição.</li>
<li><strong>Gerar Resposta:</strong> O script PHP gera a resposta da requisição, incluindo o cabeçalho HTTP e o corpo da resposta.</li>
<li><strong>Envio da Resposta:</strong> O servidor Swoole envia a resposta ao cliente, encerrando o ciclo de vida da requisição.</li>
</ol>
<p>E nesse momento, o servidor Swoole está pronto para processar novas requisições, mantendo um pool de processos PHP disponíveis para processar as requisições de forma assíncrona.</p>
<p>A diferença entre o ciclo de vida de uma requisição no PHP-FPM e no Swoole está na forma como o servidor PHP é inicializado e como as requisições são processadas. No PHP-FPM, o servidor PHP é inicializado para processar uma única requisição de cada vez, enquanto no Swoole, o servidor PHP é inicializado para processar várias requisições de forma assíncrona.</p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>Neste artigo, exploramos o uso de PHP para programação paralela e assíncrona. A programação paralela e assíncrona são técnicas de programação que podem ser utilizadas para melhorar o desempenho de uma aplicação e lidar com um grande número de requisições de forma eficiente.</p>
<p>Nem tudo é regra, e nem sempre a programação paralela ou assíncrona é a melhor solução para um problema. No entanto, é sempre bom conhecer as diferentes técnicas de programação disponíveis e saber quando utilizá-las de forma eficiente.</p>
<p>Espero que este artigo tenha sido útil e que você tenha aprendido algo novo sobre programação paralela e assíncrona em PHP. Espero que futuramente eu consiga fazer um artigo mais detalhado sobre cada uma dessas técnicas, com exemplos mais complexos e detalhados.</p>
<p>Qualquer dúvida, correção ou sugestão, fique à vontade para entrar em contato. Obrigado por ler até aqui!</p>
<h3 id="heading-referencias">Referências</h3>
<ul>
<li><a target="_blank" href="https://www.php.net/manual/en/book.parallel.php">PHP Parallel Extension</a></li>
<li><a target="_blank" href="https://www.php.net/manual/en/book.pthreads.php">PHP pthreads Extension</a></li>
<li><a target="_blank" href="https://www.swoole.co.uk/">Swoole Extension</a></li>
<li><a target="_blank" href="https://www.php.net/manual/en/install.fpm.php">PHP-FPM</a></li>
<li><a target="_blank" href="https://www.php.net/manual/en/language.oop5.autoload.php">PHP Autoload</a></li>
<li><a target="_blank" href="https://getcomposer.org/">PHP Composer</a></li>
<li><a target="_blank" href="https://www.php-fig.org/psr/">PHP PSR</a></li>
<li><a target="_blank" href="https://fastcgi-archives.github.io/">FastCGI</a></li>
</ul>
<h3 id="heading-autor">Autor</h3>
<ul>
<li><a target="_blank" href="https://linkedin.com/in/luiz-schons">Luiz Schons</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Tabelas Hash]]></title><description><![CDATA[Uma tabela hash é uma estrutura de dados que associa chaves de pesquisa a valores.
Sua principal função é, a partir de uma chave simples, fazer uma busca rápida e eficiente para encontrar o valor desejado.
1. Funções Hash
1.1. Introdução
A função has...]]></description><link>https://luizschons.com/tabelas-hash-1f1a85a83795</link><guid isPermaLink="true">https://luizschons.com/tabelas-hash-1f1a85a83795</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Wed, 06 Mar 2024 22:52:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586243421/155936fd-0213-47ef-bc8a-168f55e0d62c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Uma tabela hash é uma estrutura de dados que associa chaves de pesquisa a valores.</p>
<p>Sua principal função é, a partir de uma chave simples, fazer uma busca rápida e eficiente para encontrar o valor desejado.</p>
<h3 id="heading-1-funcoes-hash">1. Funções Hash</h3>
<h3 id="heading-11-introducao">1.1. Introdução</h3>
<p>A função hash é uma função que, a partir de uma entrada de dados, gera um valor numérico que identifica a posição de um elemento em uma tabela hash.</p>
<p>Nós já vimos algumas outras estruturas de dados aqui nesse perfil, como buscar um elemento em uma lista encadeada ou em uma árvore binária, e vimos que a complexidade dessas operações é O(n) e O(log n), respectivamente.</p>
<p>A tabela hash, por sua vez, consegue fazer essa busca em O(1), ou seja, em tempo constante.</p>
<p>Isso significa que, não importa o tamanho da tabela, a busca será feita no mesmo tempo.</p>
<h3 id="heading-12-exemplo">1.2. Exemplo</h3>
<p>Muitas vezes, a função hash é usada para criar um índice para um array, e é por isso que a função hash deve ser rápida e eficiente.</p>
<p>Desenvolvi uma função hash muito simples, que pega uma palavra e retorna um número que representa essa palavra.</p>
<p>package main  </p>
<p>import (<br /> "fmt"<br />)  </p>
<p>func main() {<br /> for {<br />  run()<br /> }<br />}  </p>
<p>func run(){<br /> array_palavras := [10000]string{}<br /> fmt.Println("Digite uma palavra para ser hasheada")<br /> var palavra string<br /> fmt.Scanln(&amp;palavra)<br /> hash_palavra := fake_hash(palavra)<br /> fmt.Println("A palavra", palavra, "tem o hash", hash_palavra)<br /> array_palavras[hash_palavra] = palavra<br /> fmt.Println("A palavra", palavra, "foi adicionada ao array na posicao", hash_palavra)<br /> fmt.Println("Digite um hash para buscar a palavra correspondente")<br /> var hash int<br /> fmt.Scanln(&amp;hash)<br /> fmt.Println("A palavra correspondente ao hash", hash, "é", array_palavras[hash])<br />}  </p>
<p>func fake_hash(palavra string) int {<br /> hash := 0<br /> for i := 0; i &lt; len(palavra); i++ {<br />  hash += int(palavra[i])<br /> }<br /> return hash<br />}</p>
<p>Nesse exemplo, a função fake_hash pega a palavra e soma os valores ASCII de cada caractere, retornando um número que representa a palavra.</p>
<p>Mas fique tranquilo, provavelmente você não vai precisar criar uma função hash, pois as linguagens de programação já possuem funções hash prontas e otimizadas.</p>
<p>Pode ser que na sua linguagem de programação a função hash seja chamada de outra coisa, como “map” ou “dicionário”, mas o conceito é o mesmo.</p>
<h3 id="heading-2-usabilidade">2. Usabilidade</h3>
<h3 id="heading-21-lista-telefonica">2.1. Lista Telefônica</h3>
<p>Um exemplo clássico de uso de tabela hash é a lista telefônica.</p>
<p>Imagine que você quer encontrar o número de telefone de uma pessoa.</p>
<p>Se a lista telefônica fosse uma lista encadeada, você teria que percorrer toda a lista até encontrar o nome da pessoa.</p>
<p>Se fosse uma árvore binária, você teria que percorrer a árvore até encontrar o nome da pessoa.</p>
<p>Mas, como a lista telefônica é uma tabela hash, você pode encontrar o número de telefone de uma pessoa em tempo constante, ou seja, em O(1).</p>
<p>Vamos entender mais sobre isso.</p>
<p>Ao adicionar um nome e um número de telefone à lista telefônica, a função hash é usada para gerar um índice para esse nome.</p>
<p>Quando você quer encontrar o número de telefone de uma pessoa, a função hash é usada para gerar o índice correspondente ao nome da pessoa, e o número de telefone é retornado.</p>
<p>Dessa forma:</p>
<p>package main  </p>
<p>import (<br />    "fmt"<br />)<br />func main() {<br />    lista_telefonica := make(map[string]string)<br />    lista_telefonica["João"] = "1234-5678"<br />    lista_telefonica["Maria"] = "8765-4321"<br />    lista_telefonica["José"] = "4321-5678"<br />    lista_telefonica["Ana"] = "5678-4321"<br />    fmt.Println("O número de telefone de João é", lista_telefonica["João"])<br />    fmt.Println("O número de telefone de Maria é", lista_telefonica["Maria"])<br />    fmt.Println("O número de telefone de José é", lista_telefonica["José"])<br />    fmt.Println("O número de telefone de Ana é", lista_telefonica["Ana"])<br />}</p>
<p>Nesse exemplo, a função hash é usada para gerar um índice para cada nome, e o número de telefone é retornado em tempo constante.</p>
<h3 id="heading-22-dns">2.2. DNS</h3>
<p>Outro exemplo clássico de uso de tabela hash é o DNS (Domain Name System).</p>
<p>O DNS é um sistema que traduz nomes de domínio da Internet em endereços IP.</p>
<p>Imagine que você quer acessar um site, como <a target="_blank" href="http://www.google.com/">www.google.com</a>.</p>
<p>Se o DNS não fosse uma tabela hash, você teria que percorrer toda a lista de domínios até encontrar o nome do site, imagina o tempo que isso levaria.</p>
<p>Mas, como o DNS é uma tabela hash, você pode encontrar o endereço IP de um site em tempo constante, ou seja, em O(1).</p>
<p>Vamos entender mais sobre isso com um exemplo.</p>
<p>package main  </p>
<p>import (<br />    "fmt"<br />)<br />func main() {<br />    dns := make(map[string]string)<br />    dns["www.google.com"] = "192.168.5.5"<br />    dns["www.facebook.com"] = "192.168.40.21"<br />    dns["www.twitter.com"] = "192.168.11.11"<br />    fmt.Println("O endereço IP de www.google.com é", dns["www.google.com"])<br />    fmt.Println("O endereço IP de www.facebook.com é", dns["www.facebook.com"])<br />    fmt.Println("O endereço IP de www.twitter.com é", dns["www.twitter.com"])<br />}</p>
<p>Entende como são exemplos bem similares? A ideia é a mesma, a tabela hash é usada para gerar um índice para cada nome, e o endereço IP é retornado em tempo constante.</p>
<h3 id="heading-3-colisoes">3. Colisões</h3>
<h3 id="heading-31-introducao">3.1. Introdução</h3>
<p>Uma colisão ocorre quando duas chaves de pesquisa diferentes têm o mesmo valor hash.</p>
<p>Mas isso é possível? Como a função hash gera um valor único para cada chave de pesquisa?</p>
<p>Bom, a função hash não gera um valor único para cada chave de pesquisa, ela gera um valor que representa a chave de pesquisa.</p>
<p>E, como o número de chaves de pesquisa é muito maior do que o número de valores hash, é possível que duas chaves de pesquisa diferentes tenham o mesmo valor hash.</p>
<h3 id="heading-32-tratamento-de-colisoes">3.2. Tratamento de Colisões</h3>
<p>Existem várias maneiras de tratar colisões, mas as duas mais comuns são:</p>
<ul>
<li>Encadeamento</li>
<li>Endereçamento Aberto</li>
</ul>
<h4 id="heading-321-encadeamento">3.2.1. Encadeamento</h4>
<p>No encadeamento, cada entrada da tabela hash é uma lista encadeada.</p>
<p>Quando ocorre uma colisão, a chave de pesquisa é adicionada à lista encadeada correspondente.</p>
<p>Isso significa que, se duas chaves de pesquisa diferentes têm o mesmo valor hash, elas são adicionadas à mesma lista encadeada.</p>
<p>A principal vantagem do encadeamento é que ele é simples de implementar, mas a principal desvantagem é que ele pode ser ineficiente em termos de espaço e desempenho.</p>
<h4 id="heading-322-enderecamento-aberto">3.2.2. Endereçamento Aberto</h4>
<p>No endereçamento aberto, quando ocorre uma colisão, a chave de pesquisa é adicionada a outra posição da tabela hash.</p>
<p>Isso significa que, se duas chaves de pesquisa diferentes têm o mesmo valor hash, a segunda chave de pesquisa é adicionada a outra posição da tabela hash.</p>
<p>A principal vantagem do endereçamento aberto é que ele é eficiente em termos de espaço e desempenho, mas a principal desvantagem é que ele é mais complexo de implementar.</p>
<h3 id="heading-4-desempenho">4. Desempenho</h3>
<h3 id="heading-41-fator-de-carga">4.1. Fator de Carga</h3>
<p>O fator de carga é a razão entre o número de chaves de pesquisa e o número de posições da tabela hash.</p>
<p>Quanto maior o fator de carga, maior a probabilidade de colisões.</p>
<p>Por isso, é importante manter o fator de carga baixo, para garantir um bom desempenho da tabela hash.</p>
<p>Um fator de carga ideal é menor que 0,7, ou seja, menos de 70% das posições da tabela hash estão ocupadas.</p>
<h4 id="heading-411-como-calcular-o-fator-de-carga">4.1.1. Como Calcular o Fator de Carga</h4>
<p>O fator de carga é calculado da seguinte forma:</p>
<p>NK = número de chaves de pesquisa<br />NP = número de posições da tabela hash</p>
<p>NK / NP = fator de carga</p>
<p>Por exemplo, se a tabela hash tem 100 posições e 70 chaves de pesquisa, o fator de carga é 0,7.</p>
<p>70 / 100 = 0,7</p>
<h3 id="heading-42-redimensionamento">4.2. Redimensionamento</h3>
<p>Quando o fator de carga é maior que 0,7, é necessário redimensionar a tabela hash.</p>
<p>O redimensionamento da tabela hash é feito da seguinte forma:</p>
<ul>
<li>Crie uma nova tabela hash com o dobro do tamanho da tabela hash original</li>
<li>Adicione todas as chaves de pesquisa da tabela hash original à nova tabela hash</li>
<li>Descarte a tabela hash original</li>
</ul>
<p>O redimensionamento da tabela hash é uma operação custosa, mas é necessária para garantir um bom desempenho da tabela hash.</p>
<h3 id="heading-5-sha">5. SHA</h3>
<p>SHA (Secure Hash Algorithm) é uma família de funções hash criptográficas.</p>
<p>Ela é uma ótima função hash, pois gera um valor único para cada chave de pesquisa.</p>
<p>SHA é amplamente utilizada em criptografia, segurança da informação e autenticação.</p>
<p>SHA é uma função hash muito segura, e é praticamente impossível encontrar duas chaves de pesquisa diferentes com o mesmo valor hash.</p>
<p>Uma das principais vantagens de SHA é que ela é rápida, eficiente e unidirecional, ou seja, é fácil calcular o valor hash de uma chave de pesquisa, mas é praticamente impossível calcular a chave de pesquisa a partir do valor hash.</p>
<p>Segue um exemplo de como usar SHA em Go:</p>
<p>package main<br />import (<br />    "crypto/sha256"<br />    "fmt"<br />)  </p>
<p>func main() {<br />    palavra := "hello"<br />    hash := sha256.Sum256([]byte(palavra))<br />    fmt.Printf("O hash de %s é %x\n", palavra, hash)<br />}</p>
<p>Nesse exemplo, a função hash SHA-256 é usada para gerar um valor hash para a palavra “hello”.</p>
<p>Mas se você quiser usar o SHA-256 para gerar a palavra “hello” a partir do valor hash, você não vai conseguir.</p>
<h3 id="heading-6-conclusao">6. Conclusão</h3>
<p>As tabelas hash são estruturas de dados muito eficientes para fazer buscas rápidas e eficientes.</p>
<p>Elas são amplamente utilizadas em aplicações do mundo real, como listas telefônicas, DNS, criptografia e segurança da informação.</p>
<p>Você aprendeu sobre funções hash, usabilidade, colisões, desempenho e SHA.</p>
<p>Nunca implemente uma função hash e use em produção, sempre use funções hash prontas e otimizadas da sua linguagem de programação.</p>
<p>Espero que você tenha aprendido bastante sobre tabelas hash, e que você possa aplicar esse conhecimento em suas aplicações do mundo real.</p>
<p>Se você tiver alguma dúvida ou sugestão, deixe nos comentários.</p>
<p>Até a próxima!</p>
]]></content:encoded></item><item><title><![CDATA[Quicksort]]></title><description><![CDATA[Quicksort é um algoritmo de ordenação muito eficiente, inventado por C.A.R. Hoare em 1960. Ele é amplamente utilizado para ordenação de arrays. O algoritmo que apresentamos a seguir é uma versão recursiva do Quicksort que seleciona um elemento como p...]]></description><link>https://luizschons.com/quicksort-33f8e917ab6c</link><guid isPermaLink="true">https://luizschons.com/quicksort-33f8e917ab6c</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Wed, 28 Feb 2024 00:09:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586112430/07eb835b-da5f-4436-b39b-a5b2fcc4c5c7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Quicksort é um algoritmo de ordenação muito eficiente, inventado por C.A.R. Hoare em 1960. Ele é amplamente utilizado para ordenação de arrays. O algoritmo que apresentamos a seguir é uma versão recursiva do Quicksort que seleciona um elemento como pivô e particiona o array de forma que todos os elementos menores que o pivô fiquem antes dele e os maiores fiquem depois. Os subarrays são então ordenados recursivamente.</p>
<p>Mas antes de começarmos a falar sobre o algoritmo, você precisa entender o que são métodos de DC (Divisão e Conquista).</p>
<h3 id="heading-metodos-de-dc">Métodos de DC</h3>
<p>Métodos de DC são algoritmos que resolvem um problema dividindo-o em subproblemas, resolvendo os subproblemas recursivamente e combinando as soluções dos subproblemas para resolver o problema original.</p>
<p>Vamos ver um exemplo de um algoritmo que utiliza DC.</p>
<h3 id="heading-exemplo">Exemplo</h3>
<p>Imagina que você tenha um array de inteiros e quer saber a soma de todos os elementos desse array. Você pode resolver esse problema utilizando DC da seguinte forma:</p>
<p>Array: [1, 2, 3, 4, 5]</p>
<p>Qual é o caso base? O caso base é quando o array tem apenas um elemento. Nesse caso, a soma é o próprio elemento.</p>
<p>Como iremos chegar no caso base? Vamos remover um elemento e ver o que sobra.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586090466/a10290d3-4010-4716-8fc4-b65d59558f23.png" alt /></p>
<p>Agora que chegamos no caso base, vamos resolver o problema. A soma de todos os elementos do array [5] é 5. Agora, vamos somar o 4 que removemos anteriormente. A soma de todos os elementos do array [4, 5] é 9. Agora, vamos somar o 3 que removemos anteriormente. A soma de todos os elementos do array [3, 9] é 12. E assim por diante.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586091937/f05822b2-a2fd-4bf6-aea3-e2049ad244b4.png" alt /></p>
<p>A soma de todos os elementos do array [1, 2, 3, 4, 5] é 15.</p>
<p>Esse é um caso simples de DC e muitos algoritmos utilizam esse conceito para resolver problemas.</p>
<h3 id="heading-por-que-nao-usar-um-loop">Por que não usar um loop?</h3>
<p>Você pode estar se perguntando por que não usar um loop para resolver esse problema. E a resposta é: você pode! Mas, em alguns casos, a solução utilizando DC é mais simples e mais fácil de entender.</p>
<p>Outro ponto importante é que, em algumas linguagens, principalmente as funcionais, não existe a estrutura de repetição (for, while, etc). Então, a única forma de resolver um problema é utilizando DC.</p>
<p>Entendendo esse algoritimo, você consegue trabalhar com outras linguagens de programação e entender como elas funcionam.</p>
<p>Caso tenha alguma dúvida, busque por mais exemplos e tente resolver problemas utilizando DC.</p>
<h3 id="heading-quicksort">Quicksort</h3>
<p>Agora que você entendeu o que é DC, vamos falar sobre o Quicksort.</p>
<p>O Quicksort é um algoritmo de ordenação muito eficiente, inventado por C.A.R. Hoare em 1960. Ele é amplamente utilizado para ordenação de arrays. O algoritmo que apresentamos a seguir é uma versão recursiva do Quicksort que seleciona um elemento como pivô e particiona o array de forma que todos os elementos menores que o pivô fiquem antes dele e os maiores fiquem depois. Os subarrays são então ordenados recursivamente.</p>
<h3 id="heading-exemplo-1">Exemplo</h3>
<p>Vamos ver um exemplo de como o Quicksort funciona.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586094051/5195328a-abf0-4d07-be67-675cd27dfc0d.png" alt /></p>
<p>Passo 1: Escolha um elemento como pivô. Vamos escolher o 6.</p>
<p>Passo 2: Particione o array de forma que todos os elementos menores que o pivô fiquem antes dele e os maiores fiquem depois.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586095573/5c2bacf4-226e-47d9-bf60-144eea312205.png" alt /></p>
<p>Passo 3: Ordenar os subarrays recursivamente.</p>
<p>O que significa ordenar os subarrays recursivamente? Significa que vamos repetir os passos 1 e 2 para os subarrays, escolhendo um pivô e particionando o array.</p>
<p>Vamos escolher o 1 como pivô.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586097406/11e39580-eeee-46e7-84a2-fac3b07437e7.png" alt /></p>
<p>Vamos escolher o 2 como pivô.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586099064/22e0a07e-fcb2-4d68-917c-5d84a92b907d.png" alt /></p>
<p>Agora somos obrigados a escolher o 3 como pivô.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586100502/7bcf8627-69bb-4cf2-921f-c820c064fe67.png" alt /></p>
<p>Agora que chegamos no caso base, vamos ordenar os subarrays recursivamente.</p>
<p>Voltando agora os arrays até organizarmos o array da esquerda.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586102188/0b523144-1510-49ae-8b14-de4164606250.png" alt /></p>
<p>Agora vamos organizar o array da direita.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586103296/3d7d40e5-e410-4ff6-b42c-5e41372a229a.png" alt /></p>
<p>Passo 1: Escolha um elemento como pivô. Vamos escolher o 10.</p>
<p>Passo 2: Particione o array de forma que todos os elementos menores que o pivô fiquem antes dele e os maiores fiquem depois.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586105219/9aacc718-2522-4392-800a-0111b53d6cf0.png" alt /></p>
<p>Agora que chegamos no caso base, vamos ordenar os subarrays recursivamente.</p>
<p>Voltando agora os arrays até organizarmos o array da direita.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586108528/2a0e8dcd-a3ec-4a26-b4fe-1221e875c665.png" alt /></p>
<p>Agora que organizamos os subarrays, o array original está ordenado.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586110191/caaef6a6-ec30-4b91-ab22-9d7ad14273e2.png" alt /></p>
<p>Esse é um exemplo de como o Quicksort funciona.</p>
<h3 id="heading-performance">Performance</h3>
<p>Dentro do desenvolvimento de software, a performance é um fator muito importante e muitas vezes usamos a Notação Big O para descrever a eficiência de um algoritmo.</p>
<p>Caso você não conheça a Notação Big O, recomendo que você leia um artigo sobre o assunto que escrevi aqui nesse link: <a target="_blank" href="https://medium.com/@sschonss/introdu%C3%A7%C3%A3o-a-algoritmos-nota%C3%A7%C3%A3o-big-o-d1d555b5e0e9">Notação Big O</a>.</p>
<p>O desempenho do Quicksort é O(n log n) no melhor caso e O(n²) no pior caso.</p>
<p>E a performance vai depender do pivô que você escolher. Se você escolher um pivô que seja o menor ou o maior elemento do array, o desempenho do Quicksort será O(n²). Mas, se você escolher um pivô que seja o elemento do meio do array, a performance do Quicksort será O(n log n).</p>
<p>Mas como escolher o pivô? Existem várias formas de escolher o pivô e a escolha do pivô vai depender do seu problema. Uma forma de escolher o pivô é escolher o elemento do meio do array.</p>
<p>Dessa forma, eu fiz um repositório no github com a implementação do Quicksort em Go. Caso você queira ver a implementação, clique <a target="_blank" href="https://github.com/sschonss/quicksort">aqui</a>.</p>
<p>Esse artigo é uma introdução ao Quicksort e espero que você tenha entendido como o algoritmo funciona, e agora se você escutar alguém falando sobre Quicksort, você vai entender do que se trata.</p>
<p>Lembre-se que a prática leva a perfeição e, quanto mais você praticar, mais você vai entender sobre o assunto.</p>
<p>Caso tenha alguma dúvida, busque por mais exemplos e tente resolver problemas utilizando Quicksort.</p>
<p>Espero que você tenha gostado do artigo e até a próxima!</p>
]]></content:encoded></item><item><title><![CDATA[Load Balancer]]></title><description><![CDATA[Balanceador de carga para servidores web
Aqui nesse perfil já falamos sobre diversos assuntos, como, por exemplo:

Licenças de software
Cache em Aplicações Web
Over Engineering
e muito mais…

Mas hoje vamos falar sobre um assunto que é muito importan...]]></description><link>https://luizschons.com/load-balancer-50398b45d227</link><guid isPermaLink="true">https://luizschons.com/load-balancer-50398b45d227</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Fri, 06 Oct 2023 02:30:35 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586119358/d6ec84bb-bf20-446d-aa3f-1f80f423c547.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-balanceador-de-carga-para-servidores-web">Balanceador de carga para servidores web</h3>
<p>Aqui nesse perfil já falamos sobre diversos assuntos, como, por exemplo:</p>
<ul>
<li><a target="_blank" href="https://medium.com/@sschonss/licen%C3%A7as-de-software-ff0b2bcfbde8">Licenças de software</a></li>
<li><a target="_blank" href="https://medium.com/@sschonss/uso-de-cache-em-aplica%C3%A7%C3%B5es-web-836f71f4ac4b">Cache em Aplicações Web</a></li>
<li><a target="_blank" href="https://medium.com/@sschonss/over-engineering-105683129610">Over Engineering</a></li>
<li>e muito mais…</li>
</ul>
<p>Mas hoje vamos falar sobre um assunto que é muito importante para a disponibilidade de aplicações web, o balanceamento de carga.</p>
<h3 id="heading-o-que-e-balanceamento-de-carga">O que é balanceamento de carga?</h3>
<p>Se você está começando a trabalhar com desenvolvimento web, provavelmente nunca ouviu falar sobre balanceamento de carga, e tenha calma, pois é um assunto bem simples.</p>
<p>Diferente do que aprendemos na faculdade ou em cursos, onde aprendemos a desenvolver aplicações web que rodam em um único servidor, na realidade, aplicações web rodam em mais de um servidor, e isso é necessário para que a aplicação tenha uma boa disponibilidade.</p>
<h3 id="heading-por-que-utilizar-mais-de-um-servidor">Por que utilizar mais de um servidor?</h3>
<p>No início do desenvolvimento temos um servidor só, e isso é o suficiente para que a aplicação funcione corretamente, mas quando a aplicação começa a crescer, e o número de acessos aumenta, um único servidor não é mais o suficiente para atender a demanda, e é aí que entra um termo muito importante, escalabilidade.</p>
<p>A escalabilidade é a capacidade de uma aplicação de aumentar a sua capacidade de atender a demanda.</p>
<p>Existem dois tipos de escalabilidade, a vertical e a horizontal.</p>
<h4 id="heading-escalabilidade-vertical">Escalabilidade vertical</h4>
<p>A escalabilidade vertical é quando aumentamos a capacidade de um servidor, adicionando mais memória, processamento, etc.</p>
<p>Chamamos isso de escalabilidade vertical, pois estamos aumentando a capacidade de um único servidor.</p>
<h4 id="heading-escalabilidade-horizontal">Escalabilidade horizontal</h4>
<p>A escalabilidade horizontal é quando aumentamos a capacidade de uma aplicação, adicionando mais servidores.</p>
<p>Chamamos isso de escalabilidade horizontal, seria algo como colocar mais servidores ao lado do servidor que já temos.</p>
<h3 id="heading-como-funciona-o-balanceamento-de-carga">Como funciona o balanceamento de carga?</h3>
<p>Quando temos mais de um servidor, precisamos de um mecanismo para distribuir as requisições entre os servidores, e esse mecanismo é o balanceador de carga.</p>
<p>O balanceador de carga é um servidor que fica na frente dos servidores que rodam a aplicação, e ele é responsável receber as requisições e distribuir.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586117006/08ffecf3-d19f-40ad-b89c-620267b359fc.png" alt /></p>
<p>Um detalhe importante é que o balanceador de carga não é um servidor comum, ele é um servidor especializado, que tem como única função, distribuir as requisições entre os servidores que rodam a aplicação.</p>
<h3 id="heading-como-funciona-o-balanceamento-de-carga-1">Como funciona o balanceamento de carga?</h3>
<p>Geralmente rodando na porta 80, o balanceador fica a frente dos servidores, nele é configurado o endereço de onde rodam a aplicação, e ele é responsável por distribuir as requisições entre os servidores conforme a sua configuração de balanceamento.</p>
<p>Existem vários tipos de balanceamento, mas os mais comuns são:</p>
<ul>
<li>Round Robin</li>
<li>Least Connections</li>
<li>Least Response Time</li>
<li>Hash</li>
<li>IP Hash</li>
</ul>
<h4 id="heading-round-robin">Round Robin</h4>
<p>O balanceamento Round Robin é o mais simples, ele distribui as requisições entre os servidores de forma circular, ou seja, a primeira requisição vai para o servidor 1, a segunda para o servidor 2, a terceira para o servidor 3, e assim por diante.</p>
<h4 id="heading-least-connections">Least Connections</h4>
<p>Distribui as requisições entre os servidores conforme o número de conexões ativas em cada servidor, ou seja, se o servidor 1 tem 10 conexões ativas, e o servidor 2 tem 5 conexões ativas, a próxima requisição vai para o servidor 2, pois ele tem menos conexões ativas.</p>
<h4 id="heading-least-response-time">Least Response Time</h4>
<p>Distribui as requisições entre os servidores segundo o tempo de resposta de cada servidor, ou seja, se o servidor 1 tem um tempo de resposta de 100ms, e o servidor 2 tem um tempo de resposta de 50ms, a próxima requisição vai para o servidor 2, pois ele tem um tempo de resposta menor.</p>
<h4 id="heading-hash">Hash</h4>
<p>Distribui as requisições entre os servidores de acordo com um hash gerado a partir de um parâmetro da requisição, por exemplo, se o parâmetro for TOKEN, e o valor do TOKEN for 123, o hash gerado será sempre o mesmo, e a requisição sempre vai para o mesmo servidor.</p>
<h4 id="heading-ip-hash">IP Hash</h4>
<p>Distribui as requisições entre os servidores conforme o IP do cliente, ou seja, todas as requisições que vierem do mesmo IP, vão para o mesmo servidor.</p>
<h3 id="heading-qual-balanceamento-utilizar">Qual balanceamento utilizar?</h3>
<p>Não existe um balanceamento melhor que o outro, cada um tem a sua aplicação, e o ideal é que você teste cada um deles, e veja qual se adapta melhor a sua aplicação.</p>
<h3 id="heading-quando-balancear-a-carga">Quando balancear a carga?</h3>
<p>O balanceamento de carga é utilizado quando temos mais de um servidor, e precisamos distribuir as requisições entre eles, mas quando temos apenas um servidor, não temos a necessidade de utilizar um balanceador de carga, pois ele só iria adicionar mais um ponto de falha na aplicação.</p>
<p>Lembre-se que nos servidores devem rodar a mesma aplicação, e devem estar sincronizados, pois se um servidor estiver com uma versão diferente da aplicação, ele pode apresentar comportamentos inesperados.</p>
<p>Geralmente usa-se o balanceamento de carga quando temos mais de um droplet, e cada droplet roda a mesma aplicação, e temos um banco de dados centralizado, acessado por todos.</p>
<h3 id="heading-servicos-de-balanceamento-de-carga">Serviços de balanceamento de carga</h3>
<p>Existem vários serviços de balanceamento de carga, mas os mais conhecidos são:</p>
<ul>
<li><a target="_blank" href="https://www.nginx.com/">Nginx</a></li>
<li><a target="_blank" href="http://www.haproxy.org/">HAProxy</a></li>
<li><a target="_blank" href="https://httpd.apache.org/">Apache</a></li>
<li><a target="_blank" href="https://aws.amazon.com/pt/elasticloadbalancing/">AWS Elastic Load Balancer</a></li>
<li><a target="_blank" href="https://cloud.google.com/load-balancing/?hl=pt-br">Google Cloud Load Balancing</a></li>
<li><a target="_blank" href="https://azure.microsoft.com/pt-br/services/load-balancer/">Azure Load Balancer</a></li>
<li>E muitos outros…</li>
</ul>
<p>Todos eles são ótimos, e cada um tem a sua aplicação, mas o mais utilizado é o Nginx, pois ele é muito leve, e tem um ótimo desempenho.</p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>O balanceamento de carga é um assunto muito importante, e é essencial para que a aplicação tenha uma boa disponibilidade, e não fique fora do ar.</p>
<p>Caso tenha alguma dúvida, ou queira contribuir com o artigo, deixe um comentário abaixo.</p>
]]></content:encoded></item><item><title><![CDATA[PRNG’s — Meus números aleatórios são realmente aleatórios?]]></title><description><![CDATA[Funções randômicas
Provavelmente você já ouviu falar do rand() ou do random() em alguma linguagem de programação, certo? Essas funções servem para gerar números aleatórios, porém será que eles são realmente aleatórios?
Hoje vamos falar sobre o que é ...]]></description><link>https://luizschons.com/prngs-meus-nc3bameros-aleatc3b3rios-sc3a3o-realmente-aleatc3b3rios-7f9cc177bca1</link><guid isPermaLink="true">https://luizschons.com/prngs-meus-nc3bameros-aleatc3b3rios-sc3a3o-realmente-aleatc3b3rios-7f9cc177bca1</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Sat, 16 Sep 2023 14:58:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586124496/35c20918-d250-49dd-a40f-436c95ab3bb4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-funcoes-randomicas">Funções randômicas</h3>
<p>Provavelmente você já ouviu falar do <code>rand()</code> ou do <code>random()</code> em alguma linguagem de programação, certo? Essas funções servem para gerar números aleatórios, porém será que eles são realmente aleatórios?</p>
<p>Hoje vamos falar sobre o que é um PRNG e como ele funciona.</p>
<h3 id="heading-exemplo-de-numero-aleatorio">Exemplo de número aleatório</h3>
<p>A linguagem que vamos usar para exemplificar os números aleatórios é o JavaScript, porém o conceito é o mesmo para qualquer linguagem. Escolhi o JavaScript, pois você pode executar o código diretamente no seu navegador.</p>
<p>O código abaixo gera um número aleatório entre 0 e 1.</p>
<p>Math.random()</p>
<p>Se você executar o código acima no seu navegador, você vai perceber que ele sempre vai gerar um número aleatório diferente, mas será que ele é realmente aleatório?</p>
<h3 id="heading-o-que-e-um-prng">O que é um PRNG?</h3>
<p>PRNG é a sigla para Pseudo Random Number Generator, ou seja, Gerador de Números Pseudo Aleatórios.</p>
<p>O que isso significa? Significa que o número gerado não é realmente aleatório, ele é gerado a partir de um algoritmo que usa uma semente (seed) para gerar o número.</p>
<h3 id="heading-o-que-e-uma-semente">O que é uma semente?</h3>
<p>A semente é um valor usado como base para gerar o número aleatório. Se você usar a mesma semente, o número gerado será sempre o mesmo.</p>
<h3 id="heading-como-funciona-um-prng">Como funciona um PRNG?</h3>
<p>Um PRNG funciona a partir de uma função que recebe uma variável(semente/seed) e retorna um número aleatório. A função deve ser capaz de gerar um número aleatório a partir de uma semente.</p>
<h3 id="heading-exemplo-de-prng">Exemplo de PRNG</h3>
<p>Vamos criar um PRNG simples que recebe uma semente e retorna um número aleatório entre 0 e 1.</p>
<p>function prng(seed) {<br />  return (seed * 9301 + 49297) % 233280 / 233280;<br />}</p>
<p>A função acima é um PRNG simples que recebe uma semente e retorna um número aleatório entre 0 e 1.</p>
<h3 id="heading-exemplo-de-uso-do-prng">Exemplo de uso do PRNG</h3>
<p>Vamos usar o PRNG que criamos para gerar um número aleatório entre 0 e 1.</p>
<p>prng(1)</p>
<p>Se você executar o código acima no seu navegador, você vai perceber que ele sempre vai gerar o mesmo número aleatório, pois estamos usando a mesma semente.</p>
<h3 id="heading-mas-como-e-gerado-a-semente">Mas como é gerado a semente?</h3>
<p>A semente é gerada a partir de um valor gerado pelo sistema operacional. Esse valor é chamado de entropia.</p>
<h3 id="heading-o-que-e-entropia">O que é entropia?</h3>
<p>Em termos gerais, refere-se à quantidade de incerteza em um sistema. Quanto maior a entropia, maior a incerteza. Isso não é exclusivo da computação, mas também se aplica a outras áreas, como física e química.</p>
<h3 id="heading-como-e-gerado-a-entropia-no-sistema-operacional">Como é gerado a entropia no sistema operacional?</h3>
<p>A entropia é gerada a partir de eventos aleatórios que ocorrem no sistema operacional, como movimento do mouse, pressionamento de teclas, etc.</p>
<h3 id="heading-como-e-gerado-a-semente-a-partir-da-entropia">Como é gerado a semente a partir da entropia?</h3>
<p>No nosso exemplo, a entropia é gerada a partir dos movimentos do mouse e pressionamento de teclas. Esses eventos são capturados pelo sistema operacional e convertidos em um valor numérico usado como semente.</p>
<h3 id="heading-e-possivel-controlar-a-entropia">É possível controlar a entropia?</h3>
<p>Sim, é possível controlar a entropia. Por exemplo, se você mover o mouse de forma aleatória, você vai gerar mais entropia do que se você mover o mouse de forma previsível.</p>
<p>De forma geral, quanto mais aleatório for o evento, maior será a entropia gerada.</p>
<h3 id="heading-entao-o-prng-e-realmente-aleatorio">Então o PRNG é realmente aleatório?</h3>
<p>Em resumo, os números gerados por PRNGs em linguagens de programação não são verdadeiramente aleatórios, mas são suficientes para muitas aplicações do dia a dia. Se você precisar de aleatoriedade verdadeira, pode ser necessário recorrer a fontes de entropia real ou serviços externos de geração de números aleatórios.</p>
<h3 id="heading-o-que-e-um-csprng">O que é um CSPRNG?</h3>
<p>CSPRNG é a sigla para Cryptographically Secure Pseudo Random Number Generator, ou seja, Gerador de Números Pseudo Aleatórios Criptograficamente Seguros.</p>
<p>Embora os PRNGs sejam adequados para muitas aplicações, eles não são adequados para aplicações que exigem uma entropia mais elevada, como criptografia. Para essas aplicações, é necessário usar um CSPRNG.</p>
<h3 id="heading-caracteristicas-de-um-csprng">Características de um CSPRNG</h3>
<p>Um CSPRNG deve ter as seguintes características:</p>
<h4 id="heading-deve-ser-imprevisivel">- Deve ser imprevisível</h4>
<p>Mesmo que você conheça o algoritmo e a semente, você não deve ser capaz de prever o próximo número gerado. Isso é fundamental para a segurança.</p>
<h4 id="heading-ampla-entropia">- Ampla Entropia</h4>
<p>Um CSPRNG deve ter uma ampla entropia, ou seja, deve ser capaz de gerar números aleatórios a partir de uma ampla gama de fontes de entropia.</p>
<h4 id="heading-repetibilidade-controlada">- Repetibilidade Controlada</h4>
<p>Um CSPRNG deve ser capaz de gerar os mesmos números aleatórios a partir da mesma semente. Isso é importante para testes e depuração.</p>
<h3 id="heading-exemplo-de-csprng">Exemplo de CSPRNG</h3>
<p>Algumas linguagens de programação já possuem um CSPRNG embutido, como no PHP.</p>
<p>ramdom_bytes();</p>
<p>Ou então Python com o módulo <code>secrets</code>.</p>
<p>import secrets  </p>
<p>secrets.randbits(16)</p>
<h3 id="heading-caraca-nao-entendi-nada">Caraca, não entendi nada!</h3>
<p>Calma, não se preocupe. O objetivo desse artigo é apenas explicar o que é um PRNG e como ele funciona. Se você não entendeu alguma coisa, não se preocupe, o importante é que você entenda o conceito.</p>
<p>Agora que você já sabe o que é um PRNG, você pode pesquisar mais sobre o assunto e aprender mais sobre o funcionamento de um PRNG.</p>
<p>O importante é que você saia daqui sabendo os seguintes conceitos:</p>
<ul>
<li>Meus números aleatórios são realmente aleatórios?</li>
<li>O que é um PRNG?</li>
<li>Como funciona um PRNG?</li>
<li>O que é uma semente?</li>
<li>O que é entropia?</li>
<li>O que é um CSPRNG?</li>
</ul>
<p>O mundo da programação é muito vasto e sempre temos algo novo para aprender.</p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>Talvez você esteja se perguntando: “Mas eu preciso saber disso?”. A resposta é: “Depende”. (já ouviu essa resposta antes né?)</p>
<p>Possa ser que você nunca precise usar um PRNG na sua vida, mas é sempre bom saber como as coisas funcionam por baixo dos panos, além de ser uma curiosidade interessante.</p>
<p>É possível que esse artigo tenha ficado um pouco confuso, pois ainda estou começando a estudar sobre o assunto, mas espero que você tenha entendido o conceito básico de um PRNG.</p>
<p>Se você gostaria de complementar esse artigo, sinta-se a vontade para fazer um comentário ou até mesmo entrar em contato comigo.</p>
<p>Até a próxima!</p>
]]></content:encoded></item><item><title><![CDATA[Uso de cache em aplicações web]]></title><description><![CDATA[Hoje em dia, com o avanço da tecnologia, é possível criar aplicações web que são capazes de atender milhares de requisições por segundo. Porém, para que isso seja possível, é necessário que a aplicação seja otimizada para que o tempo de resposta seja...]]></description><link>https://luizschons.com/uso-de-cache-em-aplicac3a7c3b5es-web-836f71f4ac4b</link><guid isPermaLink="true">https://luizschons.com/uso-de-cache-em-aplicac3a7c3b5es-web-836f71f4ac4b</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Tue, 12 Sep 2023 02:46:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586130656/7bb3cbfd-3618-4ce4-a577-e6ae8fcf742d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hoje em dia, com o avanço da tecnologia, é possível criar aplicações web que são capazes de atender milhares de requisições por segundo. Porém, para que isso seja possível, é necessário que a aplicação seja otimizada para que o tempo de resposta seja o menor possível. Uma das formas de otimizar uma aplicação é utilizando cache.</p>
<h3 id="heading-o-que-e-cache">O que é cache?</h3>
<p>Cache é um mecanismo de armazenamento temporário de dados. Ele é utilizado para que o acesso a esses dados seja mais rápido, pois o cache fica armazenado em uma memória mais rápida do que a memória principal. Porém, o cache é um espaço limitado, então ele só armazena os dados que são mais acessados.</p>
<h3 id="heading-como-funciona-o-cache">Como funciona o cache?</h3>
<p>Basicamente, o cache funciona da seguinte forma: quando um dado é acessado pela primeira vez, ele é armazenado no cache. Quando esse dado é acessado novamente, ele é retornado do cache, sem a necessidade de acessar o local onde ele está armazenado originalmente. Isso faz com que o tempo de resposta seja menor.</p>
<h3 id="heading-bala-de-prata">Bala de prata?</h3>
<p>Apesar de ser uma ótima forma de otimizar uma aplicação, o cache não é uma bala de prata. Ele não é capaz de resolver todos os problemas de performance de uma aplicação. Por exemplo, se o cache for mal utilizado, ele pode acabar piorando a performance da aplicação e até mesmo causando problemas de segurança.</p>
<h3 id="heading-ferramentas">Ferramentas</h3>
<p>Existem diversas ferramentas que podem ser utilizadas para implementar cache em uma aplicação web. Algumas delas são:</p>
<ul>
<li><a target="_blank" href="https://redis.io/">Redis</a></li>
<li><a target="_blank" href="https://memcached.org/">Memcached</a></li>
<li><a target="_blank" href="https://varnish-cache.org/">Varnish</a></li>
<li>E muitas outras…</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586128859/4f86b59b-2e4a-46f7-b3b7-0001a4064fd2.png" alt /></p>
<p>Cada uma dessas ferramentas tem suas vantagens e desvantagens, e a escolha de qual utilizar vai depender do contexto da aplicação.</p>
<p>A mais utilizada é o Redis, que é um banco de dados NoSQL em memória. Ele é muito rápido e possui diversas estruturas de dados que podem ser utilizadas para armazenar os dados em cache.</p>
<h3 id="heading-banco-de-dados-em-memoria">Banco de dados em memória?</h3>
<p>Sim, o Redis é um banco de dados em memória. Isso significa que os dados armazenados nele não são persistidos em disco, ou seja, salvo na memória principal do computador. Por isso, é necessário ter cuidado ao utilizar o Redis, pois se o computador for desligado, os dados armazenados nele serão perdidos, a menos que seja configurado para persistir os dados em disco, mas isso é assunto para outro artigo.</p>
<h3 id="heading-situacoes-em-que-o-cache-pode-ser-utilizado">Situações em que o cache pode ser utilizado</h3>
<p>O cache pode ser utilizado em diversas situações, como por exemplo:</p>
<h3 id="heading-cache-de-sessao">Cache de sessão</h3>
<p>Quando um usuário faz login em uma aplicação web, é necessário que o servidor armazene as informações da sessão desse usuário, para que ele não precise fazer login novamente a cada requisição. Porém, se a aplicação tiver milhares de usuários, armazenar as informações de sessão de todos eles pode acabar consumindo muita memória do servidor. Para evitar isso, é possível armazenar as informações de sessão em um banco de dados em memória, como o Redis.</p>
<h3 id="heading-cache-de-dados">Cache de dados</h3>
<p>Quando uma aplicação web precisa acessar um banco de dados, ela faz uma requisição ao banco de dados, que retorna os dados solicitados. Porém, se esses dados forem acessados com muita frequência, é possível armazená-los em um cache para que eles sejam retornados mais rapidamente. Dessa forma, a aplicação não precisa acessar o banco de dados toda vez que precisar desses dados, isso faz com que o tempo de resposta seja menor, o custo de consulta ao banco de dados seja reduzido e a carga no banco de dados seja menor.</p>
<h3 id="heading-cache-de-arquivos">Cache de arquivos</h3>
<p>Servir arquivos estáticos, como imagens, CSS e JavaScript, é uma das tarefas mais comuns de uma aplicação web. Porém, se esses arquivos forem acessados com muita frequência, é possível armazená-los em um cache para que eles sejam retornados mais rapidamente. Dessa forma, a aplicação não precisa acessar o disco toda vez que precisar desses arquivos, isso faz com que o tempo de resposta seja menor e a carga no disco seja menor. Existem diversas formas de fazer isso, como por exemplo:</p>
<ul>
<li>Utilizar um servidor de arquivos estáticos, como o <a target="_blank" href="https://www.nginx.com/">Nginx</a>, para servir esses arquivos.</li>
<li>Utilizar um CDN (Content Delivery Network) para servir esses arquivos.</li>
<li>Utilizar um serviço de armazenamento em nuvem, como o <a target="_blank" href="https://aws.amazon.com/pt/s3/">Amazon S3</a>, para armazenar esses arquivos.</li>
</ul>
<h3 id="heading-quando-nao-utilizar-cache">Quando não utilizar cache?</h3>
<p>Como dito anteriormente, o cache não é uma bala de prata. Usar em excesso pode acabar prejudicando o seu software.</p>
<p>Vou citar alguns exemplos de quando não utilizar cache:</p>
<h3 id="heading-dados-que-sao-atualizados-com-frequencia">Dados que são atualizados com frequência</h3>
<p>Se os dados que estão sendo armazenados em cache são atualizados com muita frequência, o cache pode acabar ficando desatualizado, o que pode causar problemas na aplicação. Por exemplo, se o cache estiver armazenando dados de um usuário, e esses dados forem atualizados, o cache ficará desatualizado, e a aplicação pode acabar retornando dados incorretos.</p>
<p>Nesses casos, é necessário invalidar o cache quando os dados forem atualizados. Isso pode ser feito de diversas formas, como por exemplo:</p>
<h4 id="heading-invalidacao-manual">Invalidação manual</h4>
<p>A invalidação manual é quando o cache é invalidado manualmente, ou seja, quando o desenvolvedor decide que o cache deve ser invalidado. Isso pode ser feito de diversas formas, como por exemplo utilizando um comando no terminal, ou utilizando uma interface gráfica.</p>
<h4 id="heading-invalidacao-automatica-por-tempo">Invalidação automática por tempo</h4>
<p>A invalidação automática por tempo é quando o cache é invalidado automaticamente após um determinado tempo. Isso pode ser feito atraves de um timestamp, ou seja, quando o cache for criado, é armazenado o timestamp de quando ele foi criado, e quando o cache for acessado, é verificado se o timestamp é maior do que o tempo de vida do cache, se for, o cache é invalidado.</p>
<h4 id="heading-invalidacao-automatica-por-evento">Invalidação automática por evento</h4>
<p>A invalidação automática por evento é quando o cache é invalidado automaticamente quando um determinado evento ocorre, como por exemplo quando um dado é atualizado ou inserido no banco de dados.</p>
<h3 id="heading-dados-que-nao-sao-acessados-com-frequencia">Dados que não são acessados com frequência</h3>
<p>Se os dados que estão sendo armazenados em cache não são acessados com frequência, o cache pode acabar ocupando espaço desnecessário na memória, o que pode causar problemas na aplicação. Isso pode acontecer, por exemplo, quando o cache é armazenado em um banco de dados em memória, como o Redis, e o espaço de memória do servidor é limitado.</p>
<h3 id="heading-dados-que-sao-muito-grandes">Dados que são muito grandes</h3>
<p>Dados de tamanho elevado podem acabar pesando muito o cache, o que pode deixar sua aplicação lenta. Nesses casos, é necessário avaliar se realmente vale a pena armazenar esses dados em cache ou fazer uma tela de loading para que o usuário aguarde o carregamento desses dados.</p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>Como foi visto, o cache é uma ótima forma de otimizar uma aplicação web, porém, é necessário ter cuidado ao utilizá-lo, pois se for mal utilizado, ele pode acabar piorando a performance da aplicação e até mesmo causando problemas de segurança.</p>
<p>Uma boa prática é utilizar um serviço de monitoramento de cache, como o <a target="_blank" href="https://redislabs.com/redis-enterprise/redis-insight/">RedisInsight</a>, para monitorar o cache e verificar se ele está sendo utilizado corretamente.</p>
<p>Existem diversas ferramentas que podem ser utilizadas para monitorar sua aplicação, como por exemplo:</p>
<ul>
<li><a target="_blank" href="https://newrelic.com/">New Relic</a></li>
<li><a target="_blank" href="https://www.datadoghq.com/">Datadog</a></li>
<li><a target="_blank" href="https://sentry.io/">Sentry</a></li>
<li><a target="_blank" href="https://grafana.com/">Grafana</a></li>
</ul>
<p>Espero que esse artigo tenha sido útil para você. Se tiver alguma dúvida ou sugestão, deixe um comentário abaixo.</p>
]]></content:encoded></item><item><title><![CDATA[Licenças de Software]]></title><description><![CDATA[Provavelmente você já deve ter visto algum arquivo de código fonte com um cabeçalho como este:
/* *  Nome do arquivo: main.c *  Descrição: Programa principal *  Autor: Luiz Schons *  Data: 01/01/2020 *  Versão: 1.0 *  Licença: MIT */
Ou então, algum ...]]></description><link>https://luizschons.com/licenc3a7as-de-software-ff0b2bcfbde8</link><guid isPermaLink="true">https://luizschons.com/licenc3a7as-de-software-ff0b2bcfbde8</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Thu, 10 Aug 2023 22:15:59 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586140450/2c342d41-fe2f-40cd-8749-fcd3b8283a6a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Provavelmente você já deve ter visto algum arquivo de código fonte com um cabeçalho como este:</p>
<p>/*<br /> *  Nome do arquivo: main.c<br /> *  Descrição: Programa principal<br /> *  Autor: Luiz Schons<br /> *  Data: 01/01/2020<br /> *  Versão: 1.0<br /> *  Licença: MIT<br /> */</p>
<p>Ou então, algum repositório no GitHub com um arquivo <code>LICENSE</code> ou <code>LICENSE.md</code> com um conteúdo parecido com este:</p>
<p>MIT License</p>
<p>Mas o que é uma licença de software? Para que serve? Por que devo me preocupar com isso?</p>
<p>Esse assunto é muito importante para qualquer desenvolvedor de software, seja ele um desenvolvedor profissional ou um estudante. Neste artigo, vamos entender o que é uma licença de software, para que serve e quais são as principais licenças de software livre.</p>
<h3 id="heading-o-que-e-uma-licenca-de-software">O que é uma licença de software?</h3>
<p>Uma licença de software é um contrato entre o autor de um software e o usuário do software. Esse contrato define quais são os direitos e deveres do autor e do usuário do software.</p>
<p>O autor do software é a pessoa ou organização que criou o software. O usuário do software é a pessoa ou organização que utiliza o software.</p>
<p>Quando usamos o termo “utilizar o software”, estamos nos referindo a qualquer atividade que envolva o software, como executar o software, estudar o código fonte do software, modificar o código fonte do software, distribuir cópias do software, etc.</p>
<p>Normalmente uma licença de software é um documento de texto que contém os termos do contrato. Esse documento pode estar no próprio código fonte do software, em um arquivo separado ou em um arquivo chamado <code>LICENSE</code> ou <code>LICENSE.md</code> na raiz do repositório do software.</p>
<h3 id="heading-quais-sao-os-tipos-de-licenca-de-software">Quais são os tipos de licença de software?</h3>
<p>Existem vários tipos de licença de software, hoje eu vou comentar sobre alguns tipos, mas não vou entrar em detalhes sobre cada um deles. Se você quiser saber mais sobre cada tipo de licença, recomendo que você leia o artigo <a target="_blank" href="https://www.gnu.org/licenses/license-list.html">Licenças de Software Livre</a> no site da <a target="_blank" href="https://www.gnu.org/">Free Software Foundation</a>.</p>
<h3 id="heading-gnu-general-public-license-gpl">GNU General Public License (GPL)</h3>
<p>A <a target="_blank" href="https://www.gnu.org/licenses/gpl-3.0.html">GNU General Public License</a> é uma licença de software livre criada pela <a target="_blank" href="https://www.gnu.org/">Free Software Foundation</a>. Essa licença permite que o usuário do software execute, estude, modifique e distribua cópias do software, mas exige que o software e qualquer trabalho derivado do software seja distribuído sob os termos da GNU GPL e os direitos autorais do software sejam atribuídos ao autor original do software.</p>
<h3 id="heading-gnu-lesser-general-public-license-lgpl">GNU Lesser General Public License (LGPL)</h3>
<p>A <a target="_blank" href="https://www.gnu.org/licenses/lgpl-3.0.html">GNU Lesser General Public License</a> é uma licença de software livre criada pela <a target="_blank" href="https://www.gnu.org/">Free Software Foundation</a>. Essa licença esta no meio termo entre as licenças permissivas e as licenças copyleft. A principal diferença entre a GNU LGPL e a GNU GPL é que a GNU LGPL permite que o usuário do software utilize o software em um software proprietário, enquanto a GNU GPL não permite. Os trabalhos derivados do software devem estar disponíveis em bibliotecas.</p>
<h3 id="heading-bsd">BSD</h3>
<p>A licença <a target="_blank" href="http://www.opensource.org/licenses/bsd-license.php">BSD</a> é uma licença de software livre criada pela <a target="_blank" href="https://www.berkeley.edu/">Universidade da Califórnia</a>. Essa licença tem poucas restrições, ela permite que o usuário do software execute, estude e modifique o software, porém informe o nome de quem realizou a contribuição.</p>
<h3 id="heading-apache-license-20">Apache License 2.0</h3>
<p>A licença <a target="_blank" href="http://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a> é uma licença de software livre criada pela <a target="_blank" href="https://www.apache.org/">Apache Software Foundation</a>. Essa licença permite ser usada em qualquer projeto, mas tem que observar as condições impostas nos termos descritos na licença. Permite a distribuição do software, modificações, sublicenciamento e uso comercial, porém deve-se informar termos de responsabilidade e avisos de direitos autorais.</p>
<h3 id="heading-mit">MIT</h3>
<p>A licença <a target="_blank" href="http://opensource.org/licenses/MIT">MIT</a> é uma licença de software livre criada pelo <a target="_blank" href="https://www.mit.edu/">Massachusetts Institute of Technology</a>. Essa licença permite que o usuário do software execute, estude, modifique e distribua cópias do software. Nessa licença não é necessário que o software e qualquer trabalho derivado do software seja distribuído sob os termos da licença MIT.</p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>Neste artigo, vimos o que é uma licença de software, para que serve e quais são os tipos de licença de software. Se você quiser saber mais sobre licenças de software, recomendo que você leia o artigo <a target="_blank" href="https://www.gnu.org/licenses/license-list.html">Licenças de Software Livre</a> no site da <a target="_blank" href="https://www.gnu.org/">Free Software Foundation</a>.</p>
<h3 id="heading-referencias">Referências</h3>
<ul>
<li><a target="_blank" href="https://www.gnu.org/licenses/license-list.html">Licenças de Software Livre</a></li>
<li><a target="_blank" href="https://www.gnu.org/licenses/gpl-3.0.html">GNU General Public License</a></li>
<li><a target="_blank" href="https://www.gnu.org/licenses/lgpl-3.0.html">GNU Lesser General Public License</a></li>
<li><a target="_blank" href="http://www.opensource.org/licenses/bsd-license.php">BSD</a></li>
<li><a target="_blank" href="http://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a></li>
<li><a target="_blank" href="http://opensource.org/licenses/MIT">MIT</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Over Engineering]]></title><description><![CDATA[O que é Over Engineering?
Over Engineering é um termo utilizado para descrever um projeto que é mais complexo do que o necessário para resolver o problema que ele se propõe a resolver. O termo é considerado pejorativo, implicando que o projeto em que...]]></description><link>https://luizschons.com/over-engineering-105683129610</link><guid isPermaLink="true">https://luizschons.com/over-engineering-105683129610</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Thu, 03 Aug 2023 00:34:54 GMT</pubDate><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586135932/20eb96f6-0ac8-41de-a701-c59389022b8d.jpeg" alt="https://www.google.com/url?sa=i&amp;url=https%3A%2F%2Fwww.pullrequest.com%2Fblog%2Fsigns-what-youre-building-is-over-engineered%2F&amp;psig=AOvVaw2qk1D8vwuEaFaR5x_hYbLi&amp;ust=1691106877141000&amp;source=images&amp;cd=vfe&amp;opi=89978449&amp;ved=0CBEQjRxqFwoTCJiexpuWv4ADFQAAAAAdAAAAABAJ" /></p>
<h3 id="heading-o-que-e-over-engineering">O que é Over Engineering?</h3>
<p>Over Engineering é um termo utilizado para descrever um projeto que é mais complexo do que o necessário para resolver o problema que ele se propõe a resolver. O termo é considerado pejorativo, implicando que o projeto em questão é o resultado de pensamento excessivo e desnecessário aplicado a um problema simples.</p>
<p>Podemos dizer que o Over Engineering é o oposto do KISS (Keep It Simple, Stupid), que é um princípio de design que defende que a maioria dos sistemas funcionam melhor se forem mantidos simples do que se forem tornados complexos; portanto, a simplicidade deve ser um objetivo chave e complexidade desnecessária deve ser evitada.</p>
<h3 id="heading-por-que-evitar-o-over-engineering">Por que evitar o Over Engineering?</h3>
<p>A questão é que o Over Engineering é algo que pode acontecer com qualquer um, e é algo que pode ser muito prejudicial para o projeto. O Over Engineering pode ser um problema para o projeto por vários motivos, como por exemplo:</p>
<ul>
<li><strong>Custo</strong>: O desenvolvedor pode acabar gastando mais do que o necessário para desenvolver o projeto, e isso pode acabar aumentando o custo do projeto.</li>
<li><strong>Tempo</strong>: Aumenta o tempo de desenvolvimento do projeto, pois o desenvolvedor pode acabar gastando mais tempo do que o necessário para desenvolver o projeto.</li>
<li><strong>Complexidade</strong>: O Over Engineering pode aumentar a complexidade do projeto</li>
<li><strong>Manutenção</strong>: O Over Engineering pode fazer a equipe de manutenção do projeto gastar mais tempo do que o necessário para manter o projeto.</li>
<li><strong>Escalabilidade</strong>: O Over Engineering muitas vezes faz com que o projeto não seja escalável ou que seja difícil de escalar.</li>
</ul>
<h3 id="heading-como-evitar-o-over-engineering">Como evitar o Over Engineering?</h3>
<p>Para evitar o Over Engineering, é importante que o desenvolvedor tenha em mente que o projeto deve ser simples e que o desenvolvedor deve evitar adicionar funcionalidades desnecessárias ao projeto. O desenvolvedor deve sempre se perguntar se a funcionalidade que ele está adicionando ao projeto é realmente necessária ou se ela é apenas uma funcionalidade que ele gostaria de ter no projeto.</p>
<p>As vezes nem sempre é sobre funcionalidades, mas sim sobre a forma como o desenvolvedor está desenvolvendo o projeto. Por exemplo, o desenvolvedor pode estar utilizando um design pattern que não é necessário para o projeto, ou o desenvolvedor pode estar utilizando uma arquitetura que não é necessária para o projeto.</p>
<h3 id="heading-exemplos-de-over-engineering">Exemplos de Over Engineering</h3>
<h3 id="heading-exemplo-1">Exemplo 1</h3>
<p>Foi solicitado um sistema para gerenciar os usuários de uma empresa. O sistema deve permitir que o usuário faça login, cadastre novos usuários, edite usuários existentes e exclua usuários existentes, um CRUD básico.</p>
<p>O desenvolvedor que está desenvolvendo o sistema decide utilizar o framework <code>hype</code> para desenvolver o sistema, pois ele acha que o sistema precisa de um framework para ser desenvolvido.</p>
<p>Porém, o desenvolvedor não sabe utilizar o framework <code>hype</code>, e ele acaba gastando muito tempo tentando aprender a utilizar esse framework.</p>
<p>Nesse meio tempo, o desenvolvedor poderia ter desenvolvido o sistema utilizando uma linguagem de programação que ele sabe utilizar, e o sistema já estaria pronto.</p>
<h3 id="heading-exemplo-2">Exemplo 2</h3>
<p>Um novo projeto foi iniciado, e o desenvolvedor que está desenvolvendo o projeto decide utilizar a arquitetura hexagonal para desenvolver o projeto, pois ele acha a arquitetura hexagonal muito interessante.</p>
<p>Mas o problema é que somente ele sabe utilizar a arquitetura hexagonal, e ele não tem tempo para ensinar a equipe como utilizar a arquitetura hexagonal.</p>
<p>Nesse meio tempo, a equipe poderia ter desenvolvido o projeto utilizando uma arquitetura que todos sabem utilizar, e o projeto já estaria pronto.</p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>Existem vários motivos para evitar o Over Engineering, e é importante que o desenvolvedor tenha em mente que o projeto deve ser simples e que o desenvolvedor deve evitar adicionar funcionalidades desnecessárias ao projeto.</p>
<p>Claro, o desenvolvedor pode adicionar funcionalidades extras ao projeto, mas é importante que o desenvolvedor se pergunte se a funcionalidade que ele está adicionando ao projeto é realmente necessária ou se ela é apenas uma funcionalidade que ele gostaria de ter no projeto.</p>
<p>Todos esses exemplos são baseados em casos de produção, é muito importante saber que para fins de estudo, é importante que o desenvolva projetos utilizando várias ferramentas e recursos, pois isso ajuda o desenvolvedor a aprender novas tecnologias e arquiteturas.</p>
<p>E é importante que o desenvolvedor saiba que o Over Engineering é algo que pode acontecer com qualquer um, não é algo que acontece apenas com desenvolvedores iniciantes ou com desenvolvedores que não sabem o que estão fazendo. Todos nós podemos acabar fazendo isso em algum momento, e é importante que o desenvolvedor saiba como evitar e como lidar com o Over Engineering.</p>
]]></content:encoded></item><item><title><![CDATA[SOFT DELETE — LARAVEL]]></title><description><![CDATA[Introdução
O famoso CRUD (Create, Read, Update, Delete) é um dos padrões mais utilizados em aplicações web, porém, em alguns casos, o Delete não é tão simples assim.
Temos casos onde o usuário não pode excluir um registro, mas ele pode desativá-lo, o...]]></description><link>https://luizschons.com/soft-delete-laravel-a64a3b7a9073</link><guid isPermaLink="true">https://luizschons.com/soft-delete-laravel-a64a3b7a9073</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Thu, 06 Jul 2023 14:11:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586248498/5d49f97a-be65-4a72-bc9f-77f3dc4bc5f5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introducao">Introdução</h3>
<p>O famoso CRUD (Create, Read, Update, Delete) é um dos padrões mais utilizados em aplicações web, porém, em alguns casos, o Delete não é tão simples assim.</p>
<p>Temos casos onde o usuário não pode excluir um registro, mas ele pode desativá-lo, ou seja, o registro não será mais exibido, mas ele ainda existe no banco de dados.</p>
<h3 id="heading-por-que-nao-excluir">Por que não excluir?</h3>
<p>Existem vários motivos para não excluir um registro, por exemplo, imagine que você tem um sistema de vendas e um cliente que já comprou um produto não pode ser excluído, pois, se ele for excluído, a venda ficará sem um cliente.</p>
<p>Ou imagine que você tem um sistema de controle de estoque e um produto que já foi vendido não pode ser excluído, pois, se ele for excluído, a venda ficará sem um produto.</p>
<p>Existem vários outros motivos para não excluir um registro, mas o que importa é que, em alguns casos, o registro não pode ser excluído.</p>
<h3 id="heading-o-que-e-soft-delete">O que é Soft Delete?</h3>
<p>Soft Delete é uma técnica que consiste em não excluir um registro, mas sim desativá-lo, ou seja, o registro não será mais exibido, mas ele ainda existe no banco de dados.</p>
<p>Seria como se o registro fosse marcado como excluído, mas não fosse excluído de fato.</p>
<h3 id="heading-de-que-forma-o-soft-delete-e-feito">De que forma o Soft Delete é feito?</h3>
<p>Existem várias formas de fazer o Soft Delete, mas a mais comum é adicionar um campo na tabela que será desativada, por exemplo, um campo chamado <code>status</code> que pode ter os valores <code>ativo</code> ou <code>inativo</code>, sendo que o valor <code>inativo</code> indica que o registro foi desativado.</p>
<p>Você também pode adicionar um campo chamado <code>deleted_at</code> que armazena a data e hora em que o registro foi desativado, sendo que, se o campo <code>deleted_at</code> estiver vazio, o registro está ativo, caso contrário, o registro está inativo.</p>
<h3 id="heading-exemplo">Exemplo</h3>
<p>Vamos supor que você tem uma tabela chamada <code>clientes</code> e você quer desativar um cliente, para isso, você pode adicionar um campo chamado <code>status</code> que pode ter os valores <code>ativo</code> ou <code>inativo</code>, sendo que o valor <code>inativo</code> indica que o registro foi desativado.</p>
<p>ALTER TABLE clientes ADD COLUMN status VARCHAR(7) NOT NULL DEFAULT 'ativo';</p>
<p>Agora, para desativar um cliente, basta alterar o valor do campo <code>status</code> para <code>inativo</code>.</p>
<p>UPDATE clientes SET status \= 'inativo' WHERE id \= 1;</p>
<p>Para verificar se um cliente está ativo ou inativo, basta verificar o valor do campo <code>status</code>.</p>
<p>SELECT * FROM clientes WHERE status \= 'ativo';</p>
<p>Mas todos concordam que isso é muito trabalhoso, pois, para cada tabela que você quiser desativar um registro, você terá que adicionar um campo chamado <code>status</code> e alterar o código para verificar o valor desse campo.</p>
<p>Dessa forma, os frameworks de desenvolvimento web criaram uma forma de fazer o Soft Delete de forma automática, ou seja, você não precisa adicionar um campo chamado <code>status</code> em cada tabela, pois o framework faz isso para você.</p>
<p>Como cada framework tem uma forma diferente de fazer o Soft Delete, vamos ver como é feito no Laravel, pois é o framework que eu mais utilizo.</p>
<h3 id="heading-soft-delete-no-laravel">Soft Delete no Laravel</h3>
<p>O Laravel utiliza o campo <code>deleted_at</code> para armazenar a data e hora em que o registro foi desativado, sendo que, se o campo <code>deleted_at</code> estiver vazio, o registro está ativo, caso contrário, o registro está inativo.</p>
<p>Tudo começa com a criação da tabela, onde você deve adicionar o campo <code>deleted_at</code> na tabela que será desativada.</p>
<p>Aqui vamos criar uma tabela no banco de dados usando o Artisan do Laravel.</p>
<p>php artisan make:migration create_clientes_table</p>
<p>Agora vamos abrir o arquivo de migração que foi criado e adicionar o campo <code>deleted_at</code> na tabela.</p>
<p>Schema::create('clientes', function (Blueprint $table) {<br />    $table-&gt;id();<br />    $table-&gt;string('nome');<br />    $table-&gt;string('email');<br />    $table-&gt;string('telefone');<br />    $table-&gt;timestamps();<br />    $table-&gt;softDeletes();<br />});</p>
<p>Só vou dar uma explicação rápida sobre o código acima, pois não é o foco do artigo.</p>
<ul>
<li>O método <code>id()</code> cria um campo chamado <code>id</code> que é a chave primária da tabela.</li>
<li>O método <code>string()</code> cria um campo do tipo <code>VARCHAR</code>.</li>
<li>O método <code>timestamps()</code> cria dois campos chamados <code>created_at</code> e <code>updated_at</code> que armazenam a data e hora em que o registro foi criado e atualizado.</li>
<li>O método <code>softDeletes()</code> cria um campo chamado <code>deleted_at</code> que armazena a data e hora em que o registro foi desativado.</li>
</ul>
<p>Após adicionar o campo <code>deleted_at</code> na tabela, você deve executar a migração para criar a tabela no banco de dados.</p>
<p>php artisan migrate</p>
<p>Agora que a tabela foi criada, vamos criar um Model para ela.</p>
<p>php artisan make:model Cliente</p>
<p>Agora vamos abrir o arquivo do Model e adicionar a trait <code>SoftDeletes</code>.</p>
<blockquote>
<p><em>O que é uma trait?</em></p>
<p><em>Uma trait é um recurso do PHP que permite que você adicione métodos em uma classe sem precisar herdar essa classe. Ou seja, você pode adicionar métodos em uma classe sem precisar herdar essa classe.</em></p>
</blockquote>
<p>use Illuminate\Database\Eloquent\Model;  </p>
<p>class Cliente extends Model<br />{<br />    use SoftDeletes;<br />    use HasFactory;  </p>
<p>    protected $fillable = [<br />        'nome',<br />        'email',<br />        'telefone',<br />    ];  </p>
<p>}</p>
<p>Só vou dar uma explicação rápida sobre o código acima, pois não é todo mundo que conhece o Laravel.</p>
<ul>
<li>O método <code>use SoftDeletes</code> adiciona a trait <code>SoftDeletes</code> no Model.</li>
<li>O método <code>use HasFactory</code> adiciona a trait <code>HasFactory</code> no Model, isso é necessário para usar o recurso de Factory do Laravel.</li>
<li>O método <code>protected $fillable</code> indica quais campos podem ser preenchidos em massa, ou seja, quais campos podem ser preenchidos usando o método <code>create()</code>.</li>
</ul>
<p>Agora que o Model foi criado, vamos criar um Controller para ele.</p>
<p>php artisan make:controller ClienteController --resource</p>
<p>O parâmetro <code>--resource</code> indica que o Controller será um Resource Controller, ou seja, um Controller que possui os métodos <code>index</code>, <code>create</code>, <code>store</code>, <code>show</code>, <code>edit</code>, <code>update</code> e <code>destroy</code>.</p>
<p>Agora vamos abrir o arquivo do Controller e adicionar o Model.</p>
<p>// ...  </p>
<p>public function destroy(Cliente $cliente)<br />{<br />    // ...<br />    $cliente-&gt;delete();<br />    // ...<br />}  </p>
<p>// ...</p>
<p>O código acima é o método <code>destroy()</code> responsável por desativar um registro, ou seja, o código acima desativa um cliente.</p>
<p>Mas como o Laravel sabe que o registro foi desativado?</p>
<p>O Laravel sabe que o registro foi desativado porque o Model <code>Cliente</code> utiliza a trait <code>SoftDeletes</code>, ou seja, o Laravel sabe que o Model <code>Cliente</code> possui um campo chamado <code>deleted_at</code> que armazena a data e hora em que o registro foi desativado.</p>
<p>Se nós não tivéssemos utilizado a trait <code>SoftDeletes</code>, o Laravel não saberia que o Model <code>Cliente</code> possui um campo chamado <code>deleted_at</code> que armazena a data e hora em que o registro foi desativado, dessa forma, ao executar o método <code>delete()</code>, o Laravel iria excluir o registro.</p>
<p>Agora que o registro foi desativado, vamos verificar se ele está ativo ou inativo.</p>
<p>// ...  </p>
<p>public function index()<br />{<br />    // ...<br />    $clientes = Cliente::all();<br />    // ...<br />}  </p>
<p>// ...</p>
<p>O código acima é o método <code>index()</code> responsável por exibir todos os registros, ou seja, o código acima exibe todos os clientes.</p>
<p>Mas como o Laravel sabe que o registro está desativado?</p>
<p>O Laravel sabe que o registro está desativado porque o Model <code>Cliente</code> utiliza a trait <code>SoftDeletes</code>, ou seja, o Laravel sabe que estamos utilizando o recurso de Soft Delete, dessa forma, ao executar o método <code>all()</code>, o Laravel não exibe os registros que estão desativados.</p>
<p>Se nós não tivéssemos utilizado a trait <code>SoftDeletes</code>, o Laravel não saberia que estamos utilizando o recurso de Soft Delete, dessa forma, ao executar o método <code>all()</code>, o Laravel exibiria todos os registros, inclusive os registros que estão desativados.</p>
<h3 id="heading-conclusao">Conclusão</h3>
<p>O Soft Delete é uma técnica que consiste em não excluir um registro, mas sim desativá-lo, ou seja, o registro não será mais exibido, mas ele ainda existe no banco de dados.</p>
<p>O Soft Delete é muito utilizado em sistemas que possuem um sistema de lixeira, ou seja, um sistema que armazena os registros desativados.</p>
<p>Durante o desenvolvimento de um sistema, você deve analisar se o registro pode ser excluído ou não, pois, se o registro não pode ser excluído, você deve utilizar essa técnica.</p>
<blockquote>
<p><em>Lembre-se que o Soft Delete não é uma regra, ou seja, você não precisa utilizar essa técnica em todos os sistemas que você desenvolver, você deve analisar se o registro pode ser excluído ou não.</em></p>
<p><em>O artigo é só uma introdução ao Soft Delete, ou seja, o artigo não aborda todos os detalhes, porém, o artigo aborda os detalhes mais básicos e importantes.</em></p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[O que é MVC? —  Conceitos Básicos]]></title><description><![CDATA[MVC é um padrão de arquitetura de software que separa a aplicação em três partes: Model, View e Controller.
Hoje em dia, o MVC é um dos padrões mais utilizados para o desenvolvimento de aplicações web em diversas linguagens de programação, incluindo ...]]></description><link>https://luizschons.com/o-que-c3a9-mvc-conceitos-bc3a1sicos-6363f9662f8c</link><guid isPermaLink="true">https://luizschons.com/o-que-c3a9-mvc-conceitos-bc3a1sicos-6363f9662f8c</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Wed, 10 May 2023 15:54:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586254006/5bfff9e8-e494-4867-8eb8-529e2ec49400.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>MVC é um padrão de arquitetura de software que separa a aplicação em três partes: Model, View e Controller.</p>
<p>Hoje em dia, o MVC é um dos padrões mais utilizados para o desenvolvimento de aplicações web em diversas linguagens de programação, incluindo o PHP.</p>
<p>Agora vamos entender melhor cada uma das partes do MVC.</p>
<h3 id="heading-model">Model</h3>
<p>O Model é a parte da aplicação que representa a camada de dados, ou seja, a representação dos dados que são manipulados pela aplicação.</p>
<p>É literalmente um modelo da aplicação, que pode ser representado por uma classe, por exemplo.</p>
<p>Seguindo o exemplo de um sistema de cadastro de clientes, o Model seria a representação dos dados do cliente, como nome, e-mail, telefone etc.</p>
<p>Segue o exemplo de um Model de cliente em Laravel:</p>
<p>&lt;?php<br />namespace App\Models;<br />use Illuminate\Database\Eloquent\Factories\HasFactory;<br />use Illuminate\Database\Eloquent\Model;<br />class Cliente extends Model<br />{<br />    use HasFactory;<br />    protected $fillable = [<br />        'nome',<br />        'email',<br />        'telefone',<br />    ];<br />}</p>
<p>Dentro do Model, podemos definir regras de negócio, como funções para validar os dados, por exemplo.</p>
<p> public function adicionar($dados) {<br />        return $this-&gt;create($dados);<br />    }      </p>
<p>    public function atualizar($dados) {<br />        return $this-&gt;update($dados);<br />    }  </p>
<p>    public function excluir() {<br />        return $this-&gt;delete();<br />    }  </p>
<p>    public function buscar($id) {<br />        return $this-&gt;find($id);<br />    }  </p>
<p>    public function listar() {<br />        return $this-&gt;all();<br />    }</p>
<p>Lembre-se que esse código é apenas um exemplo didático, e que você pode implementar as regras de negócio da forma que achar melhor.</p>
<h3 id="heading-controller">Controller</h3>
<p>Pronto, já temos nosso modelo!</p>
<p>Como usamos ele agora? Com o Controller.</p>
<p>O Controller é literalmente o controlador da aplicação, que recebe as requisições do usuário e as manipula, retornando uma resposta.</p>
<p>No nosso exemplo, o Controller seria responsável por receber as requisições do usuário, como por exemplo: salvar um novo cliente, e manipular os dados, como por exemplo, salvar o cliente no banco de dados.</p>
<p>Segue o exemplo de um Controller de cliente em Laravel:</p>
<p>[...]<br />class ClienteController extends Controller<br />{<br />    public function adicionar(Request $request) {<br />        $cliente = new Cliente();<br />        $cliente-&gt;adicionar($request-&gt;all());<br />        return response()-&gt;json(['mensagem' =&gt; 'Cliente adicionado com sucesso!']);<br />    }  </p>
<p>    public function atualizar(Request $request, $id) {<br />        $cliente = Cliente::find($id);<br />        $cliente-&gt;atualizar($request-&gt;all());<br />        return response()-&gt;json(['mensagem' =&gt; 'Cliente atualizado com sucesso!']);<br />    }  </p>
<p>    public function excluir($id) {<br />        $cliente = Cliente::find($id);<br />        $cliente-&gt;excluir();<br />        return response()-&gt;json(['mensagem' =&gt; 'Cliente excluído com sucesso!']);<br />    }  </p>
<p>    public function buscar($id) {<br />        $cliente = Cliente::find($id);<br />        return response()-&gt;json($cliente);<br />    }  </p>
<p>    public function listar() {<br />        $clientes = Cliente::listar();<br />        return response()-&gt;json($clientes);<br />    }<br />}</p>
<p>O Controller conhece o Model e pode manipular os dados através dele, mas também conhece a View e pode retornar uma resposta para o usuário através dela.</p>
<p>Dessa forma, o Controller é o intermediário entre o Model e a View.</p>
<h3 id="heading-view">View</h3>
<p>A View é a parte da aplicação que representa a camada de apresentação, ou seja, a representação da interface gráfica da aplicação.</p>
<p>É literalmente a interface gráfica da aplicação, que pode ser representada por um arquivo HTML, por exemplo.</p>
<p>Seguindo o exemplo de um sistema de cadastro de clientes, a View seria a representação da interface gráfica do sistema como formulários, botões, tabelas etc.</p>
<p>Segue o exemplo de uma View de cliente em Laravel utilizando o Blade:</p>
<p>&lt;!DOCTYPE html&gt;  </p>
<p>  </p>
<p><br />    <br />    <br />    Clientes<br />    <br />    </p>]]></content:encoded></item><item><title><![CDATA[Recursão — Caso-base e Caso Recursivo]]></title><description><![CDATA[Irei escrever sobre algoritmos e estruturas de dados em paralelo com o livro Entendendo Algoritmos: Um Guia Ilustrado Para Programadores e Outros Curiosos de Aditya Y. Bhargava.
Estou usando o livro para aprender sobre algoritmos e estruturas de dado...]]></description><link>https://luizschons.com/recursc3a3o-caso-base-e-caso-recursivo-801ae9e693ce</link><guid isPermaLink="true">https://luizschons.com/recursc3a3o-caso-base-e-caso-recursivo-801ae9e693ce</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Thu, 23 Mar 2023 22:33:00 GMT</pubDate><content:encoded><![CDATA[<p>Irei escrever sobre algoritmos e estruturas de dados em paralelo com o livro <a target="_blank" href="https://www.amazon.com.br/Entendendo-Algoritmos-Ilustrado-Programadores-Curiosos/dp/8575225634/ref=sr_1_1?qid=1677021688&amp;refinements=p_27%3AAditya+Y.+Bhargava&amp;s=books&amp;sr=1-1">Entendendo Algoritmos: Um Guia Ilustrado Para Programadores e Outros Curiosos</a> de Aditya Y. Bhargava.</p>
<p>Estou usando o livro para aprender sobre algoritmos e estruturas de dados, e escrever sobre o que estou aprendendo, pois acredito que assim eu consiga fixar melhor o conteúdo.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586257784/aa9aa18e-39b7-4861-9428-d8f9806b5da5.jpeg" alt /></p>
<h3 id="heading-capitulo-3-recursao">Capítulo 3 — Recursão</h3>
<p>Recursão é um conceito muito importante em programação, e é um dos conceitos mais difíceis de entender. A ideia de recursão é que uma função chame ela mesma, e que essa função tenha uma condição de parada. A condição de parada é o ponto em que a função não chama ela mesma novamente, e retorna um valor.</p>
<p>No livro Entendendo Algoritmos, o autor Aditya Y. Bhargava usa o exemplo de uma pessoa que está procurando uma chave dentro de uma caixa, mas dentro dessa caixa possui diversas caixas e a pessoa precisa fazer uma busca dentro de cada uma dessas caixas.</p>
<p>Irei usar o mesmo exemplo para explicar o conceito de recursão, mas farei um código em PHP para exemplificar.</p>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">procurarChave</span>(<span class="hljs-params">$caixa</span>) </span>{
    <span class="hljs-keyword">if</span> (caixaEstaVazia($caixa)) {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (chaveEstaNaCaixa($caixa)) {
    <span class="hljs-keyword">return</span> $caixa;
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">foreach</span> ($caixa-&gt;caixas <span class="hljs-keyword">as</span> $caixa) {
    $resultado = procurarChave($caixa);
        <span class="hljs-keyword">if</span> ($resultado != <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">return</span> $resultado;
        }
    }
}

<span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
}
</code></pre>
<p>Dentro da função procurarChave, temos uma condição de parada, que é quando a caixa está vazia, e não há mais caixas para procurar. Caso a caixa não esteja vazia, a função chama ela mesma, passando como parâmetro a caixa que está dentro da caixa atual.</p>
<p>No momento em que a função chama ela mesma, ela cria uma nova instância da função, e cria uma nova pilha de execução. Quando a função termina de executar, ela retorna o valor, e a pilha de execução é removida da memória.</p>
<p>A função procurarChave é uma função recursiva, pois ela chama ela mesma.</p>
<h3 id="heading-caso-base-e-caso-recursivo">Caso Base e Caso Recursivo</h3>
<p>Uma das coisas mais comuns de acontecer quando se está aprendendo sobre recursão é fazer um loop infinito, pois esquecemos de colocar a condição de parada. Para evitar esse tipo de problema, é importante entender o conceito de caso base e caso recursivo.</p>
<p>Vou usar novamente um exemplo do livro Entendendo Algoritmos para explicar o conceito de caso base e caso recursivo. Vou usar JavaScript para exemplificar.</p>
<p>A função recursiva abaixo é uma função que imprime todos os números no console, e adiciona 1 no número a cada chamada da função.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">imprimirNumero</span>(<span class="hljs-params">numero</span>) </span>{
    <span class="hljs-built_in">console</span>.log(numero);
    imprimirNumero(numero + <span class="hljs-number">1</span>);
}
</code></pre>
<p>Noto que a função não tem uma condição de parada, e que ela chama ela mesma a cada execução. Isso faz com que a função entre em um loop infinito, e que o navegador fique travado.</p>
<p>Para evitar esse problema, é necessário adicionar uma condição de parada, que é o caso base. O caso base é o ponto em que a função não chama ela mesma novamente, e retorna um valor.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">imprimirNumero</span>(<span class="hljs-params">numero</span>) </span>{
    <span class="hljs-built_in">console</span>.log(numero);
    <span class="hljs-keyword">if</span> (numero &lt; <span class="hljs-number">100</span>) {
        imprimirNumero(numero + <span class="hljs-number">1</span>);
    }
}
</code></pre>
<p>Agora a função não entra em um loop infinito, pois ela tem uma condição de parada. A função chama ela mesma até que o número seja menor que 100, e quando o número for maior ou igual a 100, a função não chama ela mesma novamente, e retorna o valor.</p>
<h3 id="heading-a-pilha-de-chamadas">A Pilha de Chamadas</h3>
<p>O seu computador organiza a memória em pilhas, e cada pilha é chamada de stack. Quando uma função é chamada, ela cria uma nova stack, e quando a função termina de executar, a stack é removida da memória.</p>
<p>Veja o exemplo abaixo em Python:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test</span>():</span>
    print(<span class="hljs-string">"Aqui está a função test"</span>)
    test2()
    print(<span class="hljs-string">"Aqui está a função test novamente"</span>)
    test3()

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test2</span>():</span>
    print(<span class="hljs-string">"Aqui está a função test2"</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test3</span>():</span>
    print(<span class="hljs-string">"Aqui está a função test3"</span>)

test()
</code></pre>
<p>Perceba que a função test chama a função test2, e depois chama a função test3. Quando a função test termina de executar, a stack é removida da memória, e a função test2 é executada. Quando a função test2 termina de executar, a stack é removida da memória, e a função test3 é executada. Quando a função test3 termina de executar, a stack é removida da memória, e o programa termina de executar.</p>
<p>Talvez tenha ficado um pouco confuso, vou tentar deixar mais claro.</p>
<p>Essa é a pilha de execução do programa:</p>
<p><img src="https://cdn-images-1.medium.com/max/800/1*JkmGi-0I_UEkMNBXv40eYg.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586260023/8bcace23-6fcc-43f8-bd72-bc0669c1de8b.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586261682/1bb2968a-f8c6-4120-90c5-5410136c42fc.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586264091/534bb2a9-c28c-4484-9891-cf9ce68682cf.png" alt /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586265709/62114813-cf88-4912-aef4-28c42cb9a79e.png" alt /></p>
<h3 id="heading-pilha-de-chamadas-e-recursao">Pilha de Chamadas e Recursão</h3>
<p>Agora que você já sabe o que é uma pilha de chamadas, vamos ver como a recursão funciona com a pilha de chamadas.</p>
<p>Vou usar o mesmo exemplo do livro Entendendo Algoritmos para exemplificar. Vou usar JavaScript para exemplificar.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fatorial</span>(<span class="hljs-params">n</span>) </span>{
    <span class="hljs-keyword">if</span> (n == <span class="hljs-number">1</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">return</span> n * fatorial(n - <span class="hljs-number">1</span>);
    }
}
</code></pre>
<p>A função fatorial recebe um número como parâmetro, e retorna o fatorial desse número. A função chama ela mesma, passando como parâmetro o número atual menos 1.</p>
<p>Quando a função fatorial é chamada, ela cria uma nova stack, e quando a função termina de executar, a stack é removida da memória.</p>
<p>Mas nesse caso, diferente do exemplo anterior, a função chama ela mesma antes de terminar de executar. Isso faz com que a função fatorial seja chamada novamente, e uma nova stack seja criada.</p>
<p>Então, no caso de um factorial de 5, a função fatorial é chamada 5 vezes, e 5 stacks são criadas. Veja o exemplo abaixo:</p>
<pre><code class="lang-javascript">fatorial(<span class="hljs-number">1</span>)

fatorial(<span class="hljs-number">2</span>)

fatorial(<span class="hljs-number">3</span>)

fatorial(<span class="hljs-number">4</span>)

fatorial(<span class="hljs-number">5</span>)
</code></pre>
<p>Perceba que sempre que a função fatorial é chamada, ela cria uma nova stack, e quando a função termina de executar, a stack é removida da memória.</p>
<p>Lembre-se, sempre que uma função é chamada, ela cria uma nova stack, e ela só é removida da memória quando a função termina de executar.</p>
<h3 id="heading-recapitulando">Recapitulando</h3>
<ul>
<li><p>Uma função recursiva é uma função que chama ela mesma.</p>
</li>
<li><p>Uma função recursiva precisa de um caso base, que é o ponto em que a função não chama ela mesma novamente, e retorna um valor.</p>
</li>
<li><p>Caso não tenha um caso base, a função entra em um loop infinito.</p>
</li>
<li><p>Quando uma função é chamada, ela cria uma nova stack, e quando a função termina de executar, a stack é removida da memória.</p>
</li>
<li><p>Cada stack é criada quando uma função é chamada, sendo removida da memória quando a função termina de executar.</p>
</li>
</ul>
<h3 id="heading-finalizacao">Finalização</h3>
<p>Dessa vez eu tentei usar mais de uma linguagem para exemplificar para deixar claro que estrutura de dados e algoritmos são independentes de linguagem.</p>
<p>Essa foi uma pequena documentação dos meus estudos, espero que possa ajudar mais pessoas.<br />Qualquer dúvida, correção ou sugestão pode deixar nos comentários.</p>
]]></content:encoded></item><item><title><![CDATA[Ordenação por Seleção — Arrays e Listas]]></title><description><![CDATA[Irei escrever sobre algoritmos e estruturas de dados em paralelo com o livro Entendendo Algoritmos: Um Guia Ilustrado Para Programadores e Outros Curiosos de Aditya Y. Bhargava.
Estou usando o livro para aprender sobre algoritmos e estruturas de dado...]]></description><link>https://luizschons.com/ordenac3a7c3a3o-por-selec3a7c3a3o-arrays-e-listas-7ad95053b866</link><guid isPermaLink="true">https://luizschons.com/ordenac3a7c3a3o-por-selec3a7c3a3o-arrays-e-listas-7ad95053b866</guid><dc:creator><![CDATA[Luiz Schons]]></dc:creator><pubDate>Fri, 17 Mar 2023 01:13:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586153368/7f7774c0-05af-4a9d-9cbf-9c25b24db561.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Irei escrever sobre algoritmos e estruturas de dados em paralelo com o livro <a target="_blank" href="https://www.amazon.com.br/Entendendo-Algoritmos-Ilustrado-Programadores-Curiosos/dp/8575225634/ref=sr_1_1?qid=1677021688&amp;refinements=p_27%3AAditya+Y.+Bhargava&amp;s=books&amp;sr=1-1">Entendendo Algoritmos: Um Guia Ilustrado Para Programadores e Outros Curiosos</a> de Aditya Y. Bhargava.</p>
<p>Estou usando o livro para aprender sobre algoritmos e estruturas de dados, e escrever sobre o que estou aprendendo, pois acredito que assim eu consiga fixar melhor o conteúdo.</p>
<h3 id="heading-capitulo-1-ordenacao-por-selecao">Capítulo 1 — Ordenação por Seleção</h3>
<h3 id="heading-arrays-e-listas-encadeadas">Arrays e Listas Encadeadas</h3>
<p>Arrays e listas encadeadas são estruturas de dados que armazenam uma coleção de itens. A diferença entre elas é que os arrays são armazenados em blocos de memória contíguos, enquanto as listas encadeadas são armazenadas em blocos de memória não contíguos.</p>
<p>Nesse capítulo do livro, é ensinado a construir um algoritmo de ordenação, pois muitos algoritmos de busca e outros algoritmos dependem de uma lista ordenada para funcionar, como, por exemplo, o algoritmo de pesquisa binária.</p>
<h3 id="heading-como-funciona-a-memoria">Como funciona a memória?</h3>
<p>A memória é um conjunto de células de memória, cada uma com um endereço único. Cada célula de memória pode armazenar um byte de informação. Um byte é um conjunto de 8 bits, e cada bit pode ser 0 ou 1.</p>
<p>Eu gosto do exemplo da biblioteca para entender como funciona a memória. Imagine que você está na biblioteca e quer pegar um livro. Você vai até a estante e pega o livro que está na posição 1. Depois você vai até a estante e pega o livro que está na posição 2. E assim por diante. Cada livro tem um número de identificação único, e você pode pegar o livro que você quiser, desde que você saiba o número de identificação dele.</p>
<p>A memória funciona da mesma forma. Cada célula de memória tem um endereço único, e você pode acessar qualquer célula de memória desde que você saiba o endereço dela.</p>
<h3 id="heading-listas-encadeadas">Listas Encadeadas</h3>
<p>Uma lista encadeada é uma estrutura de dados que armazena uma coleção de itens. Cada item da lista contém um campo de dados e um campo de referência. O campo de dados armazena o valor do item, e o campo de referência armazena o endereço da próxima célula de memória.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586149562/721e8b3f-b605-4896-a5f9-518ee2bd46ae.png" alt /></p>
<p>Referência: <a target="_blank" href="https://saulo.arisa.com.br/wiki/index.php/Listas_Encadeadas_Simples">https://saulo.arisa.com.br/wiki/index.php/Listas_Encadeadas_Simples</a></p>
<p>Dessa forma, a lista encadeada é armazenada em blocos de memória não contíguos. O primeiro item da lista é armazenado em uma célula de memória, e o campo de referência desse item aponta para o endereço da próxima célula de memória. A próxima célula de memória armazena o segundo item da lista, e o campo de referência desse item aponta para o endereço da próxima célula de memória. E assim por diante.</p>
<p>Você pode acessar qualquer item da lista encadeada desde que você saiba o endereço do item que você quer acessar.</p>
<h3 id="heading-arrays">Arrays</h3>
<p>Um array é uma estrutura de dados que armazena uma coleção de itens. Cada item do array é armazenado em uma célula de memória, e cada célula de memória tem um endereço único.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728586151216/e67959cd-dd8b-4de8-bcca-2c7d7ede86cd.png" alt /></p>
<p>Referência: <a target="_blank" href="https://www.geeksforgeeks.org/array-data-structure/">https://www.geeksforgeeks.org/array-data-structure/</a></p>
<p>Já que cada célula de memória tem um endereço único, você pode acessar qualquer item do array desde que você saiba o endereço do item que você quer acessar.</p>
<p>No entanto, os arrays são armazenados em blocos de memória contíguos. Isso significa que você não pode adicionar um novo item no meio do array, pois você precisaria mover todos os itens depois do item que você quer adicionar para uma nova posição na memória.</p>
<h3 id="heading-desempenho">Desempenho</h3>
<p>O desempenho de um algoritmo é medida em termos de tempo e espaço. O tempo é medido em termos de operações básicas, e o espaço é medido em termos de memória.</p>
<p>Caso você não saiba o que é Notação Big O, eu recomendo que você leia o artigo <a target="_blank" href="https://medium.com/@schonsluuiz/introdu%C3%A7%C3%A3o-a-algoritmos-nota%C3%A7%C3%A3o-big-o-d1d555b5e0e9">Introdução a algoritmos — Notação Big O</a>.</p>
<p>O tempo de execução de um algoritmo é medido em termos de operações básicas. Uma operação básica é uma operação que leva o mesmo tempo para ser executada, independentemente do tamanho da entrada.</p>
<p>No caso de um array, a operação básica é a leitura de um item. No caso de uma lista encadeada, a operação básica é a leitura de um item e a leitura do campo de referência. Dessa forma, a operação básica de uma lista encadeada é mais complexa que a operação básica de um array, pois são necessárias duas leituras para acessar um item.</p>
<p>Por outro lado, a operação de adicionar ou remover um item de um array é mais complexa que a operação de adicionar ou remover um item de uma lista encadeada, pois é necessário mover todos os itens depois do item que você quer adicionar ou remover.</p>
<h3 id="heading-recapitulando">Recapitulando</h3>
<ul>
<li>Arrays e listas encadeadas são estruturas de dados que armazenam uma coleção de itens.</li>
<li>Os arrays são armazenados em blocos de memória contíguos, enquanto as listas encadeadas são armazenadas em blocos de memória não contíguos.</li>
<li>Arrays possuem um tamanho fixo, enquanto listas encadeadas não possuem um tamanho fixo.</li>
<li>Cada célula de memória tem um endereço único, e você pode acessar qualquer célula de memória desde que você saiba o endereço dela.</li>
<li>A desempenho de um algoritmo é medida em termos de tempo e espaço. O tempo é medido em termos de operações básicas, e o espaço é medido em termos de memória.</li>
<li>A operação básica de uma lista encadeada é mais complexa que a operação básica de um array, pois são necessárias duas leituras para acessar um item.</li>
<li>A operação de adicionar ou remover um item de um array é mais complexa que a operação de adicionar ou remover um item de uma lista encadeada, pois é necessário mover todos os itens depois do item que você quer adicionar ou remover.</li>
</ul>
<h3 id="heading-finalizacao">Finalização</h3>
<p>Essa foi uma pequena documentação dos meus estudos, espero que possa ajudar mais pessoas.<br />Qualquer dúvida, correção ou sugestão pode deixar nos comentários.</p>
]]></content:encoded></item></channel></rss>