De Play Framework para Spring Boot sem reescrever tudo

TL;DR - O núcleo da nossa plataforma estava em Play Framework, e cada mudança ficava mais lenta. Não parei o time para uma reescrita. O Spring Boot roda do lado do Play, os fluxos novos ou que estão mudando passam um de cada vez, e cada migração começa com testes que descrevem o que o código antigo faz hoje, bugs incluídos.


Quando assumi a plataforma, o backend era uma aplicação Play Framework. Funcionava e os clientes dependiam dela. O problema era tudo em volta: um ecossistema encolhendo, cada vez menos gente que conhece, e upgrades mais difíceis a cada ano. Quem chegava no time sabia Spring. Ninguém sabia Play.

O discurso fácil era “vamos reescrever em Spring”. Já vi esse filme: um ano de reescrita enquanto o sistema antigo continua ganhando feature, e dois sistemas pra manter no final.

Então fui de strangler: o Spring Boot cresce em volta do Play até o Play não ter mais nada pra fazer.

flowchart LR
  Client[Web, mobile, integrações] --> Router[Camada de roteamento]
  Router -->|rotas migradas| Spring[Spring Boot]
  Router -->|todo o resto| Play[Play Framework]
  Spring --> DB[(PostgreSQL)]
  Play --> DB

O que migra primeiro

Não é o código mais feio. Duas perguntas decidem:

  • Com que frequência esse fluxo muda? É ali que o Play atrasa a gente toda sprint.
  • Quão fácil é isolar? Poucas tabelas, entradas e saídas claras.

Um fluxo que nunca muda pode ficar no Play por muito tempo. Ele não custa nada parado ali.

Testes antes de mover qualquer coisa

Antes de um fluxo migrar, escrevo testes de caracterização: testes que descrevem o que o código em Play faz hoje, não o que deveria fazer. Depois a versão em Spring tem que passar nos mesmos testes. Quando um falha, eu decido de propósito se é bug pra corrigir ou comportamento do qual algum cliente depende.

Foi aqui que a IA mais ajudou. Eu passava um controller do Play cheio de if aninhado e pedia todos os caminhos possíveis e um teste para cada um. Ela achou ramificações que eu tinha deixado passar. Mesmo assim li cada teste, porque às vezes ela descrevia um comportamento que o código não tinha.

Um banco, um dono por tabela

As duas aplicações usam o mesmo PostgreSQL durante a migração. Não é elegante, mas significa zero sincronização de dados e zero discussão sobre “qual lado está certo”. A regra: cada tabela tem um dono. Quando um fluxo vai para o Spring, as tabelas dele vão junto, e o Play só pode ler.

O que aprendi

A migração não é um projeto com data de fim. É um hábito: quando um fluxo precisa de uma mudança grande, ele migra em vez de ganhar mais um remendo. O time continua entregando, e o Play fica menor todo mês.