Mostrando las entradas con la etiqueta Arquitectura. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Arquitectura. Mostrar todas las entradas

viernes, 8 de abril de 2016

76. Zen de Python

La base de python es la filosofía que favorezca el código legible, y bueno ella en realidad es un gran aporte para todos los desarrollos, no solo los desarrollos de python, es algo que deberíamos hacer nuestra ya que mucho de lo que dice ahí nos ayuda en nuestro trabajo.

Piénsenla, háganla suya, conviertanla en un himno, el hacer cosas complejas no nos hace mejores, simplemente aumenta la posibilidad de cometer errores.

La mejor arquitectura siempre es la mas sencilla por que todo mundo la comprende, la puede manejar, la puede desarrollar y trabajar con ella.

Tim Peters es el desarrollador al que le debemos esta reflexión

Bello es mejor que feo.
Explícito es mejor que implícito.
Simple es mejor que complejo.
Complejo es mejor que complicado.
Plano es mejor que anidado.
Disperso es mejor que denso.
La legibilidad cuenta.
Los casos especiales no son tan especiales como para quebrantar las reglas.
Lo práctico gana a lo puro.
Los errores nunca deberían dejarse pasar silenciosamente.
A menos que hayan sido silenciados explícitamente.
Frente a la ambigüedad, rechaza la tentación de adivinar.
Debería haber una -y preferiblemente sólo una- manera obvia de hacerlo.
Aunque esa manera puede no ser obvia al principio a menos que usted sea holandés.15
Ahora es mejor que nunca.
Aunque nunca es a menudo mejor que ya mismo.
Si la implementación es difícil de explicar, es una mala idea.
Si la implementación es fácil de explicar, puede que sea una buena idea.
Los espacios de nombres (namespaces) son una gran idea ¡Hagamos más de esas cosas!

Felices Lineas

miércoles, 13 de enero de 2016

43. Deuda técnica

El proceso de desarrollo de software, es un proceso complejo, artesanal, en el que las decisiones de los involucrados a diferentes niveles pueden llevarnos al éxito o al fracaso.

La deuda técnica es un concepto que lleva a trabajar más por malas decisiones, en otras palabras por hacer mal las cosas.

Cuando el tiempo supera la calidad y por cumplir plazos se eliminan funcionalidades del producto, se omiten procesos, se permite que el producto llegue con bugs conocidos, se adquiere esa deuda técnica, deuda que en la mayoría de los casos se paga con grandes intereses.

Por qué digo esto, la deuda técnica generara problemas de re-trabajo, falta de confianza por parte del cliente, inestabilidad, bajas expectativas, no entregas a tiempo después de las primeras versiones, inestabilidad de los sistemas.

El costo puede ir desde crear nuevamente algunas partes de un sistema a recrearlo completamente cuando esta ya no es sostenible.

Demasiadas cosas que no se encuentran bien hechas hacen que pequeños cambios requieran demasiado tiempo para su ejecución, un sistema inestable puede requerir procesos de prueba muy complejos que nos hace perder nuestra ventaja competitiva.

La deuda técnica por lo regular son componentes faltantes o no desarrollados de la manera adecuada en un proyecto, bug conocidos no solucionados.

Un sistema inestable hace que el prestigio de una empresa se pierda, crea desconfianza con el consumidor y con el cliente, traslademos esto al mundo actual, principalmente a una aplicación móvil, en donde el consumidor en cuanto encuentra una falla la abandona, la deuda técnica es un riesgo muy elevado para el éxito de un producto.

Lo barato sale caro es una frase que aplica con la deuda técnica, el querer ahorrar recursos (tiempo, calidad) y tomarlos para deuda técnica, hace que los desarrollos incrementen su grado de complejidad en el momento del mantenimiento.

Una analogía de la deuda técnica, es un globo, cada vez que asumimos que algo se convierta en deuda técnica, inflamos este globo, en un principio, el globo hasta se ve lindo, pequeño, controlable, pero conforme este va creciendo y ocupando más espacio, este explota, y es cuando la deuda técnica nos ha superado.

Y que pasa cuando se asume la deuda técnica, independientemente de todos los controles que se tengan, en muchos casos los equipos de desarrollo terminan asumiendo deuda técnica, deuda que en muchos casos se ve controlable, lo que debemos hacer es gestionarla, documentarla, y pagarla, nunca dejar que se acumule, los equipos de desarrollo deben estar conscientes de su existencia y tomar medidas para controlarla, reducirla y erradicarla

La deuda técnica es un gran riesgo, que debemos evitar a toda costa.


Hasta la próxima

viernes, 18 de diciembre de 2015

36. Patrones de Diseño (IV) - Proxy

Este blog inicio con la idea de construir un código ordenado, de hacer que nuestro código tuviera una mayor calidad, y hacer que el mantenimiento del mismo fuera menos costoso, nació porque hay muchas habilidades que debe tener un arquitecto antes de poder modelar una arquitectura de un sistema.

La sección de patrones de diseño se creó para brindar herramientas para evitar ese código salvaje, la sección sigue vigente, pero el blog ha crecido y junto con él se han incorporado nuevas secciones.

Pero hoy retomaremos los patrones de diseño, vamos a hablar de un patrón, que es muy sencillo porque su uso es muy común, tan común que mucha gente que no es desarrolladora, entiende el concepto o lo han usado principalmente para conectarse a internet, me refiero al patrón Proxy.

¿Qué hace el patrón proxy?, El patrón proxy juega como un intermediario que permite la creación y acceso de un objeto a otros, es decir me sirve como un puente entre objetos, su aplicación más común es el uso de proxies en internet, para acceder a paginas o para limitar el tráfico a las mismas.


Tratemos de ilustrar el patrón:


Contamos con una interfaz en la que se definen las tareas que se realizaran, esta interfaz se encuentra implementada tanto en el Proxy como en el objeto real.

El cliente consumirá la interfaz, de esta forma el Proxy se podrá agregar como intermediario sin necesidad de efectuar modificaciones en nuestro cliente.

Cuando el cliente efectué una llamada, nuestro cliente primero ira al proxy, en donde se puede agregar funcionalidad, después de eso el proceso se ira al objeto real.

Existen muchos tipos de proxy, entre los más comunes se puede mencionar:

Proxies Virtuales: Manejan la creación de objetos, en muchos casos hay objetos que requieren un tiempo muy elevado para su creación, este tipo de proxies pueden asumir la identidad del objeto como si ya estuviera creado, en lo que el verdadero objeto se genera.

Como es esto, el proxie invoca un objeto, el proxie en este caso es un objeto ligero pero que ya tiene las características del mismo, mientras el proxie crea el verdadero objeto, el proxie actúa como el objeto que se está creando, mostrando propiedades de manera preliminar.

Imaginen una clase de dibujo compleja con la que ya se puede interactuar, pero que varios de sus componentes se muestran con barras de carga, el proxy la clase compleja, que está construyendo los objetos que están en él.

Y como se crea, se construyen los métodos para tener las firmas, pero los datos se cargan conforme se está usando el objeto, estos datos se cargan en un segundo objeto, el objeto real.

Proxies de Autenticación: Muy comunes, su labor es establecer los permisos de acceso a un objeto.


El proxie tiene las mismas firmas que el objeto que se desea controlar, sin embargo analiza el acceso al mismo objeto, y si este no cumple con cierta característica no permite el acceso al mismo.


Proxie remoto: permite enviar información a través de la red comportándose como un objeto local, cuando se implementa el proxy efectúa las tareas de comunicación.

Proxie Inteligente: Puede efectuar cambios en el mensaje con condiciones específicas, por ejemplo una codificación, agregar atributos etc.

Como pueden ver es un objeto muy sencillo porque su función es solo servir de intermediario de mensajes pero que es muy útil en aplicaciones en el mundo real.


Hasta la próxima


jueves, 10 de diciembre de 2015

35. Buen Software

Mucho se ha hablado de 4 grandes características que debe tener todo software:

·         Mantenibilidad
·         Confiabilidad
·         Eficiencia
·         Usabilidad

Son características que todo arquitecto debe tener en mente al momento de diseñar una solución, vamos a repasarlas un poco.

Ya habíamos hablado de usabilidad en usabilidad estableciendo los 10 principios que menciona Jakob Nielsen

·         Visibilidad del estado del sistema
·         Relación entre el sistema y el mundo real
·         Control y libertad del usuario
·         Consistencia y estándares
·         Prevención de errores
·         Reconocimiento antes que recuerdo
·         Flexibilidad y eficiencia de uso
·         Estética y diseño minimalista
·         Ayuda a los usuarios a reconocer
·         Ayuda y documentación

Mantenernos dentro de estos nos da un gran paso, confianza al usuario, el sistema se convierte en algo que él entiende y que facilitara su trabajo, que es nuestra principal misión.

Eficiencia: Este es otro tema que hemos tocado en este blog, http://carlosamonroy.blogspot.mx/2015/06/mi-codigo-puede-volar.html , que quiere decir usar correctamente los recursos del sistema, hacer consultas rápida, administrar correctamente la memoria, optimizar código, en la actualidad hemos perdido mucho esa capacidad de optimización debido a que al tener hardware cada vez más robusto, dejamos mucho de este trabajo al hardware, desperdiciando una gran cantidad de recursos, el no optimizar nuestro software para lograr la máxima eficiencia, cobra su factura cuando este crece, cuando este sale de un ambiente controlado y empieza a consumir recursos que son por mucho superiores a los que esperamos.

No debemos depender del hardware, debemos buscar siempre hacer las cosas de una manera eficiente, en muchos casos esto ocurre al depender de muchos componentes de terceros, o de componentes que mejoran la interfaz gráfica, estos componentes llegan a ser muy pesados, componentes que en una primera impresión son buenos, peor que causan una gran molestia al enfrentarse a problemas reales.

Confiabilidad: característica de oro, el software debe ser confiable, esto se traduce en que debe hacer correctamente su trabajo todo el tiempo, que debe tener buenas prácticas de seguridad, la información es un bien y es uno de los bienes más valiosos, si el software no es confiable, puede causar resultados que van más allá de una falla en el sistema, un quiebra de una empresa, la muerte de 28 soldados que fue consecuencia de un error en un misil Patriot http://sydney.edu.au/engineering/it/~alum/patriot_bug.html

Mantenibilidad: Todo evoluciona, es necesario adaptarnos al cambio, el software debe nacer para que este pueda evolucionar fácilmente, vivimos en una industria que se mueve a una gran velocidad, los cambios se dan de un día a otro, el tener o no una ventaja competitiva depende de tomar las oportunidades cuando estas aparezcan, que la evolución del software se pueda dar, de una manera en que se puedan satisfacer rápidamente las necesidades del usuario


Hasta la próxima

lunes, 7 de diciembre de 2015

32. Build 2016

La tecnología avanza día a día, y es muy importante conocer los nuevos retos y conocer las nuevas herramientas que tenemos para poderla usar a nuestro beneficio.

Microsoft anuncia el día de hoy la fecha del Build 2016, el máximo evento de esa empresa para los desarrolladores.

El evento sea en San Francisco del 30 de Marzo al 1 de Abril, no importa que no puedan asistir en forma presencial, este evento se trasmite en tiempo real por diversos canales, les dejo la pagina de dicho evento.


Felices lineas

jueves, 3 de diciembre de 2015

30. Usabilidad

Como técnicos perdemos rápidamente la vista del usuario, a veces pensamos que el sistema debe tener un comportamiento y que el usuario se debe adaptar al sistema.

No debemos perder algo de vista que es muy importante en nuestro trabajo, nos debemos al usuario, somos por el usuario, nuestra principal función es hacer que cualquier actividad sea más rápida y sencilla.

Sea análisis de información, sea automatizar un proceso, o una acceso a una base de datos, todas estas tareas siempre deben ser más fáciles de hacer para el usuario que lo que eran antes de que el sistema se implemente.

Debemos hablar su idioma, acercarnos a él para saber que quiere que busca y darle algo de acuerdo a sus necesidades.

Un error muy común es implementar algo, porque sabemos que es bueno o porque lo conocemos y olvidarnos del como el usuario hace sus actividades en el día a día, muchos de los sistemas impuestos, se convierten en un fracaso, porque la imposición genera resistencia.

Si yo obligo a alguien a hacer algo así este sea el mejor sistema lo va a rechazar de manera automática, lo mejor es buscar que la aceptación sede de manera natural.

Me preguntaran ¿Y cómo logro esto? Hay varias formas, la mejor es observar al usuario para determinar sus necesidades, si yo le pregunto al usuario ¿Qué necesitas? Muchas veces no lo sabe, y ¿Por qué no lo sabe? Porque con los medios con los que dispone en la actualidad ya están cubiertas sus necesidades, puede pedir más cosas, pero siempre es mejor involucrarse con las actividades para detectar los puntos de mejora, y buscar que estos se acepten de manera natural.

¿Pero cómo logro que el usuario se sienta cómodo con mi sistema? Jakob Nielsen es uno de los grandes gurús de la usabilidad, él ha establecido 10 principios que deberíamos considerar en todo sistema, estos principios ayudan a que el usuario se sienta cómodo y seguro dentro del sistema, sus principios son:

1.       Visibilidad del estado del sistema: en este punto normalmente fallamos, olvidamos informar que ocurre en el sistema y dejamos que este opere por sí solo, si bien esto es eficiente, hace que el usuario se desespere, no sabe que está pasando, peor aún puede pensar que está generando errores, que se trabo, el no informar el estado del sistema trae como consecuencia frustración, y como consecuencia nuestro sistema no será exitoso.

2.       Relación entre el sistema y el mundo real: Es muy importante tener el mismo vocabulario, que el sistema hable el vocabulario del usuario en sus términos y conceptos, que todo esté acorde a lo que el usuario conozca, y que el sistema no se convierta en tener un ente que requiera un traductor para su operación.

3.       Control y libertad del usuario: Funciones de deshacer y rehacer, que pasa si el usuario entro a una función a la que no quería por error, su proceso para salir de ella debe ser sencillo, no debería perderse en un mundo de menús, para deshacer un error.

4.       Consistencia y estándares: ¿Cuáles son los estándares del usuario? El debería entender el sistema por que el sistema habla su idioma.

5.       Prevención de errores: Un error común prevenir errores es enviar mensajes de error, esto no es la prevención de errores, un mensaje de error debe ser nuestra última opción, en muchos casos los sistema envían mensajes de error cuando ya no se puede hacer nada, y el proceso para recuperarse de ellos es largo y costoso, los sistemas deben tener un control de errores, para evitarlos, que no sea enviar un mensaje de error.

6.       Reconocimiento antes que recuerdo: El usuario no debe saberse los procesos de memoria, si se depende de la memoria para que estos se ejecuten en un orden correcto, es probable que se induzca error por parte de la misma operación del sistema, el usuario debería reconocer los pasos y actividades a realizar, y estos deben ser accesibles para el usuario todo el tiempo.

7.       Flexibilidad y eficiencia de uso: Hay varios tipos de usuarios, avanzados y básicos se debe brindar al usuario avanzado aceleradores y métodos para que este pueda mejorar la eficiencia de su trabajo, por dar un ejemplo de esto tenemos las combinaciones de teclas.

8.       Estética y diseño minimalista: Cada unidad extra de información irrelevante compite con la información relevante, se debe brindar únicamente la información importante, para que el usuario pueda interpretarla y entenderla.

9.       Ayuda a los usuarios a reconocer: Otro punto muy importante, que en la mayoría de los sistemas no se hace, cuando ocurre un error este se debe presentar en un lenguaje claro y simple, que indique el problema en forma precisa y ayude a construir su solución. El mensaje muy típico en los sistemas “Error fatal, consulte a su administrador del sistema” no es un error que cumpla con estas características, y menos cuando dicho error le da al administrador del sistema.

10.   Ayuda y documentación: Mas vale la más pálida tinta que la más brillante memoria, hoy conocemos el sistema pero que tan en 5 años cuando lo volvemos a ver, lo que para unos es lógico para otros no lo será, debemos dejar de pensar que un sistema se puede emplear con sentido común, dicen que el sentido común es el menos común de todos los sentidos, por esto hay que documentar, crear ayudas ¿Cómo trabaja?, ¿Cuáles son las reglas de negocio?  ¿Cómo se configura?, si soy un nuevo usuario ¿Cómo voy a usar el sistema?, cometemos un error muy grave aquí los desarrolladores, decimos es que el usuario no lee, si no lee los manuales para que los hago, no es lo mismo el que no los lea, pero que en caso de una duda pueda recurrir a ellos, a que en caso de una duda no exista nada a donde recurrir.

Bueno me despido por hoy, felices líneas


Carlos

viernes, 25 de septiembre de 2015

20. Métricas (Indice de Mantenibilidad)

Tengo varios temas que retomar con ustedes, temas que he dejado en este blog, pero que continuare escribiendo sobre estos, principalmente los patrones de diseño y el análisis de queries, ambos parte fundamental en el proceso de desarrollo.

Como he comentado en otros Post, Visual Studio, nos proporciona herramientas para poder medir el código, para darle una valoración al mismo, esto es importante ya que el código debe ser sencillo de entender por más de un desarrollador, es decir debe poder dársele mantenimiento de una manera sencilla.
Mientras más especializados son los componentes son más fáciles de controlar, estos se convierten en piezas esenciales de algo más grande.


Hoy vamos a hablar de la última métrica, que se encuentra en Visual Studio, el índice de mantenimiento, ¿Por qué la deje al último? Porque esta es la más sencilla, su nombre nos dice por si sola que es, esta nos dice que tan fácil es modificar  nuestro código, y mejor aún, nos lo indica con una bandera que va de rojo a verde.


Mientras el valor se encuentre más cercano al 100 es mejor, pero entonces me dirá, un índice de mantenimiento de 59 es bueno, la respuesta es sí, para el caso de .NET, como lo veremos a continuación.

Se puede decir que es un resumen de las otras métricas, el índice de mantenimiento  es una métrica creada allá por 1992 por Pau Oman y Jack Hagermeister, esta métrica agrupa varias otras como son el Volumen de Halstead (HV) esta es la única métrica que no hemos tocado en esta serie de post esta se define como el número de operaciones por el logaritmo base dos de operaciones distintas (N log2 n) , la complejidad ciclomatica (CC), las líneas de código (LOC) y la cantidad de comentarios.

Con estos valores se propuso una fórmula que nos da que tan mantenible es el código, la formula propuesta fue:

171-25ln(HV) – 0.23CC – 16.2ln(LOC) + 50.0Sin sqr(2.46*COM)

El paper original se encuentra en esta liga: ColemanPaper.pdf

Visual Studio no implementa en su totalidad esta fórmula, Visual Studio implementa una versión reducida de la misma, esta es:

Indice de Mantenibilidad = MAX(0,171-5.2 * ln(HV) – 0.23(CC) – 16.2*ln(LOC) * 100/171

Como se puede ver el equipo de Visual Studio elimino la parte que corresponde a los comentarios en el código.

Microsoft toma en cuenta estos rangos para limitar la mantenibilidad del código
El índice de mantenimiento cambia a amarillo entre 10 y 19 y a rojo ente 0 y 9, pero que es realmente el índice de mantenimiento.

0 – 9 Índice pobre
10 – 19 Índice Moderado
20 – 100 Índice Alto

Codificar no es solo colocar una instrucción tras otra, es necesario que seamos constructores de código de calidad, para reducir el esfuerzo de construcción, mejorar la calidad, disminuir los errores, mejorar el rendimiento, y lo más importante reducir el stress que se genera por códigos con problemas, que al final repercuten en la salud del desarrollador

Felices líneas

19. Métricas (Numero de lineas)

Número de líneas, esta es una de las métricas clásicas, incluso durante mucho tiempo se medían los programas por la cantidad de líneas de código que hubiera en ellos.

¿Pero que tan útil es?

Cuando hablamos de un desarrollo una operación puede ser por pocas o por muchas líneas de código dependiendo del desarrollador, por lo que una complejidad real de la solución no nos la puede dar.
Medir el trabajo en líneas de código no es una buena idea.

Sin embargo si nos ayuda en algo, nos ayuda a ver que métodos y funciones poseen gran tamaño, cuando un método es de un tamaño elevado, este se vuelve muy complejo, empieza a tener una responsabilidad muy alta, como consecuencia es más difícil de manipular.

Tradicionalmente se ha dicho que un método debe ocupar únicamente el espacio de la pantalla del equipo para ser correcto, esta observación no es del todo correcta, un método debe ser un ente altamente especializado, encargado de una actividad, esto muchas veces se puede lograr con muchas o con pocas líneas de código, el hecho de que un método tenga muchas líneas de código no necesariamente dice que está mal, o el hecho de tener muchos métodos muy pequeños con muy pocas líneas nos dice que es lo mejor. Hay que analizar cada caso, ver en que las operaciones se encuentren agrupadas, si bien divide y vencerás debe ser nuestra política, una división muy alta puede provocar que la complejidad se incremente.

Un método puede tener muchas líneas de código (no es lo deseable) pero si esto es justificado, es correcto.



Felices lineas

jueves, 24 de septiembre de 2015

18. Métricas (profundidad de herencia)

Continuemos con las métricas que nos proporciona Visual Studio, la siguiente métrica, es útil porque nos ayuda a saber que tan complejo es un código.


Pero antes necesitamos un poco de teoría básica, para determinar que es la herencia, bueno la herencia es una de las principales características de la programación Orientada a Objetos, la herencia nos permita que un objeto sea creado a partir de otro, de esta forma el nuevo objeto toma los métodos y atributos que tenía el original.

Esto nos permite agregar funcionalidad sin reescribir todo el código, por lo que la reutilización del mismo es muy alta.

Bueno que nos indica la métrica de profundidad de la herencia nos indicia que tan grande es este árbol de herencia hasta llegar a la clase base.

¿Por qué nos afecta esto?, si bien el código se puede reutilizar, manejar clases con herencia de la herencia como se diría coloquialmente, hace que los flujos se vuelvan complejos, para seguir un flujo se deben hacer muchos saltos entre las clases ¿Quién la heredo? ¿Quién la modifico la primera vez? ¿Quién lo hizo la segunda vez? Y así sucesivamente.

El resultado el código se torna complejo, y entre mayor sea este número el código se vuelve más difícil de entender.

Manejar este número en valores menores 4 es lo mejor siempre.

Sin embrago no hay que asustarse si este número es alto, muchas características de código autogenerado de Visual Studio, nacen con este número en valores mayores a 4, así que analicen en que caso es su código y en qué caso es Visual Studio el que genero este número.

Y como la obtengo, siguiendo el mismo procedimiento que hemos discutido en artículos anteriores.


Las métricas son útiles porque nos ayudan a tener un mejor código, hasta la próxima.

Saludos

miércoles, 23 de septiembre de 2015

17. ¿Qué nos hace programadores?

Hay características muy especiales que todo programador debe tener, que si bien no son indispensables nos ayudan día a día en nuestro trabajo, he hecho esta lista basado en lo que he observado, es mi propia lista espero día a día complementarla, para saber qué es lo que hay en el ADN del programador.

 Capacidad de abstracción: Convertir una idea que muchas veces el cliente no puede visualizar en código y hacer que eso sea exitoso es una de las principales habilidades que debe tener el programador, ¿Cuántas veces un cliente ha dicho necesito algo que haga algo?, es decir el mismo cliente no sabe que es lo que quiere pero sabe que existe ese algo que lo va ayudar a mejorar sus procesos, a controlar su información, a hacer aquella tarea que siempre ha hecho de una forma pero que puede ser mejorada.

Aprendizaje rápido: El programador puede entrar en cualquier área, y debe entenderla rápidamente para poder desarrollar su trabajo, entenderla, y prácticamente hacerse un experto en ella, y no solo eso tener la capacidad de eliminar la ceguera de taller de todos aquellos que día a día realizaron esa actividad, debe tener la visión de mejorar los procesos, todo lo creado por el ser humano es mejorable, esa debe ser su máxima

Reacciones rápidas: Los sistemas son rápidos, y cada día son más rápidos y manejan más información, un programador debe ser capaz de tomar toda esa información que está fluyendo y encontrar soluciones muchas veces al instante en el que ocurre el problema, muchos de los problemas que llegan a ocurrir en un proceso productivo se dan por variables no consideradas en el flujo, y en muchos casos se requieren soluciones en periodos muy cortos de tiempo.

Capacidad de trabajar bajo presión: Todas las metodologías hablan de que existen tiempos para hacer las cosas, pero el mercado no da dichos tiempo, el tiempo es clave para ganar o perder un negocio, el tiempo siempre juega en nuestra contra

  Creatividad: Las soluciones planteadas no siempre están escritas, gran parte del trabajo de desarrollo es artesanal, el programador debe poder armar todas las piezas que tiene en un gran rompecabezas y darle vida, debe ser creativo e inteligente en cómo poner esas piezas para que interactúen de la manera correcta entre ellas.

Auto-aprendizaje: En una ciencia hay leyes que no cambian a través del tiempo, nosotros tenemos tendencias (lenguajes que surgen, nuevas características) que cambian todo el tiempo, lo peor lo que nosotros tenemos esta hecho por humanos que cambian de parecer de un momento a otro, así el lenguaje evoluciona, y de un año a otro puede cambiar completamente, debemos afrontar que hay que aprender todo el tiempo, y lo peor debemos afrontar que hay casos en que hay que desechar conocimientos.

 Obsesivos – Detallistas: Esto puede traducirse en calidad, los procesos tienen muchas entradas, salidas, variables, todo aquello que les da vida, debemos tener esa obsesión de mejorarlos de ser parte de ellos de entenderlos para que hagan aquello para lo que fueron hechos

 Capacidad de comunicación (hablar y escuchar): El usuario se comunica con nosotros y nos narra algo que no existe, nosotros narramos algo que tampoco existe, pero que en las dos cabezas debe formar un nuevo ser que cumpla con una expectativa.

 Memoria: recordar un dato de manera rápida, una regla casi olvidada que si bien esta en el diseño, debe estar en tu memoria, recordar mil funciones y cuando usarlas todo eso está en tu memoria Seguridad (No temer equivocarse): Tu eres el experto, el que lo construyo y dio vida, debes tener seguridad para caminar con pasos firmes, ya que si el constructor duda se genera desconfianza en el cliente, si el cliente no confía en ti, un éxito se convertirá irrevocablemente en un fracaso.

Todo cambio es bueno: En nuestro mundo todo cambia constantemente

Felices líneas


viernes, 11 de septiembre de 2015

16. Metricas (Cohesión y Acoplamiento)

Cuántas veces hemos escuchado, un buen diseño tiene alta cohesión y bajo acoplamiento, en cuantos documentos hemos leído… una de las características de este diseño es su alta cohesión.

¿Qué es eso?

Ambas son características de la programación orientada a objetos características que son muy importantes durante la etapa de diseño que pueden ser definidas de la siguiente forma:

Cohesión: Lo podemos entender como que cada uno de nuestros módulos sea altamente especializado en sus características o componentes, dicho en un lenguaje más coloquial, hablar siempre del mismo tema, esto nos facilita el diseño, la programación, las pruebas y el mantenimiento, así mientras mayor sea la cohesión mejor es el resultado en el sistema.

Sin embargo este es un concepto abstracto, que no puede ser fácilmente evaluado por una máquina, para determinar el grado de cohesión de un sistema es necesario validar el diseño, y ver que cada módulo sea un módulo especializado.

Y que pasa con el acoplamiento, bueno este es el grado en que una clase conoce a otras, las clases no son independientes, pese a que se recomienda un acoplamiento bajo, las clases requieren conocer a otras, este grado de conocimiento entre las clases genera el acoplamiento, de tal forma que una clase con alto acoplamiento tiene acceso a muchos métodos de diferentes clases, como consecuencia la clase es más compleja, y esta complejidad es la que debemos cuidar cuando tenemos un acoplamiento muy alto.

Mientras más compleja sea una clase, más difícil será el mantenimiento, mayor cantidad y complejidad de pruebas tendrá y será más propensa a errores.

Pero también hay que considerar algo, clases sin acoplamiento no son útiles, porque ningún ente vive aislado en este mundo.


A diferencia de la coherencia, para el acoplamiento, Visual Studio si nos permite obtener por medio de una herramienta el acoplamiento, para ello debemos ir al menú analizar y solicitar las métricas de la solución.


 “Calcular métricas de código para la solución”

Visual Studio inicia con la compilación del código y posteriormente, obtenemos los resultados.


¿Qué valor es óptimo? Este número siempre se debe encontrar en un valor inferior a 9, que incluso puede ser validado por medio de la herramienta de Code análisis de Visual Studio.

Hasta pronto

jueves, 10 de septiembre de 2015

15. Métricas (Complejidad Ciclomatica)

¿Qué es eso?

Cuando hablamos de arquitectura, empezamos a buscar medidas que nos indiquen la calidad de nuestros diseños, una medida que es ampliamente usada es la complejidad ciclomatica, en palabras sencillas esta nos indica que tan compleja es una función o una clase, es decir la cantidad de rutas que existen para ella. ¿Y en que no ayuda esto? Nos enseña la cantidad de casos de prueba que se necesitan para que este componente se pueda probar al 100%.

Una declaración como esta lo hace muy importante, si bien es prácticamente imposible probar un software al 100%, mientras más complejas sean las pruebas, es más difícil garantizar la calidad del software.

Esta es una de las métricas más importantes en la ingeniería de software, principalmente por 2 características:

1.       Da una visión general de la calidad de la solución

2.       Es independiente del lenguaje

Ahora bien para nosotros como programadores de .NET Visual Studio es capaz de calcular esta métrica, para que nosotros la verifiquemos.

¿Y cómo lo interpretamos? Esto es algo que es importante de esta medida, se interpreta de una forma muy sencilla, mientras en número sea menor es mejor.


Entonces, ¿Qué valores se recomiendan? , Los valores de la complejidad ciclomatica dependen de la organización, pero es recomendable seguir la siguiente tabla:

Mínimo
Máximo
Descripción
1
10
Riesgo pequeño
11
20
Riesgo Moderado
21
50
Alto Riesgo
50

Muy alto riesgo

Bueno ya que entendemos esto, ¿Cómo lo usamos en Visual Studio?
Realmente es muy sencillo, el menú de Visual Studio, nos da una opción que es analizar


Y en esta opción tenemos un menú que dice “Calcular métricas de código para la solución”, simplemente lo seleccionamos, Visual Studio inicia con la compilación del código y posteriormente, obtenemos los resultados.


Pero entonces me dirán, ese código que les muestro tiene una complejidad ciclomatica de 173, es muy alta, sí y no.

Estoy mostrando la complejidad de toda una solución, cada uno de los métodos que da vida a la solución es evaluado, de tal forma que un método solo por el hecho de existir sube en uno dicha complejidad.



¿En qué casos se enciende una alarma? Cuando un método tiene una complejidad ciclomatica alta, es decir hace demasiadas cosa tiene muchas posibilidades, el método ya no es controlable.

Saludos

14. Calidad

Y el reloj avanza sin parar y ya es hora de entregar esa nueva versión del nuevo producto, el programa todavía no se encuentra listo, los minutos corren, los equipos de trabajo se encuentran produciendo líneas de código bajo presión, se empiezan a eliminar características deseables o no esenciales, se hace la entrega y resulta que los programadores tienen mucha ceguera de taller y hay más errores de los que esperábamos, los flujos que se probaron y se diseñaron son muy estrictos, tan así que el menor cambio hace que la aplicación falle.

La entrega al cliente es mala o se retrasa, se genera insatisfacción y además el esfuerzo extra de las últimas horas quemo a el equipo de trabajo, la cantidad de errores excesivos, hace que muchos pierdan la paciencia.

Y acabamos de perder un proyecto que pudo haber sido el proyecto mejor planeado.
Dentro de este mundo del código salvaje quiero platicar un mal habito que tenemos casi todos los programadores, una frase muy común llamada “trabajo mejor bajo presión”, que no es más que la justificación de “Se acabó el tiempo y tengo que codificar muy rápido”.

¿Realmente se acabó el tiempo?

Cuando nos encontramos del lado de la programación tenemos la tendencia a perdernos en un mar de líneas de código pensando en flujos y pensando que el tiempo siempre alcanza. Perdiendo muchas veces día a día productividad desviándonos en actividades fuera del producto original, al final ese esfuerzo extra tan común en el final de un proyecto se puede dar sin pensarlo.

¿Pero qué tan conveniente es? La respuesta es nada, no es conveniente, como humanos al estar cansados nuestra mente no reacciona igual comete más errores.

Es importante que todo el equipo sepa cómo se encuentra el estado de un proyecto, para poder hacer correcciones a tiempo, las correcciones no es trabajar más, la corrección es como encontrar la manera de dedicar el tiempo adecuado a cada actividad.

Un proyecto que se encuentre con errores tiene un costo mucho mayor a una entrega fuera de tiempo, ya que genera una mayor insatisfacción, puede ser hasta peligroso porque un flujo no probado puede causar que un sistema pierda información valiosa.

Nosotros somos los guardianes de la información, eso es para nosotros lo más importante, si la información se daña, perdemos realmente el fin por el que estamos aquí.

La imagen de la empresa, la imagen de nosotros mismos, se daña más con un producto de mala calidad, que con un producto en el que se habló a tiempo el estado del mismo y se aplicaron las medidas para que el producto sea satisfactorio para el cliente.

Terminar un proyecto no es entregar un código.

Terminar un proyecto es que el usuario se sienta bien con el programa, que lo sienta una extensión de él, y que cumpla una de las características más importantes por las que estamos aquí, simplificar las cosas hacer que el sistema sea tan sencillo que realmente permita al usuario dedicar su tiempo en otras actividades.

Un sistema debe ser de tal forma que un usuario debe saber que existe, usarlo pero sin que esto represente que se convierta en un dolor de cabeza.

Las nuevas generaciones no leen manuales, eso lo tenemos que tener en cuenta, por eso cada flujo debe ser confiable, fácil de entender y agradable en su hacer.


Saludos

miércoles, 19 de agosto de 2015

12. Patrones de Diseño (III) - Facade

La programación salvaje es como una enredadera si no tenemos cuidado en muy poco tiempo se mete en todo nuestro proceso complicando cada día más su mantenimiento.

También se puede decir que es como una hidra, que crece y se convierte en un ser de muchas cabezas.

Como programadores no siempre es posible conocer la funcionalidad de todos los módulos, lo mejor siempre es tener módulos especializados y rehusarlos cuando esto sea necesario, pero existe un gran problema en esto, las muchas cabezas que puede tener un módulo y que debemos evitar, es aquí en donde nos ayuda el patrón de diseño del que hablaremos el día de hoy, el patrón Facade, o Fachada, es un patrón estructural que nos ayuda a dar visibilidad del código.

El patrón indica que se debe tener una sola clase de entrada sin importar la complejidad del código que se encuentre en la aplicación.

El patrón ordena el código de tal forma que cuando se emplea el modulo, pese a lo complejo de su interior, solo tendrá un punto por el que toda la funcionalidad sea accedida.

Este es un patrón muy útil, y realmente muy fácil de implementar que nos va a quitar muchos dolores de cabeza en el código.

Bueno siguiendo la lógica de que un programador busca menos teoría y más código, pongamos un ejemplo del uso de este patrón.


Nuevamente tomando el ejemplo de un carro, yo tengo una clase radio, la clase radio se muestra de la siguiente forma:

Como podemos ver el tablero de control en el que el usuario del carro controla el radio es nuestra clase fachada, y esta clase dispara procesos hacia adentro del radio, estos procesos cambian la estación, suben el volumen, controlan la reproducción de MP3, sin saber qué es lo que ocurre más atrás.
Ahora veamos qué pasa si esta clase creada en el punto anterior interactúa con un usuario, que en este caso es un programa que consume el servicio que se encuentra implementado bajo este patrón de diseño.


Resultado, solo un espacio de nombres, el código está estructurado y es más fácil de implementar.

Un paso más para evitar la programación salvaje, saludos



miércoles, 22 de julio de 2015

9. Patrones (II) - Decorator

El código salvaje crece de una manera incontrolada, esto hace que en muchos casos se pierda el control del mismo, y en casos extremos se tengan que hacer completos proyectos que si bien en su fase de diseño fueron muy buenos, con una arquitectura estable, conforme se van agregando nuevas funcionalidades y más desarrolladores modifican el código, estos se convierten en verdaderos monstros de Frankenstein.

Muchas piezas de código operando para crear nuevas funcionalidades, y en ciertas ocasiones por no conocer el sistema, estas hacen que el sistema sea inestable.

El tiempo de desarrollo se incrementa, la calidad baja, y de la misma forma baja la satisfacción del cliente.

Pero, ¿Hay alguna forma de modificar funcionalidad que sea no tan dolorosa?

Vamos a platicar de un patrón de diseño que es para esto, su nombre es Decorator, y se emplea para añadir de manera dinámica funcionalidad a un objeto, de esta forma podemos incrementar las características del objeto, sin que esto nos represente un cambio doloroso.

Eso si hay que cambiar un poco nuestra mentalidad para usarlo, y pensar más en términos del patrón
Su principal característica, es que nos permite agregar de manera incremental responsabilidades, el patrón lo aplicamos como si fueran capas y las capas nos brindan nuevas características, imaginemos que es una perla que se está creando y cada capa es una aplicación del patrón.

Este es un patrón estructural y lo podemos usar durante el diseño, mantenimiento o extensión de funcionalidad.

Podemos representar el patrón de la siguiente forma


Sin embargo creo que esto lo podemos ilustrar mejor con un poco de código.

Imaginemos esto somos una fábrica de carros, y vamos y vamos a ponerle el radio a uno de nuestros carros, así que crearemos una interfaz en la cual se encontrara el método encender radio

namespace decorator01
{
    public interface ICarro
    {
        void EncenderRadio();
    }
}

El radio lo vamos a implementar en nuestro modelo básico

public class CarroEstandar : ICarro
    {
        public void EncenderRadio()
        {
            Console.WriteLine("Radio FM - Mono");
        }
    }

Como se puede ver el modelo básico cuenta con un Radio FM con sonido mono aural, bueno viene un nuevo modelo, en el cual se requieren mejoras a este radio, así que tomamos el modelo básico y lo mejoramos

  public class CarroMejorado : ICarro
    {
        ICarro CarroBase;

        public CarroMejorado (ICarro I)
        {
            CarroBase = I;
        }
   
        public void EncenderRadio()
        {
            CarroBase.EncenderRadio();
            Console.WriteLine("Radio Satelital");
        }
}

Ahora el radio cuenta con una nueva función, sin perder la primera, si tuviéramos otro modelo, podemos crearlo ahora partiendo de cualquiera de los modelos anteriores.

public class CarroBlindado : ICarro
    {
        ICarro CarroBase;

        public Boolean DobleBlindado { get; set; }

        public CarroBlindado(ICarro I)
        {
            CarroBase = I;
        }

        public void EncenderRadio()
        {
            CarroBase.EncenderRadio();
            if (DobleBlindado == true)
            {
                Console.WriteLine("Audio Alta calidad");
            }
            else
            {
                Console.WriteLine("Audio Especial");
            }
        }
    }

Construyamos ahora nuestros carros:

class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Construyendo carro estandar");
            CarroEstandar cr1 = new CarroEstandar();
            cr1.EncenderRadio();

            Console.WriteLine("Construyendo carro Mejorado");
            CarroMejorado cr2 = new CarroMejorado(cr1);
            cr2.EncenderRadio();

            Console.WriteLine("Construyendo carro blindado");
            CarroBlindado cr3 = new CarroBlindado(cr2);
            cr3.DobleBlindado = true;
            cr3.EncenderRadio();

            Console.ReadLine();
        }

Al iniciar la producción vemos lo siguiente



Como podemos observar se puede agregar funcionalidad de manera dinámica de una forma mucho más libre que empleando la herencia


Di no al código salvaje