<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Isaias Velasquez</title>
    <description>The latest articles on DEV Community by Isaias Velasquez (@isaias_velasquez_d2261770).</description>
    <link>https://dev.to/isaias_velasquez_d2261770</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2784912%2F1f4a67f2-5f91-4c99-9b77-e805933c7564.jpg</url>
      <title>DEV Community: Isaias Velasquez</title>
      <link>https://dev.to/isaias_velasquez_d2261770</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/isaias_velasquez_d2261770"/>
    <language>en</language>
    <item>
      <title>How to versionar o banco de dados com Flyway sem medo</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 22:08:04 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-versionar-o-banco-de-dados-com-flyway-sem-medo-29io</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-versionar-o-banco-de-dados-com-flyway-sem-medo-29io</guid>
      <description>&lt;p&gt;Flyway versiona o schema do banco de dados da mesma forma que o Git versiona o codigo fonte. Cada migracao e um arquivo SQL que o Flyway executa na ordem certa.&lt;/p&gt;

&lt;p&gt;Adicione a dependencia no &lt;code&gt;build.gradle.kts&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;implementation("org.flywaydb:flyway-core")
runtimeOnly("org.flywaydb:flyway-database-postgresql")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Com Spring Boot, a configuracao e simples:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# application.properties
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Crie o primeiro arquivo de migracao em &lt;code&gt;src/main/resources/db/migration/V1__criar_tabela_usuarios.sql&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE usuarios (
    id BIGSERIAL PRIMARY KEY,
    nome VARCHAR(100) NOT NULL,
    email VARCHAR(150) UNIQUE NOT NULL,
    criado_em TIMESTAMP DEFAULT NOW()
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A segunda migracao &lt;code&gt;V2__adicionar_coluna_telefone.sql&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ALTER TABLE usuarios ADD COLUMN telefone VARCHAR(20);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O padrao de nome e &lt;code&gt;V{numero}__{descricao}.sql&lt;/code&gt;. O Flyway executa em ordem numerica e nunca repete o mesmo arquivo.&lt;/p&gt;

&lt;p&gt;Para rodar as migracoes manualmente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew flywayMigrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para ver o status:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gradlew flywayInfo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso mostra quais migracoes ja foram aplicadas e quais estao pendentes.&lt;/p&gt;

&lt;p&gt;Flyway cria uma tabela chamada &lt;code&gt;flyway_schema_history&lt;/code&gt; no banco. Ela registra cada migracao executada:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT version, description, installed_on, success
FROM flyway_schema_history;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Se uma migracao falha, o Flyway marca como falha e nao continua. Voce precisa corrigir o erro e rodar &lt;code&gt;flywayRepair&lt;/code&gt; antes de tentar de novo.&lt;/p&gt;

&lt;p&gt;Para migracoes irreversiveis, adicione o script de rollback separadamente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# V3__adicionar_tabela_pedidos.sql
CREATE TABLE pedidos (
    id BIGSERIAL PRIMARY KEY,
    usuario_id BIGINT REFERENCES usuarios(id),
    total DECIMAL(10,2) NOT NULL,
    criado_em TIMESTAMP DEFAULT NOW()
);

# V3.1__rollback_V3.sql
DROP TABLE IF EXISTS pedidos;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O Flyway nao executa rollbacks automaticamente. Mas ter o script pronto ajuda em emergencias.&lt;/p&gt;

&lt;p&gt;Para ambientes com dados reais, nunca altere migracoes ja executadas. Crie uma nova migracao:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- ERRADO: alterar V2__adicionar_coluna_telefone.sql depois de rodar
-- CERTO: criar V4__alterar_coluna_telefone.sql

ALTER TABLE usuarios ALTER COLUMN telefone TYPE VARCHAR(30);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Voce pode usar Flyway com SQL puro ou com Java para logicas complexas. Mas SQL puro e mais simples e funciona em qualquer banco.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>database</category>
      <category>springboot</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to criar indices no SQL que realmente fazem diferenca</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 22:07:40 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-criar-indices-no-sql-que-realmente-fazem-diferenca-lp6</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-criar-indices-no-sql-que-realmente-fazem-diferenca-lp6</guid>
      <description>&lt;p&gt;Ter um indice certo pode fazer uma query ir de 10 segundos para milissegundos. Mas indices demais ou errados atrapalham mais que ajudam.&lt;/p&gt;

&lt;p&gt;O comando basico para criar um indice:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_clientes_email ON clientes(email);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso acelera buscas por &lt;code&gt;email&lt;/code&gt;. Sem o indice, o banco faz uma varredura completa na tabela.&lt;/p&gt;

&lt;p&gt;Para indices compostos (mais de uma coluna):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_pedidos_cliente_data ON pedidos(cliente_id, data_criacao);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A ordem das colunas importa. Esse indice ajuda queries que filtram por &lt;code&gt;cliente_id&lt;/code&gt; ou por &lt;code&gt;cliente_id&lt;/code&gt; + &lt;code&gt;data_criacao&lt;/code&gt;. Mas nao ajuda queries que filtram so por &lt;code&gt;data_criacao&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para ver se uma query esta usando indice, use &lt;code&gt;EXPLAIN&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXPLAIN ANALYZE SELECT * FROM clientes WHERE email = 'joao@email.com';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O resultado mostra se o banco fez um &lt;code&gt;Index Scan&lt;/code&gt; (bom) ou &lt;code&gt;Seq Scan&lt;/code&gt; (ruim).&lt;/p&gt;

&lt;p&gt;Indices parciais sao otimos para filtrar um subconjunto especifico:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_pedidos_pendentes ON pedidos(status)
WHERE status = 'pendente';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Se voce sempre busca pedidos pendentes, esse indice e muito menor que um indice completo.&lt;/p&gt;

&lt;p&gt;Indices unicos garantem que nao ha valores duplicados:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE UNIQUE INDEX idx_cpf_unico ON clientes(cpf);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso e equivalente a uma constraint &lt;code&gt;UNIQUE&lt;/code&gt;, mas explicito como indice.&lt;/p&gt;

&lt;p&gt;Para buscas de texto parcial (LIKE), use indices com &lt;code&gt;varchar_pattern_ops&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE INDEX idx_clientes_nome ON clientes(nome varchar_pattern_ops);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso acelera consultas como &lt;code&gt;WHERE nome LIKE 'Silva%'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Indices em tabelas grandes tem custo: eles desaceleram &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt; e &lt;code&gt;DELETE&lt;/code&gt;. Cada vez que voce insere uma linha, o banco atualiza todos os indices.&lt;/p&gt;

&lt;p&gt;Para monitorar indices nao usados:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    schemaname,
    tablename,
    indexname,
    idx_scan,
    idx_tup_read,
    idx_tup_fetch
FROM pg_stat_user_indexes
ORDER BY idx_scan ASC
LIMIT 10;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Indices com &lt;code&gt;idx_scan&lt;/code&gt; baixo sao candidatos a remocao.&lt;/p&gt;

&lt;p&gt;Uma dica pratica: indices em colunas com baixa cardinalidade (como status com 3 valores possiveis) raramente ajudam. O banco prefere ler a tabela toda em vez de usar o indice.&lt;/p&gt;

&lt;p&gt;Para colunas booleanas ou de poucos valores, indices parciais sao a melhor opcao.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>database</category>
      <category>performance</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to usar CTEs para consultas SQL mais legiveis</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 22:07:11 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-usar-ctes-para-consultas-sql-mais-legiveis-19d2</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-usar-ctes-para-consultas-sql-mais-legiveis-19d2</guid>
      <description>&lt;p&gt;CTEs (Common Table Expressions) tornam consultas SQL mais legiveis ao dividir logicas complexas em blocos nomeados. E como criar variaveis temporarias dentro da query.&lt;/p&gt;

&lt;p&gt;A sintaxe basica:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH vendas_recentes AS (
    SELECT * FROM vendas WHERE data &amp;gt;= '2025-01-01'
)
SELECT cliente_id, SUM(valor) as total
FROM vendas_recentes
GROUP BY cliente_id
ORDER BY total DESC;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O &lt;code&gt;WITH&lt;/code&gt; define um bloco temporario chamado &lt;code&gt;vendas_recentes&lt;/code&gt;. A query principal usa esse bloco como se fosse uma tabela.&lt;/p&gt;

&lt;p&gt;CTEs sao uteis para reutilizar a mesma subconsulta em varios lugares:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH gastos_por_cliente AS (
    SELECT cliente_id, SUM(valor) as total_gasto
    FROM vendas
    GROUP BY cliente_id
)
SELECT 
    c.nome,
    g.total_gasto,
    CASE 
        WHEN g.total_gasto &amp;gt; 1000 THEN 'VIP'
        ELSE 'normal'
    END as categoria
FROM clientes c
JOIN gastos_por_cliente g ON c.id = g.cliente_id
ORDER BY g.total_gasto DESC;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sem CTE, voce teria que repetir o &lt;code&gt;SUM(valor)&lt;/code&gt; ou criar uma view.&lt;/p&gt;

&lt;p&gt;CTEs recursivas permitem trabalhar com dados hierarquicos como arvores de categorias:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH RECURSIVE subcategorias AS (
    SELECT id, nome, parent_id, 1 as nivel
    FROM categorias
    WHERE parent_id IS NULL

    UNION ALL

    SELECT c.id, c.nome, c.parent_id, s.nivel + 1
    FROM categorias c
    JOIN subcategorias s ON c.parent_id = s.id
)
SELECT * FROM subcategorias ORDER BY nivel, nome;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A parte antes do &lt;code&gt;UNION ALL&lt;/code&gt; e o caso base (categorias raiz). A parte depois e a recursao que busca os filhos. O &lt;code&gt;nivel&lt;/code&gt; controla a profundidade.&lt;/p&gt;

&lt;p&gt;Para calcular o total de vendas com crescimento mes a mes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH vendas_por_mes AS (
    SELECT 
        DATE_TRUNC('month', data) as mes,
        SUM(valor) as total_mes
    FROM vendas
    GROUP BY DATE_TRUNC('month', data)
),
com_diferenca AS (
    SELECT 
        mes,
        total_mes,
        LAG(total_mes) OVER (ORDER BY mes) as mes_anterior,
        total_mes - LAG(total_mes) OVER (ORDER BY mes) as crescimento
    FROM vendas_por_mes
)
SELECT 
    mes,
    total_mes,
    COALESCE(crescimento, 0) as crescimento
FROM com_diferenca
ORDER BY mes;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Multiplas CTEs sao separadas por virgula. Cada uma pode referenciar as anteriores.&lt;/p&gt;

&lt;p&gt;Para encontrar o caminho entre dois usuarios em uma rede social:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH RECURSIVE conexoes AS (
    SELECT usuario1, usuario2, array[usuario1, usuario2] as caminho
    FROM amizades
    WHERE usuario1 = 1

    UNION ALL

    SELECT a.usuario1, a.usuario2, c.caminho || a.usuario2
    FROM amizades a
    JOIN conexoes c ON a.usuario1 = c.usuario2
    WHERE NOT a.usuario2 = ANY(c.caminho)
)
SELECT * FROM conexoes WHERE usuario2 = 10;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;CTEs nao sao sempre a opcao mais rapida. O banco pode otimizar subconsultas simples melhor que CTEs. Mas para legibilidade, CTEs ganham sempre.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>database</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to usar window functions para resolver em uma query</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 22:06:24 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-usar-window-functions-para-resolver-em-uma-query-3ioa</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-usar-window-functions-para-resolver-em-uma-query-3ioa</guid>
      <description>&lt;p&gt;Window functions resolvem em uma unica query problemas que antes exigiam subconsultas ou joins complicados. Elas calculam valores baseados em um conjunto de linhas relacionadas sem agrupar o resultado.&lt;/p&gt;

&lt;p&gt;A sintaxe basica com &lt;code&gt;ROW_NUMBER&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    nome,
    departamento,
    salario,
    ROW_NUMBER() OVER (PARTITION BY departamento ORDER BY salario DESC) as posicao
FROM funcionarios;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso numero cada funcionario dentro do seu departamento, ordenado por salario. O &lt;code&gt;PARTITION BY&lt;/code&gt; divide as linhas em grupos. O &lt;code&gt;ORDER BY&lt;/code&gt; define a ordem dentro de cada grupo.&lt;/p&gt;

&lt;p&gt;Para pegar os 3 maiores salarios de cada departamento:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WITH ranked AS (
    SELECT 
        nome,
        departamento,
        salario,
        ROW_NUMBER() OVER (PARTITION BY departamento ORDER BY salario DESC) as pos
    FROM funcionarios
)
SELECT * FROM ranked WHERE pos &amp;lt;= 3;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;RANK&lt;/code&gt; e &lt;code&gt;DENSE_RANK&lt;/code&gt; sao variantes que lidam com empates:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    nome,
    departamento,
    salario,
    RANK() OVER (ORDER BY salario DESC) as rank,
    DENSE_RANK() OVER (ORDER BY salario DESC) as dense_rank
FROM funcionarios;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;RANK&lt;/code&gt; pula numeros em caso de empate (1, 1, 3). &lt;code&gt;DENSE_RANK&lt;/code&gt; nao pula (1, 1, 2).&lt;/p&gt;

&lt;p&gt;Para calcular totais acumulados:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    data,
    valor,
    SUM(valor) OVER (ORDER BY data) as acumulado
FROM vendas
ORDER BY data;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A &lt;code&gt;SUM&lt;/code&gt; com &lt;code&gt;OVER&lt;/code&gt; sem &lt;code&gt;PARTITION BY&lt;/code&gt; calcula o total acumulado desde o inicio.&lt;/p&gt;

&lt;p&gt;Para comparar um valor com a linha anterior:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    data,
    valor,
    LAG(valor, 1) OVER (ORDER BY data) as valor_anterior,
    valor - LAG(valor, 1) OVER (ORDER BY data) as diferenca
FROM vendas
ORDER BY data;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;LAG&lt;/code&gt; olha para tras. &lt;code&gt;LEAD&lt;/code&gt; olha para frente. O segundo parametro e quantas linhas pular.&lt;/p&gt;

&lt;p&gt;Para media movel de 7 dias:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    data,
    valor,
    AVG(valor) OVER (ORDER BY data ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as media_movel_7d
FROM vendas;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O &lt;code&gt;ROWS BETWEEN&lt;/code&gt; define a janela. &lt;code&gt;6 PRECEDING&lt;/code&gt; pega as 6 linhas anteriores. &lt;code&gt;CURRENT ROW&lt;/code&gt; e a linha atual.&lt;/p&gt;

&lt;p&gt;Para percentual de cada venda dentro do total:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
    produto,
    valor,
    valor / SUM(valor) OVER () * 100 as percentual
FROM vendas;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sem &lt;code&gt;PARTITION BY&lt;/code&gt;, a &lt;code&gt;SUM&lt;/code&gt; considera todas as linhas.&lt;/p&gt;

&lt;p&gt;Window functions sao mais performaticas que subconsultas equivalentes. O banco processa tudo em um unico scan dos dados.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>sql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to fazer deploy do Spring Boot com Docker sem dor de cabeca</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 22:04:27 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-fazer-deploy-do-spring-boot-com-docker-sem-dor-de-cabeca-4l02</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-fazer-deploy-do-spring-boot-com-docker-sem-dor-de-cabeca-4l02</guid>
      <description>&lt;p&gt;Spring Boot e Docker juntos fazem o deploy ser uma tarefa simples. Com um Dockerfile bem feito, voce empacota a aplicacao e roda em qualquer ambiente sem surpresas.&lt;/p&gt;

&lt;p&gt;O Dockerfile basico para uma aplicacao Spring Boot com Java 21:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY gradlew gradlew.bat build.gradle.kts settings.gradle.kts ./
COPY gradle gradle
RUN ./gradlew dependencies
COPY src src
RUN ./gradlew bootJar -x test

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O primeiro stage compila o projeto. O segundo stage copia so o JAR. A imagem final e pequena porque nao tem Gradle nem JDK.&lt;/p&gt;

&lt;p&gt;Para construir:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t minha-api .
docker run -p 8080:8080 minha-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para passar properties externas no docker run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 8080:8080 \
    -e SPRING_PROFILES_ACTIVE=prod \
    -e APP_DB_URL=jdbc:postgresql://host.docker.internal:5432/db \
    minha-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Variaveis de ambiente sobrescrevem as properties do application.properties.&lt;/p&gt;

&lt;p&gt;Para usar Docker Compose com banco de dados:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3.8'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      SPRING_PROFILES_ACTIVE: prod
      SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/meubanco
      SPRING_DATASOURCE_USERNAME: app
      SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    environment:
      POSTGRES_DB: meubanco
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d meubanco"]
      interval: 5s
      timeout: 3s
      retries: 5
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O &lt;code&gt;depends_on&lt;/code&gt; com &lt;code&gt;condition: service_healthy&lt;/code&gt; garante que o banco esteja pronto antes da aplicacao iniciar.&lt;/p&gt;

&lt;p&gt;Para imagens ainda menores, use JRE slim ou distroless:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM eclipse-temurin:21-jre-alpine
RUN addgroup -S app &amp;amp;&amp;amp; adduser -S app -G app
USER app
COPY --from=builder /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Executar a aplicacao como usuario nao root e uma boa pratica de seguranca.&lt;/p&gt;

&lt;p&gt;Para multiplos profiles de Docker Compose:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# docker-compose.override.yml (ambiente local)
services:
  app:
    environment:
      SPRING_PROFILES_ACTIVE: dev

# docker-compose.prod.yml (producao)
services:
  app:
    environment:
      SPRING_PROFILES_ACTIVE: prod
    restart: always
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Uso: &lt;code&gt;docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>java</category>
      <category>springboot</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to fazer exception handling limpo com ControllerAdvice</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 22:02:06 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-fazer-exception-handling-limpo-com-controlleradvice-5h0</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-fazer-exception-handling-limpo-com-controlleradvice-5h0</guid>
      <description>&lt;p&gt;@ControllerAdvice e a forma mais limpa de centralizar o tratamento de erros em uma aplicacao Spring Boot. Em vez de espalhar try/catch por todos os controllers, voce trata tudo em um lugar so.&lt;/p&gt;

&lt;p&gt;Crie uma classe com &lt;code&gt;@ControllerAdvice&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ControllerAdvice
class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException::class)
    fun handleNotFound(ex: ResourceNotFoundException, request: WebRequest):
            ResponseEntity&amp;lt;Map&amp;lt;String, Any&amp;gt;&amp;gt; {
        val body = mapOf(
            "error" to "Not Found",
            "message" to ex.message,
            "status" to 404
        )
        return ResponseEntity(body, HttpStatus.NOT_FOUND)
    }

    @ExceptionHandler(MethodArgumentNotValidException::class)
    fun handleValidation(ex: MethodArgumentNotValidException):
            ResponseEntity&amp;lt;Map&amp;lt;String, Any&amp;gt;&amp;gt; {
        val erros = ex.bindingResult.fieldErrors.map {
            "${it.field}: ${it.defaultMessage}"
        }
        val body = mapOf(
            "error" to "Validation Failed",
            "details" to erros,
            "status" to 400
        )
        return ResponseEntity(body, HttpStatus.BAD_REQUEST)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Crie excecoes customizadas:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ResourceNotFoundException(message: String) : RuntimeException(message)
class BusinessException(message: String) : RuntimeException(message)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Uso no controller:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
class UsuarioController(private val service: UsuarioService) {

    @GetMapping("/usuarios/{id}")
    fun buscar(@PathVariable id: Long): ResponseEntity&amp;lt;Usuario&amp;gt; {
        val usuario = service.buscarPorId(id)
            ?: throw ResourceNotFoundException("Usuario $id nao encontrado")
        return ResponseEntity.ok(usuario)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Quando o usuario nao existe, o &lt;code&gt;ResourceNotFoundException&lt;/code&gt; e lancado. O &lt;code&gt;GlobalExceptionHandler&lt;/code&gt; captura e retorna um JSON limpo.&lt;/p&gt;

&lt;p&gt;Para validacao de entrada com &lt;code&gt;@Valid&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class CriarUsuarioRequest(
    @field:NotBlank val nome: String,
    @field:Email val email: String,
    @field:Min(18) val idade: Int
)

@PostMapping("/usuarios")
fun criar(@Valid @RequestBody request: CriarUsuarioRequest): ResponseEntity&amp;lt;Usuario&amp;gt; {
    val usuario = service.criar(request)
    return ResponseEntity(usuario, HttpStatus.CREATED)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Se a validacao falha, o &lt;code&gt;MethodArgumentNotValidException&lt;/code&gt; e lancado e o handler devolve os erros campo a campo.&lt;/p&gt;

&lt;p&gt;Para excecoes genericas nao mapeadas:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ExceptionHandler(Exception::class)
fun handleGeneric(ex: Exception): ResponseEntity&amp;lt;Map&amp;lt;String, Any&amp;gt;&amp;gt; {
    val body = mapOf(
        "error" to "Internal Server Error",
        "message" to (ex.message ?: "Erro inesperado"),
        "status" to 500
    )
    return ResponseEntity(body, HttpStatus.INTERNAL_SERVER_ERROR)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Monte a resposta padrao em uma data class:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class ErrorResponse(
    val error: String,
    val message: String?,
    val status: Int,
    val timestamp: Long = System.currentTimeMillis()
)

@ExceptionHandler(BusinessException::class)
fun handleBusiness(ex: BusinessException): ResponseEntity&amp;lt;ErrorResponse&amp;gt; {
    val body = ErrorResponse(
        error = "Business Error",
        message = ex.message,
        status = 422
    )
    return ResponseEntity(body, HttpStatus.UNPROCESSABLE_ENTITY)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para mais de um tipo de excecao no mesmo handler:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ExceptionHandler(IOException::class, DataAccessException::class)
fun handleInfra(ex: Exception): ResponseEntity&amp;lt;ErrorResponse&amp;gt; {
    return ResponseEntity(
        ErrorResponse("Infra Error", ex.message, 503),
        HttpStatus.SERVICE_UNAVAILABLE
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Com &lt;code&gt;@ControllerAdvice&lt;/code&gt; voce tem um unico ponto de tratamento de erros. O codigo dos controllers fica limpo e as respostas de erro seguem um padrao consistente.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>backend</category>
      <category>kotlin</category>
      <category>springboot</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to usar Testcontainers para testes de integracao que prestam</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:59:59 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-usar-testcontainers-para-testes-de-integracao-que-prestam-44d8</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-usar-testcontainers-para-testes-de-integracao-que-prestam-44d8</guid>
      <description>&lt;p&gt;Testcontainers e uma biblioteca que sobe containers Docker dentro dos seus testes de integracao. Em vez de mockar o banco de dados, voce usa um banco de verdade que nasce e morre com o teste.&lt;/p&gt;

&lt;p&gt;Adicione a dependencia no &lt;code&gt;build.gradle.kts&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;testImplementation("org.testcontainers:testcontainers:1.20.0")
testImplementation("org.testcontainers:postgresql:1.20.0")
testImplementation("org.testcontainers:junit-jupiter:1.20.0")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O teste mais simples com PostgreSQL:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Testcontainers
@SpringBootTest
class UsuarioRepositoryTest {

    companion object {
        @Container
        val postgres = PostgreSQLContainer&amp;lt;Nothing&amp;gt;("postgres:16").apply {
            withDatabaseName("testdb")
            withUsername("test")
            withPassword("test")
        }
    }

    @Autowired
    lateinit var repo: UsuarioRepository

    @Test
    fun deveSalvarUsuario() {
        val usuario = Usuario(nome = "Joao", email = "joao@email.com")
        val salvo = repo.save(usuario)
        assertThat(salvo.id).isNotNull()
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O Testcontainers sobe um container PostgreSQL antes dos testes e derruba depois. Nao precisa de banco instalado na maquina.&lt;/p&gt;

&lt;p&gt;Para configurar o Spring Boot automaticamente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@DynamicPropertySource
fun configurarProps(registry: DynamicPropertyRegistry) {
    registry.add("spring.datasource.url", postgres::getJdbcUrl)
    registry.add("spring.datasource.username", postgres::getUsername)
    registry.add("spring.datasource.password", postgres::getPassword)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso substitui as properties do application.properties pela URL do container que acabou de subir.&lt;/p&gt;

&lt;p&gt;Para Redis:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Container
val redis = GenericContainer&amp;lt;Nothing&amp;gt;("redis:7").apply {
    withExposedPorts(6379)
}

@DynamicPropertySource
fun redisProps(registry: DynamicPropertyRegistry) {
    registry.add("spring.redis.host", redis::getHost)
    registry.add("spring.redis.port") { redis.getMappedPort(6379).toString() }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Testcontainers tambem suporta Kafka:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Container
val kafka = KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:7.6.0"))

@DynamicPropertySource
fun kafkaProps(registry: DynamicPropertyRegistry) {
    registry.add("spring.kafka.bootstrap-servers", kafka::getBootstrapServers)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para reaproveitar o container entre varios testes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Testcontainers
abstract class AbstractIntegrationTest {
    companion object {
        @Container
        val postgres = PostgreSQLContainer&amp;lt;Nothing&amp;gt;("postgres:16").apply {
            withDatabaseName("testdb")
            withUsername("test")
            withPassword("test")
            start()
        }

        @DynamicPropertySource
        @JvmStatic
        fun props(registry: DynamicPropertyRegistry) {
            registry.add("spring.datasource.url", postgres::getJdbcUrl)
            registry.add("spring.datasource.username", postgres::getUsername)
            registry.add("spring.datasource.password", postgres::getPassword)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Agora toda classe que estender &lt;code&gt;AbstractIntegrationTest&lt;/code&gt; ganha um banco PostgreSQL real.&lt;/p&gt;

&lt;p&gt;Dica: se os testes ficarem lentos, use &lt;code&gt;withReuse(true)&lt;/code&gt; no container. Isso mantem o container vivo entre execucoes. So nao esqueca de configurar &lt;code&gt;testcontainers.reuse.enable=true&lt;/code&gt; em &lt;code&gt;~/.testcontainers.properties&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>kotlin</category>
      <category>springboot</category>
      <category>testing</category>
    </item>
    <item>
      <title>How to externalizar properties no Spring Boot sem surpresas</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:59:32 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-externalizar-properties-no-spring-boot-sem-surpresas-534a</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-externalizar-properties-no-spring-boot-sem-surpresas-534a</guid>
      <description>&lt;p&gt;Properties externalizadas sao uma das maiores vantagens do Spring Boot. Elas permitem mudar o comportamento da aplicacao sem recompilar nada.&lt;/p&gt;

&lt;p&gt;O jeito mais comum e usar o &lt;code&gt;application.properties&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# application.properties
app.nome=MeuServico
app.versao=1.0.0
server.port=8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para acessar no codigo:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
class ConfigService {
    @Value("\${app.nome}")
    lateinit var nomeApp: String

    @Value("\${app.versao}")
    lateinit var versao: String

    fun mostrar() {
        println("$nomeApp - v$versao")
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Um problema comum: se a chave nao existe, o Spring lanca uma excecao na inicializacao. Para evitar isso, use valores default:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Value("\${app.autor:desconhecido}")
lateinit var autor: String
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para ambientes diferentes, crie arquivos separados:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# application-dev.properties
server.port=8081
spring.datasource.url=jdbc:h2:mem:devdb

# application-prod.properties
server.port=80
spring.datasource.url=jdbc:postgresql://prod:5432/db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Ative o perfil com &lt;code&gt;SPRING_PROFILES_ACTIVE&lt;/code&gt; ou &lt;code&gt;--spring.profiles.active&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SPRING_PROFILES_ACTIVE=prod java -jar app.jar
java -jar app.jar --spring.profiles.active=dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Properties tambem podem vir de variaveis de ambiente. O Spring Boot mapeia automaticamente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Variavel de ambiente
export APP_NOME=MeuApp

# No application.properties
app.nome=\${APP_NOME:default}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A configuracao externalizada segue uma ordem de precedencia. Variaveis de ambiente sobrescrevem application.properties, que sobrescrevem valores default.&lt;/p&gt;

&lt;p&gt;Para grupos de properties, use &lt;code&gt;@ConfigurationProperties&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# application.properties
app.mail.host=smtp.gmail.com
app.mail.port=587
app.mail.username=user@gmail.com

@ConfigurationProperties(prefix = "app.mail")
@Component
class MailProperties {
    var host: String = ""
    var port: Int = 587
    var username: String = ""
}

@Service
class MailService(private val props: MailProperties) {
    fun configurar() {
        println("SMTP: ${props.host}:${props.port}")
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;@ConfigurationProperties&lt;/code&gt; agrupa todas as properties com prefixo &lt;code&gt;app.mail&lt;/code&gt; em um objeto tipado. Muito mais limpo que varios &lt;code&gt;@Value&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para usar arquivos YAML:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# application.yml
app:
  nome: MeuServico
  database:
    url: jdbc:postgresql://localhost:5432/db
    pool:
      max: 10
      min: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Properties de ultimo recurso: &lt;code&gt;@PropertySource&lt;/code&gt; para carregar um arquivo especifico:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Configuration
@PropertySource("classpath:config/custom.properties")
class CustomConfig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Nunca coloque senhas e chaves de API no application.properties. Use variaveis de ambiente ou um servico de secrets.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>backend</category>
      <category>kotlin</category>
      <category>springboot</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to usar awk e sed no processamento de texto do dia a dia</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:59:08 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-usar-awk-e-sed-no-processamento-de-texto-do-dia-a-dia-2nfc</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-usar-awk-e-sed-no-processamento-de-texto-do-dia-a-dia-2nfc</guid>
      <description>&lt;p&gt;awk e sed sao dois comandos classicos do Unix que continuam sendo uteis mesmo com ferramentas modernas. Eles processam texto linha por linha sem precisar de scripts grandes.&lt;/p&gt;

&lt;p&gt;Sed e um editor de texto nao interativo. O uso mais comum e substituicao:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sed 's/antigo/novo/g' arquivo.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O &lt;code&gt;s&lt;/code&gt; significa substituir, o &lt;code&gt;g&lt;/code&gt; significa global (todas as ocorrencias na linha).&lt;/p&gt;

&lt;p&gt;Para editar o arquivo direto:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sed -i 's/erro/ERRO/g' arquivo.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Substituir em multiplos arquivos:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sed -i 's/pagina2antiga/paginanova/g' *.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para deletar linhas que contem um padrao:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sed -i '/debug/d' arquivo.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O &lt;code&gt;d&lt;/code&gt; deleta a linha inteira.&lt;/p&gt;

&lt;p&gt;Para mostrar apenas as linhas 10 a 20:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sed -n '10,20p' arquivo.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O &lt;code&gt;-n&lt;/code&gt; suprime a saida padrao. O &lt;code&gt;p&lt;/code&gt; imprime as linhas selecionadas.&lt;/p&gt;

&lt;p&gt;Agora awk. Awk processa linhas como campos separados por espaco (ou outro delimitador):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk '{print $1, $3}' arquivo.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso imprime o primeiro e terceiro campo de cada linha.&lt;/p&gt;

&lt;p&gt;Para usar outro delimitador, como CSV:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk -F',' '{print $1, $2}' dados.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Filtragem condicional:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk '$3 &amp;gt; 100 {print $1, $3}' dados.txt
awk '/ERROR/ {print $1, $2, $NF}' sistema.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O &lt;code&gt;$NF&lt;/code&gt; e o ultimo campo da linha.&lt;/p&gt;

&lt;p&gt;Um exemplo pratico com logs Docker:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker logs meu-container | awk '/ERROR/ {print $1, $2, $NF}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para formatar saida de comandos:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ps aux | awk '{printf "%-10s %-6s %s\n", $1, $2, $11}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Awk tambem faz contas:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;awk '{soma += $3} END {print "Total:", soma}' valores.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O bloco &lt;code&gt;END&lt;/code&gt; executa depois de processar todas as linhas.&lt;/p&gt;

&lt;p&gt;Combinando awk e sed para limpar dados:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat dados_sujos.csv | sed 's/"//g' | awk -F',' '{print $1, $2}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sed remove as aspas duplas. Awk extrai as duas primeiras colunas.&lt;/p&gt;

&lt;p&gt;Awk e sed resolvem problemas de processamento de texto em uma linha onde linguagens como Python exigiriam um arquivo separado. Para tarefas rapidas no terminal, eles sao insubstituiveis.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>cli</category>
      <category>linux</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to criar aliases e funcoes no bash que viram costume</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:58:50 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-criar-aliases-e-funcoes-no-bash-que-viram-costume-3dm8</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-criar-aliases-e-funcoes-no-bash-que-viram-costume-3dm8</guid>
      <description>&lt;p&gt;Aliases e funcoes no bash transformam comandos longos em atalhos de uma palavra. Depois que voce comeca a usar, nao volta mais.&lt;/p&gt;

&lt;p&gt;Para criar um alias simples, adicione no &lt;code&gt;~/.bashrc&lt;/code&gt; ou &lt;code&gt;~/.bash_aliases&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias ll='ls -la --color=auto'
alias gs='git status'
alias gc='git commit -m'
alias gp='git push'
alias dc='docker compose'
alias dps='docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Recarregue com:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Aliases aceitam parametros no final. Para parametros no meio, use funcoes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gmkdir() {
    mkdir -p "$1" &amp;amp;&amp;amp; cd "$1"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Uso: &lt;code&gt;gmkdir novo-projeto&lt;/code&gt; cria a pasta e ja entra nela.&lt;/p&gt;

&lt;p&gt;Funcoes de busca frequente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;findtext() {
    grep -rn "$1" --include="*.py" --include="*.java" "$2" .
}

findfile() {
    find . -name "*$1*" 2&amp;gt;/dev/null
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Uso: &lt;code&gt;findtext "TODO" src/&lt;/code&gt; ou &lt;code&gt;findfile "Dockerfile"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Funcao para navegar rapido no Git:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcob() {
    git checkout -b "$1" 2&amp;gt;/dev/null || git checkout "$1"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Uso: &lt;code&gt;gcob main&lt;/code&gt; faz checkout para main. &lt;code&gt;gcob feature/x&lt;/code&gt; cria e vai para o branch novo.&lt;/p&gt;

&lt;p&gt;Para navegar entre projetos:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;proj() {
    cd ~/projects/"$1" 2&amp;gt;/dev/null || echo "projeto nao encontrado"
}

compro() {
    compgen -W "$(ls ~/projects)" -- "$1"
}
complete -F compro proj
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Agora &lt;code&gt;proj meu-app&lt;/code&gt; ja leva para &lt;code&gt;~/projects/meu-app&lt;/code&gt;. O autocomplete via &lt;code&gt;complete -F&lt;/code&gt; mostra a lista de projetos ao apertar Tab.&lt;/p&gt;

&lt;p&gt;Funcao para backup rapido:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;backup() {
    cp "$1"{,.bak}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Uso: &lt;code&gt;backup config.yaml&lt;/code&gt; cria &lt;code&gt;config.yaml.bak&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Mini calculadora no terminal:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;calc() {
    echo "$*" | bc -l
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Uso: &lt;code&gt;calc "42 * 3.14 + 10"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para extrair qualquer tipo de arquivo sem lembrar o comando:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extract() {
    case "$1" in
        *.tar.gz)  tar xzf "$1" ;;
        *.tar.bz2) tar xjf "$1" ;;
        *.zip)     unzip "$1" ;;
        *.rar)     unrar x "$1" ;;
        *.7z)      7z x "$1" ;;
        *)         echo "formato nao reconhecido" ;;
    esac
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Coloque tudo em um arquivo separado como &lt;code&gt;~/.bash_aliases&lt;/code&gt; e mande source no &lt;code&gt;~/.bashrc&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Assim voce mantem os aliases organizados sem poluir o &lt;code&gt;~/.bashrc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>cli</category>
      <category>linux</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to usar stash, bisect e worktree no Git</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:58:29 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-usar-stash-bisect-e-worktree-no-git-270h</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-usar-stash-bisect-e-worktree-no-git-270h</guid>
      <description>&lt;p&gt;Git tem comandos que vao alem do commit e push. Tres deles salvam tempo em situacoes especificas: stash, bisect e worktree.&lt;/p&gt;

&lt;p&gt;Stash guarda modificacoes nao commitadas para voce poder mudar de branch sem perder o trabalho:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "nova feature" &amp;gt; arquivo.txt
git stash push -m "WIP: comeco da feature"
git stash list
git stash pop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para guardar apenas arquivos especificos:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git stash push -m "so mudancas no frontend" src/frontend/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para ver o que tem dentro de um stash sem aplicar:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git stash show -p stash@{0}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Bisect faz busca binaria no historico para encontrar o commit que introduziu um bug:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git bisect start
git bisect bad       # versao atual esta quebrada
git bisect good v1.0 # versao v1.0 estava funcionando
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O Git vai fazendo checkout nos commits do meio do caminho. Voce testa e marca:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git bisect good  # esse commit funciona
git bisect bad   # esse commit esta quebrado
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Quando encontrar o commit culpado, o Git mostra a mensagem. Para sair:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git bisect reset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Da para automatizar com um script:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git bisect start HEAD v1.0
git bisect run python test_bug.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O Git executa &lt;code&gt;test_bug.py&lt;/code&gt; em cada commit. Se o script retorna 0, marca como good. Se retorna 1, marca como bad.&lt;/p&gt;

&lt;p&gt;Worktree permite ter multiplos branches checked out ao mesmo tempo em pastas separadas:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git worktree add ../projeto-hotfix hotfix/urgente
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso cria uma pasta &lt;code&gt;projeto-hotfix&lt;/code&gt; ao lado do seu projeto com o branch &lt;code&gt;hotfix/urgente&lt;/code&gt; ja checked out. Voce trabalha nos dois ao mesmo tempo sem precisar esconder nada com stash.&lt;/p&gt;

&lt;p&gt;Para listar worktrees ativas:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git worktree list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para remover uma worktree:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git worktree remove ../projeto-hotfix
git branch -d hotfix/urgente
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Worktree e ideal para revisao de PR. Voce faz checkout do branch do PR em outra pasta, revisa, testa, e volta para seu branch sem perder contexto.&lt;/p&gt;

&lt;p&gt;Stash resolve trocas rapidas de contexto. Bisect encontra bugs em minutos que levariam horas manualmente. Worktree elimina o atrito de alternar entre branches. Os tres juntos cobrem situacoes que o commit simples nao resolve.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>git</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to turbinar o terminal com jq, fzf e ripgrep</title>
      <dc:creator>Isaias Velasquez</dc:creator>
      <pubDate>Sat, 11 Jul 2026 21:58:14 +0000</pubDate>
      <link>https://dev.to/isaias_velasquez_d2261770/how-to-turbinar-o-terminal-com-jq-fzf-e-ripgrep-i6f</link>
      <guid>https://dev.to/isaias_velasquez_d2261770/how-to-turbinar-o-terminal-com-jq-fzf-e-ripgrep-i6f</guid>
      <description>&lt;p&gt;jq, fzf e ripgrep sao tres ferramentas de terminal que mudaram a forma como trabalho com arquivos e dados. Cada uma resolve um problema especifico e juntas formam um trio poderoso.&lt;/p&gt;

&lt;p&gt;Primeiro, ripgrep (rg). Ele substitui o grep tradicional com uma busca muito mais rapida e com sintaxe mais amigavel:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rg "funcao main" src/
rg "TODO|FIXME" --type py
rg "import" -l src/  # so nomes de arquivo
rg "case class" --ignore-case
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Instale no Ubuntu ou WSL:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install ripgrep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;No macOS:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install ripgrep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O ripgrep respeita &lt;code&gt;.gitignore&lt;/code&gt; por padrao. Nao precisa ficar excluindo node_modules ou target manualmente.&lt;/p&gt;

&lt;p&gt;Agora fzf. E um fuzzy finder que deixa voce buscar e selecionar qualquer coisa no terminal de forma interativa:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;history | fzf  # busca em comandos recentes
Ctrl+R no terminal ja usa fzf se configurado
Ctrl+T para buscar arquivos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Instale:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Depois de instalado, aperte Ctrl+R no terminal. Voce digita parte de um comando antigo e o fzf filtra e seleciona.&lt;/p&gt;

&lt;p&gt;Combine fzf com ripgrep para buscar arquivos de forma inteligente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rg --files | fzf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para abrir um arquivo qualquer do projeto:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vim $(rg --files | fzf)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Ou com fd (outra ferramenta rapida para listar arquivos):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install fd-find
vim $(fd . | fzf)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Agora jq. E um processador de JSON que roda no terminal. Perfeito para trabalhar com APIs:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://api.github.com/repos/user/repo | jq '.stargazers_count'
curl https://api.github.com/repos/user/repo | jq '.name, .description'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Para extrair dados de uma lista:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://api.github.com/users/octocat/repos | jq '.[] | .name'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Filtrar por condicao:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://api.github.com/users/octocat/repos | jq '.[] | select(.language == "Python") | .name'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Formatar saida:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl https://api.github.com/users/octocat/repos | jq '.[] | {nome: .name, estrelas: .stargazers_count}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Instale:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install jq
# ou
brew install jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Juntando os tres. Aqui esta um exemplo pratico:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rg --files | fzf --preview 'bat --color=always {}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Isso lista todos os arquivos do projeto com ripgrep, filtra interativamente com fzf e mostra uma pre-visualizacao com bat (outro substituto do cat com syntax highlight).&lt;/p&gt;

&lt;p&gt;Para buscar dentro de logs JSON:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat arquivo.log | jq 'select(.level == "ERROR") | .message' | fzf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Essas tres ferramentas sao instalacao obrigatoria em qualquer maquina que voce use para desenvolver.&lt;/p&gt;

&lt;p&gt;That's all for now.&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>cli</category>
      <category>linux</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
