Esta guía de estilo está parcialmente basada en la de gitHub y en mi experiencia propia. Su objetivo es evitar grandes desvíos en estilo y fomentar buenas prácticas.
Clean code that works. — Ward Cunningham
Así que esta Objective C Style Guide se hace pública para que sirva de ayuda a otros equipos, a padawans que están empezando y generar polémica fomentar el intercambio de ideas.
Diseño
- KISS: Keep it Simple, Stupid.
- Lo explícito es preferible a lo implícito.
- El código claro es preferible al código «guay».
- Si además, es elegante, mejor.
- Si tu diseño es difícil de explicar, es por que es malo.
- Tu código se va a leer mil veces y compilar unas pocas: la legibilidad es vital.
- No extiendas si puedes delegar.
- Ante la duda, plagia a Cocoa.
- Usa la autodelegación para comportamiento por defecto.
- Usa la expresiones literales para crear NSArray y NSDictionary.
- No uses la nueva sintaxis de corchetes para indexar colecciones. Envía mensajes. Bastantes corchetes tenemos ya.
- Para Apps universales, procura detectar el User Idiom al arrancar y configura la App para uno u otro, de manera que el resto del código cambie lo menos posible. Esto reduce la complejidad ciclomática del código y sigue el principio DRY.
MVC
No hay atajos para el MVC, el MVC es el atajo. Be MVC, my friend. Síguelo a rajatabla.
UIViewController
No dejes que tus subclases de UIViewController se hagan excesivamente grandes. Si supera un tamaño razonable, refactoriza y saca funcionalidades a nuevas clases. Ni el Controlador es una God Class, ni MVC significa Massive View Controller.
Modelo y Código de Red
El código de acceso a red (sincronización y demás) NO debe de ir dentro del modelo, sino en un NetworkController. Ver comentario anterior.
Indentado
Usa tabulaciones, espacios, lo que sea, siempre y cuando seas coherente en un mismo proyecto. Una buena opción por defecto es la que implementa Xcode (espacios para el indentado y un «ancho» de 4).
Llaves
Usa llaves siempre, incluso en ifs y bucles de una sola linea. Esta medida defensiva impide que al añadir una nueva linea, el código deje de funcionar.
Por el nombre de Jobs, pon la llave inicial donde te salga de los corchetes. Eso sí, sé coherente en un mismo proyecto.
Propiedades y variables de instancia
- Usa siempre propiedades, a no ser que tengas una muy buena razón para ello.
- Para los modificadores de las propiedades, sigue los Mandamientos de la Propiedades, tal y como se explica en el curso.
- Sólo usa @synthesize para aquellos casos en que es absolutamente indispensable.
- Las variables de instancia siempre llevan un guión bajo como prefijo, por ejemplo _firstName.
Métodos de clase
Los métodos de clase que crean instancias, deben de devolver instancetype.
Constantes
Usa constantes de «estilo C»
// Header file extern NSString *const AGTWidgetTurboMode; // Implementation file NSString * const AGTWidgetTurboMode = @"AGTWidgetTurboMode";
con el prefijo de clase seguido del nombre de la clase con la cual está asociada y el verbo apropiado.
Si prefieres, usa métodos de clase para las constantes, en la clase a la cual está asociada:
// In AGTWidget class +(NSString *) turboMode{ return @"AGTWidgetTurboMode"; }
Elige el que quieras y luego sé coherente en el proyecto.
No uses #define, si puedes usar cualquiera de las alternativas anteriores.
Nomenclatura
Prefijo de clases
Toda clase, y ficheros derivados como Xibs, lleva el prefijo AGT.
Ni que decir tiene, que si no trabajas para Agbo, NO uses AGT. Invéntate el tuyo, gracias.
- Nombres de clase, variables, métodos, constantes, comentarios y commits a git se escriben siempre en Inglés. Sin excepciones.
- Si un método necesita un comentario, es porque el nombre no es lo bastante largo y explícito. En serio.
- Usa siempre el camelCase. Sin excepciones.
Notificaciones
Todos los métodos que responden a una notificación deben empezar con el prefijo notify, y llevar el nombre de la notificación como comentario. Por ejemplo:
// CharacterDidChange -(void) notifyThatCharacterDidChange: (AGTStarWarsCharacter *) aCharacter;
Esto facilita enormemente buscar e identificar quién puñetas responde a una notificación en un proyecto complejo.
Delegados
- Los nombres de protocolos de delegado serán siempre <nombre de la clase><delegate>.
- Los nombres de los métodos de delegado seguirán el patrón did, will, should de Cocoa y pasan el remitente como primer parámetro.
- Sin excepciones.
Categorías
- Los nombres de las categorías deben siempre indicar qué funcionalidad añaden.
- Los nombres de los métodos deben de llevar siempre el prefijo de clase en minúsculas. Por ejemplo agtWrappedInNavigationController:
- Esto nos protege en caso de que Apple en el futuro invente un método con ese mismo nombre (wrappedInNavigationController:).
Constantes
Las constantes deben de empezar siempre por el prefijo de clase, por ejemplo AGT. No llames tus constantes con un prefijo k (kSoyUnaConstanteDelAnnoDelPedo). Es anticuado y da a entender que se trata de C y código de bajo nivel en general.
Nomenclatura Húngara
No uses la nomenclatura húngara en Objective C.
#define
Siempre en mayúsculas. Sin excepciones. Si puedes usar una constante normal y corriente, no uses un define.
Ficheros de Clases
No pongas más de una clase por fichero, esto no es C++.
Fichero de cabecera
- KISS: Keep it Simple, Stupid. Pon en él solo lo indispensable. Todo aquello que sea irrelevante para el usuario de la clase, debe de estar en una class extension en el fichero de implementación.
- Sigue el orden @property, class methods, instance methods, empezando por los inicializadores.
- Si usas ObjectiveC++, jamás podrá aparecer NADA de código C++ en el fichero de cabecera (esto «contaminaría» a todos los ficheros que lo importen).
- Usa siempre que posible @class en vez de #import para tus propias clases.
Fichero de Implementación
Empieza con la class extension y luego el grupo @implementation.
Usa #pragma mark – para agrupar los métodos por su funcionalidad:
- Life cycle (init, viewDidAppear, etc…)
- Acciones
- Propiedades (getters or setters personalizados)
- Métodos de delegado
- Handlers de notificaciones
- Métodos «privados»
- Métodos «públicos»
- Etc…
Tipos y Enums
- Usa siempre los typedef del sistema en vez del tipo «desnudo». Por ejemplo, NSInteger en vez de int, CGFloat en vez de float, BOOL en vez de bool, etc… Esto te protege cuando hay cambios en el tamaño de los tipos, como al pasar de 32 bits a 64 bits.
- Usa NSEnum para las enumeraciones.
Personalización de UI
Usa siempre el proxy de Appearance en un método del AppDelegate (configureAppearance) y haz TODA la personalización ahí a no ser que resulte totalmente imposible. El código de personalización debe de estar centralizado en este único punto.
Librerías externas
No uses librerías externas mastodónticas (tipo AFNetworking) si sólo vas a usar una ínfima parte de las funcionalidades que aporta. En esos casos, examina el código que te interesa, entiende su funcionamiento y róbalo. En caso contrario estarás incorporando una enorme caja negra a tu proyecto y reduce tu comprensión del mismo. Para cajas negras, nos basta Cocoa.
No introduzcas dependencias externas innecesarias.
TDD
Con mesura. Como herramienta para diseñar sistemas complejos y de forma reactiva ante bugs. No te vuelvas loco y te dediques a testarlo todo. No harás otra cosa.
Core Data
- Usa Core Data hasta para ir al baño.
- Usa mogenerator para generar tus subclases de NSManagedObject.
- Añade métodos de clase para crear instancias de tus subclases de NSManagedObject. Los objetos de Core Data deben de parecer objetos «normales» de Cocoa.
- Usa KVO en vez de setters o getter personalizados en la subclases de NSManagedObject.
Macros
No las uses jamás: interfieren el el code completion y dificultan la depuración.
Comunicación entre objetos
Usa siempre le mecanismo más sencillo posible: target action -> delegate -> notifications.
Bloques
Oculta el código GCD puro y duro en métodos que reciben bloques como parámetros.
Usa los bloques para reducir la complejidad de tu código:
- eliminar delegados
- aplazar tareas
- abstraer código redundante y repetitivo.
- y más usos de bloques en Objective C
Cosas chachis y nuevas
- Storyboards: NO. En serio.
- @import: espera hasta que se resuelvan los problemas actuales (por ejemplo con MapKit)
- Auto Layout: Opción por defecto. Solo uses el sistema anterior si absolutamente indispensable.