10 formas de mejorar tu código

[ACTUALIZACIÓN 030509: Añadido ejemplo de Antiobjeto.]

El otro día vi la presentación 10 Ways to Improve your Code que Neal Ford hizo en la QCon SF 2008 sobre cómo escribir mejor código y que ha publicado el portal InfoQ.

Es una presentación genial y muy práctica. Enseguida te das cuenta de que estás ante un gran programador que además sabe explicarse muy bien. Así que decidí tomar apuntes de estas 10 formas de escribir mejor código, que aprovecho para plasmar aquí y no olvidarlas.

1 - Métodos compuestos

Divide tus métodos en métodos más pequeños que realicen una única tarea claramente identificada. Así se obtiene un código más intuitivo y fácil de probar formado por métodos pequeños, cohesivos y reutilizables. Además es un código autodocumentado porque los nombres de los métodos se convierten en documentación.

2 - Diseño y Desarrollo orientado a pruebas (TDD)

Piensa en cómo se usará una clase y diseñarás mejor su interfaz y su relación con otras clases.
Una clase bien diseñada es fácil de probar.

3 - Análisis estático

Usa herramientas de análisis de código, como Findbugs, para evitar bugs, no violar buenas prácticas y escribir código más fácil de mantener.

4 - Buenos ciudadanos

En POO los ciudadanos son las clases. Una buena clase es aquella que se relaciona bien con las demás. Un ejemplo de mal ciudadano es el Singleton. Los singletons mezclan responsabilidades (su funcionalidad más asegurar 1 única instancia), son difíciles (sino imposibles) de probar y aumentan brutalmente el acoplamiento entre clases al usarse como las antiguas variables globales. En lugar de un singleton, usa un pojo con constructor privado para la funcionalidad y haz que sea una factoría la responsable de crearlo (usando reflection para saltarse el constructor privado) y asegurarse que sólo haya 1 instancia. Más sobre el peligro de los singletons aquí.

5 - YAGNI: you arent gonna need it

No programes lo que no vas a necesitar. Construye la funcionalidad más simple que necesites en cada momento.
No desarrolles de forma especulativa, pensando en posibles necesidades futuras.
Me encanta esta imagen:


6 - Cuestiona el porqué

No hagas las cosas porque sí. Piensa antes y comprueba.
A menudo, dentro de una empresa o equipo, se toman como leyes invariables algunas recomendaciones o soluciones concretas y circunstanciales. Incluso cuando su creador ha desaparecido. Seguro que todos tenemos algúna historia con esto...
Además a veces lo intuitivo no es cierto. Neal cita un estudio donde se observó que la programación por parejas produce código 15% menos rápido pero con 15% menos de defectos.

7 - SLAP

Usa el mismo nivel de abstracción para las líneas de un método.
Así conseguirás métodos compuestos de forma natural.

8 - Programación poliglota

Domina distintos lenguajes para resolver cada problema con el lenguaje más apropiado.

9 - Cada matiz

Aprende y aprovecha los matices especiales del lenguaje. Pej. en Java con reflection puedes hacer maravillas, como cambiar el modificador de acceso de métodos en tiempo de ejecución o construir objetos de clases definidas dinamicamente.

10 - Antiobjetos

Solemos modelar los objetos a imagen y semejanza del mundo real. Sin embargo, en ocasiones, es útil obviar la realidad para crear soluciones menos complejas. Es lo que se conoce como antiobjetos. Por ejemplo, si pensamos en el famoso juego Pac-Man, es lógico imaginar que son los fantasmas los que calculan su camino hacia pacman en base al tablero, su posición, la de pacman y si se comió la fruta. Pero en realidad es el tablero quien mueve los fantasmas!


Y tú, ¿conoces alguna otra forma?

15 comentarios :: 10 formas de mejorar tu código

  1. No estoy muy de acuerdo con algunos
    El 1 y el 7 son obvios, pero admito que hay que repetirlos contsantemente a los demas y a uno mismo.
    El 2, el 3, el 5 y el 6 100% de acuerdo.
    El 4 100% en desacuerdo con el ejemplo. El singleton es útil, hay que saber usarlo. De hecho el artículo recomendado nunca dice que no hay que usarlo, solo que hay que tener cuidado. Y usar reflection para invocar un constructor privado es un ejemplo de mal diseño.
    El 8 es medio inaplicable, al menos en todos los lugares que he trabajado el lenguaje se decide basicamente por cuestiones no tecnicas ("Esto se hace en java porque acá se hacen las webs en java y punto"), aunque admito que siempre es util saber mas de un lenguaje
    El 9 no me gusta. Aprender cada matiz y detalle de un lenguaje es bueno, pero usar cada matiz y detalle es el camino mas corto al código inmantenible. Siempre es mejor usar las características mas conocidas del lenguaje, porque los que vengan despues pueden no ser superexpertos. Reflection es muy úitl para hacer un framework o generar vistas dinámicas, pero en clases de negocios debería estar prohibido.
    Respecto al 10.....mm...salvo para simulaciones o cosas así, en general, los programas tienen muchas clases que no tienen contrapartida del mundo real...por ejemplo, las factorías, las clases de persistencia...a vceces se puede simplificar el mundo real, pero en general es mas complicado el diseño que lo que se quiere representar.
    Para aportar un poco despues de criticar tanto, una técnica que me parece muy productiva y es sencilla es especificar claramente las convenciones de nombres del programa, y respetarlas a rajatabla. Por ejemplo, usar para las clases de persistencia exactamente los mismos nombres de campos que para las columnas de la base de datos. Eso hace que los mapeos sean automáticos.
    O acordar que si una clase hereda de otra, el nombre de la clase hija debe terminar con el nombre de la clase padre, como NullArgumentException, o AdministratorUser. Eso hace más facil de recordar la relacion en todos los casos.

  2. Hola Pablo. Lo primero gracias por tu comentario. Un poco de charla siempre viene bien.

    Coincido contigo en que los singletons son útiles y más si se usan bien. Yo los he usado durante años! Pero son clases muy dificiles de probar. Cuanto más test haces, más te estorban o directamente no te dejan hacer ciertos tipos de tests. Hasta que te pasas a usar un contenedor de inyección de dependencias.

    También es cierto que normalmente la decisión de elegir el lenguaje principal de una aplicación te viene tomada de antemano. Sin embargo, existe un miedo atroz en el programador común a aprender/usar algo distinto a Java. Incluso dentro de una aplicación Java! Sea javascript, SQL, PL/SQL, Actionscript,... O incluso las nuevas características de Java5! Que todavía tiene más delito...

    Respecto a los matices, creo que tu punto de vista es muy pesimista. Es como los patrones de diseño. Un sobreuso puede ser catastrófico, pero no por eso vamos a no estudiarlos y usarlos cuando encajan. La simplicidad lo primero. Pero eso no quita que estudies tu lenguaje.

    Me hacen mucha gracia todos esos programadores que dicen abiertamente "yo controlo Java" y no saben qué es reflection, ni conocen del api Collections más allá del ArrayList, ni Threads, ni muchas otras clases y conceptos básicos.

    Lo del antiobjeto merece una aclaración. En realidad una factoria no es un antiobjeto, cumple con su función paralela en el mundo real: crear cosas/objetos.
    El antiobjeto es un objeto que no hace lo que supondriamos a primera vista. Pej. en el pacman, todos pensariamos que son los fantasmas los que calculan su camino para atrapar a pacman. Pero en realidad es el laberinto quien mueve a los fantasmas!

  3. No se cuales son los programdores comunes que tienen "un miedo atroz" a aprender/usar otro lenguaje...al menos todos los que yo he conocido, usan al menos 2 o 3, si contamos javascript y sql. Y muchos tiene un background de c++, o visual basic. O trabajan, como yo, medio tiempo en c#. Y ni hablar de usar las características nuevas de java5...yo ya odio cuando tengo que empezar a castear cosas en algun mantenimiento de código en java 1.4, o jme, por la falta de generics.

    Y voy a insistir con no usar características poco comunes del lenguaje. El código debe ser claro, y el uso de las cosas que nadie usa mas parece pedantería que simplificación. Claro que la simplicidad lo primero. Pero si uno usa reflection para cambiar el accesor de un método privado al que tiene que llamar indefectiblemente...era mas simple usar un método público. A mi particularmente me encanta usar reflection, por ejemplo, para crear pantallas dinamicamente, porque odio repetir las cosas. Y trato de usar Executors en vez de threads desnudas, porque es mas simple, pero la verdad, como nadie mas los usa, solo es mas simple para mí. Y un lenguaje de programación es tambien un lenguaje a secas, uno de sus objetivos es comunicar. Y no se puede comunicar nada usando palabras que nadie conoce.
    Respecto a los Antiobjetos...vi el ejemplo del pacman en la wiki....y me cuesta creer que el pacman fue programado en un lenguaje orientado a objetos. Y fuera de ese no hay ejemplo, ni se citan fuentes ni nada.
    Y va otra forma de mejorar el código, para ser positivo: Usar un set de herramientas estandard entre todos los desarrolladores. Si alguien quiere cambiar alguna, que se decida entre todos.
    Saludos!

  4. Estoy contigo en la importancia de mantener el código simple y comprensible. Precisamente porque he tenido que mantener mucho código y frameworks caseros llenos de pedantería (has elegido la palabra perfecta).

    Pero no considero que usar 2 líneas de reflection para hacer público un método privado sea rebuscado ni pedante. Si sabes reflection seguramente ya lo hayas hecho para hacer testing de metodos privados en proyectos legacy. Y si no sabes puede ser un buen gancho para conocer este matiz de Java que se aprende en 5 minutos y que como tu has dicho se usa en muchos frameworks y es muy útil.
    Además si está bien programado, estas 2 lineas estarán fuera de la vista en un pequeño método de una clase auxiliar (como el ejemplo de la factoria y el pojo de Neal).

    Pero insisto en la importancia de la simplicidad. Desde luego si piensas que estás haciendo un código dificil de entender a primera vista, lo mejor es hacerlo más simple aunque eso signifique no usar alguna característica guay.

    Claro que a veces la simplicidad de un código es muy subjetiva. A mi por ejemplo no me gusta nada el operador ?. Puedo pasar por ver uno en método, pero me acuerdo una vez que vi 3 encadenados!
    A Neal pej. no le gustan los constructores sin parametros y le gusta saltarse la convecion de nombrado de métodos y usar el caracter _ como separador de palabras en los métodos test.

    Respecto a lo del pacman y la poo, joder pues no habia caido! Supongo que tomarán el concepto de antiobjeto fuera de la POO. Pero no lo sé. Yo he encontrado algo más aquí: http://www.cs.colorado.edu/~ralex/papers/PDF/OOPSLA06antiobjects.pdf
    Pero es todo IA y ya si que lo veo fuera del código habitual que hacemos a diario.
    Es lo que tienen los decálogos que siempre suele haber 1 punto o 2 cogidos por los pelos.

    Lo del conjunto de herramientas estándar no me parece del todo bien. Veo bien y obligatorio tener un conjunto mínimo recomendado, pero luego me gusta dejar libertad para que la gente use otras herramientas si se sienten más cómodos.
    Por ejemplo, corporativamente tenemos que usar Windows, sin embargo son muchos los que prefieren usar Linux con lo que ello conlleva respecto a otras herramientas. Yo nunca se lo he prohibido. Sólo obligo a usar Word porque con OpenOffice no se lleva nada bien.

    PD: Lo del programador común en ningún caso iba hacía ti. Espero que no te lo tomaras a mal. Pero aquí en España el nivel medio es muy bajo. Me alegro que tengas unos compañeros tan competentes!

  5. Hola, querría poner mis dos centimillos en forma de recomendaciones de lectura (lo siento, en inglés):
    * "Implementation Patterns" de Beck
    * "Clean Code" de UncleBob

    y también otro enlace a un artículo sobre "testabilidad" (perdón por la palabrota).

  6. Hola José Manuel. Muchas gracias por la aportación.

    Me apunto el enlace en delicius para leerlo con calma.

    De Clean Code he leido buenas críticas, así que si lo recomiendas lo tendré en cuenta.

    Aunque Implementation Patterns sí que lo leí el año pasado y la verdad es que no me gustó mucho. Me pareció un poco flojo. Me esperaba más viniendo de Kent Beck.

  7. ¡Maldita sea! ¡Has hablado mal de Kent Beck! :-)

    Bueno, "Implementation Patterns" quizás es un libro para muy novatos, pero a mi me parece que hace reflexiones muy interesantes. Para alguien que empieza o para alguien que tiene que apoyar el crecimiento profesional de otros, creo que es un libro imprescindible.

    Idem con "Clean Code", aunque quizás haga aportaciones más "elaboradas", pero también más discutibles.

    Creo que en ambos casos, cuando los lees, tiendes a adoptar la posición del "vaya, lo que me estás contando no es nada nuevo" y, por tanto, tiendes a adoptar inmediatamente la posición del "bueno, bueno, no será para tanto". Lo que pasa es que (salvo contadísimas excepciones) nuestra experiencia no suele llegar a ser comparable con la de UncleBob o Kent Beck.

  8. La culpa es suya! Después de TDD By Example puso el listón muy alto :P

    Lo cierto es que hubo capítulos que me salté a medias porque me aburría. Poca chicha.
    Eso sí el capítulo de Collections está muy currado.

    Ahora voy a ver si ocupo el hueco de la mesilla con Release it!

  9. Bueno, reitero y aclaro: para frameworks y testeo, y alguna otra cosa, viva reflection. Pero para lógica de negocios, prohibido.
    Si en una clase yo veo un método privado, tengo derecho a suponer que nadie lo usa "normalmente". De hecho, otra de las contras de reflection es que escapa a las herramientas de verificación estática de código (al menos las que yo conozco). Y es muy bueno usar herramientas de verificación estática de código.

    Volviendo al tema antiobjects...creo recordar, me puedo equivocar, que en el Design Patterns de GoF uno de los ejemplos básicos que usan para mostrar factorías y algo mas es un laberinto, y los objetos son las paredes. Ojo, que no me guste el ejemplo no significa que no adhiera al principio general de que no siempre los objetos "del mundo real" son los que necesitamos en nuestro porgrama. Pero (y quizas sea un defecto de mi código, ojo) mis diseños suelen tener mas clases que las que se ven en el mundo real, no menos.

    Lo de el programador común va hacia mi, porque soy un programador común, como casi todos. Creerse especialmente bueno o especialmente malo es siempre un error... Es curioso que yo creo que el programador común conoce muchos lenguajes, pero poco de cada uno, y tu dices que conoce solo uno, pero que debe conocerlo bien a fondo...¿será que el programador común argentino sea distinto del programador común español en eso?¿o simplemente será una casualidad de nuestras experiencias personales?¿o no habré entendido lo que dices?

    Y me entró una duda: ¿Cómo hace Neal para evitar el constructor sin parámetros? Yo siempre lo tengo que usar (o al menos escribir), por un motivo o por otro. Y tampoco me gusta.

    Y no molesto más.
    Saludos!

  10. Ok Pablo, no entro más, creo que ambos puntos de vista han quedado claros y en realidad las diferencias son detalles.

    Neal dice que el constructor sin parametros (en una clase de dominio) solo debe existir si tiene sentido que exista un objeto vacio (propiedades a null). En caso contrario el constructor debe especificar el contrato de creación.
    A mi no me parece tan importante, sobretodo porque no me gustan nada los constructores con más de 2 parametros. Prefiero uno vacio y luego hacer sets. No se si es cuestion de gustos o que estoy acostumbrado a crear objetos sin pk q se asigna posteriormente al hacer el insert en bbdd.

    Sí que me gustaría aclarar que yo no me creo nada. Ni bueno ni malo. Y muchos menos especial. La lista de programadores mejores que yo simplemente es infinita. Y no hace falta recurrir a individuos de la talla de los antes citados.
    Sólo soy una persona a la que le apasiona programar. En realidad construir cosas en general. Y como me gusta tanto, me esfuerzo en aprender y mejorar. Prueba de ello es esta presentación y un larga lista de libros.

    Yo no he dicho que se deba conocer 1 único lenguaje a fondo. Sólo he dicho que es muy curioso lo que algunos entienden por "conocer" (en realida he dicho "controlar"). Pero creo que ese tema, junto con las diferencias entre nuestros paises son demasiado complejos para tratarlos aquí.

    Un saludo para ti también. Y de nuevo, gracias por participar.

  11. Julio César dijo: no me gustan nada los constructores con más de 2 parametros. Prefiero uno vacio y luego hacer sets.Arrepientete de tus palabras impías o deja de leer a Martin Fowler. :-)

    Estoy de acuerdo con tu primera parte de la afirmación (y sobre todo con la explicación que haces de lo que dice Neal Ford). En términos de DDD (Domain-Driven Design), aconsejo encarecidamente distinguir entre entidades (Entities) y objetos de valor (ValueObjects).

  12. A mi es que el modelo me gusta como las chicas: anoréxico!

    Ahora en serio, no se si es que estoy demasiado Springizado pero me gusta más tener mi capa service y mi capa dao separaditas. Supongo que también tiene que ver con el tipo de aplicaciones en las que trabajo, basicamente de gestión sobre una bbdd ama y señora.
    ¿Por qué acaso en una aplicación de gestión no son todas las clases del modelo Value Objects? Para mi la unica diferencia es en si mueven los datos del cliente a la app o si de la app a la bbdd. Siempre desde mi pto d vista...

    La verdad es que me parece un tema muy interesante, que merece un par de cañas. Malditas provincias...

  13. Lo siento, Julio, no he podido evitar el seguir esta discusión en un formato más "extenso". No lo he hecho con intención de crear polémica ni de quitarte lectores, je, je... lo que pasa es que necesitaba "más sitio" para explicarme bien.

    En cuanto a la cervecita... coge la que quieras. :-)

  14. Me parece una gran idea. Yo estuve apunto de proponertela. Te sigo en tu blog.

    Aquí tengo el flickr chapado, asi que la cerveza me la tomaré en casa a tu salud :-)

  15. ¿El flickr cerrado por seguridad? Desde luego, no pillaréis el H1N1. :-)

Publicar un comentario