Refatoração de código legado em Swift: guia passo a passo

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

Introdução: por que refatorar código legado em Swift?



Trabalhar com código legado é uma parte inevitável da vida de um desenvolvedor iOS/macOS. Projetos escritos em versões antigas do Swift (2.x, 3.x) ou mesmo em Objective-C frequentemente contêm classes monolíticas, duplicação de lógica e falta de modularidade. Sem refatoração, esse código se torna uma fonte de bugs e retarda a adição de novas funcionalidades.



Neste artigo, vamos explorar estratégias práticas para refatorar código legado em Swift. Você aprenderá como melhorar a arquitetura com segurança, sem quebrar a funcionalidade existente. Todos os exemplos são aplicáveis tanto para aplicativos iOS quanto macOS.



1. Análise e preparação: por onde começar?



Antes de alterar o código, é necessário entender seu estado atual. Sem análise, você corre o risco de quebrar funcionalidades que estão funcionando.



1.1. Cobertura de testes (Characterization Tests)



O primeiro passo é escrever testes de caracterização. Eles fixam o comportamento atual do código, mesmo que pareça incorreto. Somente depois disso você pode fazer alterações com segurança.



// Exemplo de função legada: UserManager.swiftclass UserManager {    func fetchUser(by id: Int) -> String {        // Implementação antiga com force unwrap        let dict = ["id": id, "name": "João"] as [String : Any]        return dict["name"] as! String    }}

// Teste de caracterizaçãoimport XCTestclass UserManagerTests: XCTestCase { func testFetchUserReturnsName() { let manager = UserManager() let result = manager.fetchUser(by: 1) XCTAssertEqual(result, "João") }}


1.2. Inventário de "más práticas"



Faça uma lista de padrões problemáticos no código:

  • Force unwrapping (!) — principal fonte de crashes.
  • Singletons globais — dificultam os testes.
  • Números e strings mágicas — reduzem a legibilidade.
  • Métodos longos (mais de 50 linhas) — violam o SRP.
  • Falta de tipos (uso de Any).


2. Refatoração passo a passo: do simples ao complexo



A refatoração de código legado é melhor feita em pequenos passos. Cada alteração deve ser reversível e acompanhada de testes.



2.1. Eliminando o force unwrapping



Substitua ! por construções seguras: guard let ou if let.



// Antes da refatoraçãoclass NetworkService {    func loadData() -> Data {        let url = URL(string: "https://api.example.com")!        return try! Data(contentsOf: url)    }}

// Depois da refatoraçãoclass NetworkService { enum NetworkError: Error { case invalidURL case dataLoadingFailed } func loadData() throws -> Data { guard let url = URL(string: "https://api.example.com") else { throw NetworkError.invalidURL } do { return try Data(contentsOf: url) } catch { throw NetworkError.dataLoadingFailed } }}


2.2. Decomposição de classes "divinas"



Classes legadas frequentemente violam o princípio da responsabilidade única (SRP). Divida-as em entidades menores.



// Problema: a classe faz tudoclass ProfileViewController: UIViewController {    func fetchProfile() { /* requisição de rede */ }    func parseJSON() { /* parsing */ }    func updateUI() { /* atualização da UI */ }    func saveToCoreData() { /* salvamento */ }}

// Solução: divisão em módulosprotocol ProfileRepository { func fetchProfile(completion: @escaping (Result<Profile, Error>) -> Void)}

class ProfileNetworkRepository: ProfileRepository { func fetchProfile(completion: @escaping (Result<Profile, Error>) -> Void) { // Lógica de rede

Blogs

Book Recommendations