Logo Tech Writers

Tech writers

Esse é o nosso blog para apaixonados por tecnologia! Aqui, softplayers e outros especialistas compartilham conhecimentos fundamentais para o desenvolvimento dessa comunidade.

SEJA UM TECH WRITER
Como o Karpenter otimizou a gestão da nossa infraestrutura EKS na AWS
Tech Writers Maio 13, 2025

Como o Karpenter otimizou a gestão da nossa infraestrutura EKS na AWS

Empresas enfrentam desafios diários na gestão de infraestrutura Kubernetes, especialmente para manter eficiência e reduzir custos. Aqui na Softplan, descobrimos uma solução que transforma a maneira de gerenciar nossos clusters EKS na AWS: o Karpenter. Desafios na gestão de instâncias Antes de falar de Karpenter é preciso dar alguns passos atrás e explicar um pouco do que se trata um auto escalonamento de nodes. Suponha que temos nosso cluster com algumas máquinas (instâncias) disponíveis executando nossos workloads. O que acontece se por acaso houver um pico de uso em nossas aplicações e seja necessário subir mais instâncias (réplicas) de nossos pods? Sem um autoscaling precisaríamos provisionar um node, orientá-lo a juntar-se ao nosso cluster para aí sim nossos pods estarem aptos a serem iniciados nessa nova instância. Lembrando que o provisionamento de uma instância não é instantâneo, há todo um bootstrapping da máquina, configurações de rede e muitas outras coisas antes dela ficar totalmente disponível. Certo, falamos sobre pico de usuários em nossas aplicações, mas e quando houver ociosidade? Queremos mesmo deixar esses nodes em pé com poder computacional subutilizado? Para resolver essa e outras questões, entra em cena o conceito de auto scalers. Auto Scalers As implementações de auto scalers são responsáveis basicamente pelo provisionamento e consolidação de nodes. Aqui estamos falando de escalonamento horizontal, ou seja, adicionando mais máquinas em nosso cluster. Há diversas implementações de node autoscaling, mas neste artigo o foco será na implementação da AWS e por que decidimos migrar para uma outra solução. Abaixo uma figura exemplificando o funcionamento do node autoscaling: Figura 01: autoscaling AWS - Auto Scaling Groups Ao definir um grupo de escalonamento na AWS precisamos definir diversas propriedades, como o número mínimo/máximo de instâncias de nodes permitidas para este grupo, recursos utilizados, tipo de disco, configurações de rede (subnets, etc) e muitos outros detalhes. Por exemplo, para um determinado tipo de aplicação que utilize mais CPU vamos configurar um grupo que contenha tipos de instância com mais CPU do que memória. No fim possivelmente teremos alguns grupos distintos para certos tipos de aplicações. Juntando as peças – Cluster Auto Scaler Para que meu cluster consiga “conversar” com meu cloud provider (neste exemplo AWS), precisamos de um componente chamado Cluster Auto Scaler, ou CAS.Este componente foi criado pela própria comunidade que mantém o Kubernetes, e está disponível aqui. Uma configuração padrão do CAS pode ser vista abaixo, utilizando o helm para instalação: nameOverride: cluster-autoscaler awsRegion: us-east-1 autoDiscovery: clusterName: meu-cluster image: repository: registry.k8s.io/autoscaling/cluster-autoscaler tag: v1.30.1 tolerations: - key: infra operator: Exists effect: NoSchedule nodeSelector: environment: "infra" rbac: create: true serviceAccount: name: cluster-autoscaler annotations: eks.amazonaws.com/role-arn: "role-aws" extraArgs: v: 1 stderrthreshold: info Com isso configurado e instalado e nossos autoscaling groups criados acabamos de habilitar o gerenciamento automático de nossos nodes! Por que decidimos migrar para o Karpenter Nosso caso de uso aqui na Projuris é o seguinte: temos um cluster de desenvolvimento e outro de produção. Depois da migração para o Gitlab SaaS tínhamos um desafio de como provisionar os runners para a execução de nossas pipelines. Ficou decidido que usaríamos o cluster de desenvolvimento para provisionamento desses runners. Na “primeira versão” optamos pelo cluster auto scaler por ser uma configuração mais simples e que já atendia nosso setup em produção. Mas aí começamos a enfrentar alguns problemas com esta escolha: Tempo de provisionamento: ao iniciar uma pipeline o tempo de provisionamento da máquina era um pouco lento. O grande ponto é que o cluster auto scaler paga um “pedágio” no cloud provider para provisionamento de um novo node. Dificuldade na configuração de grupos: como temos alguns “perfis” de pipeline essa gestão ficou um pouco complicada, porque para cada novo perfil um novo node group precisa ser criado. Custo: para mitigar o problema de lentidão no startup de um novo node tínhamos um perfil de máquina “online” que ficava o tempo todo de pé, mesmo sem executar nenhuma pipeline. O que é o Karpenter? É uma solução de cluster autoscaling criada pela AWS, que promete o provisionamento e consolidação de nodes sempre com o menor custo possível. Ele é inteligente o suficiente para saber que por exemplo, ao comprar uma máquina na AWS do tipo on-demand, dependendo da situação, é mais em conta do que se fosse uma máquina spot. E essa é apenas uma das características dessa ferramenta. O Karpenter também trabalha com a ideia de “grupos” de máquinas (que no mundo do Karpenter chamamos de NodePools), só que a diferença é que fazemos isso através de CRDs (custom resource definitions) do próprio Karpenter, ou seja, temos manifestos dentro de nosso cluster com todas essas configurações, eliminando a necessidade de qualquer node group criado na AWS. Exemplo de um NodePool no Karpenter: apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: karpenter-gitlab-runner-small-online spec: template: metadata: labels: workload: gitlab-runners environment: karpenter-nodes-gitlab-runner-build-small-online spec: requirements: - key: "karpenter.sh/capacity-type" operator: In values: ["spot", “on-demand”] - key: "node.kubernetes.io/instance-type" operator: In values: ["m5d.large", "m5n.large", "m6id.large", "m6in.large"] nodeClassRef: group: karpenter.k8s.aws kind: EC2NodeClass name: my-node-class taints: - key: "gitlab-runner-karpenter" value: "true" effect: NoSchedule expireAfter: Never disruption: consolidationPolicy: WhenEmpty consolidateAfter: 5m budgets: - nodes: "20%" limits: cpu: "500" memory: 500Gi Além do NodePool precisamos criar um NodeClass para definir detalhes específicos de instâncias AWS: apiVersion: karpenter.k8s.aws/v1 kind: EC2NodeClass metadata: name: my-node-class spec: amiFamily: AL2 role: "aws-role" tags: Name: nodes-k8s-nodes-gitlab-runner-small-online subnetSelectorTerms: - tags: karpenter.sh/subnet: "my-subnet" securityGroupSelectorTerms: - id: "sg-123" - id: "sg-456" - id: "sg-789" amiSelectorTerms: - id: "imagem ami" kubelet: clusterDNS: ["111.222.333.44"] blockDeviceMappings: - deviceName: /dev/xvda ebs: volumeSize: 40Gi volumeType: gp3 encrypted: true OBS: perceba que o nome “my-node-class” precisa bater com o node class configurado no node pool. Como o Karpenter nos ajudou a superar os desafios apresentados? Tempo de provisionamento: como o Karpenter conversa diretamente com as APIs do cloud provider não é necessário pagar o pedágio do cluster auto scaler. Tínhamos muitos problemas de timeout no provisionamento de novos nodes, após a troca pelo Karpenter esse problema simplesmente desapareceu justamente porque o provisionamento é mais eficiente. Dificuldade na configuração de grupos: com a solução de NodePools e NodeClass do Karpenter essa configuração ficou trivial, e o mais importante, versionada em nosso controle de versões no Gitlab. Ou seja, precisa incluir um perfil de máquina novo no NodePool? Sem problemas, basta um commit e o Karpenter já irá considerar isso nos novos provisionamentos. Custo: Conseguimos utilizar a utilização de máquinas, pois agora runners com características semelhantes são alocados em nodes que suportem os requisitos de memória e CPU exigidos. Ou seja, estamos realmente usando todo o poder computacional que aquele node proporciona. Isso vale também para a consolidação de nodes. Com o cluster auto scaler haviam scripts complexos para fazer o drain dos nodes antes da consolidação. Com o Karpenter isso é configurado no NodePool de maneira muito simplificada. Um ótimo argumento para a gestão que justifique o investimento nesse tipo de mudança é custo. Abaixo temos um comparativo do custo utilizando o Cluster AutoScaler e o Karpenter em Janeiro/25, onde conseguimos uma economia de 16% no total: Figura 02: Período de 01/01 à 15/01 com ClusterAutoScaler Figura 03: Período de 16/01 à 31/01 com o Karpenter Considerações finais A migração para o Karpenter foi uma escolha acertada. Conseguimos simplificar a gestão de nossos nodes com diferentes perfis de forma bastante simplificada. Ainda há espaço para algumas melhorias, como por exemplo a utilização de um único NodePool para simplificar ainda mais, e deixar que os runners configurem labels específicas para o perfil de máquina que deve ser provisionado para o runner (mais em https://kubernetes.io/docs/reference/labels-annotations-taints/).

A força da colaboração e o cliente como protagonista: impactos da evolução de produtos no Grupo Softplan
Tech Writers Abril 29, 2025

A força da colaboração e o cliente como protagonista: impactos da evolução de produtos no Grupo Softplan

No Grupo Softplan, a evolução dos produtos é um esforço contínuo que envolve a colaboração entre times e um compromisso profundo com o cliente. Em minha função como Product Growth, troco constantemente ideias com outras equipes e recebo feedbacks valiosos dos clientes, seja pela análise de como utilizam o produto ou através de canais específicos de comunicação, como e-mail. Essas interações me proporcionam uma visão clara do impacto que a evolução contínua dos produtos tem no sucesso da empresa e no valor entregue aos clientes. Este artigo explora como a colaboração entre times e o foco no cliente impulsionam a evolução dos nossos produtos, promovendo o crescimento do Grupo Softplan e o sucesso daqueles que utilizam nossas soluções. Colaboração entre times: o motor da inovação O desenvolvimento e a melhoria de produtos no Grupo Softplan exigem uma integração contínua entre diversos times. As soluções de software precisam ser eficazes e alinhadas às demandas do mercado. Embora não faça parte diretamente da definição do roadmap, minha função permite trazer insights valiosos com base em interações com clientes e dados de performance. Isso contribui diretamente para a priorização de iniciativas de desenvolvimento. Estudos da Forbes indicam que empresas que incentivam a colaboração interna têm 4,5 vezes mais chances de reter os melhores talentos e inovar com mais eficiência (Forbes on Collaboration). No Grupo Softplan, a colaboração eficaz é um dos pilares para garantir que as necessidades dos clientes sejam atendidas com agilidade e eficiência. As áreas de produto, marketing, growth e comercial trabalham juntas continuamente, sempre buscando alinhar as iniciativas com as demandas do mercado. Esse trabalho colaborativo, aliado ao apoio da equipe de Growth na priorização das iniciativas, integra diferentes perspectivas e áreas da empresa, permitindo ajustes constantes nos produtos e impulsionando a criação de inovações a partir dessas interações entre departamentos. Cliente como protagonista: o guia das nossas decisões No Grupo Softplan, o cliente está no centro de todas as decisões, especialmente na Unidade de Indústria e Construção, onde o valor de "cliente como protagonista" orienta nossa forma de trabalho. Utilizamos canais específicos para coletar feedbacks contínuos, e esses insights moldam as iniciativas de produto. Conforme apontado pela Salesforce, 80% dos clientes consideram a experiência oferecida por uma empresa tão importante quanto seus produtos e serviços (Salesforce State of the Connected Customer). Na prática, isso significa que, ao ouvir os usuários e ajustar nossos produtos com base em suas demandas, fortalecemos o relacionamento e aumentamos a lealdade à nossa marca. Um exemplo disso foi a recente atualização de funcionalidades, baseada no feedback dos clientes, que trouxe comunicações mais diversificadas em módulos do produto, alinhando-se às necessidades identificadas. Essa abordagem orientada pelo cliente não apenas atende às necessidades atuais, mas também nos permite antecipar demandas futuras. Esse processo contínuo solidifica nosso papel como parceiro estratégico para os clientes. Impacto no mercado: inovação e crescimento O Grupo Softplan se destaca no mercado por seu compromisso com a inovação e foco em resultados concretos. Ajustar nossos produtos com base no feedback direto dos clientes tem um impacto direto no crescimento da empresa e na satisfação dos usuários. Como mencionado, a atualização das comunicações mais diversificadas em módulos do produto foi uma resposta direta a esses feedbacks, destacando como a comunicação contínua com o cliente guia a evolução das nossas soluções. De acordo com a PwC, empresas que priorizam a experiência do cliente podem ver um aumento de 16% na receita e uma maior retenção de clientes (PwC Future of Customer Experience Survey). Essa realidade também se aplica ao Grupo Softplan, onde o ajuste contínuo e o foco nas necessidades dos clientes nos ajudam a entregar soluções relevantes que se destacam no mercado. O uso estratégico do feedback do cliente não só melhora a experiência do usuário, como também garante que estamos sempre um passo à frente em termos de inovação e competitividade. Venha crescer com a gente O Grupo Softplan se destaca por escutar seus clientes e unir seus times para criar soluções que impulsionam os negócios. O valor de "cliente como protagonista" é um guia prático e presente em nossa jornada de evolução de produtos. Colaboramos, inovamos e nos adaptamos, sempre garantindo que as necessidades dos clientes estejam no centro das nossas decisões. Se você valoriza um ambiente que fomenta colaboração e inovação, com oportunidades de aprendizado contínuo e crescimento, o Grupo Softplan é o lugar certo para você. Aqui, nossos valores e objetivos estratégicos são reforçados por treinamentos e pela oportunidade de trabalhar em projetos desafiadores que transformam o mercado de software. Junte-se a nós e faça parte de uma equipe que transforma a vida dos clientes e inova o mercado. Acesse nossa página de carreira.

A Evolução Digital no Setor Público: Gestão de Produtos B2G
Tech Writers Abril 16, 2025

A Evolução Digital no Setor Público: Gestão de Produtos B2G

Nos últimos anos, o setor público tem ampliado seus serviços digitais para os cidadãos. A pandemia de 2020 acelerou essa tendência, impulsionando a modernização de órgãos como Tribunais de Justiça, Ministérios Públicos e Defensorias. Essa transformação visa melhorar a eficiência dos serviços públicos e facilitar o acesso da população. Historicamente, as áreas de Tecnologia da Informação desses órgãos adotaram modelos de gestão de projetos que priorizam a entrega de escopos definidos, com prazos e equipes limitadas às demandas específicas. Contudo, a necessidade crescente de agilidade tem impulsionado a transição para a gestão de produtos. Nesse contexto, o conceito de Business-to-Government (B2G) ganha relevância, destacando a importância da gestão de produtos na oferta de soluções inovadoras para o governo. Como Product Manager atuando em produtos B2G, meu foco é entregar soluções alinhadas às necessidades dos usuários finais. Diferente do setor B2B, onde há um funil de vendas estruturado, a gestão de produtos no setor público exige a adoção de métricas e ferramentas adaptadas a esse ecossistema. Dia a dia de Products Managers no setor público As interações com os clientes iniciam-se após a assinatura do contrato, quando o primeiro contato ocorre com o grupo gestor, formado por servidores responsáveis pela implantação do produto. A partir desse ponto, são obtidos insights sobre as necessidades dos usuários finais, permitindo um entendimento inicial do fluxo de trabalho. Para priorizar o backlog, utilizamos a matriz RICE (Reach, Impact, Confidence, Effort), garantindo que as decisões considerem tanto as exigências contratuais quanto as necessidades dos usuários. Essa priorização ocorre de forma contínua, acompanhando a evolução do produto e dos contratos estabelecidos. No ciclo de desenvolvimento, aplicamos técnicas de experimentação, prototipação e testes de usabilidade com grupos pilotos. Coletamos dados quantitativos e qualitativos para medir a adesão e definir melhorias nas funcionalidades do produto. Exemplo de matriz RICE Com estas premissas em mente, aplicamos aos usuários piloto por exemplo, técnicas de experimentação, prototipação, condução de testes de usabilidade para novas funcionalidades. Também realizamos coletas constantes de dados quantitativos e qualitativos da jornada utilizada por eles, conforme aumenta a adesão. A partir das métricas coletadas, podemos definir se as funcionalidades principais ou acessórias da jornada do nosso usuário precisam ser evoluídas. Exemplo de insights quantitativos com informações da jornada do usuário na organização de tarefas utilizando a ferramenta MixPanel Exemplo de uso da ferramenta INDECX para informações qualitativas a respeito do produto ou funcionalidade Tríade de produto entregando resultados eficientes A gestão de produtos no setor público exige uma abordagem colaborativa, integrando time técnico, equipe de experiência do usuário e cliente. Essa interação contínua fortalece o alinhamento estratégico e a clareza sobre a evolução do produto. O roadmap do produto é compartilhado com o cliente para garantir transparência e previsibilidade nas entregas. Tríade de produto O Grupo Softplan se consolidou como referência na transformação digital do setor público, gerando impactos positivos para os cidadãos. Soluções como o Sistema de Automatização da Justiça (SAJ) proporcionam eficiência e celeridade nos serviços públicos. Como Product Manager na Softplan, contribuo para a gestão de produtos voltados ao setor público. Um exemplo é o SAJ Defensorias, cujo painel de tarefas foi desenvolvido após estudo de negócios e análise técnica baseada na tríade de produtos. Esse painel centraliza atividades diárias, priorizando tarefas a serem executadas imediatamente e organizando as finalizadas para referência futura. Solução SAJ Softplan Nosso objetivo é oferecer produtos intuitivos e eficientes, que atendam às demandas cotidianas dos defensores públicos e contribuam para a melhoria da prestação de serviços à sociedade. Painel de tarefas do Defensor no SAJ Defensorias As iniciativas digitais no setor público têm grande potencial de crescimento, impulsionadas pela cultura de produtos. A transformação digital é irreversível e continuará evoluindo para atender às expectativas da sociedade por serviços mais ágeis, eficientes e transparentes.

Exaustão do ThreadPool do .Net
Tech Writers Março 25, 2025

Exaustão do ThreadPool do .Net

Mais de uma vez em minha carreira me deparei com este cenário: a aplicação .Net frequentemente mostrando tempos de resposta elevados. Esta alta latência pode ter várias causas, como lentidão no acesso a algum recurso externo (um banco de dados ou uma API, por exemplo), uso de CPU “batendo” em 100%, sobrecarga de acesso a disco, entre outras. Quero adicionar à lista anterior outra possibilidade, muitas vezes pouco considerada: exaustão do ThreadPool. Será apresentado de forma bem rápida como o ThreadPool do .Net funciona, e exemplos de códigos onde isto pode acontecer. Por fim, será demonstrado como evitar este problema. O ThreadPool do .Net O modelo de programação assíncrona baseado em Tasks (Task-based asynchronous programming) do .Net é bastante conhecido pela comunidade de desenvolvimento, mas acredito que seja pouco compreendido em seus detalhes de implementação - e é nos detalhes onde mora o perigo, como bem diz o ditado. Por trás do mecanismo de execução de Tasks do .Net existe um Scheduler, responsável, como seu nome já indica, por escalonar a execução das Tasks. Salvo alguma mudança explícita, o scheduler padrão do .Net é o ThreadPoolTaskScheduler, que também como o nome indica, utiliza o ThreadPool padrão do .Net para realizar seu trabalho. O ThreadPool gerencia então, como já se esperava, um pool de threads, para as quais ele atribui as Tasks que recebe usando uma fila. É nesta fila onde as Tasks ficam armazenadas até que haja um thread livre no pool, para então iniciar seu processamento. Por padrão, o número mínimo de threads do pool é igual ao número de processadores lógicos do host. E aqui está o detalhe em seu funcionamento: quando existem mais Tasks a serem executadas do que o número de threads do pool, o ThreadPool pode esperar uma thread ficar livre ou criar mais threads. Se escolher criar uma nova thread e se o número atual de threads do pool for igual ou maior que o número mínimo configurado, este crescimento demora entre 1 e 2 segundos para cada nova thread adicionada ao pool. Observação: a partir do .Net 6 foram introduzidas melhorias neste processo, permitindo que haja um aumento mais rápido no número de threads do ThreadPool, mas ainda assim a ideia principal se mantém. Vamos a um exemplo para deixar mais claro: suponha um computador com 4 cores. O valor mínimo do ThreadPool será 4. Se todas as Tasks que chegarem processarem rapidamente seu trabalho, o pool poderá inclusive ter menos do que o mínimo de 4 threads ativas. Agora, imagine que 4 Tasks de duração um pouco mais longa chegaram simultaneamente, utilizando então todas as threads do pool. Quando a próxima Task chegar à fila, ele precisará esperar entre 1 e 2 segundos, até que uma nova thread seja adicionada ao pool, para então sair da fila e começar a processar. Se esta nova Task também tiver uma duração mais longa, as próximas Tasks esperarão novamente na fila e precisarão “pagar o pedágio” de 1 a 2 segundos antes de poderem começar a executar. Se esse comportamento de novas Tasks de longa duração se mantiver por algum tempo, a sensação para os clientes deste processo será de lentidão, para qualquer nova tarefa que chegar à fila do ThreadPool. Este cenário é chamado de exaustão do ThreadPool (ThreadPool exhaustion ou ThreadPool starvation). Isso ocorrerá até que as Tasks finalizem seu trabalho e comecem a retornar as threads ao pool, possibilitando a redução da fila de Tasks pendentes, ou que o pool consiga crescer suficientemente para atender à demanda atual. Isso pode demorar vários segundos, dependendo da carga, e só então a lentidão observada anteriormente deixará de existir. Código síncrono x assíncrono É preciso agora fazer uma distinção importante sobre tipos de trabalho de longa duração. Geralmente eles podem ser classificados em 2 tipos: limitados pela CPU/GPU (CPU-bound ou GPU-bound), como a execução de cálculos complexos, ou limitados por operações de entrada/saída (I/O-bound), como o acesso a bancos de dados ou chamadas à rede. No caso de tarefas CPU-bound, salvo otimizações de algoritmos, não há muito o que fazer: é preciso ter processadores em quantidade suficiente para atender à demanda. Mas, no caso de tarefas I/O-bound, é possível liberar o processador para responder a outras requisições enquanto se espera a finalização da operação de I/O. E é exatamente isso que o ThreadPool faz quando APIs assíncronas de I/O são usadas. Neste caso, mesmo que a tarefa específica ainda seja demorada, a thread será retornada para o pool e poderá atender a uma outra Task da fila. Quando a operação de I/O finalizar, a Task será enfileirada novamente para então continuar a executar. Para saber mais detalhes sobre como o ThreadPool aguarda o fim de operações de I/O, clique aqui. Entretanto, é importante observar que ainda existem APIs síncronas de I/O, que causam o bloqueio da thread e impedem sua liberação para o pool. Estas APIs - e qualquer outro tipo de chamada que bloqueie uma thread antes de retornar a execução - comprometem o bom funcionamento do ThreadPool, podendo causar sua exaustão quando submetidos a cargas suficientemente grandes e/ou longas. Podemos dizer então que o ThreadPool – e por extensão o ASP.NET Core/Kestrel, desenhados para operar assincronamente – é otimizado para execução de tarefas de baixa complexidade computacional, com cargas I/O bound assíncronas. Neste cenário, um pequeno número de threads é capaz de processar um número bastante elevado de tasks/requisições de maneira eficiente. Bloqueio de threads com ASP.NET Core Vamos ver alguns exemplos de código que causam o bloqueio de threads do pool, usando ASP.NET Core 8. Observação: estes códigos são exemplos simples, que não visam representar nenhuma prática, recomendação ou estilo em especial, exceto os pontos relacionados à demonstração do ThreadPool especificamente. Para manter o comportamento idêntico entre os exemplos, será usado uma requisição a banco de dados SQL Server que simulará uma carga de trabalho que demora 1 segundo para retornar, usando a sentença WAITFOR DELAY. Para gerar uma carga de utilização e demonstrar os efeitos práticos de cada exemplo, utilizaremos o siege, um utilitário de linha de comando gratuito destinado a esta finalidade. Em todos os exemplos será simulada uma carga de 120 acessos concorrentes durante 1 minuto, com um atraso aleatório de até 200 milissegundos entre as requisições. Estes números são suficientes para demonstrar os efeitos sobre o ThreadPool sem gerar timeouts no acesso ao banco de dados. Versão Síncrona Vamos começar com uma implementação completamente síncrona: A action DbCall é síncrona, e o método ExecuteNonQuery do DbCommand/SqlCommand é síncrono, portanto, bloqueará a thread até que haja o retorno do banco de dados. Abaixo está o resultado da simulação da carga (com o comando siege utilizado). Vejam que conseguimos uma taxa de 27 requisições por segundo (Transaction rate), e um tempo de resposta médio (Response time) de cerca de 4 segundos, com a requisição mais longa (Longest transaction) durando mais de 16 segundos – um desempenho bastante precário. Versão Assíncrona – Tentativa 1 Vamos agora utilizar uma action assíncrona (retornando Task<string>), mas ainda utilizar o método síncrono ExecuteNonQuery. Executando o mesmo cenário de carga anterior, temos o seguinte resultado. Vejam que o resultado foi ainda pior neste caso, com taxa de requisições de 14 por segundo (contra 27 da versão completamente síncrona) e tempo médio de resposta de mais de 7 segundos (contra 4 da anterior). Versão Assíncrona – Tentativa 2 Nesta próxima versão, temos uma implementação que exemplifica uma tentativa comum – e não recomendada – de transformar uma chamada de I/O síncrona (no nosso caso, o ExecuteNonQuery ) em uma “API assíncrona”, usando Task.Run. O resultado, após a simulação, mostra que o resultado é próximo da versão síncrona: taxa de requisições de 24 por segundo, tempo médio de resposta de mais de 4 segundos e requisição mais longa levando mais de 14 segundos para retornar. Versão Assíncrona – Tentativa 3 Agora a variação conhecida como “sync over async”, onde utilizamos métodos assíncronos, como o ExecuteNonQueryAsync deste exemplo, mas é chamado o método .Wait() da Task retornada pelo método, como mostrado abaixo. Tanto o .Wait() quanto a propriedade .Result de uma Task tem o mesmo comportamento: causam o bloqueio da thread em execução! Executando nossa simulação, podemos ver abaixo como o resultado também é ruim, com taxa de 32 requisições por segundo, tempo médio de mais de 3 segundos, com requisições chegando a levar 25 segundos para retornar. Não à toa, o uso de .Wait() ou .Result em uma Task é desaconselhado em código assíncrono. Solução do problema Finalmente, vamos ao código criado para funcionar da forma mais eficiente, através do de APIs assíncronas e aplicando async / await corretamente, seguindo recomendação da Microsoft. Temos então a action assíncrona, com a chamada ExecuteNonQueryAsync com await. O resultado da simulação fala por si só: taxa de requisições de 88 por segundo, tempo médio de resposta de 1,23 segundos e requisição levando no máximo 3 segundos para retornar - números em geral 3 vezes melhores que qualquer opção anterior. A tabela abaixo sumariza os resultados das diferentes versões, para uma melhor comparação dos dados entre elas. Versão do códigoTaxa de requisições ( /s)Tempo médio (s)Tempo máximo (s)Síncrona27,384,1416,93Assíncrona 114,337,9414,03Assíncrona 224,904,5714,80Assíncrona 332,433,5225,03Solução88,911,233,18 Solução paliativa Vale mencionar que podemos configurar o ThreadPool para ter um número mínimo de threads maior do que o padrão (o número de processadores lógicos). Com isto, ele conseguirá rapidamente aumentar o número de threads sem pagar aquele “pedágio” de 1 ou 2 segundos. Existem pelo menos 3 formas para se fazer isto: por configuração dinâmica, usando o arquivo runtimeconfig.json, por configuração do projeto, ajustando a propriedade ThreadPoolMinThreads, ou por código, chamando o método ThreadPool.SetMinThreads. Isto deve ser encarado como uma medida temporária, enquanto não se faz os devidos ajustes em código como mostrado anteriormente, ou após os devidos testes prévios para confirmar que traz benefícios sem efeitos colaterais de desempenho, conforme recomendação pela Microsoft. Conclusão A exaustão do ThreadPool é um detalhe de implementação que pode trazer consequências inesperadas. E que podem ser difíceis de detectar se considerarmos que .Net possui várias maneiras de obter o mesmo resultado, mesmo em suas APIs mais conhecidas – acredito que motivado por anos de evoluções na linguagem e do ASP.NET, sempre visando compatibilidade retroativa. Quando falamos de funcionamento em taxas ou volumes crescentes, como ao passar de dezenas para centenas de requisições, é essencial conhecer as práticas e recomendações mais recentes. Além disso, conhecer um ou outro detalhe de implementação pode ser um diferencial para se evitar problemas de escala ou diagnosticá-los mais rapidamente. Fique de olho nas próximas publicações do Proud Tech Writers. Em um próximo artigo, vamos explorar como diagnosticar a exaustão do ThreadPool e identificar a origem do problema em código a partir de um processo em execução.

O que é UX Writing e tudo o que você precisa saber para criar experiências incríveis
Tech Writers Fevereiro 11, 2025

O que é UX Writing e tudo o que você precisa saber para criar experiências incríveis

O que é UX Writing e como impacta positivamente o produto de um negócio? Veja boas práticas, responsabilidades, metodologias, e muito mais! UX Writing envolve a criação de conteúdo valioso em interfaces e produtos digitais, incluindo textos, baseando-se na experiência do usuário, ou seja, visando entregar a melhor experiência para o público. Esta prática está relacionada a conceitos de marketing, design e arquitetura da informação, e tem como objetivo encantar e oferecer valor por meio de peças informativas. Um exemplo de UX Writing é quando você acessa alguma plataforma de ensino online, ou algum aplicativo que, assim que você faz o seu login, já demonstra com um tutorial objetivo cada passo que o usuário deve dar. Abaixo, um exemplo do aplicativo ProJuris ADV da Softplan, que mostra uma interface clean e amigável antes do usuário decidir se vai criar uma conta no aplicativo ou efetuar login, mostrando algumas coisas que podem ser executadas na aplicação. A experiência do usuário tem se tornado cada vez mais importante para a atração, conversão e retenção de clientes. Aspectos como a agilidade de navegação do seu site, a escaneabilidade e a maneira intuitiva de navegar, e, até mesmo as cores escolhidas para o design das páginas afetam diretamente as decisões dos usuários em qualquer plataforma digital. Quando falamos de plataformas digitais com UX Writing, podemos ver como exemplo, o Gestor Obras, que, já na primeira página do sistema, mostra um tutorial prático de como ele funciona. Ao passo que você clica onde tem a indicação, ele irá mostrar os próximos passos e funções de cada parte do sistema. Um outro exemplo de UX Writing, que passa informações diretas e objetivas, é no Sienge, mostrando em uma imagem algumas vantagens de utilizar o sistema, além de uma comunicação direta no CTA “Peça uma Demonstração”, fugindo do comum “Saiba Mais” e chamando para uma ação bem objetiva. Por isso, se a sua empresa ainda não otimiza constantemente seus canais de comunicação com o usuário, principalmente seu website, chegou a hora de revisar algumas escolhas. Afinal, o usuário é quem utiliza seu produto ou serviço. Para isso, não apenas o design do site é crucial na hora da otimização, mas também o atendimento e a  comunicação clara e objetiva nos canais da marca serão essenciais para criar mais conexão com seus consumidores. Para se ter uma ideia da experiência do usuário e como ela é agregadora, este ano foi realizada uma pesquisa pela Foundever, que revelou que 80% dos clientes consideram a experiência como um aspecto muito mais valioso do que os próprios produtos e serviços. Quando executada de forma eficiente, a prática de UX Writing se torna uma vantagem competitiva significativa em um mercado cada vez mais rigoroso em termos de qualidade e usuários que exigem os melhores produtos digitais. Quais são as principais características de UX Writing? UX Writing consiste em algumas características importantes para que seja executado de maneira correta e consistente. É importante ter isso em mente para melhores criações que realmente irão causar impacto na experiência do usuário positivamente. Clareza e Objetividade: o conteúdo deve ser claro e direto, facilitando a compreensão rápida pelo usuário. Consistência: a linguagem e o tom devem ser uniformes em todos os pontos de contato com o usuário, criando uma experiência coesa. Empatia: entender e antecipar as necessidades e expectativas dos usuários para criar textos que realmente os ajudem. Foco na Ação: orientar os usuários sobre o que fazer a seguir, utilizando chamadas para ação (CTAs) claras. Brevidade: utilizar o menor número de palavras possível sem sacrificar a clareza, respeitando o tempo e a atenção dos usuários. Escaneabilidade: estruturar o texto de forma que seja fácil de ler e percorrer rapidamente, com o uso de títulos, subtítulos, listas e parágrafos curtos. Acessibilidade: garantir que o conteúdo seja acessível a todos os usuários, incluindo aqueles com algum tipo de deficiência, através de uma linguagem simples e inclusiva. Orientação Visual: integrar o texto de maneira harmoniosa com os elementos visuais da interface, contribuindo para uma experiência de usuário agradável e intuitiva. Personalização: adaptar o conteúdo ao contexto e às preferências do usuário, oferecendo uma experiência mais relevante e personalizada. Tom e Voz da Marca: refletir a personalidade e os valores da marca em todos os textos, fortalecendo a identidade e a conexão com o público. Exemplos da aplicação de UX Writing É fácil confundir UX Writing com outras estratégias de escrita. Por isso, vamos demonstrar como aplicar UX Writing em seu website ou aplicações digitais. Personalização Quer ver um exemplo de UX Writing com personalização? O Spotify é um serviço de streaming, que, ao passo que você o utiliza, personaliza músicas que acabam sendo indicadas para os usuários, com músicas parecidas que o usuário costuma ouvir. Além disso, todo fim de ano, a plataforma entrega para cada usuário, seu resumo anual do que mais foi ouvido durante todo o período, além de quais artistas, podcasts e gêneros foram ouvidos. Tudo isso é feito com uma linguagem objetiva e clara para o usuário entender exatamente todo seu resumo, sem espaços para dúvidas. Foto: Reprodução/Spotify  Textos Objetivos e Claros Agora, para um aplicativo, por exemplo, é essencial que os textos sejam bem objetivos! Assim, as taxas de erro do usuário ao utilizá-lo certamente serão muito menores, além da navegabilidade ser mais intuitiva. Exemplo bom e ruim de um botão de ação com UX Writing aplicado. Fonte: Adobe Se antecipe aos erros Já falamos sobre a importância de dar ao usuário uma boa experiência, e isso inclui antecipar para ele, qualquer possibilidade de erro futuro. No exemplo abaixo, podemos ver o preenchimento de um formulário, onde o e-mail não é preenchido corretamente e a aplicação comunica que o usuário veja a mensagem, próxima do campo preenchido com erro, do lado esquerdo. Fonte: Adobe Diferenças entre Copywriting, UX Writing e Tech Writing  Embora relacionadas, as estratégias de copywriting, UX Writing e Tech Writing têm suas diferenças. Vamos ver quais são as principais dentro de algumas abordagens? Objetivo Copywriting: o objetivo é persuadir o leitor a tomar uma ação específica, como comprar um produto, inscrever-se em uma newsletter ou clicar em um link. Portanto, é focado em conversões e vendas. UX Writing: facilita a interação do usuário com um produto ou serviço digital, tornando a experiência mais intuitiva, agradável e eficiente. Com UX Writing, o usuário é guiado através da interface e na conclusão de tarefas. Tech Writing: o objetivo é explicar de maneira clara e precisa como usar produtos ou tecnologias complexas. Focado em fornecer instruções detalhadas e informativas. Abordagem Copywriting: utiliza técnicas de persuasão e retórica para capturar a atenção do leitor e motivá-lo a ter alguma ação. O tom é mais emocional e apelativo. UX Writing: adota uma abordagem funcional e informativa, priorizando clareza, simplicidade e utilidade. O tom é objetivo, focado em orientar e ajudar o usuário. Tech Writing: foca em detalhamento e precisão, proporcionando instruções passo a passo e explicações técnicas. O tom é técnico e informativo, com linguagem clara e objetiva. Local de Aplicação Copywriting: encontrado em materiais de marketing como anúncios, e-mails promocionais, páginas de vendas, posts de blog e conteúdo para redes sociais. UX Writing: presente em interfaces digitais, como aplicativos, sites, e-commerce, dashboards, e qualquer ponto de interação do usuário com o sistema. Exemplos incluem botões, mensagens de erro, instruções e menus de navegação. Tech Writing: aparece em manuais de usuário, guias de instalação, documentação de software, FAQs, tutoriais e bases de conhecimento. Métricas de Sucesso Copywriting: medido por métricas de conversão, como taxa de cliques (CTR), taxa de conversão, volume de vendas e retorno sobre investimento (ROI). UX Writing: medido pela usabilidade e satisfação do usuário, como taxas de erro reduzidas, tempo de conclusão de tarefas, retenção de usuários e feedback positivo sobre a experiência do usuário. Tech Writing: medido pela clareza e eficácia da documentação, como número de tickets de suporte, feedback dos usuários, tempo para encontrar informações e facilidade de uso da documentação. Colaboração Copywriting: colabora com equipes de marketing, vendas e branding. UX Writing: trabalha com designers de UX/UI, desenvolvedores, pesquisadores de experiência do usuário e gerentes de produto para integrar a escrita ao design e à funcionalidade do produto. Tech Writing: colabora com engenheiros, desenvolvedores, gerentes de produto e equipes de suporte para garantir que a documentação seja precisa e útil. Por fim, enquanto o copywriting busca persuadir e converter, o UX writing visa facilitar e orientar, e o tech writing se concentra em explicar e instruir. Cada estratégia utiliza a escrita como ferramenta principal, mas com focos e aplicações diferentes, mas que se complementam em algum momento da jornada do usuário. Como aplicar UX Writing em Produto para agregar valor? Agora que você já entende o que é UX Writing, já pode entender como aplicar a estratégia. Nesse caso, quando falamos de UX Writing e Produto, esses termos devem andar lado a lado na criação e otimização constante de um produto. Aqui inclusive podemos falar sobre o “Product Writer”, profissional totalmente focado em atuar em Produto que busca melhorias, pesquisando e entendendo o ponto de vista dos usuários sobre um determinado produto e definem soluções de escrita. Então, devemos entender como UX Writing agrega valor a produtos digitais de diversas maneiras, contribuindo significativamente para a experiência do usuário e, consequentemente, para o sucesso do produto. Vamos ver algumas práticas que podem ser executadas em produtos digitais? 1. Clareza nas Mensagens de Erro e Sucesso Mensagens de Erro: devem ser claras e específicas, informando ao usuário o que deu errado e como corrigir o problema. Por exemplo, "A senha deve ter pelo menos 8 caracteres" é mais útil do que "Erro na senha". Mensagens de Sucesso: confirmações claras que informam ao usuário que a ação foi concluída com sucesso. Por exemplo, "Sua compra foi realizada com sucesso!". 2. Instruções e Guias de Uso Onboarding: fornecer tutoriais e guias passo a passo para novos usuários, ajudando-os a se familiarizar com o produto. Tooltips e Pop-ups: instruções contextuais que aparecem no momento certo para orientar o usuário sem interromper sua experiência. 3. Chamadas para Ação (CTAs) Eficientes Botões e Links: usar verbos de ação claros e diretos, como "Compre Agora", "Inscreva-se" ou "Saiba Mais". Evitar termos vagos como "Clique Aqui". Hierarquia Visual: garantir que os CTAs sejam visualmente destacados para guiar a atenção do usuário. 4. Melhoria na Navegação Menus e Labels: usar terminologia familiar e intuitiva nos menus e rótulos. Por exemplo, "Conta" em vez de "Perfil do Usuário". Breadcrumbs: implementar breadcrumbs para ajudar os usuários a entenderem onde estão na navegação do site e como voltar a páginas anteriores. 5. Microcopy Formulários: fornecer instruções claras e concisas para cada campo de entrada. Exemplos: "Digite seu e-mail" ao invés de apenas "E-mail". Feedback Imediato: oferecer feedback instantâneo ao preencher formulários, como marcar campos corretos com um sinal verde. 6. Ajustes para Acessibilidade Texto Alternativo (Alt Text): adicionar descrições úteis em imagens, gráficos e ícones para melhorar a acessibilidade. Linguagem Simples: evitar jargões e termos técnicos complexos, tornando o conteúdo acessível a todos os usuários, incluindo aqueles com deficiências cognitivas. 7. Consistência no Tom de Voz Manual de Estilo: desenvolver e aderir a um manual de estilo que define a voz e o tom da marca, garantindo uma comunicação consistente em todas as plataformas. Revisão Regular: revisar e atualizar regularmente os conteúdos para manter a consistência e a relevância. 8. Conteúdo Educativo FAQs e Documentação: criar e manter seções de perguntas frequentes e documentação de ajuda que sejam claras, detalhadas e fáceis de navegar. Vídeos Tutoriais e Dicas: integrar vídeos e dicas rápidas que ajudem os usuários a entenderem e utilizar melhor as funcionalidades de um produto. 9. Testes e Interações Testes A/B: realizar testes A/B para avaliar a eficácia de diferentes versões de microcopy, CTAs e mensagens de erro. Feedback do Usuário: coletar e analisar feedback dos usuários para identificar áreas de melhoria e ajustar o conteúdo conforme necessário. Conclusão Perceba como muitas ações podem ser bem simples e que irão ajudar muito um produto a entregar uma boa experiência do usuário, com mais eficiência e satisfação. O seu produto pode acabar criando mais conexão com seus usuários, estimulando a fidelização e, assim, criando uma rede de consumidores que organicamente irão evangelizar sobre o seu produto e como ele vale a pena. Por fim, não perca tempo. Investir em Experiência do Usuário irá render melhorias para seu produto ou serviço e tornará a sua empresa mais acessível e em destaque no mercado.

Angular: Por que você deve considerar esse framework front-end para sua empresa
Tech Writers Fevereiro 02, 2024

Angular: Por que você deve considerar esse framework front-end para sua empresa

Um medo de toda equipe é escolher uma ferramenta que se tornará obsoleta rápido. Caso você esteja desenvolvendo aplicações há alguns anos, possivelmente já vivenciou isso. Por isso, a escolha de boas ferramentas é uma tarefa que envolve responsabilidade, pois pode guiar o projeto (e a empresa) para o sucesso ou para um mar de problemas e gastos. Neste artigo, vamos entender os usos e benefícios do framework Angular. Escolher um framework front-end não é diferente e também envolve pesquisas e estudos. A escolha de uma “stack”, como chamamos nesse mundo, é trivial tanto para o presente mas também para o futuro. No entanto, algumas perguntas irão surgir no meio dessa escolha:  Encontraremos profissionais capacitados para lidar com esse framework?  Conseguiremos manter um ritmo de atualizações?  Há um plano bem definido para a direção que o framework está indo?  Há uma comunidade (entendemos aqui também por grandes empresas apoiando) engajada?  Todas essas perguntas devem ser respondidas antes de começar qualquer projeto, pois negligenciar uma telas pode levar a cenários devastadores para o produto, e consequentemente para a empresa e seus lucros.  Motivações para se usar um framework  A resposta talvez mais direta seja que as vezes é bom não ficar reinventando a roda. Problemas rotineiros como lidar com rotas de uma aplicação web, ou mesmo o controle de dependências, geração do bundle otimizado para publicação em produção, todas essas tarefas já tem boas soluções desenvolvidas, e, por isso, escolher um framework que te entrega esse conjunto de ferramentas é perfeito para ganhar produtividade, solidez no desenvolvimento de uma aplicação e também manter a mesma sempre atualizada seguindo as melhores práticas.  Bem como as motivações diretas, posso citar também:  A facilidade de encontrar ferramentas que se integram com o framework  A busca por um software com qualidade, integrado a testes e outras ferramentas que irão tornar o processo de desenvolvimento maduro  Muitas situações e problemas já resolvidos (porque há muita gente trabalhando com a tecnologia)  Motivações para o uso do framework do Angular:  Construído usando Typescript, uma das linguagens mais populares do momento  Arquitetura MVC  Controle e Injeção de dependências  Modularização (com opção de carregamento lazy load)  Boas bibliotecas para integração  Comunidade grande e engajada  1835 contribuidores no repositório oficial  Oficialmente apoiada e mantida pelo time do Google  A solidez do Angular  Atualmente, podemos afirmar com clareza que o framework é estável, recebendo atualizações frequentes por sua natureza fundada no open-source. Isso porque é mantido pelo time do Google, que procura sempre deixar o roadmap do que está por vir o mais claro possível, o que é muito bom. Além disso, a comunidade Angular é bastante ativa e engajada. É difícil você ter um problema que já não foi resolvido.  Uma das preocupações de todo desenvolvedor é em relação a mudanças drásticas de uma ferramenta. Quem viveu a época da mudança da V1 para V2 do Angular sabe essa dor, praticamente a mudança foi total. Porém, o framework de forma correta se fundou com base no Typescript que trouxe robustez e mais um motivo para sua adoção: com o Typescript, temos possibilidades que o Javascript sozinho não consegue resolver: tipagem forte, integração com o IDE facilitando a vida dos desenvolvedores, reconhecimento de erros em tempo de desenvolvimento, e muito mais.  Atualmente, o framework está na versão 17 e vem ganhando cada vez mais maturidade e solidez, com o incremento de funcionalidades inovadoras como defer lançada recentemente.  Upgrade facilitado  O framework fornece um guideline para todo upgrade através do site https://update.angular.io, esse recurso ajuda muito a guiar a atualização do seu projeto.  CLI completo  O Angular é um framework. Logo, ao instalar seu pacote teremos o CLI pronto para inicializar novos projetos, gerar componentes, executar testes, gerar o pacote final e manter as atualizações da sua aplicação:  Para criar seu primeiro projeto, basta abrir o seu terminal, e rodar o comando a seguir:  Sólidos projetos de interface  Se você precisa de um design para sua aplicação que fornece componentes já prontos para uso como alertas, janelas de modal, avisos snackbar, tabelas, cards, uma das possibilidades mais populares é a escolha do Material Angular, um bom ponto para seguir o seu software com ele é porque é mantido pelo Google, logo sempre que o framework avança em versão o Material usualmente acompanha essa atualização.  Além do Material, existem outras opções na comunidade, como o PrimeNG, que trás um conjunto muito interessante (e grande) de componentes.  Suporte a biblioteca Nx  O Angular possui suporte completo ao projeto Nx, que possibilita escalar seu projeto de forma bastante consistente, garantindo principalmente cache e possibilidades avançadas para você manter e escalar sua aplicação local ou no seu ambiente de CI.  Aqui estão alguns exemplos específicos de como o Nx pode ser usado para melhorar um projeto Angular:  Você pode criar uma biblioteca Angular que pode ser reutilizada em vários projetos.  Você pode criar um monorepo que contenha todos os seus projetos Angular, o que facilita a colaboração entre equipes.  Você pode automatizar tarefas de desenvolvimento comuns, como a execução de testes e a implantação de seus projetos.  Testes (unitários e E2E)  Além do Karma e o Protactor que nasceram com o framework, agora você é livre para usar projetos populares como Jest, Vitest e Cypress.  State com Redux  Uma das bibliotecas mais utilizadas pela comunidade é a NgRx Store, que fornece gerenciamento de estado reativo para aplicativos Angular inspirados em Redux.  GDEs brasileiros  No Brasil temos atualmente dois GDEs Angular, o que é importante para nosso país e também para geração de conteúdo Angular em português, trazendo para nossa comunidade novidades e insights sempre atualizados direto do time do Google.  Loiane Gronner William Grasel Alvaro Camillo Neto Grandes empresas utilizando e apoiando  Talvez a mais notória seja o Google, mantenedor oficial do framework. A empresa possui diversos produtos construídos usando Angular e nos últimos anos vem apoiando ainda mais o desenvolvimento e evolução da ferramenta.  Um ponto importante ao escolher um framework é saber que grandes empresas estão utilizando, isso porque nos dá um sinal de que aquela ferramenta terá apoio para atualizações e evolução já que ninguém gosta de ficar reescrevendo produtos do zero, aqui vou citar algumas empresas globais que usam Angular em seus produtos, sites, serviços para a web:  Google  Firebase  Microsoft  Mercedes Benz  Santander  Dell  Siemens  Epic  Blizzard’s  No cenário nacional também temos exemplos de grandes empresas utilizando o framework com sucesso, podemos citar algumas:  Unimed Cacau Show  Americanas  Checklist Fácil  Picpay  Quer saber mais? Se interessou em começar com Angular? Acesse https://angular.dev/, a mais nova documentação do framework que trás tutoriais, playground e uma boa documentação bem explicada.  Bom código!