Blog

  • Quando Confiar é Mais Rápido: O Papel do Optimistic Locking em Arquiteturas de Alta Escalabilidade

    Quando Confiar é Mais Rápido: O Papel do Optimistic Locking em Arquiteturas de Alta Escalabilidade

    Com o crescimento exponencial das aplicações web e mobile, as arquiteturas de software precisam evoluir para lidar com volumes cada vez maiores de requisições e dados. Nesse contexto, a escalabilidade e a eficiência se tornam requisitos essenciais. Uma das estratégias que mais se destacam nesse cenário é o Optimistic Locking.

    Diferente das abordagens tradicionais baseadas em bloqueios, essa técnica parte do princípio de que conflitos são exceções, não a regra, permitindo que múltiplas transações acessem e modifiquem dados simultaneamente. Este artigo explora como e por que confiar nessa abordagem pode, paradoxalmente, tornar sistemas mais rápidos e previsíveis em ambientes de alta concorrência.

    Fundamentos do Optimistic Locking

    Definição e Princípios

    Optimistic Locking é uma técnica de controle de concorrência que assume que a maioria das transações ocorre sem conflitos. Em vez de bloquear recursos durante sua manipulação, o sistema permite que diversas transações operem paralelamente sobre os mesmos dados, resolvendo eventuais inconsistências apenas no momento da confirmação das alterações. Essa estratégia reduz o tempo de espera e aumenta a taxa de throughput, tornando-se particularmente eficiente em cenários distribuídos.

    Trata-se de uma das formas mais eficazes de ampliar a concorrência sem degradar a consistência, especialmente em sistemas de alta carga. A sincronização é adiada para os momentos em que realmente se faz necessária, o que maximiza o paralelismo e reduz o tempo ocioso de recursos (GRAMOLI; KUZNETSOV; RAVI, 2012).

    O Custo da Concorrência e o Papel da Memória Transacional

    A escolha entre Optimistic e Pessimistic Locking não é trivial. O custo de gerenciar concorrência pode, em alguns casos, superar os ganhos obtidos com o paralelismo, principalmente quando o sistema depende fortemente de bloqueios transacionais (KUZNETSOV; RAVI, 2011). Por isso, compreender o perfil das operações e a frequência dos conflitos é essencial para definir a abordagem ideal.

    Por outro lado, soluções baseadas em validação de versões ou timestamps conseguem reduzir drasticamente o overhead de sincronização, mantendo a integridade dos dados com menor impacto na performance.

    Optimistic Locking surge, portanto, como um ponto de equilíbrio entre liberdade e segurança. Ele reduz a contenção sem comprometer a integridade, principalmente quando aliado a mecanismos de retry automatizado e processamento assíncrono em filas distribuídas.

    Latência, Previsibilidade e Arquiteturas Modernas

    Soluções modernas, como o sistema Plor (CHEN et al., 2022), evidenciam que a previsibilidade da latência é um dos maiores desafios em sistemas transacionais. O Optimistic Locking, quando corretamente implementado, contribui para reduzir a tail latency, o tempo de resposta nos piores casos, resultando em operações mais uniformes e previsíveis (CHEN et al., 2022).

    Infraestruturas de grande escala, como as da ByteDance, aplicam princípios de controle otimista em seus sistemas de agendamento e gerenciamento de recursos, exemplificados pelo projeto Gödel (XIANG et al., 2023). A filosofia é simples, mas poderosa: sincronizar o mínimo possível, confiar nas estatísticas de sucesso e otimizar o desempenho para o caso comum.

    Confiar sem Perder Consistência

    Em bancos NoSQL, onde a consistência eventual é frequentemente adotada, o equilíbrio entre desempenho e integridade é ainda mais delicado. Kanungo e Morena (2024) destacam que o modelo de consistência impacta diretamente o throughput e, consequentemente, a experiência do usuário (KANUNGO; MORENA, 2024).

    Optimistic Locking atua como uma ponte entre os mundos da consistência forte e da escalabilidade global: ele possibilita operações consistentes localmente, sem comprometer o desempenho em larga escala.

    Além disso, em ecossistemas baseados em mensageria e microserviços independentes, essa abordagem se mostra especialmente vantajosa. O controle é distribuído, e o custo de um rollback isolado tende a ser muito menor do que o de manter bloqueios persistentes entre serviços.

    Como Funciona

    Processo Básico

    O funcionamento do Optimistic Locking pode ser dividido em três etapas principais:

    1. Leitura: o sistema obtém o estado atual do recurso.
    2. Modificação: a aplicação realiza as alterações localmente, em memória.
    3. Validação: antes de confirmar as mudanças, o sistema verifica se o dado não foi alterado por outra transação.

    Imagem SVG do Artigo

    Comparação com o Pessimistic Locking

    A principal vantagem do Optimistic Locking é sua capacidade de maximizar a concorrência. Em sistemas onde os conflitos são raros, essa abordagem permite um desempenho significativamente superior, pois evita bloqueios desnecessários e libera recursos mais rapidamente.

    Pessimistic Locking, em contrapartida, bloqueia recursos até que a transação seja concluída, o que pode gerar contenção e degradação de desempenho em cenários de alta carga. O resultado é um aumento na latência e no tempo de espera, especialmente em sistemas com grande volume de transações simultâneas.

    Implementação do Optimistic Locking em C#

    Exemplo Básico

    A seguir, apresentamos um exemplo simplificado de como implementar o Optimistic Locking em C# utilizando Entity Framework:

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        [Timestamp] // Atributo para controle de versão
        public byte[] RowVersion { get; set; }
    }
    
    public void UpdateProduct(Product updatedProduct)
    {
        using (var context = new ApplicationDbContext())
        {
            context.Products.Attach(updatedProduct);
            context.Entry(updatedProduct).State = EntityState.Modified;
    
            try
            {
                context.SaveChanges(); // Tentativa de salvar as alterações
            }
            catch (DbUpdateConcurrencyException)
            {
                // Tratamento de conflito
                Console.WriteLine("O produto foi modificado por outra transação.");
            }
        }
    }

    Exemplo Avançado com Transações

    Para cenários mais complexos, considere o seguinte exemplo que utiliza transações explícitas:

    public void UpdateProductWithTransaction(Product updatedProduct)
    {
        using (var transaction = context.Database.BeginTransaction())
        {
            try
            {
                context.Products.Attach(updatedProduct);
                context.Entry(updatedProduct).State = EntityState.Modified;
                context.SaveChanges();
                transaction.Commit(); // Confirma as alterações
            }
            catch (DbUpdateConcurrencyException)
            {
                transaction.Rollback(); // Reverte a transação em caso de conflito
                Console.WriteLine("Conflito detectado ao atualizar o produto.");
            }
        }
    }

    Quando Usar o Optimistic Locking

    Cenários Ideais

    O Optimistic Locking é ideal em cenários onde:

    • As operações de escrita são raras em relação às operações de leitura.
    • Os dados frequentemente não são atualizados simultaneamente por múltiplas transações.
    • A latência deve ser minimizada, e o tempo de espera deve ser reduzido.

    Cenários a Evitar

    Por outro lado, o uso do Optimistic Locking deve ser evitado quando:

    • As transações de escrita são frequentes e ocorrem em alta concorrência.
    • Os dados precisam de um controle de concorrência estrito.

    Conclusão

    O Optimistic Locking se apresenta como uma solução eficaz para melhorar o desempenho e a escalabilidade em sistemas modernos. Ao adotar essa abordagem, desenvolvedores podem oferecer experiências de usuário mais rápidas e responsivas, mesmo sob alta carga. A confiança nos dados e a capacidade de operar em ambientes de alta concorrência são fundamentais para o sucesso das aplicações contemporâneas.

    Referências

    • GRAMOLI, Vincent; KUZNETSOV, Petr; RAVI, Srivatsan. Optimism for boosting concurrency. arXiv preprint arXiv:1203.4751, 2012.
    • KUZNETSOV, Petr; RAVI, Srivatsan. On the cost of concurrency in transactional memory. In: International Conference On Principles Of Distributed Systems. Berlin, Heidelberg: Springer Berlin Heidelberg, 2011. p. 112-127.
    • CHEN, Youmin et al. Plor: General transactions with predictable, low tail latency. In: Proceedings of the 2022 International Conference on Management of Data. 2022. p. 19-33.
    • KANUNGO, Sonal; MORENA, Rustom D. Original Research Article Concurrency versus consistency in NoSQL databases. Journal of Autonomous Intelligence, v. 7, n. 3, 2024.
    • XIANG, Wu et al. Gödel: Unified large-scale resource management and scheduling at bytedance. In: Proceedings of the 2023 ACM Symposium on Cloud Computing. 2023. p. 308-323.
  • Os riscos ocultos de criar um site somente com IA

    Os riscos ocultos de criar um site somente com IA

    Por que a adoção tecnológica precisa evoluir junto com a responsabilidade técnica, a atuação humana e uma visão sustentável de longo prazo

    image.jpeg
    Reprodução/Freepik

    Tenho observado algo interessante nos últimos meses. Cada vez mais profissionais digitais, empreendedores e até desenvolvedores experientes começaram a criar sites inteiros usando apenas inteligência artificial.

    Você descreve a ideia, espera alguns minutos e recebe layout, texto, imagem e até trechos de código prontos. Parece o cenário perfeito de produtividade, mas, quando olhamos mais a fundo, essa rapidez vem carregada de riscos que nem sempre aparecem à primeira vista.

    Antes, desenvolver um site envolvia planejamento, validação técnica e testes. Era comum revisar cada linha de código e definir claramente o que o projeto deveria atender. Agora, muita gente publica direto o que a IA entrega porque “funciona”, sem entender o que está por trás.

    O visual pode estar impecável, mas, por dentro, há vulnerabilidades, falhas de conformidade e riscos jurídicos que só aparecem quando o site já está no ar.

    Quando o problema começa?

    A IA é excelente para agilizar, mas geralmente não tem senso de responsabilidade técnica ou legal. Ela se baseia em exemplos públicos e, muitas vezes, traz soluções genéricas. O que um desenvolvedor normalmente revisaria passa despercebido.

    Os erros mais comuns que tenho visto incluem:

    • uso de dependências antigas;

    • formulários sem validação adequada;

    • endpoints acessíveis sem autenticação;

    • trechos de código com risco de XSS, SQL Injection e CSRF.

    E há outro ponto delicado: na pressa, muita gente acaba colocando informações sensíveis nos prompts, como senhas ou chaves de API. Pode parecer inofensivo no momento, mas, uma vez registrado no histórico, não dá para garantir que ficará protegido.

    Uma pesquisa com desenvolvedores em grandes companhias americanas mostra que 92% já utilizam inteligência artificial no trabalho ou em projetos pessoais. A tecnologia está em alta, mas nem sempre acompanhada da mesma maturidade na hora de validar os riscos.

    Dados, formulários e compliance: onde geralmente falha

    Quando a IA gera páginas com formulários ou login, as proteções básicas quase nunca vêm configuradas. Se o site coleta informações de usuários, entram regras como LGPD e GDPR, que exigem clareza sobre finalidade, armazenamento e retenção dos dados.

    Entre os itens mais esquecidos estão política de privacidade, aviso de cookies, base legal para tratamento dos dados e até opções para exclusão ou portabilidade.

    Quando envolve pagamento, o cenário fica ainda mais crítico. Conectar APIs alternativas ou endpoints não oficiais pode abrir espaço para fraudes e comprometer a reputação do negócio.

    Infraestrutura faz diferença

    Mesmo que o código não tenha sido construído da melhor forma, a infraestrutura certa pode evitar que uma falha se transforme em um incidente durante a operação. Hospedagens mais modernas já incluem proteções automáticas, como:

    • SSL ativo desde o início, garantindo que a comunicação entre usuário e servidor seja criptografada ainda no primeiro acesso.

    • HTTPS obrigatório em todas as rotas, impedindo a troca de dados por conexões inseguras e reduzindo brechas para interceptação.

    Além disso, oferecem recursos como CDN com mitigação de ataques, servidores auditados e integrações seguras com bancos de dados e serviços de pagamento, reduzindo a exposição a riscos mesmo em projetos criados com agilidade.

    Um recurso que considero fundamental é o uso de variáveis de ambiente pelo painel da hospedagem. Isso permite que a equipe configure senhas e tokens com segurança, sem precisar incluir esses dados diretamente no prompt da IA ou dentro do código.

    IA é ótima como parceira criativa, mas não como responsável técnica

    Eu costumo dizer que a IA funciona como aceleradora de ideias. Afinal, a tecnologia ajuda a testar caminhos, sugerir estruturas e reduzir tarefas repetitivas.

    Mas confiar que ela dará a validação final é arriscado. Essas ferramentas não avaliam conformidade, não identificam riscos operacionais e não têm percepção de impacto regulatório.

    A revisão humana continua sendo indispensável. Quem entende de tecnologia sabe que publicar algo é uma decisão de responsabilidade, não apenas de velocidade.

    Rapidez é importante, desde que acompanhada de controle

    Criar um site em minutos é um marco tecnológico, e isso precisa ser reconhecido. Mas colocar algo no ar sem revisão é como pisar fundo no acelerador sem saber se o freio vai responder. A velocidade empolga, mas o risco está logo à frente.

    A evolução não está em escolher entre agilidade ou segurança, mas na soma das duas. Ou seja, IA como apoio criativo, infraestrutura como proteção e olhar técnico como etapa final, o que permite avançar rápido sem comprometer o projeto.

    No Brasil, já sentimos o impacto dessa transformação: entre a população conectada, 93% utiliza esse tipo de ferramenta. Isso mostra o potencial, mas também reforça a importância de conduzir esse avanço com cautela.

    O futuro do desenvolvimento digital precisa ser sustentável e pensado com responsabilidade. A tecnologia continua avançando, mas ainda é a atuação do especialista humano que garante que esse progresso gere resultados consistentes.

    Como a Hostinger facilita a segurança

    Usar ferramentas como o Hostinger Horizons reduz significativamente esses riscos, porque a infraestrutura já incorpora camadas essenciais de proteção. Mesmo que a IA gere algo com falhas, o ambiente ao redor ajuda a compensar.

    Alguns recursos que tornam o processo mais seguro:

    • SSL ativado automaticamente

    • HTTPS obrigatório

    • CDN integrada com mitigação de ataques

    • servidores auditados e certificações como ISO

    • validação automática de código e alertas de erro

    • prompts de revisão de segurança dentro da própria ferramenta

    • integrações nativas com bancos de dados e gateways confiáveis

    Outro ponto importante é que o Horizons não exige que você cole chaves sensíveis no prompt. É possível adicionar variáveis de ambiente diretamente no sistema, o que evita um dos erros mais comuns em projetos criados com IA.

  • N8N: O que é a ferramenta open source que está revolucionando a automação em TI?

    N8N: O que é a ferramenta open source que está revolucionando a automação em TI?

    A automação de processos deixou de ser um recurso restrito a grandes corporações para se tornar parte essencial da rotina de tecnologia em empresas de todos os portes. Nesse contexto, o N8N, plataforma open source de automação de fluxos, vem ganhando espaço entre equipes de TI que buscam eficiência, integração e maior controle sobre suas operações.

    O N8N permite conectar diferentes sistemas e criar fluxos automatizados por meio de uma interface visual simples. Com isso, tarefas repetitivas passam a ser executadas automaticamente, reduzindo erros manuais e liberando tempo para atividades mais estratégicas. A ferramenta tem sido usada para integrar aplicações de CRM, ERP, bancos de dados, APIs e outros serviços, funcionando como um elo entre setores que antes operavam de forma isolada.

    O modelo open source tem um papel central nesse avanço. Por ser de código aberto, o N8N pode ser instalado, modificado e escalado livremente, sem as restrições de licenciamento típicas de soluções proprietárias. Essa característica atrai especialmente empresas que buscam autonomia tecnológica e custos mais previsíveis em suas operações.

    Automação como caminho para eficiência

    Equipes de tecnologia que adotam o N8N relatam ganhos expressivos em produtividade. O sistema permite criar fluxos que automatizam desde tarefas simples, como notificações e atualizações de planilhas, até integrações mais complexas entre sistemas de gestão e plataformas de comunicação. Essa capacidade de adaptação faz com que a ferramenta seja usada em diferentes áreas, do marketing ao suporte técnico.

    Além da economia de tempo, a automação de fluxos traz precisão operacional. Processos que dependiam de atualizações manuais passam a seguir regras pré-definidas, evitando falhas humanas e garantindo que as informações circulem de forma mais consistente entre as equipes. Isso melhora a comunicação interna e contribui para decisões baseadas em dados mais confiáveis.

    Outro fator importante é o impacto sobre a cultura organizacional. Ao reduzir tarefas repetitivas, a automação permite que profissionais de TI se concentrem em atividades analíticas e de inovação, aumentando o valor estratégico da área dentro das empresas.

    O papel do open source na transformação digital

    O crescimento do N8N reflete um movimento mais amplo de valorização das tecnologias open source no ambiente corporativo. Cada vez mais, empresas reconhecem que o acesso ao código-fonte permite maior personalização, segurança e independência de fornecedores. Esse modelo colaborativo também incentiva a troca de conhecimento entre desenvolvedores e acelera a evolução das ferramentas.

    Um relatório recente da Perforce Software, elaborado em parceria com a Eclipse Foundation e a Open Source Initiative, indica que 95% das organizações globais mantiveram ou ampliaram o uso de software open source em 2025.

    Infraestrutura e implantação sob medida

    Um dos diferenciais do N8N é a liberdade de escolha na forma de hospedagem. Ele pode ser executado em nuvem pública, em servidores dedicados ou em ambientes próprios, de acordo com as necessidades de cada organização. Essa versatilidade facilita a adequação a políticas internas de segurança e conformidade.

    Provedores de infraestrutura já começaram a incluir o N8N em seus catálogos de soluções, oferecendo instaladores automatizados e opções de hospedagem gerenciadas. Entre eles estão empresas que disponibilizam a ferramenta em ambiente auto-hospedado, como é o caso da KingHost, permitindo rodar fluxos ilimitados em um servidor VPS. Essa configuração garante total controle sobre o desempenho e liberdade de automação, além de reduzir custos de operação.

    Para equipes de TI, essa flexibilidade representa um ganho estratégico. A instalação local elimina dependências externas e possibilita ajustes finos de acordo com o volume de dados ou a complexidade dos fluxos criados.

    Automação no centro das estratégias de TI

    A busca por eficiência operacional e integração entre sistemas coloca a automação como prioridade nas estratégias de tecnologia corporativa. O N8N tem se destacado por unir simplicidade e robustez, oferecendo às empresas uma forma prática de conectar diferentes plataformas e otimizar processos.

    Ao adotar a ferramenta, as organizações criam fluxos automatizados que reduzem a carga de trabalho manual e aumentam a velocidade de resposta das equipes. Isso contribui diretamente para a agilidade dos negócios e a sustentabilidade das operações.

    Em um cenário em que os dados precisam circular rapidamente entre diferentes áreas, a automação de fluxos deixa de ser uma conveniência e passa a ser um requisito. Ferramentas como o N8N demonstram que é possível alcançar esse nível de integração com baixo investimento e alto grau de personalização.

    Um novo estágio da automação corporativa

    O avanço do N8N mostra que a automação está se tornando um componente estrutural das estratégias de TI. A combinação de código aberto, facilidade de uso e ampla compatibilidade com outras ferramentas faz da plataforma uma solução adequada para empresas que desejam crescer de forma sustentável e independente.

    A tendência é que o N8N continue ganhando espaço à medida que mais organizações percebem os benefícios de controlar suas próprias integrações e fluxos de trabalho. Com a expansão do uso de soluções open source, a automação deixa de ser apenas uma questão técnica e passa a representar um movimento de transformação cultural dentro das empresas.

  • Um Segredo do # Predicate em Swift: Por Que Uma Linha Muda Tudo?

    Um Segredo do # Predicate em Swift: Por Que Uma Linha Muda Tudo?

    Um “predicate” é uma condição booleana usada para selecionar ou filtrar registros. Ele responde “este objeto atende ao critério?” e retorna verdadeiro ou falso.

    Em bancos/ORMs, o predicate é enviado para o mecanismo de persistência, que retorna apenas os registros que satisfazem a condição.

    Já no ecossistema da Apple temos:

    • NSPredicate: API clássica (Core Data, Foundation) baseada em strings formatadas, como `NSPredicate(format: “age >= %d”, 18)` . É flexível, mas menos segura (erros só aparecem em runtime).
    • #Predicate: DSL moderno e tipado (SwiftData/SwiftUI). Você escreve condições com código Swift e o macro gera uma expressão booleana segura em tempo de compilação.

    Uso em SwiftData/SwiftUI

    @Query(filter: #Predicate<Model> { … }) , o $0 representa um registro do tipo Model . Você compara campos com valores capturados:

    // Exemplo com strings: 
    #Predicate<CompanyAndLocation> { 
      $0.company.name == companyName && $0.location.location == locationName 
    }
    
    // Exemplo por identidade:
    #Predicate<CompanyAndLocation> { 
      $0.company.id == companyId && $0.location.id == locationId 
    }

    Isso permite que o filtro rode no store, retornando apenas os itens que batem com o critério.

    Quando usar o #Predicate?

    • Filtrar uma coleção persistida via @Query ou FetchDescriptor para trazer do banco somente o que importa.
    • Substitui NSPredicate quando você quer segurança de tipos e integração direta com SwiftData.

    Quais são as vantagens do #Predicate?

    • Tipado e checado em compile-time.
    • Integra-se ao @Query e FetchDescriptor , reduzindo erros de formatação.
    • Melhora completions e refatorações (se você renomear um campo, o compilador ajuda).

    Cuidado com algumas pequenas armadilhas!?

    • Comparar “key path com key path” em vez de “campo com valor” causa erros de tipo no DSL.
    • Referenciar self ou propriedades de @Model dentro do bloco sem capturar valores simples pode quebrar a expansão do macro.
    • Comparar relacionamentos por objeto inteiro pode falhar dependendo da versão do SDK; comparar por id ou por atributos únicos é mais robusto.

    Show me the code:

    // PredicateApp.swift
    
    import SwiftUI
    import SwiftData
    
    @main
    struct PredicateApp: App {
        var body: some Scene {
            WindowGroup {
                DataView(
                    company: Company(name: "Company 1", type: 1),
                    location: Location(location: "Location 1", value: 100)
                )
            }
        }
    }
    // CompanyAndLocation.swift
    
    import SwiftData
    @Model
    class Company {
      #Unique<Company>([\.name])
      var name: String
      var type: Int
    
      init(name: String, type: Int) {
        self.name = name
        self.type = type
      }
    }
    
    @Model
    class Location {
      #Unique<Location>([\.location])
      var location: String
      var value: Int
        
      init(location: String, value: Int) {
        self.location = location
        self.value = value
      }
    }
    
    @Model
    class CompanyAndLocation {
      #Unique<CompanyAndLocation>([\.company, \.location])
      var company: Company
      var location: Location
        
      init(company: Company, location: Location) {
        self.company = company
        self.location = location
      }
    }
    // DataView.swift
    
    import SwiftUI
    import SwiftData
    
    struct DataView: View {
        
        @Environment(\.modelContext) var modelContext
        var company: Company
        var location: Location
        @Query var companyAndLocation: [CompanyAndLocation]
        
        var body: some View {
            Text("Hello World!")
        }
        
        init(company: Company, location: Location) {
            self.company = company
            self.location = location
            
            let predicate = #Predicate<CompanyAndLocation>
            {
                $0.company == self.company && $0.location == self.location
            }
            
            _companyAndLocation = Query(filter: predicate)
        }
    }

    Crie um projeto SwiftUI, adicione estes 3 arquivos e compile o projeto. E se você este erro significa que está tudo certo (em receber o erro).

    Cannot convert value of type 'PredicateExpressions.Conjunction<PredicateExpressions.
    Equal<PredicateExpressions.KeyPath<PredicateExpressions.Variable<CompanyAndLocation>, Company>, 
    PredicateExpressions.KeyPath<PredicateExpressions.Value<DataView>, Company>>, 
    PredicateExpressions.Equal<PredicateExpressions.KeyPath<PredicateExpressions.Variable<CompanyAndLocation>, 
    Location>, PredicateExpressions.KeyPath<PredicateExpressions.Value<DataView>, 
    Location>>>' to closure result type 'any StandardPredicateExpression<Bool>'

    Esse erro indica que estamos tentando comparar objetos complexos diretamente, quando o #Predicate só aceita comparações de tipos escalares (Int, String, UUID, etc.). Também o erro indica que o fechamento de Predicate está retornando um tipo interno do DSL (Conjunction<Equal<…>> ) que não está sendo aceito como any StandardPredicateExpression, normalmente por construção incorreta do predicate (mistura de variável x valor ou uso de key paths em vez de valores).

    O problema está nesta parte do código:

    let predicate = #Predicate<CompanyAndLocation>
    {
      $0.company == self.company && $0.location == self.location
    }

    Poderíamos resolver assim:

    let companyName = company.name
    let locationName = location.location
    let predicate = #Predicate<CompanyAndLocation> 
    {
      $0.company.name == companyName && $0.location.location == locationName
    }

    Se eu não precisasse comparar o objeto completo. Mas e se eu precisasse?Neste caso para 2 propriedades seria simples, mas se este objeto tivesse mais propriedades? E se esse objeto fosse atualizado com mais propriedades com o decorrer do tempo? Então eu teria que voltar nesse código para atualizá-lo e garantir uma comparação completa.

    Podemos tentar assim:

    let predicate = #Predicate<CompanyAndLocation> {
      $0.company.id == company.id && $0.location.id == location.id
    }

    Aqui estamos tentando acessar company.id e location.id diretamente. O macro não consegue rastrear essas propriedades dinâmicas de objetos externos. Ele espera valores simples e escalares que possam ser “capturados” como constantes. Ou seja, não funciona.

    A solução: Compare os identificadores, não os objetos:

    Essa é uma questão comum com Swift’s #Predicate macro. O problema está em como o macro captura variáveis. O #Predicate funciona através de type-safe query generation, ou seja, precisa traduzir sua expressão Swift para uma query que pode ser executada no banco de dados (CoreData ou SwiftData).

    Então resolvemos assim:

    let companyId = company.id
    let locationId = location.id
    let predicate = #Predicate<CompanyAndLocation> 
    {
      $0.company.id == companyId && $0.location.id == locationId
    }
    • As variáveis companyId e locationId são capturadas pelo closure como valores simples (Equatable)
    • O macro consegue identificá-las como constantes externas e substituí-las corretamente na query

    Conclusão:

    #Predicate só consegue traduzir para queries de banco de dados expressões que comparam valores escalares (números, strings, UUIDs). Comparações entre objetos complexos não podem ser traduzidas para SQL/query de dados.

    Então dentro de um #Predicatecompare os identificadores e não os objetossempre extraia os valores que você quer comparar em variáveis locais simples antes de usá-las no closure. Isso permite que o macro entenda exatamente quais constantes devem ser “compiladas” na query.

    If you’ve enjoyed this article, subscribe and get an email as soon as I publish!
    Happy Coding!

  • Melhores práticas de segurança com o GitHub Copilot

    Melhores práticas de segurança com o GitHub Copilot

    Todo mundo quer escrever código limpo, funcional e… seguro. 

    A parte da segurança às vezes passa batida, principalmente se você não teve treinamento específico nessa área. Mas a boa notícia é que o GitHub Copilot pode ser um ótimo aliado nesse processo.

    Neste post, vou te mostrar como usar o Copilot e outras ferramentas do GitHub para tornar seus projetos mais seguros, mesmo que você não seja especialista em segurança.

    O desafio da segurança no dia a dia

    Equipes de segurança geralmente não têm braço suficiente pra proteger todo o código de uma empresa. Resultado: quem escreve código acaba sendo a primeira linha de defesa. Só que nem todo mundo teve formação ou tempo pra estudar segurança a fundo.

    É aí que entra o GitHub. 

    Além do Copilot, existem várias ferramentas que você pode usar, principalmente se estiver trabalhando com projetos Open Source.

    O Copilot pode ajudar

    O GitHub Copilot não serve só pra escrever código rapidinho. Ele também pode te ajudar a escrever código mais seguro. Mas, claro, ele não faz mágica sozinho. Você precisa saber como usar.

    Um exemplo prático: 

    Digamos que você esteja usando uma `query SQL` com `INSERT` no seu projeto. 

    Já ouviu falar de `SQL injection`? É quando alguém mal-intencionado usa campos de entrada (como um campo de nome ou comentário) pra rodar comandos que podem comprometer todo o seu banco de dados.

    Uma forma simples de evitar isso é usar consultas parametrizadas. E você pode pedir isso diretamente ao Copilot com um comentário claro, como:

    /*

    inserir do carrinho usando uma consulta parametrizada:

    mail, product_name, user_name, product_id, address, phone, ship_date, price

    */

    O Copilot vai sugerir uma versão mais segura. Revise a sugestão, veja se faz sentido, e só então aceite.

    Outra dica: selecione um trecho de código e pergunte no Copilot Chat se ele vê alguma vulnerabilidade. Você também pode usar @workspace pra analisar o projeto inteiro. 

    Perguntas como “qual é a superfície de ataque?” ou “há alguma vulnerabilidade nesta função?” funcionam muito bem.

    Quer sugestões mais específicas? Usa o comando /fix, que sugere melhorias de segurança, performance e boas práticas.

    Ah, e se você quiser mais ideias de prompts legais, dá uma olhada no Copilot Chat Cookbook, onde você encontra exemplos de prompts para usar com o GitHub Copilot Chat.

    Ferramentas gratuitas de segurança no GitHub

    O Copilot ajuda bastante, mas você não deve confiar só nele. 

    Por isso, o GitHub oferece várias ferramentas gratuitas de segurança pra projetos públicos.

    Aqui vão algumas que eu recomendo ativar:

    Dependabot

    Ele verifica se suas dependências estão atualizadas e cria PRs automáticos quando encontra vulnerabilidades. Pra ativar, vá em Settings > Code security > Dependabot.

    Code scanning com CodeQL

    Detecta vulnerabilidades e problemas comuns no código. Vá em Settings > Code security > Code scanning, clique em Set up > Default e ative o CodeQL.

    Copilot Autofix

    Quando combinado com o Code scanning, o Copilot pode sugerir automaticamente correções pra vulnerabilidades encontradas. Fica logo abaixo do botão de ativar o CodeQL.

    Secret scanning

    Verifica se você expôs tokens, senhas ou chaves no seu repositório. E com a opção de Push protection ativada, ele bloqueia commits com segredos em tempo real.

    Tem muito mais, mas essas são ótimas pra começar. Se quiser explorar mais, recomendo a documentação de segurança do GitHub.

    Resumo pra salvar nos favoritos

    Se você chegou até aqui, aqui vai um resumão dos próximos passos:

    • Use o Copilot pra identificar e corrigir vulnerabilidades (/fix, prompts no chat, etc).
    • Ative as ferramentas de segurança do GitHub: Dependabot, CodeQL, Copilot Autofix e Secret scanning.
    • Aproveite que tudo isso é gratuito pra repositórios públicos.
    • E sempre revise o que o Copilot sugerir. Ele ajuda, mas quem valida é você.

    Gostou das dicas? Me conta o que você já usa ou se tem alguma dúvida.
    💚

     

  • Spring Boot 4 e Spring Framework 7: Principais recursos e alterações

    Spring Boot 4 e Spring Framework 7: Principais recursos e alterações

    O Spring Boot 4 será lançado em novembro de 2025 (versões Milestones já disponíveis), desenvolvido com base no novo Spring Framework 7.0.0.

    Se você desenvolve aplicativos Java modernos, esta versão traz uma série de atualizações e novos recursos que vale a pena explorar.

    Após a grande migração do Spring Boot 3.x para o Jakarta EE 10, o Spring Boot 4 continua a jornada de modernização com um alinhamento mais forte com o Jakarta EE 11, JDKs modernos e práticas de desenvolvimento nativas da nuvem. Este é um marco importante que define o tom para a próxima década de desenvolvimento Java.

    Neste artigo, destacaremos as mudanças mais importantes e o que elas significam para seus projetos.

    Atualizações da plataforma Spring Boot 4

    1. Suporte a Java e JVM

    JDK mínimo: 17 (LTS e amplamente adotado).
    JDK recomendado: 25 (lançamento em setembro de 2025).
    Alinhamento total com GraalVM 24 para compilações de imagens nativas.

    2. Alinhamento com Jakarta EE 11

    Servlet 6.1 para APIs web modernas.
    JPA 3.2 + Hibernate ORM 7.0 para persistência mais eficiente.
    Bean Validation 3.1 com restrições aprimoradas e suporte a Kotlin/registros.

    3. Suporte a Kotlin 2.2

    Suporte aos recursos da linguagem Kotlin 2.2.
    Suporte mais suave a corrotinas.
    Melhor integração com a compilação Gradle.

    4. Nativo da nuvem e conteinerização

    Buildpacks aprimorados com camadas de imagem mais rápidas.
    Compilações nativas do Docker mais eficientes.
    Integração do Micrometer 2.x + OpenTelemetry.

    5. Produtividade e experiência do desenvolvedor

    Atualizações da CLI do Spring Boot (gerenciamento de dependências, estrutura de testes).
    Novos pontos de extremidade do Actuator.
    Gerenciamento mais fácil de propriedades e perfis.

    6. Segurança

    Baseado no Spring Security 7.
    Integração mais forte com OAuth 2.2 / OIDC.
    Padrões de criptografia aprimorados.

    7. Preparação para o futuro com Spring AI e APIs nativas

    Hooks iniciais para integrações Spring AI.
    APIs melhores para dicas de imagens nativas GraalVM.

    Recursos do Spring Framework 7

    1. Versões elegantes da API

    O Spring Framework 7 agora oferece suporte a versões da API diretamente na anotação @RequestMapping, facilitando a manutenção de várias versões de seus endpoints REST e garantindo compatibilidade com versões anteriores.

    Você pode especificar a versão desejada usando o cabeçalho Versão em sua solicitação HTTP. O controlador encaminhará a solicitação para o método apropriado com base na versão fornecida.

    Para chamar a versão 1 da API (retorna uma lista simples de produtos):

    Para chamar a versão 2 da API (retorna pesquisa aprimorada com metadados):

    GET /api/products/search?query=laptop&limit=20

    2. Segurança nula com JSpecify

    O Spring Framework 7 migrou para anotações JSpecify, melhorando a segurança nula e a integração com Kotlin. O JSpecify fornece contratos de nulidade mais precisos para parâmetros de método, tipos de retorno e campos, ajudando os desenvolvedores a detectar possíveis bugs relacionados a nulos em tempo de compilação.

    Veja como você pode usar anotações JSpecify em um componente Spring:

    Neste exemplo, o parâmetro userId pode ser nulo, mas o método garante um valor de retorno diferente de nulo. Isso ajuda a evitar exceções de ponteiro nulo e melhora a confiabilidade do código, especialmente ao integrar com Kotlin ou outras linguagens nulas seguras.

    3. Registro programático de beans com BeanRegistrar

    O Spring Framework 7 introduz o contrato BeanRegistrar, permitindo que os desenvolvedores registrem beans programaticamente com mais flexibilidade. Isso é útil para cenários avançados em que vários beans precisam ser registrados dinamicamente, além do que é possível com os métodos @Bean.

    Você pode registrar beans com base nas condições de tempo de execução ou configuração externa, tornando sua aplicação mais dinâmica e modular.

    4. Suporte aprimorado para opcionais em expressões SpEL

    O SpEL (Spring Expression Language) agora oferece melhor suporte para tipos opcionais, incluindo operações null-safe e o operador Elvis. Isso facilita o trabalho com valores opcionais em configurações e definições de beans.

    Você pode lidar com valores ausentes com segurança e evitar exceções de ponteiro nulo em sua configuração e conexão de beans.

    5. Recursos de resiliência

    @Retryable, @ConcurrencyLimit, @EnableResilientMethods

    Novas anotações como @Retryable e @ConcurrencyLimit ajudam a criar aplicativos mais resilientes, habilitando a lógica de repetição e os limites de simultaneidade diretamente nos métodos de serviço. A anotação @EnableResilientMethods ativa esses recursos para os beans.

    Você pode adicionar controle de repetição e simultaneidade à sua lógica de negócios com anotações simples, melhorando a confiabilidade e a escalabilidade.

    6. Configuração dedicada para clientes HTTP com @ImportHttpServices

    O Spring Framework 7 adiciona a anotação @ImportHttpServices, facilitando a configuração e o agrupamento de clientes HTTP. Isso simplifica a configuração de aplicativos que interagem com vários serviços externos.

    Você pode organizar e configurar vários clientes HTTP de maneira eficiente, reduzindo o código padrão e melhorando a manutenção.

    7. Suporte a streaming com InputStream e OutputStream em clientes HTTP

    Os clientes HTTP agora oferecem suporte a corpos de solicitação e resposta de streaming usando InputStream e OutputStream. Isso é especialmente útil para lidar com arquivos grandes ou fluxos de dados de maneira eficiente.

    Você pode lidar com uploads e downloads de arquivos grandes sem carregar tudo na memória, melhorando o desempenho e a escalabilidade.

    8. Novo JmsClient e aprimoramentos no JdbcClient

    O novo JmsClient fornece uma API moderna para trabalhar com JMS (Java Message Service), enquanto o JdbcClient foi aprimorado para operações de banco de dados mais fáceis e flexíveis.

    Você obtém uma API mais fluente e moderna para mensagens e acesso ao banco de dados, reduzindo o código repetitivo e melhorando a produtividade do desenvolvedor.

    9. Configuração centralizada para conversores de mensagens HTTP

    O Spring Framework 7 introduz a configuração centralizada para conversores de mensagens HTTP, facilitando a personalização da forma como os dados são serializados e desserializados em aplicações web.

    Você pode personalizar facilmente a lógica de serialização e desserialização para suas APIs em um único local, melhorando a consistência e a manutenção.

    10. Novo RestTestClient para testes de API REST

    O RestTestClient é uma nova ferramenta para testes de APIs REST, oferecendo uma API fluente e suporte para servidores ativos e configurações simuladas. Ele simplifica a criação e a manutenção de testes de integração para seus pontos finais.

    Você pode escrever testes de integração concisos e legíveis para seus pontos finais REST, melhorando a cobertura e a confiabilidade dos testes.

    11. Correspondência de caminho aprimorada com suporte PathPattern melhorado

    A correspondência de caminho no Spring MVC foi aprimorada com o suporte PathPattern melhorado, substituindo opções legadas e fornecendo correspondência de modelo URI mais poderosa e flexível para seus controladores.

    Você pode definir padrões de URI mais flexíveis e poderosos para seus controladores, tornando o roteamento e o design de pontos finais mais fáceis e expressivos.

    12. Remoções e descontinuações de APIs

    O Spring Boot 4 e o Spring Framework 7 removeram vários recursos legados e descontinuaram APIs para otimizar a estrutura e incentivar práticas de desenvolvimento modernas.

    Abaixo, você encontra mais detalhes sobre cada remoção e descontinuação.

    Alterações no módulo

    O módulo spring-jcl foi descontinuado em favor do Apache Commons Logging, simplificando a infraestrutura de registro em log. Além disso, as anotações de javax.annotation e javax.inject não são mais suportadas — você precisará migrar para seus equivalentes em Jakarta: jakarta.annotation e jakarta.inject.

    Simplificação do mapeamento de caminho

    Várias opções de mapeamento de caminho foram removidas do Spring MVC. Recursos como suffixPatternMatch, trailingSlashMatch e favorPathExtension não são mais suportados em métodos de controlador anotados e negociação de conteúdo.

    Anteriormente, era possível usar o roteamento baseado em sufixo:

    Ou configure a correspondência de padrões de sufixo na configuração Java:

    Essas opções foram removidas. Em vez disso, use tipos de mídia explícitos e modelos de URI para um roteamento mais limpo e previsível.

    XML Configuration Deprecation

    XML configuration for Spring MVC is now deprecated. If you’re still using XML-based configuration like this:

    Recomenda-se migrar para a configuração baseada em Java:

    Atualizações de teste e serialização

    O suporte para JUnit 4 e Jackson 2.x também está obsoleto, incentivando a migração para JUnit 5 e versões mais recentes do Jackson para obter melhor desempenho e recursos de teste modernos.

    Lista de verificação de migração

    Atualize para JDK 17+ (recomenda-se 25).
    Substitua javax.* por jakarta.*.
    Revise a correspondência de caminho MVC — correspondência de sufixo e barra removida.
    Mova as configurações XML → configuração baseada em Java.
    Atualize os testes: JUnit 5 + Jackson 3.x.
    Verifique as dicas nativas do GraalVM se estiver usando imagens nativas.
    Java 17+, atualizações de pacotes, configurações XML e Junit 5 são algumas mudanças que você pode começar agora, para garantir que seu projeto esteja pronto e simplificar o processo de migração.

    Considerações finais

    O Spring Boot 4 e o Spring Framework 7 marcam um grande passo à frente para o desenvolvimento Java, trazendo mais segurança, flexibilidade e recursos para aplicativos modernos. Se você está pensando em atualizar seu projeto, recomendo revisar as alterações cuidadosamente e testar exaustivamente antes de passar para a produção. O Spring Boot 3.5.x atual terá suporte OSS até junho de 2026, então planeje-se adequadamente!

    Boa programação!

    Referências

    Documentação de referência do Spring Boot 4.0
    Documentação de referência do Spring Framework 7.0
    Notas de lançamento do Spring Framework 7.0
    Notas de lançamento do Spring Boot 4.0

  • Tutorial app de criptomoedas com React Native

    Tutorial app de criptomoedas com React Native

    As criptomoedas estão com tudo atualmente e neste tutorial eu vou juntar elas com outra de minhas paixões que é o desenvolvimento mobile. Eu não sei se você sabe mas minha pós-graduação foi neste assunto, em 2012-13 e anos mais tarde o primeiro livro que escrevi também foi sobre desenvolvimento mobile, o Criando apps para Empresas com Android. Já criptomoedas entraram na minha vida em 2017, no bull run que o Bitcoin teve naquela época e quando escrevi originalmente este tutorial de bot cripto.

    Para o tutorial de hoje eu quero criar com você um app de criptomoedas que funcione em Android e iOS, ajudando você a acompanhar o mercado. Nada muito elaborado, mas que sirva de primeiros passos para algo inédito e mais bacana que você tenha a ideia de construir. Usaremos aqui a tecnologia React Native, que permite criar apps nativos para estas duas plataforma usando apenas a linguagem JavaScript.

    Não apenas isso, usaremos o pacote Expo para React Native, uma plataforma que simplifica bastante o desenvolvimento e principalmente os testes e build e sem a necessidade de ter um Mac para isso.

    1 – Setup do Projeto

    O primeiro passo é você criar seu projeto usando o Expo. Para isso, use o comando abaixo em uma pasta na sua máquina, escolhendo o template Blank com JavaScript quando for questionado.

    Eu chamei meu projeto de CryptoWatch, pois é isso que basicamente ele vai ser, um “observador de criptos”, mas renomeie conforme julgar melhor.

    Após todas as dependências serem baixadas e instaladas, convém entrar na pasta cryptowatch e rodar o projeto para ver se deu tudo certo na criação.

    2 – Conectando na Stream

    A primeira coisa que vamos fazer é a que o pessoal costuma errar mais que é na conexão à stream de websockets da Binance. Para fazer isso vamos importar o hook que criamos e vamos usá-lo para estabelecer a conexão, inicialmente  fixa no par BTCUSDT.

    Isso deve ser feito no App.js, o arquivo central da nossa aplicação. Usaremos um state para que a cada atualização de dados o nosso front reaja exibindo o que recebeu.

    
    import { Text, View } from 'react-native';
    import {useState} from 'react';
    import useWebSocket from './useWebSocket';
    
    export default function App() {
    
      const [data, setData] = useState({});
    
      useWebSocket(`wss://stream.binance.com:9443/ws/btcusdt@ticker`, {
        onOpen: () => { },
        onMessage: (message) => {
            if(!message) return;
            const data = JSON.parse(message.data);
            setData({
                priceChange: parseFloat(data.p),
                priceChangePercent: parseFloat(data.P),
                close: data.c,
                high: data.h,
                low: data.l,
                quoteVolume: data.q
            });
        },
        onError: (event) => console.error(event),
        shouldReconnect: (closeEvent) => true,
        reconnectInterval: 3000
    });
    
      return (
        <View>
          <Text>{JSON.stringify(data)}</Text>
        </View>
      );
    }
    

    A configuração mais importante do hook useWebSocket é a URL onde ele vai se conectar e a função onMessage que vai ser disparada toda vez que ele receber um dado atualizado, o que vem via o objeto message. Mais à frente, vamos fazer ele se conectar na stream de dados da cripto que interessa ao usuário, ao invés de deixá-la fixa como fizemos.

    O resultado é que quando você abrir o app ele vai se conectar na Binance e passar a receber os dados atualizados de uma cripto a cada segundo, que estamos apenas colocando na tela, como abaixo.

    Cada uma dessas informações retornadas pela Binance é melhor descrita na documentação oficial deles, mas tem muita coisa de valor aí que podemos usar para construir uma tela bacana. Não consegue entender a documentação? O vídeo abaixo vai ajudar.

    Agora que aprendemos a fazer a conexão, vamos construir a nossa tela!

    #3 – Input de Dados

    Eu sou péssimo em frontend. Não me leve à mal, eu sei construir, mas falando de criatividade, de design, eu sou uma negação, hehe. Por isso que gosto de bibliotecas como Bootstrap para a web e para o React Native eu costumo usar o React Native Elements, que comentei e que deixamos instalado anteriormente. Agora vamos usá-lo!

    Ainda no app.js, vamos ajustar a tela para que tenhamos um campo de texto e um botão. O usuário digitará o par de moedas no campo e pressionará o botão, mudando a conexão para a nova stream. Não vou colocar a conexão enquanto ele digita para não ficar fazendo conexões erradas na Binance, o que poderia prejudicar a reputação do nosso IP.

    
    import { View } from 'react-native';
    import { useState } from 'react';
    import useWebSocket from './useWebSocket';
    import { Input, Text } from '@rn-vui/themed';
    import { Feather as Icon } from '@expo/vector-icons';
    
    export default function App() {
    
      const [text, setText] = useState('BTCUSDT');
      const [symbol, setSymbol] = useState('btcusdt')
      const [data, setData] = useState({});
    
      //...código do useWebSocket permanece aqui...
    
      return (
        <View style={{ flexDirection: 'column', marginTop: 40, margin: 20, alignContent: 'center' }}>
          <Text h1>CryptoWatch 1.0</Text>
          <Input
            title="Digite o par de moedas."
            autoCapitalize='characters'
            leftIcon={<Icon name='dollar-sign' size={24} color='black' />}
            value={text}
            rightIcon={<Icon.Button name="search" size={24} color='black' backgroundColor='transparent' onPress={evt => setSymbol(text.toLowerCase())} />}
            onChangeText={txt => setText(txt.toUpperCase())} />
          <Text>{JSON.stringify(data)}</Text>
        </View>
      );
    }
    

    Primeiro vamos falar das novas importações: trouxe o Input e o Text da biblioteca React Native Elements Vikalp e também o Feather, que renomeei para Icon, da biblioteca interna do Expo. Por padrão o Expo oferece várias bibliotecas de ícones pra gente e a Feather Icons é uma das mais populares. Vamos usá-los em nosso projeto.

    Adicionamos agora dois novos states, um para o texto que o usuário estará digitando e outro para o symbol (par de moedas) já digitado, e que é usado para fazer a conexão no lugar certo (repare a URL no useWebSocket). Importante frisar também que colocamos valores default nesses states.

    E a última alteração e mais drástica foi no JSX de retorno da interface, onde coloquei um Text com propriedade h1 para ser o título da tela, coloquei um input com ícone na esquerda e ícone clicável na direita (já vou falar dele) e logo abaixo ficou o texto que já tínhamos antes.

    O ícone clicável à direita do Input serve como botão de confirmação do texto digitado. Enquanto o usuário vai digitando, a propriedade onChangeText vai disparando a atualização do state text. Quando o botão é clicado, o onPress do Icon.Button é disparado, alterando o state de symbol.

    E como em toda boa aplicação React, quando um state muda, o componente é renderizado novamente.

    Repare também que adicionei vários estilos em cada componente, usando a propriedade style. Essa propriedade funciona de maneira idêntica ao CSS do mundo web.

    O resultado atualizado você confere abaixo. Experimente digitar outro par e clicar na lupa e verá que as informações abaixo passam a corresponder ao novo par.

    #4 – Listagem das Informações

    Agora vamos para a última parte do nosso app, onde vamos pegar aquelas informações que estão chegando e que hoje jogamos de qualquer jeito na tela e vamos transformar em uma tabela mais amigável para o usuário ler e entender.

    Usaremos aqui uma combinação de componentes Text, já que são textos alterados via programação, sem interferência do usuário. A base é essa aqui e será repetida à exaustão:

    
    <View style={styles.line}>
      <Text style={styles.bold}>Preço Atual: </Text>
      <Text>{data.close}</Text>
    </View>
    

    No exemplo acima, temos uma view com um estilo de linha (que vou mostrar abaixo), um text com estilo negrito pro rótulo da informação (estilo bold) e outro text com a informação que vem da stream (sem estilo algum).

    Para os estilos, você deve importar o StyleSheet do pacote react-native e criar um objeto styles definindo os estilos citados acima, como abaixo.

    
    import { View, StyleSheet } from 'react-native';
    
    const styles = StyleSheet.create({
      line: {
        flexDirection: 'row',
        width: '100%',
        marginHorizontal: 10,
        marginVertical: 10
      },
      bold: {
        fontWeight: 'bold'
      }
    })
    

    Agora, o bloco completo com todas as tags para composição das informações na tela.

    
    <View style={styles.line}>
      <Text style={styles.bold}>Preço Atual: </Text>
      <Text>{data.close}</Text>
    </View>
    <View style={styles.line}>
      <Text style={styles.bold}>Alteração: </Text>
      <Text>{getSignal(data.priceChange)} ({getSignal(data.priceChangePercent)}%)</Text>
    </View>
    <View style={styles.line}>
      <Text style={styles.bold}>Máxima 24h: </Text>
      <Text>{data.high}</Text>
    </View>
    <View style={styles.line}>
      <Text style={styles.bold}>Mínima 24h: </Text>
      <Text>{data.low}</Text>
    </View>
    <View style={styles.line}>
      <Text style={styles.bold}>Trades: </Text>
      <Text>{data.numberOfTrades}</Text>
    </View>
    <View style={styles.line}>
      <Text style={styles.bold}>Volume: </Text>
      <Text>{data.quoteVolume}</Text>
    </View>
    

    Repare que acima tem dois campos que eu uso uma função getSignal para colocar um sinal de positivo ou negativo no número. Esta função está abaixo e é bem simples. Aliás, é por causa desse ajuste que quando recebemos os campos de preço eu faço um parseFloat lá no useWebSocket.

    
    function getSignal(value) {
      return value >= 0 ? `+${value}` : value;
    }
    

    O resultado você confere abaixo.

    E com isto finalizamos este tutorial. Se você fez as outras séries de React Native que tem aqui no blog como a básica e a do CRUD agora sua cabeça está fervendo com as possibilidades. Abaixo eu listo alguns pacotes famosos que podem lhe ajudar na criação de mais funcionalidades ou mesmo de outros apps ligados a este mundo de criptomoedas:

    • EthersJS: para dapps web3 que se conecta na blockchain;
    • Axios: para consumir as APIs REST da Binance, de outras corretoras ou de backends próprios;
    • OpenAI: para criar funcionalidades que usem IA;

    Até a próxima!

    TUTORIAL VERSÃO EM VÍDEO

    Dito isso, vamos ao tutorial. Se preferir, você pode assistir ele no vídeo abaixo ao invés de ler (tem pouca variação, o post está mais atualizado).

  • 🚀 Novidades GitHub Universe 2025

    🚀 Novidades GitHub Universe 2025

    O GitHub Universe é a conferência global anual onde o GitHub anuncia as principais inovações e as ferramentas moldarão o futuro do desenvolvimento de software. A edição de 2025 marcou uma transição definitiva para a era da inteligência artificial, com um foco claro na experiência das pessoas desenvolvedoras e na capacitação das equipes.

    Com a missão de “Explorar as mais recentes ferramentas do GitHub que moldam o software agente e a escolha das pessoas desenvolvedoras”, a conferência estabeleceu um novo marco, anunciando desde um centro de controle unificado para agentes até integrações profundas no fluxo de trabalho.

    E no post de hoje, vi trazer as novidades mais importantes anunciadas no evento:

    🤖 A Nova Era dos Agentes: Apresentando o Agent HQ

    (Novidades em Breve)

    O anúncio mais impactante é o Agent HQ, que promete ser um centro de comando unificado para orquestrar qualquer agente de código, de qualquer lugar. Esta nova evolução trará recursos cruciais para a gestão de tarefas complexas:

    • Introdução ao Agent HQ- Leia o Blog
    • Centro de Controle e Missões: Uma visão unificada para atribuir, guiar, rastrear e revisar tarefas complexas executadas por agentes em todo o ecossistema GitHub.Leia o Changelog
    • Agentes Customizados: Capacidade de personalizar agentes com prompts, ferramentas e contextos específicos para tarefas de desenvolvimento e compartilhamento entre equipes. Leia o Changelog

    🌐 Fluxos de Trabalho Inteligentes com Copilot Integrado

    (Disponível Agora)

    O GitHub Copilot está se expandindo para se tornar um assistente de fluxo de trabalho ainda mais integrado.

    • Conecte o Copilot ao seu Fluxo de Trabalho – Explore o Copilot
    • Copilot Designável: Agora é possível atribuir tarefas ao Copilot diretamente em ferramentas populares de gerenciamento, como Slack, Microsoft Teams, Linear e Azure Boards.
    • Explore as Integrações do Copilot
    • Revisão de Código Agente: O Copilot aprimora suas revisões de código combinando a inteligência do modelo com a ferramenta CodeQL. Leia o Changelog

    💻 Experiência de Código Aprimorada no VS Code

    _
    (Disponível Agora)_

    O Visual Studio Code, ambiente de desenvolvimento essencial, recebe atualizações focadas em planejamento e conformidade.

    • Modo de Planejamento (Plan Mode): As pessoas desenvolvedoras podem usar o Plan Mode para criar um plano passo a passo antes de escrever o código. Leia o Changelog
    • Seus Agentes, Suas Regras: Defina diretrizes de projeto no arquivo AGENTS.md para que cada agente siga os padrões da equipe. Leia a Documentação
    • Integração MCP Simplificada: Acesse e instale servidores MCP (Model Control Plane) diretamente do GitHub MCP Registry dentro do VS Code. Explore o Suporte ao MCP

    💼 Governança e Visibilidade para Empresas

    (Disponível Agora)

    Para o ambiente Enterprise, o foco é em governança, segurança e métricas de adoção de IA.

    • GitHub Code Quality: Oferece visibilidade e relatórios em toda a organização para melhorar a qualidade do código. Leia o Changelog
    • Painel de Métricas do Copilot: Dashboard e API com um quadro completo de uso do Copilot, incluindo métricas de usuários ativos e adoção. Leia o Changelog
    • Governança de Fluxos de Agentes: Permite que as empresas centralizem o gerenciamento de agentes, definam políticas de segurança e configurem acessos. Leia o Changelog

    📊 O Estado do Octoverse em 2025

    (Disponível Agora)

    O relatório anual do Octoverse também foi lançado, revelando as principais tendências da comunidade.

    Em resumo…

    O GitHub Universe 2025 não apenas apresentou ferramentas; ele delineou o mapa para o futuro do desenvolvimento.
    Com o Agent HQ e a expansão do Copilot, o GitHub está garantindo que as pessoas desenvolvedoras mantenham o controle, a visibilidade e a capacidade de escolha, mesmo enquanto a IA assume tarefas mais complexas.
    Essas inovações solidificam a visão do GitHub: transformar desafios em soluções automatizadas e permitir que as pessoas desenvolvedoras se concentrem no que fazem de melhor: inovar e criar.

    Explore os links acima para mergulhar na nova era do desenvolvimento agente! ✨

  • Grafana + OpenTelemetry: exemplo de implementação de observabilidade em várias stacks

    Grafana + OpenTelemetry: exemplo de implementação de observabilidade em várias stacks

    OpenTelemetry vem sendo cada vez mais adotado como a principal alternativa para a coleta de logs, métricas e traces em aplicações nas mais variadas stacks. Grafana, Jaeger, Zipkin, Elastic APM, Application Insights/Azure Monitor, Dynatrace, Datadog são apenas algumas das soluções que posso citar aqui e que contem hoje com o suporte a OpenTelemetry.

    No caso específico do Grafana, uma mudança ocorrida na virada de 2024 para 2025 merece a atenção de todos: o Grafana Alloy, um novo Collector para OpenTelemetry. O diagrama deste post exemplifica o uso desta nova solução, com o direcionamento de traces para o Grafana Tempo, de métricas para o Prometheus e de logs para o Grafana Loki.

    Já abordei inclusive a utilização do Grafana Alloy em diversos vídeos recentes no Canal .NET (e em outras comunidades), com destaque para um exemplo (clique neste link para abrir o YouTube) que envolve a simulação de uma arquitetura de microsseviços utilizando .NET, Java, Node e Python:

    Uma parte importante dos meus testes com soluções de observabilidade passa sempre pela execução de scripts do Docker Compose, de forma a subir rapidamente serviços para testes de avaliação. Containers seguem na minha opinião como um importante instrumento para agilizar tais testes, além de simplificar o entendimento de tecnologias de apoio a serem adotadas em um projeto.

    Os exemplos mencionados estão nos seguintes repositórios do GitHub (dêem um star ⭐ 🌟 apoiando se acharem útil os conteúdos):

    * Docker Compose com definições do ambiente: https://lnkd.in/dWCs9wnm
    * .NET: https://lnkd.in/dQvD8v-n
    * Java: https://lnkd.in/dSQafsEa
    * Node: https://lnkd.in/dr3RDvky
    * Python: https://lnkd.in/dswYrU4r
    * Repo com este diagrama de arquitetura: https://lnkd.in/dpzvbcin

  • Como funcionam os operadores de atribuição lógica do ES2021 (JS)

    Como funcionam os operadores de atribuição lógica do ES2021 (JS)

    Desde o lançamento da versão ECMAScript 6, em 2015, o TC19 têm trabalhado para trazer funcionalidades e melhorias para o JavaScript anualmente, afinal, foram muitos e muitos anos de espera até que o ES6 aparecesse.

    É claro que as funcionalidades que são aprovadas são em pouca quantidade, afinal, o processo para que uma funcionalidade seja aprovada é longo e exige muita discussão e testes antes de ser oficializada.

    Como já era de se esperar, a versão da ECMAScript está entre nós e traz algumas melhorias bem legais. Entre elas, estão:

    • Operadores de atribuição lógica (Logical assignment operators);
    • String.replaceAll();
    • Promise.any();
    • Entre outros.

    Neste artigo quero falar sobre os operadores de atribuição lógica. Em outros artigos podemos tratar sobre os demais. Combinado?

    Se você ainda não está familiarizado com o ECMAScript 6 (e suas versões posteriores), recomendo dar uma olhada no meu livro ECMAScript 6 — Entre de Cabeça no Futuro do JavaScript e meus cursos de ES6ES7 e ES8! Tenho certeza que te ajudarão! 🙂

    Operadores de atribuição lógica

    Estes novos operadores são muito parecidos com os operadores lógicos que já estamos acostumados, no entanto, trazem algumas novidades muito úteis, principalmente para atribuirmos valores padrões para variáveis.

    São três operadores: OR, AND e Null.

    Operador de atribuição lógica OR

    Este operador é representado pelo símbolo:

    x ||= y

    Este operador funciona da mesma maneira que a operação x || (x = y) . Ou seja, a variável y somente terá o seu valor atribuído a x se ele possuir um valor considerado falso (falsy) no contexto booleano. Caso contrário, x permanece com o seu valor original.

    Parece confuso? Tenho certeza que o exemplo abaixo te ajudará a mais sentido para este caso. Veja só:

    const chave = () => {
      // faz alguma lógica que retorna uma chave
      return "chave";
    }// Exemplo 1
    const usuario = {nome: "Diego", idade: 29, chave:""};
    usuario.chave ||= chave(); 
    console.log(usuario.chave); // chave// Exemplo 2
    usuario.chave = "outra chave";
    usuario.chave ||= chave();
    console.log(usuario.chave); // outra chave

    Note que no exemplo 1, como no objeto usuário o valor do atributo chaveé vazio (representado por aspas vazias), o valor resultado é a string retornada na função. No exemplo 2 isso não acontece, pois o valor já não é mais falso no contexto booleano.

    Operador de atribuição lógica AND

    Este operador é representado pelo símbolo:

    x &&= y

    Este operador funciona totalmente contrário ao operador de atribuição lógica OR, ou seja, o valor da variável y será atribuída a x, se este já possui um valor verdadeiro (truthy). Caso contrário, ele permanece com o valor que ele já tinha.

    Veja como isso acontece com base no exemplo anterior:

    const chave = () => {
      // faz alguma lógica que retorna uma chave
      return "chave";
    }// Exemplo 1
    const usuario = {nome: "Diego", idade: 29, chave:""};
    usuario.chave &&= chave(); 
    console.log(usuario.chave); // // Exemplo 2
    usuario.chave = "outra chave";
    usuario.chave &&= chave();
    console.log(usuario.chave); // chave

    Repare que os exemplos 1 e 2 são bem claros. No primeiro, como o valor do atributo chave é vazio, o operador não atribui nada. No segundo caso, ele atribui, pois o atributo chave agora possui um valor diferente de falso (no contexto booleano).

    Operador de atribuição lógica Null

    x ??= y

    Este talvez seja o operador mais fácil de se entender. O valor de y será atribuído a x se, e somente se, este tem o valor null ou undefined. E se tratando do JavaScript, nada melhor do que uma maneira fácil de lidar com estes valores, não é?

    Veja o exemplo:

    const chave = () => {
      // faz alguma lógica que retorna uma chave
      return "chave";
    }// Exemplo 1
    const usuario = {nome: "Diego", idade: 29, chave: null};
    usuario.chave ??= chave(); 
    console.log(usuario.chave); // chave// Exemplo 2
    usuario.chave = "outra chave";
    usuario.chave ??= chave();
    console.log(usuario.chave); // outra chave

    No exemplo 1, atribuímos null como valor do atributo chave do objeto usuário. Quando o operador é chamado, ele nota este valor e então atribui o valor que determinado como retorno na função chave.

    No exemplo 2 isso não acontece pois o valor já não é mais null ou undefined .

    Conclusão

    O JavaScript não é a linguagem mais querida do mundo atualmente a toa. As pequenas melhorias que são trazidas anualmente faz com que a linguagem nunca pare de evoluir, no entanto, isso também exige que nós, programadores e programadoras, continuemos nos atualizando para saber quais são e como usar esses novos recursos.

    Você pode fazer os testes no repl do Babel.

    Versão em Vídeo

    Além das instruções que darei abaixo, você também pode acompanhar todos os passos que serão feitos na versão em vídeo!

    Curta e se inscreva!