Un mal código puede funcionar. Pero si el código no es limpio, puede poner de rodillas a una empresa de desarrollo de software. En todo el mundo se pierden recursos extraordinarios por culpa de un código mal diseñado. Pero no tiene por qué ser así. En agosto de 2008, el aclamado experto en software Robert C Martin presentó un exhaustivo libro titulado Código limpio. El libro le inculca los valores fundamentales de un artesano del software y enfoques para diseñar un código limpio y convertirle en un mejor programador.
¿CÓMO NOS HA AYUDADO ESTE LIBRO?
Este libro nos ayudó a comprender que convertirnos en mejores artesanos del software y escribir código limpio es lo que debemos hacer para considerarnos profesionales. El código limpio arroja luz sobre las pruebas unitarias, el formateo, la depuración y la utilización de nombres descriptivos, que nos ayudan a escribir un código más limpio y robusto para nuestros clientes. Escribir código limpio es una cuestión de hábito personal y mucho de habilidad. Con el tiempo, tendrá que crecer a través de la experiencia y el conocimiento para escribir código limpio.
EL LIBRO EXPLICADO EN MENOS DE 60 SEGUNDOS
El autor hace hincapié en que las funciones deben ser pequeñas, realizar una única tarea y tener nombres descriptivos. Sostiene que si una función requiere muchos argumentos de configuración, considere integrarlos en una única variable de opciones de configuración.
El libro hace hincapié en que los desarrolladores se atengan al principio de responsabilidad única, que establece que una clase o módulo debe tener una sola razón para cambiar. Este principio nos dio una definición de responsabilidad y directrices para el tamaño de las clases. Las clases deben tener una sola responsabilidad y una sola razón para cambiar.
LAS TRES MEJORES CITAS
«El código sin pruebas no es limpio. Por muy elegante que sea, por muy legible y accesible que sea, es impuro si no tiene pruebas».
«Todo sistema se construye a partir de un lenguaje específico del dominio diseñado por los programadores para describir ese sistema. Las funciones son los verbos de ese lenguaje y las clases son los sustantivos».
«La gestión de errores es importante, pero si oscurece la lógica, está mal».
RESÚMENES Y NOTAS DE LIBROS
Capítulo uno: Código limpio
El código limpio importa: un código incorrecto acabará por hundir una empresa porque, a mayor desarrollo, la productividad se acerca progresivamente a cero.
El coste total de poseer un código desordenado aumenta con el tiempo. Cuanto más desordenado se vuelve el código, menos posibilidades hay de limpiarlo. La productividad del equipo disminuye a medida que crece el desorden porque están bajo presión para cumplir un plazo o quieren aumentar la productividad.
Reconstruir un sistema desde cero consume tiempo y recursos. La refactorización y las mejoras graduales suelen ser las mejores opciones a tomar. Mantener limpio su código es rentable y una cuestión de supervivencia profesional.
Pasaría meses intentando realizar una tarea que sólo le habría llevado horas en código desordenado. El buen código pudre rápidamente el código erróneo porque el cambio de requisitos en los planteamientos frustra el diseño original.
El código limpio está bien probado y realiza una tarea con eficacia, ya que el código pésimo suele hacer demasiadas cosas por negligencia.
Los códigos desordenados ralentizan a los desarrolladores, aunque todos se sienten presionados a hacer un desastre para cumplir los plazos. Por lo general, no cumplirá el plazo haciendo un desastre. La única forma de cumplir el plazo es mantener un código limpio.
Cita favorita del capítulo: «Escribir código limpio es lo que debe hacer para llamarse profesional. No hay excusa razonable para hacer algo que no sea lo mejor posible».
Capítulo dos: Nombres significativos
No es exigente comentar que los nombres deben revelar su propósito. Seleccionar buenos nombres consume tiempo pero ahorra más de lo que cuesta. Cuide los nombres elegidos y cámbielos cuando encuentre otros mejores.
Elegir un buen nombre es complejo, y el nombre de una función o variable debe explicar qué es, cómo se utiliza y por qué existe. Si un nombre requiere un comentario, no revela su intención.
Debe evitar dejar pistas falsas que oculten el significado del código. Evite las palabras cuyo significado establecido difiera del que usted pretende darle.
Evite utilizar abreviaturas en los nombres de las funciones y en los nombres de las variables de un solo carácter, excepto en el caso de nombres de uso común como «i» para la variable contador de un bucle.
Las variables deben ser pronunciables para que pueda hablar de ellas y decirlas en voz alta. Sólo podrá hablar de ellas con sus compañeros de equipo si puede pronunciarlas.
Los nombres de una sola letra y las constantes numéricas tienen un problema específico. Cuesta trabajo localizarlos a través de un cuerpo de texto. Los nombres de una sola letra sólo pueden utilizarse como variables locales dentro de métodos cortos.
Cita favorita del capítulo: «Un nombre largo y descriptivo es mejor que un comentario largo y descriptivo».
Capítulo 3: Funciones
La primera regla de las funciones es que deben ser menores y la segunda es que deben ejecutar una sola tarea. Las funciones deben ser insignificantes hasta el punto de contener estructuras anidadas. Por lo tanto, el nivel de sangría de una función no debe ser superior a uno o dos. Esto facilita la lectura y la comprensión de las funciones.
Las funciones deberían tener el menor número posible de parámetros. Los parámetros suelen dificultar la comprensión de las funciones y se encuentran en un nivel inferior de abstracción. Evite el uso de parámetros lo mejor que pueda introduciendo clases ayudantes abstractas o convirtiendo los argumentos en variables miembro.
Para asegurarse de que sus funciones realizan una tarea, debe asegurarse de que las sentencias dentro de sus funciones están todas al mismo nivel de abstracción.
Utilice nombres significativos para etiquetar sus funciones. Los nombres descriptivos explican lo que hace una función. Cuanto más pequeña y centrada sea una función, más fácil será elegir un nombre descriptivo.
Cita favorita del capítulo: «Sabes que estás trabajando en código limpio cuando cada rutina resulta ser más o menos lo que esperabas».
Capítulo 4: Comentarios
El uso real de los comentarios compensa su fracaso a la hora de expresarse en código. Los comentarios son fallos sistemáticos. Debe tenerlos porque sólo a veces se le ocurre cómo describirse sin ellos.
Un código limpio y expresivo con pocos comentarios es mucho mejor que un código desordenado y complejo con muchos comentarios. Por lo tanto, dedique tiempo a limpiar el desorden de su código en lugar de dedicarlo a escribir comentarios que expliquen su desorden.
La mayoría de los comentarios son muletas y justificaciones de un código deficiente. Los comentarios pueden evitarse utilizando variables claramente nombradas y extrayendo secciones de código en funciones claramente nombradas.
No utilice Javadocs por el mero hecho de utilizarlos. Los comentarios que explican qué hace un método, qué argumentos toma y qué devuelve suelen ser redundantes en el mejor de los casos y engañosos en el peor.
Los comentarios deben incluir toda la información aplicable y el contexto que necesitará quien los lea. No sea perezoso al escribir los comentarios.
Cita favorita del capítulo: «No comente el código malo, reescríbalo».
Capítulo 5: Formateo
Asegúrese de que su código tiene un formato atractivo. Seleccione un conjunto específico de reglas manejables que controlen el formato de su código. A continuación, aplique de forma coherente esas reglas a su código. Es mejor si dispone de una herramienta para implementar esas reglas de formato.
El formato del código es esencial. Es demasiado crucial para ser ignorado. No cuente con que los humanos detecten y corrijan manualmente cada error de formato. En su lugar, utilice un formateador de código y un alineador de código automatizados. Esto es eficiente y productivo y ahorra tiempo durante las revisiones del código.
Los archivos fuente deben ser como un artículo de periódico. El nombre debe ser sencillo pero explicativo. El nombre debe ser suficiente para saber si se encuentra en un módulo adecuado. Las partes superiores de su archivo fuente deben ofrecer conceptos y algoritmos de alto nivel. Después, los detalles deberían aumentar a medida que se desciende.
Las variables deben declararse cerca de donde se utilizan. Para funciones pequeñas, esto suele ser al principio de la función. Incluso para funciones cortas, formatéelas bien en lugar de escribirlas en una sola línea.
Cita favorita del capítulo: «El formato del código es importante. Es demasiado importante como para ignorarlo, y es demasiado importante como para tratarlo religiosamente. El formato del código tiene que ver con la comunicación, y la comunicación es la primera orden del día del desarrollador profesional.»
Capítulo 6: Objetos y estructuras de datos
Usted mantiene sus variables privadas porque no quiere que nadie más dependa de ellas. Quiere conservar la libertad de cambiar su tipo o implementación impulsivamente. Muchos desarrolladores añaden automáticamente getters y setters a sus objetos, revelando sus variables privadas como si fueran públicas.
No añada getters y setters por defecto, sino que proporcione una interfaz abstracta a los datos para que pueda ajustar la implementación sin pensar en los clientes.
Los objetos ponen sus datos detrás de abstracciones y revelan funciones que trabajan sobre esos datos fuera de la vista. Las estructuras de datos exponen sus datos y no tienen funciones significativas.
La Ley de Deméter establece que un módulo no debe conocer las entrañas del objeto que manipula. Esto significa que un objeto no debe revelar su estructura interna a través de accesores porque hacerlo es exponer, en lugar de ocultar, su estructura interna. Dado que los objetos ocultan datos y exponen comportamientos, añadir nuevos objetos sin cambiar los comportamientos actuales no supone ningún esfuerzo. Las estructuras de datos revelan datos y no tienen comportamientos inusuales, lo que facilita la adición de nuevos comportamientos a las estructuras de datos existentes.
Cita favorita del capítulo: «En cualquier sistema, a veces querremos la flexibilidad para añadir nuevos tipos de datos, por lo que preferimos los objetos para esa parte del sistema. Otras veces querremos la flexibilidad para añadir nuevos comportamientos. Así que preferimos tipos de datos y procedimientos en esa parte del sistema».
Capítulo 7: Tratamiento de errores
La gestión de errores es esencial, y suele haber mucha durante la programación. Aun así, no debe ocultar la intención principal del código. Por lo tanto, utilice expectativas en lugar de códigos de retorno.
Las excepciones deben ser informativas y proporcionar detalles objetivos, contextuales y del tipo de error para que alguien que reciba el mensaje de error pueda solucionar el problema con eficacia.
Las excepciones definen el ámbito de su programa. Cuando implementa código en la parte try de una sentencia try-catch-finally, expresa que la ejecución puede terminar en cualquier punto y reiniciarse en el catch.
Cuando envuelve las API de terceros en una fina capa de abstracción, resulta más fácil cambiar una biblioteca por otra en el futuro y burlarse de la biblioteca durante las pruebas.
Cita favorita del capítulo: «El código limpio es legible, pero también debe ser robusto. No son objetivos contradictorios. Podemos escribir código limpio robusto si consideramos que la gestión de errores es una preocupación especial.»
Capítulo 8: Límites
El código de terceros le ayudará a conseguir más funcionalidad en menos tiempo. No es su trabajo probar el código de terceros, pero debería interesarle escribir pruebas para el código de terceros que utilice.
Las pruebas de aprendizaje son experimentos precisos que le ayudan a aumentar su comprensión. Las pruebas de aprendizaje confirman que los paquetes de terceros que utiliza funcionan de la forma que usted prevé. No hay garantías de que el código de terceros siga siendo compatible con sus necesidades cuando se combine.
Un buen software se adapta a los cambios sin inversiones significativas y sin tener que volver a trabajar. Cuando utiliza un código que escapa a su control, debe tener un cuidado excepcional para proteger su inversión y garantizar que los cambios futuros sean manejables.
Los límites de terceros se gestionan teniendo unos pocos lugares en el código que hagan referencia a ellos.
Evite que gran parte de su código conozca las particularidades de terceros. Es mejor confiar en algo que puede controlar que en algo que no puede controlar.
Cita favorita del capítulo: «Debemos evitar que gran parte de nuestro código conozca detalles de terceros. Es mejor depender de algo que controlas que de algo que no controlas, no sea que te controle a ti».
Capítulo 9: Pruebas unitarias
El desarrollo dirigido por pruebas requiere que escriba pruebas unitarias antes de escribir código de producción. No puede escribir código de producción hasta que no haya escrito una prueba unitaria que falle. El código de prueba debe ser tan limpio como el código de producción, con limitadas excepciones, normalmente relacionadas con la memoria o la eficiencia.
Asegúrese de mantener sus pruebas limpias o menos; las perderá. Y en su ausencia, perderá lo único que mantiene su código reutilizable, flexible y mantenible. No temerá hacer cambios en el código cuando las pruebas estén presentes, pero cada cambio es un error factible sin ellas.
La legibilidad es lo que hace que una prueba sea limpia. La legibilidad puede que sea incluso más esencial en las pruebas unitarias que en el código de producción. La claridad, la sencillez y la densidad de expresión es lo que hace que las pruebas sean legibles. En una prueba, hay que decir mucho con el menor número posible de expresiones.
Normalmente, le gustaría probar un único concepto en cada función de prueba. No querrá funciones de prueba extendidas que vayan probando una cosa diversificada tras otra.
Al igual que el código de producción, las pruebas también son cruciales para la solidez del proyecto. Las pruebas son necesarias porque mejoran y preservan la reutilización, el mantenimiento y la flexibilidad del código. Mantenga las pruebas limpias y procure que sean significativas y breves. Desarrolle API que actúen como un lenguaje específico del dominio que le ayude a escribir pruebas.
Cita favorita del capítulo: «Las pruebas deben escribirse en el momento oportuno. Las pruebas unitarias deben escribirse justo antes del código de producción que las hace pasar».
Capítulo diez: Clases
Las clases deben comenzar con una lista de variables. Las constantes estáticas públicas deben ir primero, luego las variables estáticas privadas, seguidas de las variables de instancia privadas. Ponga las utilidades privadas llamadas por una función pública justo después.
La primera regla de las clases es que tienen que ser pequeñas. Al igual que las funciones, ser pequeño es la regla principal para crear clases. Pero la verdadera pregunta es siempre «¿cómo de pequeñas?». Con las funciones, usted calcula el tamaño contando las líneas físicas. Con las clases, se mide el tamaño contando responsabilidades.
Las clases deben tener un número reducido de variables de instancia. Cada método de una clase debe controlar una o varias de esas variables. Cuantas más variables influya un método, más cohesionado estará con su clase.
Utilice muchas clases pequeñas en lugar de unas pocas clases grandes en su aplicación. Esto minimiza la cantidad de información que un compañero desarrollador necesitará comprender cuando trabaje en una tarea determinada.
Cita favorita del capítulo: «Una clase o módulo debe tener una, y sólo una, razón para cambiar».
¿CÓMO PUEDE AYUDAR ESTE LIBRO A LOS DESARROLLADORES DE SOFTWARE?
«Código limpio», de Robert C. Martin, puede ayudar a los desarrolladores de software a mejorar la calidad de su código. Proporciona consejos prácticos y directrices sobre cómo escribir un código legible, mantenible y eficiente. El libro abarca temas de nomenclatura, comentarios, formato y pruebas, y hace hincapié en la importancia de la sencillez, la claridad y la coherencia en las prácticas de codificación. Siguiendo los principios descritos en el libro, los desarrolladores pueden reducir la deuda técnica, aumentar la productividad y crear un software más accesible de entender, modificar y ampliar. Proporciona a los programadores de software un enfoque integral de la codificación que puede ayudarles a mejorar sus habilidades y reducir el coste del mantenimiento. Este libro ayuda a los programadores a escribir código fácil de modificar y refactorizar en el futuro. Es una lectura obligada para cualquier desarrollador de software que desee convertirse en un mejor programador.