Clean Code en Swift: principios y ejemplos prácticos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Clean Code en Swift: principios y ejemplos prácticos

\n\n

El código limpio (Clean Code) no es solo un término de moda, sino una habilidad fundamental para cualquier desarrollador profesional. En el ecosistema Swift (iOS/macOS), la calidad del código afecta directamente la velocidad de desarrollo, la cantidad de errores y la facilidad de mantenimiento del proyecto. En este artículo, analizaremos los principios clave de Clean Code aplicados a Swift y mostraremos su implementación con ejemplos prácticos.

\n\n

1. Nomenclatura: hable el lenguaje del dominio

\n\n

Un buen nombre de variable, función o clase reemplaza los comentarios. En Swift, con su rico sistema de tipos y valores opcionales, la nomenclatura correcta es especialmente importante.

\n\n

Ejemplo incorrecto:

\n
func calc(a: [String: Any]) -> Double {\n    var x = 0.0\n    for (_, v) in a {\n        if let n = v as? Double {\n            x += n\n        }\n    }\n    return x\n}
\n\n

Ejemplo correcto (Clean Code):

\n
func calculateTotalPrice(of products: [Product]) -> Double {\n    return products.reduce(0) { $0 + $1.price }\n}
\n\n

Principios de nomenclatura en Swift:

\n
    \n
  • La claridad es más importante que la brevedad: remove(at:) es mejor que rem(at:).
  • \n
  • Use sustantivos para tipos: UserViewController, NetworkManager.
  • \n
  • Verbos para funciones: fetchData(), saveToCache().
  • \n
  • Variables booleanas: comience con is, has, should — isEnabled, hasContent.
  • \n
  • Evite abreviaturas: backgroundColor en lugar de bgColor.
  • \n
\n\n

2. Principio de responsabilidad única (SRP) en Swift

\n\n

Cada clase, estructura o función debe tener una sola razón para cambiar. En el desarrollo de iOS, esto es especialmente relevante para los ViewControllers, que a menudo se convierten en "objetos divinos".

\n\n

Violación de SRP (ViewController típico):

\n
class ProfileViewController: UIViewController {\n    @IBOutlet weak var nameLabel: UILabel!\n    @IBOutlet weak var avatarImageView: UIImageView!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        // Carga de datos\n        let url = URL(string: "https://api.example.com/user")!\n        let data = try! Data(contentsOf: url)\n        let json = try! JSONSerialization.jsonObject(with: data) as! [String: Any]\n        nameLabel.text = json["name"] as? String\n        \n        // Carga de avatar\n        let imageUrl = URL(string: json["avatar"] as! String)!\n        let imageData = try! Data(contentsOf: imageUrl)\n        avatarImageView.image = UIImage(data: imageData)\n        \n        // Guardar en caché\n        UserDefaults.standard.set(json, forKey: "cachedUser")\n    }\n}
\n\n

Refactorización cumpliendo SRP:

\n
// 1. Servicio separado para trabajar con la red\nclass UserNetworkService {\n    func fetchUser(completion: @escaping (Result<User, Error>) -> Void) {\n        // ... lógica de red\n    }\n}\n\n// 2. Gestor de caché separado\nclass UserCacheManager {\n    func saveUser(_ user: User) {\n        // ... lógica de caché\n    }\n}\n\n// 3. ViewModel para la lógica de negocio\nclass ProfileViewModel {\n    private let networkService = UserNetworkService()\n    private let cacheManager = UserCacheManager()\n    \n    func loadProfile(completion: @escaping (User) -> Void) {\n        networkService.fetchUser { [weak self] result in\n            switch result {\n            case .success(let user):\n                self?.cacheManager.saveUser(user)\n                completion(user)\n            case .failure:\n                // Cargar desde caché en caso de error\n                if let cachedUser = self?.cacheManager.lo                

Blogs

Book Recommendations