Refatoração de código legado em Swift: do A ao Z

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Refatoração de código legado em Swift: do A ao Z

\n

Trabalhar com código legado (legacy code) é uma parte inevitável da vida do desenvolvedor iOS/macOS. Frequentemente, é um código escrito nas primeiras versões do Swift ou até mesmo em Objective-C, sem testes, com "números mágicos" e UIViewController gigantescos. Neste artigo, vamos analisar uma estratégia passo a passo para refatorar esse código, transformando-o em um projeto moderno, sustentável e testável.

\n\n

1. Preparação e segurança: antes de tocar no código

\n

A regra mais importante da refatoração: não quebre o que funciona. Sem testes, qualquer mudança é um salto no escuro.

\n
    \n
  • Cobertura com testes (Characterization Tests): Escreva testes que capturem o comportamento atual. Mesmo que o código pareça incorreto, primeiro documente seu funcionamento.
  • \n
  • Sistema de controle de versão: Faça um commit com o estado atual. Use um branch de funcionalidade.
  • \n
  • Ferramentas: Xcode com Edit > Refactor (Renomear, Extrair Método), além de linters (SwiftLint) para manter um estilo consistente.
  • \n
\n\n
// Exemplo de "congelamento" do comportamento para um método antigo\nclass LegacyCalculator {\n    func calculateTotal(items: [Int]) -> Int {\n        // Lógica antiga e ilegível\n        var result = 0\n        for i in items {\n            result += i * 2\n        }\n        return result + 10\n    }\n}\n\n// Teste que captura o comportamento\nfunc testCalculateTotal() {\n    let sut = LegacyCalculator()\n    let result = sut.calculateTotal(items: [1, 2, 3])\n    XCTAssertEqual(result, 22) // (1+2+3)*2 + 10 = 22\n}\n
\n\n

2. Estratégia "Saco de pancadas": Variáveis globais e singletons

\n

O código legado é notoriamente conhecido por seus estados globais e singletons. Isso torna o código fortemente acoplado e imprevisível.

\n

Problema:

\n
class NetworkManager {\n    static let shared = NetworkManager()\n    var baseURL: String = "http://old.api.com"\n    func fetchData() { ... }\n}\n
\n

Solução: Injeção de dependência (Dependency Injection). Crie um protocolo e passe as dependências através do inicializador.

\n
protocol NetworkService {\n    func fetchData()\n}\n\nclass ModernViewModel {\n    private let network: NetworkService\n    \n    init(network: NetworkService) {\n        self.network = network\n    }\n    \n    func load() {\n        network.fetchData()\n    }\n}\n
\n

Essa abordagem permite substituir facilmente os serviços nos testes e torna o código modular.

\n\n

3. Combatendo o "Controlador Gordo" (Massive View Controller)

\n

Clássico do legado iOS: um UIViewController que faz tudo — desde requisições de rede até formatação da interface. A refatoração passa pela separação de responsabilidades (SRP).

\n\n

Passo 1: Extraia a lógica de negócios para um modelo separado (ViewModel).

\n
// Antes no controlador\nfunc buttonTapped() {\n    let data = fetchData()\n    let total = data.reduce(0, +)\n    label.text = "Soma: \\(total)"\n}\n\n// Depois: ViewModel\nclass MyViewModel {\n    func calculateTotal(data: [Int]) -> String {\n        let total = data.reduce(0, +)\n        return "Soma: \\(total)"\n    }\n}\n
\n\n

Passo 2: Extraia a configuração da interface para métodos ou fábricas separadas.

\n
    \n
  • Crie uma classe ViewBuilder para hierarquias complexas.
  • \n
  • Use UICollectionViewDiffableDataSource em vez do antigo dataSource.
  • \n
\n\n

4. Modernização: de Objective-C para Swift e novas APIs

\n

Frequentemente, o código legado contém uma mistura de Objective-C e Swift. Ao refatorar, é importante atualizar construções obsoletas:

\n\n
    \n
  • Substituir NSError por throws: O Swift moderno usa exceções para tratamento de erros.
  • \n
  • Abandonar ! (

Blogs

Book Recommendations