Índice
Principios
Nivel único de abstracción
Mantener un nivel de abstracción favorece la legibilidad.
Cambiabilidad | |
---|---|
Corrección | |
Eficacia de la producción | |
Mejora continua | |
Desarrollador único |
Una línea de código puede tener distintos niveles de abstracción. La asignación de un valor a una variable está en un nivel de abstracción más bajo que una llamada a un método, por ejemplo. Después de todo, puede haber mucha más lógica detrás de la llamada a un método que en la asignación de una variable. Incluso las llamadas a métodos pueden estar en diferentes niveles de abstracción. Llamar a un método desde un framework está a un nivel diferente que llamar a un método desde la aplicación.
Para que el código sea fácil de leer y comprender, en un método sólo debe utilizarse un nivel de abstracción. De lo contrario, al lector le resultará difícil distinguir entre lo esencial y los detalles. Si es necesario hacer retoques, éstos no deben mezclarse con la llamada a métodos.
Una analogía útil es mirar los artículos del periódico: en la parte superior está lo más importante, el titular. Debe dar una idea aproximada de lo que trata el artículo. En la primera frase del artículo, se describe a un alto nivel de abstracción. Cuanto más avanzas en el artículo, más detalles surgen. Podemos estructurar nuestro código de la misma manera. El nombre de la clase es el encabezamiento. Le siguen los métodos públicos a un alto nivel de abstracción. Éstos pueden llamar a métodos de un nivel inferior, hasta que finalmente quedan los "métodos de bit wicket". Esta categorización me permite, como lector de la clase, decidir qué nivel de detalle quiero ver. Si sólo me interesa a grandes rasgos cómo funciona la clase, sólo necesito mirar los métodos públicos. En ellos, la funcionalidad se resuelve a un alto nivel de abstracción. Si me interesan más detalles, puedo profundizar y mirar los métodos privados.
Fuentes bibliográficas: Clean Code, página 36 y siguientes.
Principio de Responsabilidad Única (PRU)
La concentración facilita la comprensión. Una clase con exactamente una tarea es más fácil de entender que un taller general.
Cambiabilidad | |
---|---|
Corrección | |
Eficacia de la producción | |
Mejora continua | |
Desarrollador único |
El principio de responsabilidad única (SRP) es uno de los SÓLIDO Principios. Dice así: Una clase sólo debe un tener responsabilidad.
El trasfondo del principio de responsabilidad única es la idea de que los cambios o ampliaciones de la funcionalidad de una aplicación deben limitarse a unas pocas clases. Cuantas más clases haya que adaptar, mayor es el riesgo de que los cambios necesarios causen problemas en lugares que no tienen nada que ver con el núcleo de la ampliación. La violación del principio de responsabilidad única conduce al acoplamiento y, por tanto, a una mayor complejidad, lo que dificulta la comprensión del código.
Separación de intereses (SoC)
Si una unidad de código no tiene una tarea clara, es difícil entenderla, aplicarla y, si es necesario, corregirla o ampliarla.
Cambiabilidad | |
---|---|
Corrección | |
Eficacia de la producción | |
Mejora continua | |
Equipo |
Traducido como separación de preocupaciones, este principio significa que varias preocupaciones no deben resumirse en una sola clase. ¿Qué son los intereses? Las preocupaciones son propósitos "completamente diferentes". También se dice que las preocupaciones son ortogonales entre sí y, sobre todo, ortogonales a la funcionalidad principal de una unidad funcional. Ejemplos de preocupaciones típicas son Seguimiento, registro, transaccionalidad, almacenamiento en caché. Estas preocupaciones deben externalizarse a unidades funcionales especializadas de acuerdo con el principio de separación de preocupaciones.
El principio de separación de responsabilidades está estrechamente relacionado con el principio de responsabilidad única. Las preocupaciones son un superconjunto de responsabilidades. Idealmente, cada responsabilidad consiste exactamente en una preocupación, es decir, su funcionalidad principal. Sin embargo, a menudo se mezclan varios problemas en una responsabilidad. Como esto suele ser técnicamente inevitable, el principio no establece que una responsabilidad sólo pueda constar de un núcleo, sino que las preocupaciones deben estar separadas. Dentro de un método, por ejemplo, debe ser claramente reconocible que hay varias preocupaciones. Además, las preocupaciones no deben estar dispersas por todo el método, sino agrupadas de forma que quede claro qué pertenece a una preocupación.
En el diseño orientado al dominio, por ejemplo, se intenta separar estrictamente el dominio de negocio de la infraestructura. Esto significa que una clase del dominio de negocio no debe contener ninguna infraestructura, como por ejemplo para el acceso a la base de datos, sino que sólo debe representar la lógica de negocio. La persistencia es una "preocupación" que no tiene nada que ver con la lógica empresarial. La separación de preocupaciones conduce a un acoplamiento débil y a una alta cohesión. Los componentes individuales se centran cada uno en una tarea, una preocupación, y por lo tanto son fáciles de entender. Todas las partes que componen el componente se centran en esta única tarea, por lo que están estrechamente relacionadas (alta cohesión). La separación de intereses también facilita la comprobación de los componentes. Esto se debe a que si el propósito de una unidad de código está centrado, se requieren pruebas menos extensas. Hay que probar menos combinaciones de parámetros de prueba en relación con la unidad de código que se va a probar. Para que la separación de preocupaciones sea coherente, la orientación a objetos debe ampliarse para incluir el concepto de programación orientada a aspectos (AOP). Esto permite extraer completamente de un método aspectos como la transaccionalidad, el rastreo o el almacenamiento en caché.
Convenciones del código fuente
El código se lee más a menudo de lo que se escribe. Por eso son importantes las convenciones que facilitan una lectura y comprensión rápidas del código.
Cambiabilidad | |
---|---|
Corrección | |
Eficacia de la producción | |
Mejora continua | |
Equipo |
Consideramos importantes los siguientes aspectos:
- Normas de denominación
- Comentario correcto
Esto no quiere decir que otras convenciones carezcan de importancia, simplemente queremos empezar con estas dos porque nos parecen elementales. Con todas las convenciones de código, hay algo que nos parece muy importante: no se trata tanto de la forma concreta, sino de la adhesión coherente a la convención. Y se trata de la conciencia de que las convenciones son necesarias.
Normas de denominación
Sin reglas de nomenclatura, hay que sintonizar una y otra vez con el estilo de cada desarrollador.
Las reglas de denominación deben ayudar al lector del código a entenderlo. Como es útil, por ejemplo, distinguir los campos de las variables locales, esto podría apoyarse en una regla de nomenclatura. El aspecto de esta convención en cada caso es cuestión de gustos. Algunos prefieren "this.xyz" otros "_xyz". La variante que elijas no nos importa. Lo que nos importa es que la convención se cumpla de forma coherente. La necesidad de una regla de nomenclatura para los campos, por ejemplo, también depende del contexto. En una clase de 400 líneas, una regla de nomenclatura que dé más importancia a los campos que a las variables sería muy importante para nosotros, mientras que en clases manejables tiende a pasar a un segundo plano. Con la ayuda del análisis de la causa raíz, el desarrollador de código limpio llega al fondo de la causa real de la necesidad de una regla de nomenclatura.
Comentar correctamente
Los comentarios innecesarios o incluso incorrectos ralentizan la lectura. El código debe ser tan claro e inequívoco que pueda prescindir de comentarios si es posible.
Para decirlo sin rodeos, un comentario en el código es una indicación de que el código aún puede mejorarse. Lo típico en estos casos son 3 líneas de código que se sobrescriben con un comentario. En este punto, probablemente ayude extraer las tres líneas como un método (Refactorización: Extraer método) y utilizar el comentario como nombre del método. En general, la necesidad de comentarios puede reducirse utilizando buenos nombres para variables, métodos, clases, etc.
En lugar de
int longitud; // en mm
mejor
int longitudEnMM;
En lugar de
public double Precio() { // Calcula el precio bruto ... }
mejor
public Dinero BruttoPreis() { ... }
No se debe comentar lo que se hace, sino, si acaso, por qué se hace algo.
Prácticas
Seguimiento de problemas
Sólo lo que anote no se olvidará y podrá delegarse y controlarse eficazmente.
Cambiabilidad | |
---|---|
Corrección | |
Eficacia de la producción | |
Mejora continua | |
Equipo |
La gestión estructurada de todos los asuntos es esencial para garantizar que nada se pierda. Y sólo si es posible tener una visión de conjunto de todos los temas abiertos se pueden priorizar y poner en orden. Para ello no se necesitan necesariamente herramientas sofisticadas; un tablero con tarjetas de cartón también puede servir. Sobre todo, no hay que centrarse en la herramienta, sino en la actividad.
Véase también Herramientas.
Pruebas de integración automatizadas
Las pruebas de integración garantizan que el código hace lo que se supone que debe hacer. No automatizar esta actividad recurrente sería una pérdida de tiempo.
Cambiabilidad | |
---|---|
Corrección | |
Eficacia de la producción | |
Mejora continua | |
Desarrollador único |
Ya hemos descrito el requisito previo fundamental para cualquier cambio en el código del grado rojo utilizando un sistema de control de versiones. Podemos hacer cambios en el código, borrar archivos y directorios enteros sin preocuparnos, y el sistema de control de versiones significa que todo se puede recuperar de nuevo.
Si ahora hacemos cambios en el código, debemos estar seguros de que no estamos rompiendo nada. Y sólo podemos conseguir esta certeza si probamos si la aplicación sigue comportándose como antes después del cambio. Realizar estas pruebas manualmente después de cada cambio no sería práctico; tenemos que automatizarlas. Uno de los grandes males del desarrollo de software es el miedo a pasar algo por alto al realizar cambios en el código, a no tener en cuenta un detalle y provocar así un error en un código que antes funcionaba. Por regla general, ni siquiera importa si los cambios pretenden mejorar el código (refactorización) o implementar requisitos adicionales. Mientras no estemos seguros, después de hacer un cambio, de que todo sigue funcionando como antes, el miedo persiste. Esto nos lleva a dejar el código como está en caso de duda, porque funciona. Las refactorizaciones necesarias se omiten por miedo a cometer errores.
Para que también podamos participar en proyectos en curso (los llamados Terrenos baldíos proyectos, a diferencia de Greenfield "greenfield") para crear esta red de seguridad, necesitamos procedimientos que puedan aplicarse al código existente. Las pruebas de integración automatizadas son adecuadas para ello. O bien empiezan en la parte superior de la interfaz de usuario y prueban la aplicación a través de todas las capas, o bien empiezan más abajo. En ambos casos, se comprueba la interacción de varias unidades funcionales.
Por eso, antes de realizar cambios o ampliaciones en el código, creamos pruebas de integración para las áreas de código afectadas. Para ello se pueden utilizar herramientas y técnicas como WatiN, UI Automation, etc. Por supuesto, también son deseables las pruebas unitarias que comprueban unidades funcionales individuales de forma aislada. Para ello, sin embargo, el código debe cumplir unos requisitos que probablemente no siempre se cumplan: el código ya debe cumplir los Principio de responsabilidad única deben tenerse en cuenta. De lo contrario, las dependencias entre las unidades funcionales (componentes, clases o métodos) son tan grandes que no pueden probarse de forma aislada. El objetivo a largo plazo es, por supuesto, una base de código en la que sea posible realizar pruebas unitarias. Es más: en el futuro, crearemos las pruebas antes de la implementación (Pruebe primero). Pero para llegar a ese punto mediante la refactorización, primero es necesario realizar pruebas de integración que garanticen que la aplicación sigue comportándose como antes de la refactorización.
Véase también Herramientas.
Leer, leer, leer
¡Leer educa!
Cambiabilidad | |
---|---|
Corrección | |
Eficacia de la producción | |
Mejora continua | |
Desarrollador único |
Leer educa: estamos firmemente convencidos de que esto también se aplica a los desarrolladores de software. La tecnología del software sigue evolucionando. Además de los grandes desarrollos, como la programación procedimental, la programación orientada a objetos, la programación funcional, la programación orientada a aspectos, etc., hay constantes desarrollos a menor escala con los que tiene que lidiar un desarrollador de software profesional. Por un lado, existen técnicas como Inyección de dependencia o Mapeador relacional de objetos. Pero también hay etapas de desarrollo dentro de estas técnicas, como por ejemplo Lenguajes específicos de dominio (DSL) para la configuración frente a la configuración basada en XML. Además de los aspectos técnicos del desarrollo de software, el proceso también evoluciona constantemente. Se ha reconocido que los modelos en cascada no funcionan y se están desarrollando diversos procesos ágiles. El desarrollador de código limpio debe tener todo esto en cuenta.
Por tanto, sugerimos leer al menos 6 libros especializados al año. Además, hay que leer publicaciones periódicas con regularidad, y con ello nos referimos tanto a los blogs como a las revistas especializadas.
Encontrará sugerencias en Bibliografía.
Reseñas
Cuatro ojos ven más que dos. Cuando un desarrollador explica su código al otro, suelen surgir detalles que aún no se habían tenido en cuenta.
Cambiabilidad | |
---|---|
Corrección | |
Eficacia de la producción | |
Mejora continua | |
Equipo |
Las revisiones se presentan de dos formas simplificadas: como un proceso continuo en la programación por parejas y como un paso independiente del proceso en la revisión del código. El objetivo es el mismo en ambos casos: el código debe ser revisado por un segundo desarrollador. Así se evita la "ceguera operativa". El mero hecho de que un desarrollador presente y describa su código a otro desarrollador da lugar a experiencias "ajá".
Por lo general, los puntos fuertes y débiles de una base de código sólo se detectan mediante el debate con otros desarrolladores. El proceso de mejora continua, en particular, hace necesario conocer las opiniones de otros desarrolladores.
Por supuesto, no sólo el código fuente es una base adecuada para las revisiones. Ofrecen una oportunidad favorable para comprobar los resultados de cada actividad de desarrollo, siempre que conduzcan a un resultado "legible". Además de las revisiones puramente informales, como la programación en parejas o la evaluación por parte de una segunda persona, también existe la revisión formal con un proceso de revisión y las funciones correspondientes. Otros tipos de revisión bien conocidos son el walkthrough, la revisión técnica, la revisión por pares y la inspección.
Las revisiones complementan las pruebas dinámicas, como la prueba unitaria automática o la prueba de integración automática del grado amarillo resp. grado naranja. A diferencia de estas pruebas, las revisiones también son muy adecuadas para encontrar errores en los requisitos. Además, pueden utilizarse en una fase muy temprana del proceso de desarrollo, por lo que los errores pueden detectarse muy pronto. Y cuanto antes se detecten, menos costará eliminarlos.
Fuentes
Fuente | Autor | Breve descripción |
---|---|---|
Conocimientos básicos de pruebas de software, formación y perfeccionamiento para | T. Linz y A. Spillner | El libro de texto para Certified Tester Foundation Level según ISTQB |
Tester certificado de nivel Foundation según el estándar ISTQB |
Al grado naranja le sigue el Grado amarillo a.