☕ Um Café no Bellacosa Mainframe
Gostou do conteúdo? Ajude a manter o café quente, o COBOL compilando e o mainframe acordado. 😄
☕ Pague um café ao Bellacosa

Translate

quarta-feira, 11 de janeiro de 2017

Microsserviços : Quando um Programador Descobre que Dividir um Monólito em Cinquenta Pedaços Não o Transforma Automaticamente em Arquitetura

 

Bellacosa Mainframe apresenta microsserviços para programador cobol

☕ Um Café no Bellacosa Mainframe

Microsserviços sem Mistérios para Programadores COBOL

Quando um Programador Descobre que Dividir um Monólito em Cinquenta Pedaços Não o Transforma Automaticamente em Arquitetura

O jovem programador caminhava lentamente pelo corredor do data center.

À esquerda, enormes gabinetes de mainframe piscavam com a serenidade de quem processava milhões de transações sem precisar publicar frases motivacionais no LinkedIn. À direita, servidores modernos executavam containers, APIs, pipelines, gateways, brokers, sidecars e outros pequenos animais digitais que aparentemente se multiplicavam quando ninguém estava olhando.

Em suas mãos, o aprendiz carregava um diagrama colorido chamado:

“How to Design Microservices”

Ele encontrou o velho Mestre Bellacosa sentado diante de um terminal 3270, segurando uma pequena xícara de café.

— Mestre — perguntou o aprendiz — finalmente compreendi os microsserviços. Basta pegar um programa grande, separá-lo em vários programas pequenos e colocá-los em containers.

O mestre tomou um gole de café.

Olhou para o jovem.

Olhou para o terminal.

Olhou novamente para o jovem.

— Pequeno gafanhoto — respondeu — se você cortar um elefante em cinquenta pedaços, não terá cinquenta animais independentes. Terá apenas um grande problema distribuído pelo chão.

O aprendiz permaneceu em silêncio.

Ao longe, ouviu-se o som de um job terminando com RC=0000.

E assim começou mais uma aula no Bellacosa Mainframe.


1. O que são microsserviços, afinal?

Microsserviços não são simplesmente programas pequenos.

Também não são:

  • containers;

  • APIs REST;

  • funções Java;

  • pods Kubernetes;

  • repositórios Git;

  • filas de mensagens;

  • aplicações hospedadas na nuvem.

Essas tecnologias podem participar de uma arquitetura de microsserviços, mas nenhuma delas, isoladamente, cria um microsserviço.

Um microsserviço é uma unidade de software construída em torno de uma responsabilidade clara do negócio.

Ele deve possuir, tanto quanto possível:

  • objetivo bem definido;

  • regras próprias;

  • dados sob seu controle;

  • interface conhecida;

  • equipe responsável;

  • ciclo de vida independente;

  • capacidade de ser implantado sem obrigar todo o sistema a mudar;

  • capacidade de falhar sem destruir a empresa inteira.

Para um programador COBOL iniciante, podemos comparar um microsserviço a um programa bem delimitado, mas com uma diferença importante: ele não vive apenas como uma rotina interna chamada por CALL.

Ele vive em um mundo distribuído.

Nesse mundo, a comunicação pode atravessar:

  • redes;

  • balanceadores;

  • APIs;

  • filas;

  • certificados;

  • gateways;

  • firewalls;

  • serviços de autenticação;

  • bancos distintos;

  • ambientes diferentes.

Uma simples chamada deixa de ser algo como:

CALL 'CALCJURO' USING WS-VALOR WS-TAXA WS-RESULTADO

e passa a ser algo parecido com:

Programa solicitante
        ↓
API Gateway
        ↓
Autenticação
        ↓
Serviço de cálculo
        ↓
Banco de dados
        ↓
Resposta pela rede

No programa COBOL local, se CALCJURO estiver disponível, a chamada acontece dentro do mesmo ambiente de execução.

No ambiente distribuído, tudo pode acontecer:

  • a rede pode estar lenta;

  • o DNS pode falhar;

  • o serviço pode estar reiniciando;

  • o certificado pode ter expirado;

  • o banco pode estar bloqueado;

  • a resposta pode chegar depois do timeout;

  • a operação pode ter sido concluída, embora o cliente não tenha recebido confirmação.

O primeiro ensinamento é simples:

Microsserviços não reduzem a complexidade. Eles transferem parte da complexidade do código para a comunicação, a infraestrutura e a operação.


2. Comece pelo negócio, não pelo programa

O primeiro passo mostrado no diagrama é:

Definir capacidades de negócio.

Esse é o fundamento de tudo.

Imagine um banco.

O banco precisa realizar capacidades como:

  • cadastrar clientes;

  • abrir contas;

  • receber depósitos;

  • efetuar transferências;

  • administrar cartões;

  • calcular limites;

  • detectar fraudes;

  • emitir cobranças;

  • produzir extratos.

Essas são capacidades que fazem sentido para o negócio.

Agora compare com uma divisão puramente técnica:

  • serviço de leitura de tabela;

  • serviço de gravação de arquivo;

  • serviço de validação;

  • serviço de impressão;

  • serviço de conversão de data;

  • serviço de cálculo de dígito.

Essas funções podem existir no sistema, mas não representam necessariamente serviços independentes.

O erro clássico de modernização acontece quando alguém analisa um ambiente legado e conclui:

— Temos 900 programas COBOL. Logo, criaremos 900 microsserviços.

Nesse momento, em algum lugar do universo, um arquiteto experiente derruba lentamente sua caneca.

Um programa COBOL pode ser:

  • um módulo reutilizável;

  • uma etapa de um job;

  • uma rotina de validação;

  • um programa de acesso a dados;

  • um programa online CICS;

  • um módulo chamado por dezenas de outros;

  • uma pequena parte de uma capacidade muito maior.

Transformar cada programa em serviço remoto pode substituir chamadas locais extremamente rápidas por centenas de interações de rede.

Aquilo que antes era:

PERFORM VALIDAR-CLIENTE

pode acabar virando:

Aplicação chama serviço de cliente
Serviço de cliente chama serviço de endereço
Serviço de endereço chama serviço de CEP
Serviço de CEP chama serviço de região
Serviço de região chama serviço tributário

Tudo isso apenas para descobrir que o campo WS-CEP está vazio.

O verdadeiro ponto de partida é perguntar:

  • O que a empresa realmente faz?

  • Quais funções entregam valor?

  • Quais regras mudam de forma independente?

  • Quais áreas possuem responsabilidades próprias?

  • Quais capacidades precisam escalar separadamente?

  • Quais processos podem falhar sem interromper os demais?

Curiosidade do templo

No Domain-Driven Design, uma capacidade empresarial costuma ser estudada dentro de um domínio.

Por exemplo:

Domínio: Comércio eletrônico

Pode conter subdomínios como:

Catálogo
Pedidos
Estoque
Pagamento
Entrega
Fidelidade

Cada domínio possui linguagem, regras e objetivos próprios.

Isso é muito diferente de dividir o sistema apenas por linguagem de programação, tabela ou tipo de arquivo.


3. Identifique os limites do serviço

O segundo passo é descobrir onde um serviço termina e o outro começa.

Esse limite é chamado de service boundary.

Considere a palavra “cliente”.

Para a área de vendas, cliente pode significar:

  • nome;

  • telefone;

  • preferências;

  • histórico comercial.

Para o setor financeiro, cliente pode significar:

  • documento;

  • limite;

  • inadimplência;

  • risco de crédito.

Para o setor de entrega, cliente pode significar:

  • nome do destinatário;

  • endereço;

  • instrução de recebimento.

São visões diferentes da mesma pessoa.

Não é obrigatório construir uma estrutura universal gigantesca contendo tudo o que todos os setores sabem.

No COBOL, essa estrutura poderia acabar assim:

01 CLIENTE-GLOBAL.
   05 CLIENTE-DADOS-PESSOAIS.
   05 CLIENTE-DADOS-FINANCEIROS.
   05 CLIENTE-DADOS-LOGISTICOS.
   05 CLIENTE-PREFERENCIAS.
   05 CLIENTE-DADOS-FISCAIS.
   05 CLIENTE-HISTORICO.
   05 CLIENTE-CAMPOS-FUTUROS.
   05 CLIENTE-CAMPOS-QUE-NINGUEM-SABE-PARA-QUE-SERVEM.

Depois de alguns anos, ninguém teria coragem de alterar esse copybook.

Cada serviço deve conhecer apenas a visão necessária para cumprir sua responsabilidade.

O serviço de entregas não precisa conhecer a renda do cliente.

O serviço de marketing não precisa conhecer o número completo do cartão.

O serviço de catálogo não precisa saber a situação de uma cobrança bancária.

Um bom limite reduz a quantidade de conhecimento compartilhado.

Sinal de limite ruim

Imagine um serviço chamado “Serviço Central”.

Ele:

  • cadastra cliente;

  • calcula preço;

  • reserva estoque;

  • processa pagamento;

  • emite nota;

  • envia e-mail;

  • agenda entrega;

  • atualiza pontos;

  • gera relatório;

  • consulta fraude.

O serviço possui uma API moderna, executa em container e aparece em um desenho cheio de hexágonos.

Mesmo assim, ele continua sendo um monólito.

A roupa mudou.

O imperador continua o mesmo.


4. Escolha a granularidade adequada

O terceiro passo é decidir o tamanho dos serviços.

Esse é um dos pontos mais difíceis porque não existe um número mágico.

Um microsserviço não precisa ter:

  • cem linhas;

  • mil linhas;

  • cinco classes;

  • uma tabela;

  • um endpoint.

O tamanho correto depende da responsabilidade.

Grande demais

Se o serviço cuida de várias capacidades distintas, ele começa a se transformar em outro monólito.

Sintomas:

  • várias equipes alteram o mesmo código;

  • o deployment é arriscado;

  • qualquer mudança exige testes enormes;

  • escalar uma função obriga escalar todas;

  • módulos internos ficam fortemente acoplados.

Pequeno demais

Se cada função mínima vira um serviço, surge uma explosão de componentes.

Podemos imaginar:

Serviço Valida CPF
Serviço Calcula Dígito do CPF
Serviço Remove Pontuação do CPF
Serviço Formata CPF
Serviço Verifica CPF Vazio
Serviço Registra CPF

Agora cadastrar uma pessoa requer uma peregrinação por seis serviços.

O mestre chama isso de:

A Técnica do Nanosserviço de Mil Cortes.

Nenhum corte parece fatal isoladamente, mas o sistema morre lentamente em latência, logs, pipelines e reuniões.

O custo real de cada serviço

Todo novo serviço precisa de:

  • código;

  • testes;

  • repositório;

  • pipeline;

  • documentação;

  • configuração;

  • logs;

  • métricas;

  • alertas;

  • controle de acesso;

  • certificados;

  • versionamento;

  • processo de deployment;

  • suporte;

  • tratamento de falhas;

  • equipe responsável.

Portanto, um serviço de 300 linhas pode gerar uma carga operacional muito maior do que um módulo COBOL de 20 mil linhas bem organizado.

Pergunta prática

Um serviço está em boa granularidade quando podemos dizer:

“Este componente é responsável por esta capacidade e pode evoluir sem exigir mudanças constantes em todo o restante.”

Não existe perfeição inicial.

Os limites podem evoluir à medida que o conhecimento sobre o negócio aumenta.


5. Projete a API como um contrato

Depois que as responsabilidades estão claras, precisamos definir como os serviços se comunicam.

A API é o contrato público do serviço.

Ela deve expressar ações de negócio, não detalhes internos de banco.

Exemplo ruim

POST /insertPedido
PUT /updateStatusPedido
GET /selectPedido
DELETE /deletePedido

Esse modelo simplesmente expõe operações de tabela.

É o equivalente digital de colocar uma janela na parede do banco de dados e deixar cada sistema meter a mão lá dentro.

Exemplo melhor

POST /pedidos
GET /pedidos/123
POST /pedidos/123/cancelamento
POST /pedidos/123/confirmacao

Essas operações representam intenções empresariais.

A API deve definir claramente:

  • formato da requisição;

  • formato da resposta;

  • campos obrigatórios;

  • códigos de erro;

  • autenticação;

  • autorização;

  • versionamento;

  • regras de repetição;

  • limites de consumo;

  • comportamento em falhas.

Idempotência

Esse nome estranho é essencial.

Imagine que uma aplicação solicite um pagamento.

Ela envia a requisição, mas a resposta demora.

O cliente não sabe se o pagamento foi processado.

Então envia novamente.

Sem idempotência, o usuário pode ser cobrado duas vezes.

Uma chave idempotente pode identificar a solicitação:

IDEMPOTENCY-KEY: PAGAMENTO-2026-0009981

Se o serviço receber a mesma chave novamente, devolve o resultado já registrado.

No mundo COBOL, pense em um identificador único de transação armazenado antes do processamento.

Antes de executar, o sistema verifica:

IF TRANSACAO-JA-PROCESSADA
   RETORNAR-RESULTADO-ANTERIOR
ELSE
   PROCESSAR-TRANSACAO
END-IF

Em sistemas distribuídos, isso não é luxo.

É sobrevivência.


6. Cada serviço deve possuir seus dados

O quinto passo do diagrama fala de data ownership.

Um serviço deve controlar os dados de sua responsabilidade.

Isso não significa necessariamente possuir uma máquina física exclusiva.

Significa que outros serviços não devem alterar diretamente suas estruturas internas.

Considere:

Serviço de Pedidos
Serviço de Pagamentos
Serviço de Estoque
Serviço de Entregas

Se todos acessarem e atualizarem as mesmas tabelas, qualquer mudança poderá afetar todos.

O banco compartilhado cria dependências ocultas:

  • uma coluna removida quebra outro serviço;

  • uma atualização direta ignora regras;

  • um relatório pesado afeta transações;

  • ninguém sabe quem é o dono da tabela;

  • todos precisam coordenar deployments.

O sistema pode ter vinte aplicações separadas, mas continuar sendo um monólito de banco de dados.

Estratégia recomendada

Pedidos controla pedidos
Pagamento controla cobranças
Estoque controla quantidades e reservas
Entrega controla remessas

Quando um serviço precisa de informação de outro, utiliza:

  • API;

  • mensagem;

  • evento;

  • réplica controlada;

  • cache;

  • visão materializada.

“Mas e o JOIN?”

O programador COBOL acostumado ao Db2 pergunta:

— Mestre, como faremos o JOIN?

O mestre responde:

— Com cuidado, pequeno gafanhoto.

Em microsserviços, os dados podem estar separados.

Um relatório consolidado pode usar:

  • data warehouse;

  • data lake;

  • modelo de leitura;

  • CQRS;

  • eventos;

  • réplica de consulta;

  • processo batch de consolidação.

Não é recomendável montar todo relatório corporativo chamando quinze APIs em tempo real.

Isso cria uma consulta que depende simultaneamente de quinze serviços.

Se um falhar, o relatório pode virar uma página branca contendo a mensagem:

“Erro inesperado. Tente novamente mais tarde.”

A mensagem oficial da era digital.


7. Comunicação síncrona e assíncrona

O sexto passo é escolher como os serviços conversam.

Comunicação síncrona

Um serviço envia uma solicitação e espera uma resposta.

Exemplos:

  • REST;

  • SOAP;

  • gRPC;

  • z/OS Connect;

  • chamadas via gateway.

Fluxo:

Cliente → Pedido → Estoque → Resposta

É útil quando a resposta é necessária naquele momento.

Por exemplo:

  • consultar saldo;

  • validar limite;

  • obter preço;

  • confirmar disponibilidade.

Mas há um risco.

Se A chama B, B chama C, C chama D e D chama E, temos uma corrente.

A → B → C → D → E

Todos precisam funcionar dentro do tempo esperado.

A latência se acumula.

As probabilidades de falha também.

O usuário clicou uma vez, mas o sistema realizou uma pequena expedição ao Himalaia.

Comunicação assíncrona

O serviço publica uma mensagem e continua.

Exemplo:

PedidoCriado
     ↓
IBM MQ, Kafka ou outro broker
     ├── Estoque
     ├── Pagamento
     ├── Notificação
     └── Fidelidade

Isso permite desacoplamento.

O serviço de pedidos não precisa esperar que o e-mail seja enviado para confirmar o pedido.

A notificação pode ocorrer alguns segundos depois.

A mensageria também ajuda a absorver picos.

Se chegam dez mil pedidos, a fila pode armazená-los enquanto os consumidores processam gradualmente.

Comando e evento

Um comando solicita uma ação:

ReservarEstoque

Um evento declara um fato:

EstoqueReservado

Essa diferença é importante.

O comando pode falhar ou ser recusado.

O evento representa algo que já ocorreu.

Easter egg do mainframe

Programadores mainframe já trabalham com ideias semelhantes há décadas:

  • MQ;

  • filas;

  • processamento batch;

  • desacoplamento;

  • checkpoints;

  • reprocessamento;

  • arquivos de entrada e saída;

  • controle de transação.

Muitas práticas apresentadas como descobertas revolucionárias da computação moderna estavam tranquilamente funcionando em data centers quando os atuais evangelistas de cloud ainda assistiam desenho animado em televisão de tubo.


8. Falhas devem ser previstas

O sétimo passo é tratar falhas desde o início.

Em um programa local, muitos componentes vivem no mesmo ambiente.

Em microsserviços, a rede é parte do sistema.

E a rede possui um senso de humor sombrio.

Timeout

Toda chamada remota precisa de um limite.

Sem timeout, o programa pode esperar indefinidamente.

Exemplo:

Serviço de pedido chama pagamento
Pagamento não responde
Após dois segundos, a chamada é encerrada

O timeout precisa ser escolhido com base em dados reais.

Muito curto:

  • operações válidas são canceladas.

Muito longo:

  • recursos ficam presos;

  • usuários aguardam;

  • filas de threads se acumulam.

Retry

O retry tenta novamente uma operação temporariamente falha.

Pode funcionar para:

  • erro de rede;

  • serviço temporariamente indisponível;

  • timeout transitório;

  • resposta 503.

Não deve ser usado para:

  • senha inválida;

  • saldo insuficiente;

  • documento incorreto;

  • regra de negócio rejeitada;

  • mensagem malformada.

Tentar novamente uma operação impossível é apenas falhar com dedicação.

Backoff e jitter

As tentativas não devem ocorrer todas imediatamente.

Podemos esperar:

500 milissegundos
1 segundo
2 segundos
4 segundos

O jitter adiciona uma variação aleatória.

Sem isso, milhares de clientes podem repetir ao mesmo tempo e esmagar o serviço que estava tentando se recuperar.

Circuit breaker

O circuit breaker interrompe chamadas para um serviço que está falhando.

Estados comuns:

CLOSED
OPEN
HALF-OPEN

Quando fechado, chamadas passam.

Quando aberto, chamadas são bloqueadas rapidamente.

No estado semiaberto, algumas chamadas de teste verificam se houve recuperação.

Pense em um disjuntor elétrico.

Ele não discute filosofia com o curto-circuito.

Ele interrompe a corrente.

Fallback

O fallback fornece alternativa:

  • cache;

  • informação parcial;

  • resposta padrão segura;

  • fila para processamento posterior.

Mas o fallback não pode inventar dados críticos.

Se o saldo não está disponível, o sistema não deve escolher um valor aleatório apenas para manter a experiência “fluida”.


9. Sagas e transações distribuídas

No mainframe, estamos acostumados com transações fortes.

Uma unidade de trabalho pode terminar com:

COMMIT

ou:

ROLLBACK

Em microsserviços, uma transação pode atravessar vários bancos.

Exemplo:

  1. Criar pedido;

  2. Reservar estoque;

  3. Cobrar pagamento;

  4. Criar entrega.

Se o pagamento falhar depois da reserva, o que acontece?

Uma solução é usar o padrão Saga.

Cada etapa possui uma ação e, quando necessário, uma compensação.

Criar pedido
Reservar estoque
Pagamento falhou
Liberar estoque
Cancelar pedido

A compensação não apaga magicamente o passado.

Ela executa uma nova operação que neutraliza o efeito anterior.

Por exemplo:

  • débito realizado;

  • transferência cancelada;

  • crédito compensatório efetuado.

Isso exige regras claras.

A palavra “desfazer” parece simples até envolver:

  • dinheiro;

  • estoque;

  • impostos;

  • nota fiscal;

  • transporte;

  • auditoria.


10. Observabilidade: enxergar o sistema

O oitavo passo é adicionar observabilidade.

Em um monólito, podemos investigar:

  • um log;

  • um dump;

  • uma região CICS;

  • um job;

  • uma tabela;

  • um programa.

Em microsserviços, uma requisição pode atravessar dezenas de componentes.

Precisamos de:

  • logs;

  • métricas;

  • traces.

Logs

Um log útil deve informar:

  • data e hora;

  • serviço;

  • operação;

  • identificador da transação;

  • resultado;

  • tempo;

  • erro;

  • ambiente.

Um log inútil diz:

Ocorreu um erro.

Esse tipo de mensagem possui a precisão investigativa de um oráculo gripado.

Métricas

Métricas respondem perguntas como:

  • quantas requisições chegaram?

  • qual a latência média?

  • quantas falharam?

  • quantos timeouts ocorreram?

  • qual a profundidade da fila?

  • quantas mensagens aguardam processamento?

  • quantos circuit breakers estão abertos?

Tracing distribuído

Um trace acompanha a jornada de uma solicitação.

Gateway: 20 ms
Pedido: 40 ms
Estoque: 80 ms
Pagamento: 950 ms
Notificação: 25 ms

Agora podemos localizar o gargalo.

Sem um correlation ID, investigar um problema distribuído é como procurar um job no JES2 sabendo apenas que ele “rodou na terça-feira”.

Observabilidade empresarial

Não basta saber que CPU e memória estão normais.

Devemos observar:

  • pedidos concluídos;

  • pagamentos recusados;

  • transferências pendentes;

  • reservas expiradas;

  • mensagens em dead-letter queue;

  • divergências de conciliação.

O sistema pode estar tecnicamente perfeito e comercialmente inútil.

Todos os containers verdes.

Nenhuma venda concluída.


11. Segurança em todos os serviços

O nono passo é proteger cada serviço.

Não podemos confiar automaticamente em tudo que está dentro da rede.

A segurança deve considerar:

  • autenticação;

  • autorização;

  • criptografia;

  • segredos;

  • comunicação entre serviços;

  • privilégio mínimo.

Autenticação

Responde:

Quem é você?

Autorização

Responde:

O que você pode fazer?

Uma pessoa autenticada não deve automaticamente poder:

  • alterar limites;

  • consultar qualquer conta;

  • cancelar transferências;

  • acessar dados administrativos.

Identidade entre serviços

Serviços também precisam se identificar.

Podem usar:

  • certificados;

  • mTLS;

  • tokens;

  • contas de serviço;

  • scopes;

  • políticas de rede.

Gestão de segredos

Nunca devemos guardar senhas e tokens:

  • no código;

  • em repositórios;

  • em imagens de container;

  • em logs;

  • em arquivos abertos;

  • em variáveis sem proteção.

No universo mainframe, isso se relaciona com:

  • RACF;

  • SAF;

  • perfis;

  • certificados;

  • keystores;

  • controle de datasets;

  • privilégio mínimo.

Regra do templo

O serviço de notificações não precisa atualizar conta bancária.

O serviço de catálogo não precisa consultar cartão.

O serviço de entrega não precisa acessar dados de fraude.

Cada serviço deve possuir apenas os acessos necessários.


12. Automação de deployment

O décimo passo é automatizar a entrega.

Microsserviços aumentam o número de componentes.

Sem automação, cada deployment vira uma cerimônia.

Imagine cinquenta serviços exigindo:

  • cópia manual;

  • mudança de parâmetro;

  • abertura de chamado;

  • autorização;

  • teste manual;

  • atualização de planilha;

  • conferência por e-mail;

  • reunião de aprovação.

A empresa não criou agilidade.

Criou cinquenta pequenas repartições públicas digitais.

Pipeline típico

Commit
  ↓
Build
  ↓
Teste unitário
  ↓
Análise de qualidade
  ↓
Análise de segurança
  ↓
Teste de contrato
  ↓
Empacotamento
  ↓
Homologação
  ↓
Teste integrado
  ↓
Produção
  ↓
Verificação

Deployment independente

Um serviço deve poder ser implantado sem exigir publicação simultânea de todos os outros.

Se cinco serviços sempre precisam mudar juntos, o acoplamento continua forte.

Eles apenas moram em apartamentos diferentes, mas ainda compartilham o mesmo banheiro.

Estratégias

Rolling

Substitui instâncias gradualmente.

Blue-green

Mantém dois ambientes:

Blue: versão atual
Green: nova versão

Depois da validação, o tráfego muda.

Canary

Uma pequena parcela recebe a nova versão.

5% nova
95% antiga

Se tudo estiver bem, a nova versão avança.

Banco de dados e rollback

Código pode voltar rapidamente.

Banco de dados nem sempre.

Por isso, mudanças de schema devem acontecer em etapas.

Um padrão útil é:

  1. adicionar nova estrutura;

  2. manter compatibilidade;

  3. atualizar aplicações;

  4. migrar dados;

  5. remover estrutura antiga posteriormente.

Esse padrão é conhecido como expand and contract.


13. Microsserviços e COBOL podem viver juntos

Uma das maiores confusões é pensar que microsserviços exigem substituir COBOL.

Não exigem.

Um programa COBOL pode ser exposto ou integrado por:

  • CICS;

  • IMS;

  • IBM MQ;

  • z/OS Connect;

  • APIs REST;

  • eventos;

  • Kafka;

  • adaptadores;

  • pipelines CI/CD;

  • OpenAPI.

Uma transação CICS bem definida pode funcionar como serviço empresarial.

Ela pode possuir:

  • entrada conhecida;

  • saída conhecida;

  • regra delimitada;

  • segurança;

  • transação;

  • alta disponibilidade;

  • auditoria;

  • monitoramento.

Em alguns casos, uma transação COBOL possui limites mais claros do que uma aplicação moderna dividida artificialmente em dezenas de containers.

Padrão Strangler Fig

Uma estratégia segura de modernização é envolver o legado e substituir partes gradualmente.

Usuário
   ↓
Camada de APIs
   ↓
Sistema legado + novos serviços

Com o tempo, determinadas capacidades são extraídas.

O tráfego passa gradualmente para os novos componentes.

Não é necessário desligar o mainframe em uma sexta-feira às 18h e esperar que tudo funcione na segunda-feira.

Essa estratégia normalmente termina com:

  • pizza fria;

  • executivos nervosos;

  • consultores desaparecidos;

  • e um programa COBOL sendo religado às três da manhã.


14. Passo a passo para um projeto real

O jovem aprendiz perguntou:

— Mestre, como começo sem transformar a empresa em um laboratório de caos?

O mestre respondeu:

Passo 1 — Mapear o negócio

Liste processos reais:

  • pedidos;

  • pagamentos;

  • cadastro;

  • faturamento;

  • entrega;

  • atendimento.

Não comece pelas tabelas ou programas.

Passo 2 — Descobrir responsabilidades

Para cada processo, determine:

  • quem decide?

  • quem possui as regras?

  • quem altera?

  • quem utiliza os dados?

  • quem responde pela operação?

Passo 3 — Mapear sistemas atuais

Identifique:

  • programas COBOL;

  • transações CICS;

  • jobs;

  • tabelas Db2;

  • arquivos VSAM;

  • filas MQ;

  • interfaces;

  • dependências.

Passo 4 — Escolher uma capacidade pequena, mas relevante

Evite começar pelo processo mais crítico da empresa.

Escolha algo:

  • com limites claros;

  • risco controlado;

  • valor perceptível;

  • poucas dependências.

Passo 5 — Criar contrato

Defina:

  • API;

  • mensagens;

  • erros;

  • autenticação;

  • versionamento;

  • idempotência.

Passo 6 — Definir propriedade dos dados

Determine:

  • quais dados pertencem ao serviço;

  • como serão migrados;

  • como outros consumidores terão acesso;

  • como evitar atualizações diretas.

Passo 7 — Planejar falhas

Pergunte:

  • o que acontece se o serviço parar?

  • o que acontece se a mensagem duplicar?

  • o que acontece se a resposta atrasar?

  • como reprocessar?

  • como compensar?

  • como recuperar?

Passo 8 — Instrumentar

Inclua desde o início:

  • logs estruturados;

  • métricas;

  • traces;

  • alertas;

  • correlation ID.

Passo 9 — Automatizar

Crie pipeline de:

  • build;

  • teste;

  • segurança;

  • deployment;

  • rollback;

  • validação.

Passo 10 — Medir resultados

Verifique se realmente melhorou:

  • tempo de entrega;

  • frequência de deployment;

  • número de falhas;

  • tempo de recuperação;

  • acoplamento;

  • satisfação da equipe;

  • custo operacional.

Não aceite sucesso apenas porque o diagrama ficou bonito.


15. Sinais de que o caminho está errado

Observe os seguintes sintomas:

Todos os serviços são implantados juntos

Isso indica dependência excessiva.

Todos usam o mesmo banco

A independência pode ser apenas visual.

Uma operação simples chama dezenas de serviços

A granularidade provavelmente está pequena demais.

Ninguém sabe quem é o responsável

Serviço sem dono vira ruína digital.

Qualquer mudança quebra consumidores

O contrato está instável.

Há retries sem limite

Uma pequena falha pode virar tempestade.

Não existe correlation ID

O suporte trabalhará por adivinhação.

Existem muitos serviços e poucas equipes

A operação ficará abandonada.

Kubernetes foi instalado antes de compreender o domínio

O projeto começou pelo telhado.


16. Quando não usar microsserviços

O aprendiz esperava uma defesa absoluta.

Mas o mestre surpreendeu:

— Nem todo sistema precisa de microsserviços.

Um monólito modular pode ser melhor quando:

  • a equipe é pequena;

  • o produto está começando;

  • o domínio ainda não é conhecido;

  • a infraestrutura é limitada;

  • o volume é moderado;

  • todas as partes mudam juntas;

  • não existe maturidade operacional.

Um monólito modular oferece:

  • transações locais;

  • debugging mais simples;

  • menor custo;

  • testes mais diretos;

  • menos falhas de rede;

  • deployment único;

  • operação centralizada.

O problema não é o monólito.

O problema é o monólito desorganizado.

Da mesma forma, o mérito não está nos microsserviços.

O mérito está nos serviços bem delimitados.

Um monólito bem construído pode ser elegante.

Um conjunto de microsserviços mal construído pode parecer uma cidade em que cada cômodo da casa possui prefeitura, alfândega e controle de passaporte.


17. Curiosidades e easter eggs do templo

Easter egg 1 — “Novo” nem sempre é novo

Mensageria, transações, isolamento, filas e processamento distribuído existem há décadas em ambientes corporativos.

O vocabulário mudou.

Os problemas continuam reconhecíveis.

Easter egg 2 — O mainframe já conhecia resiliência

CICS, IMS, MQ, RACF, WLM, sysplex e outros componentes foram construídos para:

  • disponibilidade;

  • segurança;

  • recuperação;

  • gerenciamento de carga;

  • integridade transacional.

O microsserviço moderno não inventou a necessidade de sobrevivência em produção.

Easter egg 3 — O verdadeiro monólito distribuído

Quando todos os serviços:

  • compartilham banco;

  • mudam juntos;

  • dependem uns dos outros;

  • falham em cadeia;

  • pertencem à mesma equipe;

temos um monólito distribuído.

Ele possui todas as dificuldades do monólito e todas as dificuldades da rede.

Uma obra-prima do sofrimento híbrido.

Easter egg 4 — A lei do café

Quanto maior a cadeia de serviços, maior a probabilidade de o operador precisar preparar café antes de terminar o trace.

Essa lei ainda aguarda validação acadêmica, mas já foi confirmada empiricamente em milhares de data centers.


Conclusão — A lição do pequeno gafanhoto

O jovem programador fechou o diagrama.

Agora compreendia que microsserviços não eram apenas caixas coloridas conectadas por flechas.

Eles exigiam decisões profundas sobre:

  • negócio;

  • limites;

  • responsabilidade;

  • dados;

  • comunicação;

  • falhas;

  • segurança;

  • observabilidade;

  • deployment;

  • equipes.

O mestre Bellacosa levantou-se e caminhou até o mainframe.

— Pequeno gafanhoto — disse ele — o objetivo não é criar mais serviços.

— Então qual é o objetivo, mestre?

— Criar partes do sistema que possam compreender sua própria missão, carregar seus próprios dados, falar claramente com as demais e sobreviver quando o mundo ao redor estiver falhando.

O jovem refletiu.

— E como saberei se projetei corretamente?

O mestre apontou para o terminal.

— Quando uma equipe puder modificar uma capacidade, testá-la, implantá-la e recuperá-la sem convocar cinquenta pessoas para uma reunião de emergência, você estará próximo do caminho.

— E se eu dividir tudo em serviços pequenos?

— Você terá muitos serviços pequenos.

— E isso não é microsserviço?

— Não necessariamente.

— E se eu usar containers?

— Terá containers.

— Kubernetes?

— Terá Kubernetes.

— APIs?

— Terá APIs.

— Cloud?

— Terá uma fatura mensal muito interessante.

O aprendiz finalmente sorriu.

Na tela, o sistema registrou:

MICROSERVICE DESIGN TRAINING
STATUS: COMPLETED
RETURN CODE: 0000

Mas antes que ele comemorasse, surgiu uma segunda mensagem:

WARNING:
PRODUCTION IS A DISTRIBUTED SYSTEM.
EXPECT THE UNEXPECTED.

O mestre terminou o café.

O jovem observou as luzes do data center.

E, em algum lugar entre uma transação CICS, uma fila MQ, uma API REST e um container perdido no cluster, ele finalmente compreendeu:

Uma boa arquitetura de microsserviços não nasce quando dividimos o sistema em pedaços. Ela nasce quando compreendemos quais pedaços realmente possuem motivo para existir de forma independente.

E esse, caro Padawan do COBOL, é o primeiro golpe da antiga arte de projetar sistemas distribuídos sem transformar a produção em um episódio perdido de Kung Fu, dirigido por um arquiteto, revisado por um monge e patrocinado pelo departamento de incidentes críticos.

☕ Gostou deste café?
Siga o Bellacosa Mainframe e acompanhe os próximos artigos.
SEGUIR O BLOG

Sem comentários:

Enviar um comentário

De Fã para Fã. Conteúdo não oficial produzido como homenagem, comentário, análise ou paródia. Personagens, marcas e obras eventualmente mencionados pertencem aos seus respectivos titulares.
Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...