2010-12-09 10 views
37

Quería preguntarles sus opiniones sobre los olores de código en Objective C, específicamente Cocoa Touch. Estoy trabajando en un juego bastante complejo, y estoy a punto de comenzar la Gran Refactorización de diciembre.Haciendo que las clases Objective-C se vean hermosas

Un buen número de mis clases, los modelos en particular, están llenos de métodos que se ocupan de la lógica empresarial interna; Los esconderé en una categoría privada, en mi guerra contra los archivos de encabezado masivos. Esas categorías privadas contienen una gran cantidad de declaraciones, y esto me hace sentir incómodo ... casi como Objective-C que me hace sentir culpable por todos estos métodos.

Cuanto más refactorice (¡algo bueno!), Más tengo que mantener toda esta duplicación (no tan buena). Simplemente se siente mal.

En un lenguaje como Ruby, la comunidad pone MUCHO énfasis en métodos muy cortos, claros y hermosos. Mi pregunta es, para Objective C (Cocoa Touch específicamente), ¿por cuánto tiempo se vuelven típicos sus métodos, cuán grandes son sus controladores y cuántos métodos por clase encuentran todos ustedes? ¿Hay ejemplos hermosos y bonitos de Clases formadas por métodos cortos en el Objetivo C, o simplemente no es una parte importante de la cultura del idioma?

DIVULGACIÓN: Actualmente estoy leyendo "El pequeño Schemer", que debe explicar mi tristeza, re: Objetivo C.

+0

+1 gran pregunta! – Rog

+0

Gracias! Se hizo evidente que este era un problema serio cuando comencé a pensar en cuánto tiempo lleva responder las preguntas obj-c que ruby. Grr ... –

+0

Puede que le interese este [stack-exchange proposal] (http: //area51.stackexchange.com/proposals/11464/code-review? referrer = aWNm_PdciyFqjFW8CUacGw2 "revisión del código"). Está casi listo para comenzar la versión beta, solo necesita algunos más. – greatwolf

Respuesta

15

Belleza es subjetiva.Para mí, una clase de Objective-C es hermosa si es legible (sé lo que se supone que debe hacer) y mantenible (puedo ver qué partes son responsables de hacer qué). Tampoco me gusta que se me quite el código de lectura por un idioma desconocido. Más o menos como cuando estás leyendo un libro y lees algo que te saca de la inmersión y te recuerda que estás leyendo.

Probablemente obtendrá muchos consejos diferentes, mutuamente excluyentes, pero aquí están mis pensamientos.

  • No hay nada malo con los métodos privados en una categoría privada. Para eso está ahí. Si no te gustan las declaraciones que obstruyen el archivo, utiliza el código desplegable en el IDE o las extensiones como categoría en un archivo diferente.
  • Agrupe los métodos relacionados y márquelos con #pragma mark declaraciones
  • Cualquiera que sea el diseño de código que use, la coherencia es importante. Tómese unos minutos y escriba sus propias pautas (aquí están mine) así que si olvida lo que se supone que debe estar haciendo, tiene una referencia.
  • El controlador no tiene que ser el delegado y el origen de datos, siempre puede tener otras clases para estos.
  • Utilice nombres descriptivos para métodos y propiedades. Sí, puede documentarlos, pero no puede ver la documentación cuando Xcode aplica la finalización del código, donde los métodos y propiedades bien nombrados dan sus frutos. Además, los comentarios del código se vuelven obsoletos si no se actualizan mientras el código cambia.
  • No intente escribir código inteligente. Puede pensar que es mejor encadenar una secuencia de llamadas de método en una línea, pero el compilador optimiza mejor de lo que podría pensar. Está bien usar variables temporales para mantener los valores (en su mayoría, estos son sólo indicadores de todos modos, por lo que son relativamente pequeños) si mejora la legibilidad. Escriba el código para que los humanos lean.
  • DRY se aplica tanto a Objective-C como a otros idiomas. No te preocupes por refactorizar el código en más métodos. No tiene nada de malo tener muchos métodos siempre que sean útiles.
+9

He renunciado a '#pragma mark' en favor de' // MARK: 'tiene el mismo efecto en el menú en Xcode pero no causa advertencias en el código que es portátil entre los compiladores. Además, '// MARK: -' es una ayuda real (también funciona con el pragma). Pone una regla horizontal en el menú. – JeremyP

+0

Gracias por esto, todos fueron geniales, y nos vienen muy bien durante la Gran Refactorización. –

2

Mis 2 centavos:

  1. Propiedades son por lo general mejor que viejo -style getter + setter. Incluso si usa propiedades @dinámicas, declarelas con @property, esto es mucho más informativo y más breve.
  2. Personalmente no simule métodos "privados" para las clases. Sí, puedo escribir una categoría en algún lugar del archivo .m (m), pero dado que Obj-C no tiene una forma pura de declarar un método privado, ¿por qué debería inventar uno? De todos modos, incluso si realmente necesita algo así, declare un "MyClassPrivate.h" por separado con una categoría e inclúyalo en los archivos .m (m) para evitar la duplicación de las declaraciones.
  3. Encuadernación. Encuadernación para la mayoría de los controladores < -> relaciones de interfaz de usuario, use transformadores, formateadores, simplemente no escriba métodos para leer/escribir valores de controles manualmente. Hace que el código parezca algo de la era MFC.
  4. C++, muchos códigos se ven mucho mejor y más cortos cuando se escriben en C++. Como el compilador entiende las clases de C++, es un buen punto para refactorizar, especialmente cuando se trabaja con un código de bajo nivel.
  5. Normalmente divido grandes controladores. Algo más de 500 líneas de código es un buen candidato para la refactorización para mí. Por ejemplo, tengo un controlador de ventana de documento, ya que algunas versiones de la aplicación se amplían con las opciones de importación/exportación de imágenes. El controlador crece hasta 1.000 líneas donde 1/2 es el "material de imagen". Eso es un "disparador" para mí para hacer un ImageStuffController, crear una instancia en el NIB y poner todo el código relativo a la imagen allí.

Todo lo anterior me facilita mantener mi código. Para proyectos grandes, donde dividir los controladores y las clases para mantener pequeños resultados, gran cantidad de archivos, generalmente intento extraer algún código en un marco. Por ejemplo, si una gran parte de la aplicación se está comunicando con servicios web externos, generalmente hay una forma directa de extraer un MyWebServices.framework de la aplicación principal.

+12

# 4 es una idea terrible y terrible. La primera vez que escuché a alguien decir que traducir a C++ para hacer que el código se vea mejor. –

+1

jshier, C++ permite definir un operador + para NSPoint, por ejemplo. Para mí, p1 + p2 se ve mucho mejor que NSOffsetPoint (p1, p2). C++ es mucho más limpio cuando se trabaja con estructuras de datos como mapas y listas (a menos que el resultado se use directamente en la interfaz de usuario, ahí es donde debe ir con clases NS). Siguiente - tareas de matemáticas. La biblioteca de C++ para matrices y vectores suele ser mucho más fácil de usar que NSAffineTransform y otros. Las clases NS son una vez más buenas cuando se trabaja con NSGraphicsContext, pero algunas matemáticas back-end definitivamente se deben procesar con C++ para simplificar el código. En mi humilde opinión, por supuesto – Gobra

7

Lo primero que hago incluso antes de implementar clase o método es preguntar: "¿Cómo quisiera usar esto desde el exterior?"

Nunca, nunca empiezo escribiendo primero las partes internas de mis clases y mis métodos. Al comenzar con una API pública elegante, los internos tienden a ser elegantes de forma gratuita, y si no lo hacen, entonces la fealdad está contenida al menos en un único método o clase, y no se permite contaminar el resto del código con su olor. .

Hay muchos patrones de diseño, dos décadas de codificación me han enseñado que el único patrón que resiste el paso del tiempo es: KISS. Keep It Simple Stupid.

Algunas reglas generales, para cualquier lenguaje o entorno:

  • Siga su presentimiento sobre cualquier consejo que has leído o escuchado!
  • ¡Salgo temprano!
    • ¡Si es necesario, verifique las entradas temprano y rescate rápidamente! Menos limpieza para hacer.
  • Nunca agregue algo a su código que no utilice.
    • Una opción para "reverso" puede parecer algo agradable de tener en el camino.
    • En ese caso agrégalo en el futuro. No pierdas tiempo agregando complejidad que no necesitas.
  • Los nombres de los métodos deben describir lo que se hace, nunca cómo se hace.
    • Se debe permitir que los métodos cambien su implementación sin cambiar su nombre, siempre que el resultado sea el mismo.
    • Si no puede entender qué hace un método con su nombre, ¡cambie el nombre!
    • Si la parte de cómo es lo suficientemente compleja, entonces use los comentarios para describir su implementación.
  • ¡No temas a los singletons!
    • ¡Si su aplicación solo tiene un modelo de datos, entonces es un singleton!
    • Pasar una sola variable por todo el lugar es simplemente pretender que es algo más que un singleton y agregar complejidad como bonificación.
  • Planee las fallas desde el principio.
    • Siempre use para doFoo:error en lugar de doFoo: desde el principio.
    • Crea buenas instancias NSError con descripciones localizadas legibles por el usuario final desde el principio.
    • Es un gran problema para actualizar los mensajes de error a una gran aplicación existente.
    • ¡Y siempre habrá errores si tiene usuarios y E/S involucrados!
  • Cacao/Objective-C es Objeto * Orientado, no ** Clase orientadas como la mayoría de los chicos populares por ahí que dicen ser programación orientada a objetos.
    • No introduzca una clase de valores tontos con solo propiedades, una clase sin métodos que realicen el trabajo real podría ser una estructura.
    • ¡Deje que sus objetos sean inteligentes! ¿Por qué agregar una nueva clase FooParser si todo lo que necesita es un método fooFromString: en Foo?
  • en el cacao lo que puede hacer es siempre más importante que lo que eres .
    • No introduzca un protocolo si un objetivo/acción puede hacerlo.
    • No verifique que las instancias se ajusten a los protocolos, es un tipo de clase, que depende del compilador.
+0

Apple prefiere clases de proporciones solo sobre estructuras (lo siento, no hay referencia). Además, la introspección * puede * ser útil cuando se trata de 'id', subclases o métodos de protocolo opcionales. –

+0

@Scott - Jupp, esto cambia después de la introducción de ARC. ARC no puede jugar bien con las referencias de objeto en las estructuras, pero sí con las clases. – PeyloW

+0

Completamente de acuerdo con esto, resume mi experiencia también :) – theLastNightTrain

Cuestiones relacionadas