Tag: Public

Mostrando todas as entradas e posts com a tag "Public"

Entradas do Diário

Reflexão sobre organização de código

Reflexão sobre organização de código

Há uma reflexão interessante sobre como organizar o código.

Faz muito tempo que deixei de me preocupar com estruturas de diretórios, tamanhos de arquivos ou localização física do código. Isso porque minha organização não depende da estrutura no disco, mas sim da própria estrutura da linguagem - pacotes, funções e módulos. Além disso, uso ferramentas que me levam diretamente ao ponto do código que quero editar.

Por exemplo, em vez de procurar manualmente por arquivos ou pastas, configurei meu editor para que, ao pressionar Enter sobre o nome de uma função ou objeto, ele vá diretamente para sua definição, e ao pressionar Backspace, volte ao ponto anterior. Tenho vários outros atalhos semelhantes, que me permitem navegar pelo código - não pelos arquivos.

Esse modo de trabalho tem alguns efeitos. Qualquer forma de indireção no código torna a navegação menos fluida, por isso evito o uso de interfaces quando não são realmente necessárias.

Prefiro navegar pela lógica do código e não pelo sistema de arquivos, pois isso reduz a carga cognitiva durante a escrita e, principalmente, durante a depuração. Há muitos anos estudo maneiras de reduzir essa carga, eliminando distrações e mantendo o foco na tarefa.

Sistemas de arquivos não são código, nem se transformam em código - são apenas mais uma camada de indireção, e toda indireção tem um custo.

Esse método funciona bem para mim porque foi moldado para o meu modo de pensar. Outras pessoas têm abordagens diferentes que fazem mais sentido para elas. Ainda assim, percebo que, cada vez mais, bons programadores tendem a organizar-se com base na estrutura do código, e não na estrutura dos arquivos.

Há uma reflexão interessante sobre como organizar o código.


Habilitar QUIC/HTTP3.

Habilitar QUIC/HTTP3.

Para quem usa o Caddy versão >= 2.6, basta liberar o acesso UDP na porta 443 no firewall do servidor. O Caddy já vem com suporte nativo ao HTTP/3.

Testei com curl e com alguns navegadores e funcionou perfeitamente.

curl -I --http3 https://empreendedor.dev

Se o navegador não suportar HTTP/3, ele volta para HTTP/2 automaticamente.

Para quem usa o Caddy versão >= 2.6, basta liberar o acesso UDP na porta 443 no firewall do servidor. O Caddy já vem com suporte nativo ao HTTP/3.


Git Blame

Git Blame

Git blame para uma linha específica ou um intervalo de linhas em um arquivo.

git blame -L 102,102 main.go
git blame -L 100,110 main.go

O resultado será algo como:

a1b2c3d4 (Cesar Gimenes 2025-09-10  102)     valor := calc()

Onde a1b2c3d4 é o hash do commit.

Para ver o commit completo:

git show a1b2c3d4

Isso mostrará todas as alterações feitas naquele commit específico.

Git blame para uma linha específica ou um intervalo de linhas em um arquivo.


Limpa campo de documento

Limpa campo de documento

Você tem um campo com o CPF ou CNPJ e quer limpar tudo que não for número?

func RemoveNonDigits(s string) string {
	var r string
	for _, c := range s {
		if unicode.IsDigit(c) {
			r += string(c)
		}
	}
	return r
}

Você tem um campo com o CPF ou CNPJ e quer limpar tudo que não for número?


PostgreSQL: Subselect para array

PostgreSQL: Subselect para array

Para criar um array a partir de um subselect em PostgreSQL use a função ARRAY junto com COALESCE para garantir que o resultado seja um array vazio caso não haja resultados.

Exemplo:

SELECT
    id,
    ...,
    coalesce(ARRAY(
        SELECT t2.some_field
            from table2 as t2
            where t1.id = t2.t1_id
        ),'{}'::text[]) as array_field
    FROM table1 as t1

Neste exemplo, array_field será um array contendo os valores de some_field da table2 relacionados ao id da table1. Se não houver correspondências, o campo será um array vazio ('{}'::text[]).


The most effective debugging tool

The most effective debugging tool

The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.

  • Brian W. Kernighan, in the paper Unix for Beginners (1979)

The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.


len no Bash

len no Bash

Script Bash para retornar o tamanho de uma string, muito útil para uso rápido no terminal.

#!/bin/bash
# Description: Get the length of a string
# Usage: len <string>
# Example: len "hello world"
# Output: 11

set -euo pipefail

[ "$#" -ne 1 ] && { echo "Usage: len <string>" >&2; exit 1; }
printf '%d\n' "${#1}"

Script Bash para retornar o tamanho de uma string, muito útil para uso rápido no terminal.



Configuração do Bash

Configuração do Bash

Algumas configurações úteis para adicionar no início de scripts Bash:

set -e # Exit on error
set -u # Treat unset variables as an error
set -x # Print commands and their arguments as they are executed
set -o pipefail # Fail on pipe errors

Ou tudo em uma linha:

set -euxo pipefail

Com isso, você garante:    

  • O script falha imediatamente se um comando falhar.
  • Variáveis não definidas causam erro.
  • Comandos e argumentos são impressos no terminal.
  • Erros em pipes são capturados.

Algumas configurações úteis para adicionar no início de scripts Bash:


AGENTS.md

AGENTS.md

Uma dica para tornar o uso de agents menos sofrido é criar um arquivo AGENTS.md na raiz do seu projeto. E colocar nele as informações e contextos que você quer que o agente siga, exemplos de comandos, descrições de tarefas, etc.

Alguns sistemas já leem esse arquivo automaticamente, mas você pode garantir isso simplesmente solicitando para o agente ler o arquivo e seguir as instruções.

Exemplos de AGENTS.md em https://agentsmd.net

Uma dica para tornar o uso de `agents` menos sofrido é criar um arquivo `AGENTS.md` na raiz do seu projeto. E colocar nele as informações e cont...


Redirecionando a saída do terminal.

Redirecionando a saída do terminal.

Você pode redirecionar toda a saída de um script para um arquivo usando um único comando no início do script.

Nesse exemplo, a saída do comando ls será direcionada para o arquivo out.txt.

#!/bin/bash
exec >out.txt 2>&1
ls -al --color

Você também pode redirecionar a saída para o console, usando /dev/console, requer permissão de root.

#!/bin/bash
exec >/dev/console 2>&1
ls -al --color

O parâmetro --color é usado para manter a saída colorida, porque o comando ls detecta se a saída é um terminal ou não, e ajusta a saída de acordo.


Baytimetro

Baytimetro

Esse fim de semana fiz algumas brincadeiras com o terminal, desenhando direto e recriei um recurso lá dos anos 80 que, apesar de extremamente simples, é muito útil: o baytimetro.

echo "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
echo "         1         2         3         4         5         6         7         8"

Ótimo chamar com seu desenho de tela e descobrir se você precisa colocar algum caractere mais para a direita ou esquerda.

É ridiculamente simples, mas fazer esse tipo de coisa tem um apelo nostálgico muito grande para mim.

Esse fim de semana fiz algumas brincadeiras com o terminal, desenhando direto e recriei um recurso lá dos anos 80 que, apesar de extremamente simp...


Função `toclip`

Função toclip

Esta é uma função Bash que uso como parte de meus scripts e ambientes de desenvolvimento. Ela copia o conteúdo do stdin para a área de transferência. Muito útil quando você está acessando um servidor via SSH.

toclip() {
    [[ ${SSH_CONNECTION-}${SSH_TTY-} ]] && {
        printf $'\033]52;c;%s\a' "$(base64 -w0 2>/dev/null || base64 | tr -d '\n')"
        return
    }

    case $OSTYPE in
        darwin*) pbcopy ;;
        linux*)
            #command -v wl-copy >/dev/null 2>&1 && wl-copy && return
            command -v xclip   >/dev/null 2>&1 && xclip -selection clipboard && return
            # Fallback Linux without xclip or wl-copy returns to OSC52
            printf $'\033]52;c;%s\a' "$(base64 -w0 2>/dev/null || base64 | tr -d '\n')"
            ;;
    esac
}

Exemplo de uso

Direto do stdin:

echo "Texto para copiar" | toclip

Copiando o conteúdo de um arquivo:

toclip < arquivo.txt

Esta é uma função Bash que uso como parte de meus scripts e ambientes de desenvolvimento. Ela copia o conteúdo do stdin para a área de transfe...


Listando servidores DNS

Listando servidores DNS

Para listar os servidores DNS usados no macOS:

scutil --dns

Útil para saber quais servidores foram pegos depois de renovar o DHCP.


Não largue o osso

Não largue o osso

Uma vez, meu tio William me contou uma história de um piloto de corrida que estava com ele e ia passar por uma curva com uma leve subida. Enquanto tangenciava a curva perfeitamente, em um único e contínuo movimento, reduziu a marcha e acelerou, ao mesmo tempo, virou a fita no toca-fitas. Sem trancos, com o carro ganhando somente a potência necessária. Fez tudo isso como se não fosse nada, enquanto conversava.

Meu tio usou essa história para me falar sobre preparo e sobre conhecer bem sua profissão. Essa habilidade não vem do nada, não é inata; vem de trabalho duro e determinação.

Para quem está lendo isso hoje, várias décadas depois, é difícil explicar a complexidade dessa manobra, naquele tempo de câmbios manuais e carburadores mecânicos. Principalmente se você não souber operar um toca-fitas.

Sinto falta dessas conversas com ele. Gostaria de ter assistido a mais corridas ao seu lado.

Nas palavras do Sr. William: – Não largue o osso.

Uma vez, meu tio William me contou uma história de um piloto de corrida que estava com ele e ia passar por uma curva com uma leve subida. Enquanto...


n8n com padman

n8n com padman

Tenho uma máquina que só tem uma regra: tudo que for executado nela deve ser feito em um container.

# podman volume create n8n_data 2>/dev/null || true
podman run -it --rm \
  --name n8n \
  -p 5678:5678 \
  -v n8n_data:/home/node/.n8n \
  -e N8N_RUNNERS_ENABLED=true \
  -e N8N_SECURE_COOKIE=false \
  -e N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true \
  docker.n8n.io/n8nio/n8n

Tenho uma máquina que só tem uma regra: tudo que for executado nela deve ser feito em um `container`.


Ajustes para rodar o n8n na rede interna

Ajustes para rodar o n8n na rede interna

Essas configurações são para rede interna, maquina não acessível pela internet, sem SSL. Use apenas em ambiente de desenvolvimento ou teste.

Diminui as permissões do arquivo de configuração do n8n.

chmod 600 /home/user/.n8n/config

Rodando na rede interna sem SSL e com task runners habilitados:

export N8N_RUNNERS_ENABLED=true #enable task runners
export N8N_SECURE_COOKIE=false #disable secure cookies
npx n8n

Essas configurações são para rede interna, maquina não acessível pela internet, sem SSL. Use apenas em ambiente de desenvolvimento ou teste.


Listar variáveis

Listar variáveis

Tecnica para fazer “debug de pobre” em Lua, listando variáveis globais e locais.

-- List all global variables
for name, value in pairs(_G) do
    local repr = tostring(value)
    print(string.format("%s = %s", name, repr))
end
-- List all local variables in the current function
-- This will only work if the code is run in a function context
local function list_locals()
    local i = 1
    while true do
        local var_name, var_value = debug.getlocal(2, i)
        if not var_name then break end
        print(string.format("%s = %s", var_name, tostring(var_value)))
        i = i + 1
    end
end

-- Example
local function demo()
    local a = 10
    local b = "hello"
    list_locals()  -- This will list local variables a and b
end

demo()

Tecnica para fazer "debug de pobre" em Lua, listando variáveis globais e locais.




Processamento de Registros em Lote com PostgreSQL e Go

Processamento de Registros em Lote com PostgreSQL e Go

Este é um padrão interessante para processamento de registros em lote no Go com PostgreSQL. Ele utiliza transações e bloqueios para garantir que os registros sejam processados de forma segura e eficiente, evitando conflito entre múltiplas instâncias do processo.

O truque é combinar o uso de FOR UPDATE SKIP LOCKED para evitar que múltiplas instâncias do processo leiam e processem o mesmo registro ao mesmo tempo, e o uso do índice (id) para evitar que algum erro de processamento faça com que o registro seja processado novamente porque não houve uma mudança de status.

Se houver um erro durante o processamento, o registro não é atualizado e permanece com o status ‘pendente’. Sem o WHERE id > $1, o loop poderia entrar em um ciclo infinito tentando processar o mesmo registro repetidamente.

	var id int
	for {
		done := func() bool {

			const sqlStatement = `SELECT
                id, ...
            FROM ...
            WHERE id > $1
            AND status = 'pendente'
            AND ...
            ORDER BY id
            FOR UPDATE SKIP LOCKED LIMIT 1;`

            // aqui inicia uma transação
            tx := ...
            defer func() {
                // mecanismo de rollback
            }()

            // então executa a consulta
            err := tx.QueryRow(sqlStatement, id).Scan(&id, ...)
            if err != nil {
                if errors.Is(err, sql.ErrNoRows) {
                    return true // não há mais registros
                }
                // trata outros erros
                ...
                return false
            }

            // aqui faz o processamento do registro e atualiza o status
            // pode ser fail, paid, processed, etc.
            // ...

            // se tudo estiver ok, confirma a transação
            err = tx.Commit()
            if err != nil {
                // trata erro de commit geralmente log.Fatal(...)
            }
            return false // indica que o loop deve continuar
        }()
        if done {
            break // não há mais registros para processar
        }
    }

Este é um exemplo bom para processamento de registros em lote e pode ser tranquilamente colocado para rodar de tempos em tempos, como um cron job, para processar registros pendentes em um banco de dados PostgreSQL.

Uma vantagem interessante é que, se o processamento demorar muito, automaticamente o cron vai carregar outras instâncias do processo, que vão pegar os registros que ainda não foram processados e não estão bloqueados (SKIP LOCKED). Isso permite que o sistema escale horizontalmente, processando mais registros em paralelo sem risco de conflitos.

Este é um padrão interessante para processamento de registros em lote no Go com PostgreSQL. Ele utiliza transações e bloqueios para garantir qu...