Mostrando entradas con la etiqueta Robert C Martin. Mostrar todas las entradas
Mostrando entradas con la etiqueta Robert C Martin. Mostrar todas las entradas

miércoles, 14 de noviembre de 2018

Principio de Inversión de Dependencia

Es un principio estructural, que habla que los módulos de alto nivel no deben depender de los módulos de bajo nivel, en otras palabras las dependencias del código se refieren solo a abstracciones, no a concreciones. El seguir este principio nos da el control sobre la dirección de todas las dependencias.

Para ilustrar lo anterior miremos la siguiente imagen.


En esta imagen vemos dos componentes uno es el de las vistas y otro es el de los controladores y como se observa un controlador necesita una instancia de la vista para poder indicar que acción realizar, pero esto presenta varios problemas, por ejemplo, no queremos que un cambio en la Vista1 nos obligue a volver a compilar o modificar nuestra clase Controlador1, para esto podemos usar la inversión de dependencia como veremos en la siguiente imagen.


Al crear una interfaz en el componente de los controladores que abstrae el comportamiento de una vista podemos invertir la dependencia, ahora el componente de las vistas depende del componente de los controladores, de esta forma protegemos al componente de los controladores de los cambios en componente de las vistas.

Que tal si vemos un ejemplo más concreto para ver esto.

Imaginemos estamos viendo el espectáculo de Gepetto y Pinocho y decidimos recrearlo en una pequeña aplicación.



Para empezar con nuestra aplicación debemos hacernos un par de preguntas.
¿Quien conoce como manipular un títere?, ¿Quien realiza la acción?. Es claro que quien sabe como manipular un títere es Gepetto y quien realiza la acción es Pinocho, solo con estas dos simples preguntas ya podemos hacernos una idea quien tiene las funciones de alto nivel y quien las de bajo nivel.

Gepetto contiene las funciones de alto nivel (Es quien conoce las reglas del negocio y sabe como manipular un titere), cuales serian estas funciones.

  • void mostrarTitereInmovil();
  • void moverCabezaDelTitere();
  • void moverBrazoIzquierdoDelTitere();
  • void moverBrazoDerechoDelTitere();
  • void moverPiernaIzquierdoDelTitere();
  • void moverPiernaDerechoDelTitere();

Pinocho contiene las funciones de bajo nivel (Es quien simplemente realiza las acciones que Gepetto sabiamente le ordena), cuales serian estas funciones.

  • void inmovil();
  • void moverCabeza();
  • void moverBrazoIzquierdo();
  • void moverBrazoDerecho();
  • void moverPiernaIzquierdo();
  • void moverPiernaDerecho();


Para ilustrar esto tendremos dos componentes uno de alto nivel (donde estará Gepetto) y otra de bajo nivel (Donde estará Pinocho). A estas alturas es obvio que Gepetto debe tener una instancia de Pinocho para poder manipularlo por lo que el diagrama se vería algo así.


Es evidente a simple vista que el componente de alto nivel depende del componente de bajo nivel lo cual es un error, imaginemos que Pinocho sale a vacaciones y viene en su reemplazo Pepito Grillo, ¿Qué pasaría?, ¿Tendríamos que hacer cambios en nuestra aplicación?, es obvio que la respuesta es si, primero Gepetto no debería estar condicionado a trabajar con un solo títere, él es un titiritero y sabe manipular a cualquier títere que le pongan, por lo cual empiezo a evidenciar un problema de abstracción, una ultima consideración seria, y que tal que él que salga a vacaciones es Gepetto, podríamos crear un nuevo titiritero para Pinocho, es evidente que con el diseño actual no podríamos, por lo que vamos a hacer una mejor abstracción y mejorar considerablemente nuestro diseño e invirtiendo la dependencia.

Creo que ya nos dimos cuenta que los conceptos principales del dominio de la aplicación son Titiritero y Títere por lo que creo que deberíamos abstraer su comportamiento creando dos Interfaces y que estas contengan la declaración de las funciones ya mencionadas.

Como segundo paso Gepetto debería implementar la interfaz Titiritero porque es claro que él es un titiritero.

El tercer paso consiste en que Pinocho implemente la interfaz Titere.

Ahora Gepetto no debe tener una instancia de Pinocho sino declara una variable de clase de tipo Titere y es necesario entonces que los titiriteros tengan una función adicional setTitere(Titere titere) tengamos presente que en un espectáculo de títeres un titiritero puede cambiar contantemente de títere y creo que esta función le caería de mil maravillas.

Por ultimo viene la pregunta crucial donde deben ir estas interfaces porque de dicha ubicación dependen si se logra la inversión de dependencia o no.  Imagino que ya tienes la respuesta, si así es, deben ir en el componente de alto nivel, nuestro nuevo diagrama queda así.


Si comparas los dos diagramas ahora la flecha de dependencia se ha invertido y el componente de bajo nivel depende del componente de alto nivel y nuestra aplicación ahora puede crecer de una forma mas flexible, puedes crear más títeres y mas titiriteros si así lo deseas.

El código fuente de este ejemplo en encuentras en mi repositorio de GitHub dedicado a la Programación Orientada a Objetos

Si deseas ampliar más este tema te recomiendo el artículo The Dependency Inversion Principle de Robert C. Martin.

Si deseas leer sobre los demás principios SOLID da click aquí.

martes, 13 de noviembre de 2018

Principio de Sustitución de Liskov

En la siguiente cita Barbara Liskov definía los subtipos:
Lo que se busca aquí es algo parecido a la siguiente propiedad de sustitución: si por cada objeto o1 del tipo S hay un objeto o2 del tipo T, como aquel para todos los programas P definidos en términos de T, el comportamiento de P no cambia cuando o1 es sustituido por o2, por lo que S es un subtipo de T.  Barbara liskov, "Data Abstraction and Hierarchy", SIGPLAN Notices 23, 5 (Mayo 1988).

Esto es lo que se conoce como Principio de Sustitución de Liskov, el cual hace parte de los principios SOLID y podemos llevarlo a otras palabras no tan formales, más simples y coloquiales, por lo que se podría decir que:

Las clases Base deben poder usar objetos de clases derivadas sin conocerlos. Es decir los tipos derivados son completamente sustituibles por sus tipos base.

En otras palabras este principio afirma que, para crear sistemas de software a partir de partes intercambiables, esas partes deben adherirse a un contrato que les permita ser sustituidas por otras.

Veamos un ejemplo para poder entender mejor esto.


Imaginemos que tenemos una clase Motor como se muestra en la imagen anterior, esta clase tiene un método prender() y dos subtipos Motor2Tiempos y Motor4Tiempos y cada uno tiene su forma de prender. Por su parte la clase Motocicleta invoca el método prender() independiente de cual de los dos subtipo utilice (Ambos subtipos son sustituibles por el tipo Motor) lo que garantiza que se esta cumpliendo el principio de sustitución de Liskov. 

Espero este sencillo ejemplo les permita entender de una forma simple este principio.

Si deseas ampliar más este tema te recomiendo el artículo The Liskov Substitution Principle de Robert C. Martin.

lunes, 10 de abril de 2017

Clean Code Capítulo 5 Formato

Este capítulo se resumen en la necesidad que debemos tener de preocuparnos por el formato de nuestro código. Por lo anterior y si se trabaja en equipo el autor expresa que se “debe acordar una serie de reglas que todos los miembros deben cumplir”.

 Como la comunicación debe ser el pilar de un desarrollador profesional, el formato son esas reglas que utilizamos al escribir nuestro código, permitiendo comunicarnos mejor. El libro Clean Code nos menciona una serie de formatos o reglas a seguir.

 Formato Vertical: se refiere al tamaño o número de líneas que debe tener un archivo fuente, esto lo quiero resumir diciendo que no hay un tamaño vertical máximo, pero que un archivo pequeño es más fácil de entender que uno muy extenso, en este punto quiero mencionar la metáfora del periódico descrita en el libro:

 “Piense en un artículo de periódico bien escrito. En la parte superior espera un titular que indique de què se trata la historia y le permita determinar si quiere leerlo o no. El primer párrafo ofrece una sinopsis de la historia, oculta los detalles y muestra conceptos generales. Al avanzar la lectura, aumenta los detalles junto con toda las fechas, nombres, citas y otros elementos.

 Un archivo de código debe ser como un artículo de periódico. El nombre debe ser sencillo pero claro. Por sí mismo, debe bastar para indicarnos si estamos o no en el módulo correcto. Los elementos superiores del archivo deben proporcionar conceptos y algoritmos de nivel superior. Los detalles deben aumentar según avanzamos, hasta que en la parte final encontremos las funciones de nivel inferior del archivo.

 Un periódico se compone de varios artículos, algunos muy reducidos y otros de gran tamaño. No hay muchos que ocupen toda la página con texto, para que el periódico sea manejable. Si el periódico fuera un único y extenso texto con una aglomeración desorganizada de hechos, fechas y nombres, no lo leerìamos.”

 Apertura Vertical entre Conceptos: Por lo general colocamos una línea tras otra, las cuales  representan un concepto, estos conceptos se deben separar mediante líneas en blanco.

 package cedaniel200.com.ejemplo;

public class Ejemplo {

        private static final String AUTOR = “cedaniel200”;
        private String mensaje;

         public void setMensaje(String mensaje){
                 this.mensaje = mensaje;
        }

        public void imprimirMensaje(){
                System.out.println(AUTOR + ”: ” + this.mensaje);
        }

 }

 Distancia Vertical: Lo conceptos relacionados deben estar juntos verticalmente, es decir, uno seguido del otro.

 Declaración de Variables: Se aconseja declararlas cerca a su uso, así, las variables locales se debe declara al comienzo de cada método, las variables de control de bucles se deben declarar dentro de este, como hay excepciones, por ejemplo cuando la declaración es muy larga, esta se debe hacer en la parte superior de un bloque o antes del bucle.

Variables de Instancia: Deben declararse en la parte superior de cada clase.

 Funciones Dependientes: Si una función llama a otra estas deben estar lo más cerca posible, es decir, la función que invoca debe ir primero seguida de la función invocada.

 Afinidad Conceptual: Este punto se refiere a ubicar lo más próximo posible los conceptos similares, por ejemplo, existe una clase que tiene varias funciones que no se invocan entre sí, pero varias funciones realizan operaciones similares, estas deben estar próximas la una de la otra, es decir, una seguida de la otra.

 Formato Horizontal: trata de la cantidad de caracteres que debe tener una línea, el autor recomienda 120 caracteres como límite. Lo que sí es cierto es que tener que utilizar el scroll horizontal para ver toda la línea es algo molesto y que dificulta la legibilidad, entonces mi recomendación es que el tamaño de la línea no exceda al de la pantalla ocasionando la necesidad de utilizar es scroll horizontal.

 Apertura y Densidad Horizontal: Trata de la utilización de los espacios en blanco horizontales para destacar las partes que componen una línea, por ejemplo en una asignación se utiliza para acentuar la separación de sus dos partes:
 int numeroMaximoAlumnos  =  12;

 también se utiliza para separar argumentos en un método:

public void imprimirMensaje(String autor,  String mensaje){
        // implementación del método

 Separar los argumentos al invocar un método:

 imprimirMensaje(“cedaniel200”, “Hola Mundo”);

 También se utilizan los espacios para acentuar precedencia de los operadores:

  int resultado = c*c - 5*c + 3*c*b;

 Sangrado: Se debe sangrar cada línea dependiendo de su nivel, un sangrado por cada nivel desde el segundo, por ejemplo:

public class Persona { // Primer nivel por lo tanto no se sangra

        private String nombre; // Segundo nivel por eso tiene un sangrado
        public void setNombre(String nombre){
                this.nombre = nombre; // Tercer nivel por eso tiene dos sangrados
        } 
}

Nota: Para más artículos relacionados ver Clean Code.

lunes, 12 de diciembre de 2016

Clean Code Capítulo 4 Comentarios


No se debería tener la necesidad de escribir algún comentario a excepción de unos pocos casos, si se sigue y aplica lo visto en los artículos anteriores de Clean Code; me refiero a ponerle nombres con sentido a las entidades del software y a sus variables, a escribir funciones cortas que hagan una sola cosa y que la secuencia de llamados en la funciones vayan contando la historia, contando qué hace el software.

Como mencioné al comienzo del artículo, hay unas cuantas excepciones en las que el autor de Clean Code nos dice que nos podemos tomar el tiempo para escribir un comentario. ¿A que se refiere con tomarnos el tiempo?, se refiere a que cuando se escribe un comentario se debe hacer consciente de lo que queremos plasmar y hacerlo de  una forma que aporta información (comentario de calidad), ya que, muchas veces no nos tomamos el tiempo necesario y nuestros comentarios terminan convirtiéndose en desinformación que hace menos legible el código; un claro ejemplo es dejar código comentado, este código es obsoleto y los programadores que lo vean muy rara vez lo borran creyendo que hay algo importante en ellos, de esta forma perduran en el tiempo. Veamos cuáles son los casos en que debemos tomarnos el tiempo para escribir un comentario:

  • Comentarios Legales, cabe aclarar que en lo posible se debe hacer referencia a una licencia estándar o a un documento externo y no poner todos los términos y condiciones en el comentario.
  • Comentarios Informativos, solo cuando sea necesario, en los otros casos tratar de utilizar nombres con sentido.
  • Explicar la Intención, pueden ayudar a entender porque un programador tomó una determinada decisión al escribir una línea o bloque de código.
  • Clarificación, estos comentarios suelen utilizarse cuando se implementa alguna API estándar que no puede ser modificada.
  • Advertir las consecuencias, en ocasiones determinado código debe escribirse estrictamente de una manera o hacer uso de algún componente, en estos casos es útil advertir la consecuencia si se modifica o cambia el código.
  • Comentario TODO, estos comentarios hacen referencia a una tarea que el programador piensa que se debe hacer pero que no realizó, como por ejemplo, una implementación por hacer, un recordatorio para agregar o eliminar alguna función.
  • Amplificación, estos comentarios buscan ampliar la importancia de un determinado fragmento de código con el fin de que no pase como irrelevante.
  • Javadoc en API públicas, sólo cuando el API es pública se debe describir, pero se debe hacer con calidad, por esto quiero citar un consejo dado por el autor de Clean Code “los javadoc pueden ser tan ambiguos, amplios y descorteses como cualquier otro tipo de documento”.

Recuerden que antes de colocar un comentario nos debemos asegurar si no hay una mejor forma de escribir el código para evitar el comentario, por tanto quiero terminar con la frase con que comienza el capítulo de comentarios en el libro Clean Code.

 “No comente el código incorrecto, reescríbalo
Brian W. Kernighan y P.J. Plaugher

Nota: Para más artículos relacionados ver Clean Code.

lunes, 5 de diciembre de 2016

Principios SOLID


SOLID, es un acrónimo introducido por Robert C. Martin (autor de libro Clean Code y coautor del manifiesto Ágil), este acrónimo representa 5 principios claves en la programación Orientada a Objetos (POO). Veamos el acrónimo y a qué principios se refiere:

Single responsibility (Principio de Responsabilidad Única)
Open-Closed (Principio de Abierto/Cerrado)
Liskov substitution (Principio de Sustitución de Liskov)
Interface segregation (Principio de Segregación de la Interfaz)
Dependency inversion (Principio de Inversión de Dependencia)

Lo ideal es que conozcas y  utilices cada uno de estos principios a la hora de desarrollar software, debido a que nos ayudan a que nuestro diseño sea bueno, limpio y claro, obteniendo así aplicaciones fáciles de mantener y escalar, pues nos ayuda a lograr uno de los objetivos relevantes de la POO, el cual consiste en tener una alta cohesión (la clase debe enfocarse en hacer una sola cosa del sistema) y un bajo acoplamiento (la clase debe tener la menor cantidad de dependencias posibles).

Los principios SOLID en combinación con Clean Code te permitirán obtener aplicaciones fáciles de leer y comprender lo que ayuda a un más al momento de mantener, escalar y conseguir alta cohesión y un bajo acoplamiento; en pocas palabras, se complementan y se potencian mutuamente.

sábado, 3 de diciembre de 2016

Clean Code Capítulo 3 Funciones


Al crear software debemos proporcionar mecanismos para llevar a cabo diferentes acciones, por esto aparecen las Funciones. En Clean Code, se hace énfasis en lo importante que es crear cada función para hacer una cosa, que vayan contando una historia y que cada una lleve a la siguiente. Si observamos secciones en funciones (por ejemplo declaraciones, inicializaciones y filtros), es una clara señal que la función hace más de una cosa, otro caso es cuando una función hace lo que dice que hace en su nombre, pero hace algo extra (se está incumpliendo la regla de hacer una cosa) generando un efecto secundario inesperado, siempre recordemos que las funciones son sin efecto secundarios, por lo tanto, si es necesario, se debe pensar en refactorizar. Una función debe responder a algo o hacer algo, pero no las dos cosas, de ahí que surge lseparación de consultas de comando, el autor lo expresa de la siguiente manera "Su función debe cambiar el estado de un objeto o devolver información sobre el mismo, pero ambas operaciones causan confusión".

Al darles nombre no olvidemos el capítulo nombres con consentido, por esto se debe usar nombre descriptivos, que revelen la verdadera intención o acción de la función, una recomendación es utilizar verbos y palabras claves como por ejemplo writeField(name). write (Verbo), Field (Palabra Clave).

Cada función debe ser de tamaño reducido, ¿Cuántas líneas? no sabría decirte con exactitud, pero si nos basamos en el libro, este nos recomienda que tengan una longitud aproximada de 20 líneas, en estas líneas hay que prestar mucha atención a los bloques y sangrados. Cuando hablo de bloques hago referencia a fragmentos de códigos dentro de if, else, for y similares, en este caso la recomendación es que su longitud sea de una sola línea (lo más probable es que se invoque a otra función); en cuanto al nivel de sangrado no debe ser mayor a dos, ayudando a que haya un nivel de abstracción por función haciendo más fácil de comprenderla, con lo anterior se puede leer el código de arriba a abajo (la regla descendente). Esta regla consiste en posicionar las funciones por nivel de abstracción, como lo explican en Clean Code "Queremos que tras todas las funciones aparezcan las del siguiente nivel de abstracción para poder leer el programa, descendiendo un nivel de abstracción por vez mientras leemos la lista de funciones".

Otra parte clave en las funciones son sus argumentos, cuyo número ideal es cero, posteriormente uno (mónadico) y dos (diádico); se debe evitar las funciones de tres argumentos (triádico), las de más de tres argumentos (poliádico) deben tener una motivo especial. Las formas monádicas habituales son tanto para preguntar sobre el argumento o para transformar el argumento en otra cosa, un caso poco habitual es para eventos, en este caso las funciones por lo general no devuelven nada. En este punto el autor desaconseja utilizar argumentos de indicador (Pasar un booleano a una función) ya que de una forma u otra está indicando que la función hace más de una cosa. Para las funciones diádicas se debe propender que los argumentos sigan y tengan un orden natural, cuando estos carecen de dicho orden debe el programador utilizar los mecanismos necesarios para evitarlas. Cuando una función requiere dos o más argumentos se suele utilizar Objetos Como argumentos, pero esto no es una trampa, pues suele suceder que las variables antes pasadas como argumentos pertenezcan a un concepto más grande. Los nombres de los argumentos deben ser claros y acordes al contexto.

Algunas funciones tienen argumentos de salida, es decir, ver argumentos que en vez de ser entrada son salidas, estos argumentos deben evitarse.

El manejo de errores en una función en muchos casos se hace por medio de códigos de error, que suelen estar en una clase o varias lo que va creando alto acoplamiento y cuando surge un nuevo tipo de error, es donde viene los dolores de cabeza, por esto es mejor emplear excepciones que devolver código de error. Al utilizar excepciones es inevitable utilizar Try/Catch esto empieza a generar estructuras anidadas por eso es una buena práctica extraer bloques Try/Catch, esto quiere decir que se debe crear una función donde se procesa el error (dónde está la estructura Try/Catch, el procesamiento de errores es una cosa), desde esta se invocará la función que realizará la acción.

Antes de terminar quiero mencionar las instrucciones Switch, donde el autor hace una mención específica diciendo "Mi regla general para las instrucciones Switch es que se pueden tolerar si solo aparecen una vez, se usan para crear objetos polimórficos y se ocultan tras una relación de herencia para que el resto del sistema no las pueda ver. Evidentemente, cada caso es diferente y en ocasiones se puede incumplir una o varias partes de esta regla".

Las funciones nos ayudan a realizar acciones concretas, es nuestro deber evitar el no repetir código, por eso se deben crear con la mayor responsabilidad y dedicación y sin miedo a reescribir cuantas veces se crea necesario hasta que el resultado satisfaga las necesidades.

Nota: Para más artículos relacionados ver Clean Code.

lunes, 28 de noviembre de 2016

Clean Code Capítulo 2 Nombres con Sentido (2/2)



Continuando con la segunda parte del capítulo 2, vamos a seguir viendo aquellas reglas para crear nombres correctos. Si aún no has visto la primera parte te invito para que la veas.

Nombres de clases: Los nombre de clases no deben ser verbos. Los nombres deben proporcionar de manera clara el propósito de la clase, por lo general debe ser un sustantivo, evitando nombres genéricos. Algunos ejemplos de nombres correctos serían: Persona, Direccion, Cliente. Algunos nombres incorrectos de clases podrían ser: Info, Procesador, CalcularNomina.

Nombre de métodos: Debe ser un verbo como por ejemplo, eliminar, agregar, guardar. Los métodos de acceso, modificación deben tener como nombre su valor y usar como prefijo get, set e is. Como recomendación el autor dice, que “Al sobrecargar constructores use métodos de factoría estáticos con nombres que describan los argumentos

No se exceda con el atractivo: Esta regla hace referencia a no utilizar nombres provenientes de formas coloquiales de decir las cosas o de jergas, dejando a un lado la claridad, ya que, si llega un nuevo programador que no conozca estas formas de decir las cosas, se llenará de desinformación. 

Un nombre por concepto: Es simple, cuando nos decidimos por una palabra para representar un concepto, esta debe ser constante por todo el código y no utilizarse en unos lados y en otros no. Por ejemplo, no es conveniente utilizar en algunos nombres de métodos la palabra get y en otros retrieve. 

No haga juego de palabras: Se refiere a no utilizar una palabra con dos fines distintos, por ejemplo, digamos que en nuestro código hemos venido utilizando la palabra remove para nombrar métodos que inactivan, y en algún momento somos tentados a utilizar remove para hacer referencia a un método que elimina, en este caso sería mejor utilizar el nombre delete para el método en cuestión.

Usar nombres de dominio de soluciones: No es necesario que todos los nombres utilizados sean extraídos del dominio del problema, ya que, los lectores del código son programadores y ellos conocen o están familiarizados con términos informáticos, de patrones, y demás. Por ejemplo para un programador va a tener mucho sentido si una clase tiene el nombre de ListAdapter.

Usar nombre de dominios de problema: Cuando no se pueda cumplir la regla anterior porque no existe un término en el ámbito de programación, se debe recurrir a un nombre del dominio del problema. El autor nos dice “Separar los conceptos de dominio de soluciones y de problemas es parte del trabajo de un buen programador y diseñador”.

Añadir contexto con sentido: Cuando los nombres no tiene sentido por sí mismo, es necesario crearle un contexto que enriquezca dicho nombre, esto puede hacerse convirtiendo variables en parte de un concepto mayor, es decir, extraer una clase de la cual hagan parte o en una función o método que aporte un contexto. Como última instancia usar prefijos.

No añadir contextos innecesarios: Se refiere a no agregar en los nombres más información de la necesaria. Imagine una clase llamada DireccionResidencia y otra DireccionTrabajo, estos nombres no son realmente adecuados para una clase, lo mejor sería una clase Direccion y estos nombres serían ideales para nombre de instancias. Otro caso es agregar prefijo al nombre de las clases.


Como hemos visto en estos dos post acerca de nombres con sentido, el elegir un nombre adecuado para cada parte del código es fundamental, tanto para la legibilidad como para entender qué se hizo o qué se va a hacer. Para dar un nombre adecuado es necesario emplear habilidad descriptiva, gran vocabulario, conocimiento técnico y dejar los miedos, es momento de empezar a buscar mejores nombres, agregar o quitar el exceso de contexto, refactorizar el código, cambiando los nombres que no sean adecuados en el código existente.

Nota: Para más artículos relacionados ver Clean Code

viernes, 25 de noviembre de 2016

Clean Code Capítulo 2 Nombres con Sentido 1/2


A medida que escribimos código es inevitable enfrentarnos a la tarea que aunque parece trivial no lo es, de asignar nombre a una variable, clase, paquete, archivo etc. Cuando digo que no es trivial, quiero hacer énfasis a su importancia y a que al poner un nombre se debe hacer con responsabilidad y profesionalismo (lógica, coherencia y mucho sentido), puesto que estos nombres empezarán a dotar de sentido al código mismo, y de eso nos daremos cuenta al momento que otros programados lo lean o hasta nosotros mismos cuando con el tiempo debamos realizar mantenimiento sobre este. El autor de Clean Code sabe esto, por tal motivo nos proporciona una serie de reglas básicas para crear nombres correctos.

Usar nombre que revelen las intenciones: Cuántas veces hemos encontrado una variable con nombre así: int a; ¿Esto te dice algo?, ¿Sabes para qué sirve la variable a o que significado tiene?, precisamente de eso se trata esta regla, dotar de significado y sentido a través de su nombre, por ello el autor nos dice “El nombre de una variable, función o clase debe responder una serie de cuestiones básicas. Debe indicar por qué existe, qué hace, y cómo se usa”. Veamos un ejemplo tomado de Clean Code.

Incorrecto
public List<int[]> getThem(){
List<int[]> list1 = new ArrayList<int[]>();
for(int[] x : theList)
if(x[0] == 4)
  list1.add(x);
return list1;
}

Correcto
public List<int[]> getFlaggedCells(){
List<int[]> flaggedCells = new ArrayList<int[]>();
for(int[] cell : gameBoard)
if(cell[STATUS_VALUE] == FLAGGED)
  flaggedCells.add(cell);
return flaggedCells;
}

Evitar la desinformación: En ocasiones damos nombre ambiguos o que pueden más que informar, desinformar, ya que, da pistas erróneas de lo que en realidad hace una función, variable o clase. En otras oportunidades tenemos variables casi con el mismo nombre donde solo las diferencia una pocas letras o una pequeña palabra, es decir, nombre con variaciones mínimas. Estos casos nos dificultan la lectura del código, razón por la que debemos mejorar en dicho aspecto. Veamos unos ejemplos.

Incorrecto
Correcto
Explicación
tmp
temperatura
Algunos pensaran que tmp, hace referencia a temporal o tiempo
lugarXCoordenadas
lugarYCoordenadas
coordenadasOrigen
corrdenadasDestino
los nombres tienen forma similar
o
-
Nombrar una variable como o puede hacer que se confunda con el cero, al igual que no brinda ninguna información

Realizar distinciones con sentido: Esta regla va de la mano con la anterior cuando se habla de no tener nombre con variaciones mínimas, debido a que esta regla propone que a dichos nombres se le agregue aparte de una notable variación, sentido, como lo dice el autor “Si los nombres tienen que ser distintos, también deben tener un significado diferente”. Imaginemos que tenemos en una función que recibe dos variables num1, num2, lo primero que notamos es que en sus nombres no tienen una gran diferencia y segundo no da mucha información, ahora, si esta función lo que hace es dividir el primer parámetro (num1) con respecto al segundo (num2), tendría mas sentido llamarlos dividendo y divisor respectivamente.

Usar nombres que se puedan pronunciar: Cuántas veces haciendo mantenimiento al código tienes que dirigirte a un colega para alguna explicación o aclaración, cómo le dirías, o mejor, cómo pronunciarías la variable llamada genymdhms (fecha de generación, año, mes, día, hora, minuto y segundo), ¿no crees que es mejor generationTimestamp? - Ejemplo tomado del libro Clean Code -. Quizás tu colega no te entienda o tenga que ver con sus propios ojos de que le estás hablando, de ahí la importancia de colocar nombres que puedas pronunciar; la programación es una actividad social.

Usar Nombres que se puedan buscar: Aunque es una regla muy lógica, solemos pasar por alto y cuando debemos buscar una variable llamada t, en todo un proyecto o solo en una clase de muchas líneas obtendremos muchos falsos positivos, no sería más fácil buscar una variable llamada TEMPERATURA_MAXIMA_PERMIDA, siendo esta una constante.

Evitar codificaciones: Crear codificaciones para nombre supone una carga extra que debemos aprender y por lo general son difíciles de pronunciar lo que estaría rompiendo la regla de Usar nombres que se puedan pronunciar.

Notación húngara: El autor nos quiere decir que este tipo de notación o codificación en la actualidad no es necesaria y lo que genera son obstáculos que dificultan la lectura del código. Pero, ¿qué es la notación húngara?, es un sistema utilizado para crear los nombres de las variables, este sistema utiliza prefijos para indicar el tipo de dichas variables, por ejemplo, se utiliza el prefijo b para las variables booleanas (bIsCanceled).

Prefijo de miembros: Ya no es necesario utilizar esa práctica que aconsejaba agregar el prefijo m_ a los nombre de variables, los entornos actuales nos permite identificar los miembros ya sea que los resalta o les cambia el color.

Interfaces e implementaciones: Agregar adornos a los nombre de las interfaces (por ejemplo una I inicio del nombre), es agregar más información de lo necesario, y en caso de necesitar implementar dicha interfaz se puede agregar el sufijo Impl, por ejemplo, si tenemos la Interfaz Presenter (note que no la llame IPresenter) su implementación podría llamarse PresenterImpl.

Evitar asignaciones mentales: La asignación mental ocurre cuando el nombre de una variable debe ser traducido mentalmente por quien lee el código para relacionar con algún término del dominio, este problema es habitual con nombres de variables de una sola letra.


Nota: Como el post se está haciendo muy extenso y no quiero cansarte, he decidido tomar aquel consejo de "divide y vencerás". Por tal razón terminaré de contarles acerca del capítulo 2 de Clean Code en el siguiente post (Clean Code Capítulo 2 Nombres con Sentido (2/2)). Para más artículos relacionados ver Clean Code

martes, 22 de noviembre de 2016

Clean Code Capítulo 1 Código Limpio


El capítulo 1 trata brevemente distintos puntos partiendo del código incorrecto, que no es más que código sin sentido, y que lastimosamente es el que más abunda en nuestras aplicaciones. Estamos hablando de código que a simple vista no deja ninguna pista de que hace o para qué sirve y por esa razón perdemos tiempo buscando su significado o buscandole sentido. Lamentablemente, estoy de acuerdo con el autor cuando dice que “Todos hemos sentido alivio de ver cómo un programa incorrecto funcionaba y hemos decidido que un mal programa que funciona es mejor que nada” y hemos postergado su solución (Ley de LeBlanc: Después es igual a nunca). Con el pasar del tiempo vemos como los problemas se van agravando y se reflejan en el costo, principalmente de tiempo (El equipo es menos productivo), pero todos sabemos que el tiempo es oro, por ende, este tiempo que nos cuesta mantener el código incorrecto (ningún cambio es trivial) se convierte en dinero y puede significar hasta la muerte de un proyecto. Por lo anterior, quiero citar al autor cuando dice “ya sabrá que dedicar tiempo a que el código sea correcto no solo es rentable, es una cuestión de supervivencia profesional”. En pocas palabras, nos llenamos de código incorrecto, pero ¿Porque ocurre esto? la respuesta está en el libro cuando declara que la culpa es nuestra, ya que, “No somos Profesionales” y no debemos descargar nuestra responsabilidad en los demás pues “Tampoco sería profesional que los programadores cedieron a la voluntad de los jefes que no entienden los riesgos de un posible desastre”. 


Seguidamente, profundiza en lo que es código limpio o de su concepto, mostrando una serie de definiciones dadas por grandes programadores como Bjarne Stroustrup, inventor de C++. Interiorizando todas estas definiciones, he llegado a la siguiente definición de código limpio:


Código con sentido, concreto, dotado de características como la simplicidad, eficiencia, legibilidad, sencillez, debe estar testeado, tener dependencias mínimas y hacer una cosa bien (este último tomado de la definición de Bjarne Stroustrup)


Por último, habla brevemente de la regla del Boy Scout, que en pocas palabras es entregar el código más limpio de lo que lo hemos recibido.


Este capítulo nos invita a que abramos nuestros ojos para ver la posible falta de profesionalismo que nos invade al momento de crear código y empecemos el cambio para escribir código limpio, buscando así ser profesionales en esta área. ¡Ya diste el primer paso!, que suele ser el más difícil. Sigue caminando.

Nota: Para más artículos relacionados ver Clean Code

lunes, 21 de noviembre de 2016

Clean Code - Código Limpio


El desarrollo de software es algo que me apasiona, particularmente la programación, lo que me ha llevado últimamente a querer dar un paso más hacia la profesionalización en este ámbito. Por tal motivo he empezado a estudiar sobre patrones de arquitectura y de diseño en lo que respecta al software, e indagar sobre el concepto de Código Limpio (Clean Code); por lo anterior inicié leyendo el libro Clean Code de Robert C. Martín, y me he animado a escribir sobre lo que voy conociendo con la lectura del mismo, una serie de artículos acerca de mis impresiones sobre el libro.


Por ahora quiero citar una frase que he visto que relacionan con este libro y es que “Todo programador debe leerlo”, cuando leí por primera vez esta frase fui un poco escéptico, pero al ir devorando cada una de las páginas e ir interiorizando poco a poco sus conceptos me ha convencido, por eso inició invitandote a leer este libro, lleno de pequeños y simples detalles que hacen grandes cambios, apoyado en lo escrito por James O. Coplien en el prólogo “Que dichas acciones sean simples no significan que sean simplistas, y mucho menos que sean sencillas”.  


Manos a la obra, tienes mucho que leer, interiorizar, cambiar y ajustar. El camino es largo pero interesante y muy gratificante en cuanto empiezas a ver los resultados. Muy pronto, a medida que vaya leyendo más sobre este grandioso libro, estaré publicando al respecto y actualizando este post con los enlaces a los respectivos artículos.

Artículos Relacionados

Te dejo acá una referencia en donde puedes comprar la versión en español o lo puedes mirar acá en Amazon.

Instalación NodeJS

Ingresamos a la página oficial de NodeJS donde lo descargaremos  https://nodejs.org/en/download/ Escogemos el instalador que se ajuste a ...