Monday, November 30, 2020

Despliegue de infraestructura en Azure usando Terraform

Ahora que estoy preparándome para el examen AZ-900: Azure Fundamentals y además de haber escrito algo sobre infraestructura como código, me animé a investigar en cómo desplegar infraestructura en Azure a través la herramienta Terraform.

Terraform nos permite describir nuestra infraestructura a través de scripts (práctica IaC). De esta forma nuestra infraestructura es tratada de la misma manera que cualquier otro código (versionar, ejecutar, probar).  

En esta ocasión voy a experimentar el despliegue de infraestructura (una Virtual Machine) en Azure a través de Terraform. ¡Adelante!

Requisitos

Terraform 

La instalación es sencilla, solo sigue lo que estable la documentación según su SO: https://learn.hashicorp.com/terraform/getting-started/install.html

Editor de código

Personalmente, mi editor de código preferido es Visual Studio Code. Para trabajar con Terraform puedes usar las siguientes extensiones: 
  • Terraform - Syntax highlighting, linting, formatting, and validation for Hashicorp's Terraform.
  • Azure Terraform - VS Code extension for developing with Terraform on Azure.

Una cuenta de Azure

Puedes conseguir 200 USD para la prueba gratuita de Azure a través del siguiente link: https://azure.microsoft.com/en-us/free/

Azure CLI

La interfaz de la línea de comandos de Azure (CLI de Azure) es un conjunto de comandos que se usa para crear y administrar recursos de Azure. Para instalarlo sigues los pasos del siguiente link: 

https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest


Comandos Terraform

  • terraform init: Es el comando de partida para iniciar una nueva o ya existente configuración.
  • terraform plan: Muestra qué infraestructura se va a crear.
  • terraform apply: Crea, modifica o elimina la infraestructura definida en el archivo de configuración.
  • terraform destroy: Elimina toda la infraestructura definida en el archivo de configuración (¡Tener cuidado!)

Paso a paso

Paso 1
Iniciar sesión en Azure CLI con el comando az login en una línea de comandos. 

Paso 2
Crear nuestro archivo de configuración Terraform (extensión .tf) y definir nuestra infraestructura a crear, en nuestro caso una máquina virtual Windows.

// configurar Azure Provider
provider "azurerm" {
  version = "=2.9.0"
  features {}
}

// crear un grupo de recursos
resource "azurerm_resource_group" "main" {
  name     = "terraform-rg"
  location = "West Europe"
}

// crear red virtual donde tiene que estar la VM
resource "azurerm_virtual_network" "main" {
  name                = "rc-network"
  address_space       = ["10.0.0.0/16"]
  location            = "${azurerm_resource_group.main.location}"
  resource_group_name = "${azurerm_resource_group.main.name}"
}

// crear una subred virtual 
resource "azurerm_subnet" "internal" {
  name                 = "internal"
  resource_group_name  = "${azurerm_resource_group.main.name}"
  virtual_network_name = "${azurerm_virtual_network.main.name}"
  address_prefix       = "10.0.2.0/24"
}

// crear una interfaz de red para la VM
resource "azurerm_network_interface" "main" {
  name                = "rc-nic"
  location            = "${azurerm_resource_group.main.location}"
  resource_group_name = "${azurerm_resource_group.main.name}"

  ip_configuration {
    name                          = "testconfiguration1"
    subnet_id                     = "${azurerm_subnet.internal.id}"
    private_ip_address_allocation = "dynamic"
  }
}

// crear la máquina virtual 
resource "azurerm_virtual_machine" "main" {
  name                  = "rcdevopsvm"
  location              = "${azurerm_resource_group.main.location}"
  resource_group_name   = "${azurerm_resource_group.main.name}"
  network_interface_ids = ["${azurerm_network_interface.main.id}"]
  vm_size               = "Standard_DS1_v2"

   delete_os_disk_on_termination = true

   delete_data_disks_on_termination = true

  storage_image_reference {
    publisher = "microsoftwindowsserver"
    offer     = "WindowsServer"
    sku       = "2016-Datacenter"
    version   = "latest"
  }

  storage_os_disk {
    name              = "rcwinserver"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }
  os_profile {
    computer_name  = "rcwinservervm"
    admin_username = "testadmin"
    admin_password = "Password1234!"
  }
  os_profile_windows_config {
    enable_automatic_upgrades = true
    provision_vm_agent = true
  }

}

Paso 3
Desde la terminal embebida de Visual Studio Code ejecutar el siguiente comando:
> terraform init

Paso 4
Para comprobar que infraestructura se va a desplegar ejecutar el siguiente comando:
> terraform plan

Paso 5
Para desplegar la infraestructura ejecutar el siguiente comando:
> terraform apply

Paso 6
Ir al portal de Azure y ver que la infraestructura se haya creado correctamente.


Paso 7
Para eliminar nuestra infraestructura de pruebas y así evitar gastos en Azure ejecutar el siguiente comando:
> terraform destroy

Conclusión

Con este ejemplo sencillo ahora entiendo un poco más el poder de gestionar la infraestructura a través de una herramienta como Terraform. Realmente se comprueba la hipótesis de que la práctica técnica de Infraestructura como Código contribuye a la entrega rápida de valor. 

En un siguiente articulo trataré el uso de Terraform usando pipelines de Azure DevOps. Algunos enlaces interesantes:

¡Gracias por llegar hasta aquí!

Cómo mantenerse al día con las oportunidades y tendencias de la industria IT

Desde hace unos años estamos presenciando una revolución en el uso de las nuevas tecnologías en nuestro día a día. Una transformación de la sociedad como consecuencia de la adopción de tecnología digital en las actividades diarias de las personas. Hoy es común ver por la calle a una persona con su smartphone, tablet o smartwatch. Y en nuestras casas ya es normal la fibra óptica o los electrodomésticos conectados a internet. 

También es cierto que tanto las organizaciones del sector público y privado son parte de esta transformación, pues progresivamente están incorporando tecnología en su núcleo para producir un cambio profundo en la gestión de las mismas. Esto implica cambiar la manera en que trabajan las personas, cambiar los modelos de negocios y cambiar la relación con clientes y proveedores. A este cambio profundo en las organizaciones es lo que se denomina Transformación Digital

Como desarrolladores de software no podemos estar ajenos a estos cambios. Si queremos seguir creciendo en el mundo IT durante los siguientes años no podemos perder de vista las tecnologías que impulsan la transformación digital. Tarea no sencilla porque requiere estar pendiente de la gran cantidad de cambios tecnológicos.

Piensa en esto: ¿Qué pasaría si tuvieras una especie de mapa que te muestre el contexto tecnológico actual que impulsa la transformación digital? Realmente sería genial.

Veamos el caso de Henry que trabaja como desarrollador desde hace 3 años. A Henry le encanta la tecnología y le gusta estar actualizado. Últimamente ha escuchado mucho el concepto de transformación digital y está interesado en hacer seguimiento de las tecnologías que están transformando los negocios. Sin embargo, se siente abrumado con la tremenda cantidad de novedades y tendencias que surgen constantemente, lo cual a veces lo desorientan.

Un día, en una amena reunión con cervezas, un compañero de la oficina le contó a Henry sobre la existencia de unos “mapas tecnológicos” que representan el contexto tecnológico actual. Estos “mapas” son propuestos por organizaciones que monitorean y analizan la industria IT. Por ejemplo, la empresa IDC llama a su mapa Third Platform, Gartner lo llama Nexus of Forces y Open Group lo denomina Open Platform 3.0.

Henry exploró la Third Platform de IDC. Este mapa le dio un panorama más claro de las tecnologías que están cambiando los negocios. Ahora Henry tiene un mecanismo para detectar las novedades que valen la pena dedicarle tiempo y atención. También está más seguro de cómo podría contribuir a la transformación digital de su organización construyendo nuevas cosas con tecnología de vanguardia.

IDC Third Platform


Aprender más sobre sobre el contexto tecnológico actual puede ayudarte a identificar qué habilidades tecnológicas te conviene desarrollar. Además, estarás al tanto de cuáles son las oportunidades y tendencias de la industria IT. Explorar un poco más sobre las tecnologías que están cambiando los negocios:

Diferencia entre principios y patrones de diseño de software

Hace poco encontré un libro de diseño de software titulado Software Design Decoded – 66 Ways Experts Think, donde se exploran hábitos, prácticas y principios que los profesionales de software usan en su día a día, mezclando la tecnología y la imaginación. La cuestión es que esta lectura me despertó la curiosidad por buscar la diferencia y relación entre dos conceptos que se usan bastante en nuestra industria: Principio de diseño y Patrón de diseño.


En primer lugar, es importante aclarar que, independientemente del nivel donde se apliquen (a nivel de funciones y clases, a nivel de componentes o a nivel arquitectónico), tanto los principios como patrones de diseño tienen un fin en común: Construir software flexible, mantenible y reusable. Visto desde otro ángulo, evitar un mal diseño caracterizado por:

  • Rigidez: Es difícil de cambiar porque cada cambio afecta a demasiadas otras partes del sistema.
  • Fragilidad: Cuando se hace un cambio, partes inesperadas del sistema se rompen.
  • Inmovilidad: Es difícil reutilizarlo en otra aplicación porque no se puede desacoplar de la aplicación actual.
  • Viscosidad: Es difícil hacer lo correcto pero fácil hacer lo incorrecto.

En segundo lugar, estos conceptos diferencian por lo siguiente:

  • Principio de diseño: Conjunto de pautas que nos ayudan a evitar un mal diseño de software. Ejemplo: Open Close Principle.
  • Patrón de diseño: Solución general reutilizable para un problema que ocurre comúnmente dentro de un contexto dado en el diseño de software. Ejemplo: Singleton.
Es decir, los principios de diseño son los objetivos deseables que uno se propone alcanzar mientras que los patrones de diseño son los recursos que se pueden utilizar para alcanzar esos objetivos. En otras palabras, los patrones de diseño emplean principios de diseño.

Los patrones de diseño son muy populares, tienen catálogos completos y son muy fáciles de encontrar información sobre estos.


Por otro lado, los principios de diseño han sido dispersados y desorganizados, y se han vuelto confusos para muchos. Existen esfuerzos de compilación de estos principios.


Finalmente, si quieres diferenciar mejor estos conceptos metiendo las manos en la masa, es decir, escribiendo código, te recomiendo que revises el libro Beginning SOLID principles and Design Patterns for ASP.NET Developers que te enseña lo esencial para aplicar los principios y patrones de diseño en el contexto del diseño orientado a objetos, utilizando ASP.NET Core.

¡Gracias por llegar hasta aquí!

Apuntes sobre instrumentación de aplicaciones

Monitoreo e instrumentación

Si te preguntaran por tu estado de salud actual ¿serías capaz de dar una respuesta objetiva? Quizás podrías hacerlo basado en tu estilo de vida o sensaciones físicas que estés experimentando actualmente. Sin embargo, un mejor enfoque sería hacerse una evaluación médica integral, que a través de instrumentos médicos y análisis profesional nos permita conocer si existen factores de riesgo de enfermedades para poder tratarlas o prevenirlas. En este sentido, es fundamental un control periódico de tu salud para su cuidado.


Cambiando de rubro y preguntando con el mismo sentido ¿cuál es el estado de salud de tu aplicación? ¿cuáles son las evidencias sobre su comportamiento en tiempo de ejecución? Conocer las respuestas a estas preguntas puede resultar de gran utilidad. Por ejemplo, cuando algo sale mal será indispensable saber qué y porqué sucedió, además de cualquier pista que nos ayude a solucionar el problema para evitar que vuelva a ocurrir en el futuro.

Para conocer el estado y salud de una aplicación está la actividad de monitoreo, la cual se puede definir como el proceso sistemático de recolectar, analizar y utilizar información para hacer seguimiento del comportamiento de la aplicación con la finalidad de diagnosticar y/o solucionar problemas.


Es evidente que la eficacia de un sistema de monitoreo está en función de la calidad de la información recabada. Para dar soporte a esto está la instrumentación. La palabra instrumentación es un término amplio que adquiere un significado particular según el contexto donde se aplique: procesos industriales, bioingeniería, electrónica, etc. En el campo de la programación se refiere al proceso de incluir código extra (código de instrumentación) a un programa para generar información sobre su comportamiento durante su ejecución.

Entonces, la instrumentación es necesaria para obtener datos que nos permitan entender aspectos como: performance, uso de recursos, comportamiento del usuario, diagnóstico de errores, etc.

Métodos de instrumentación

Dependiendo de si tenemos o no acceso al código fuente, existen dos formas básicas de agregar código de instrumentación a nuestras aplicaciones: source-code instrumentation y binary instrumentation.

Source-code instrumentation

Es el método más directo para capturar información en runtime. Este implica la disponibilidad del código fuente por lo cual se modifica directamente para agregar código de instrumentación. Un ejemplo ilustrativo de su aplicación se muestran en las siguientes imágenes (fuente https://www.slideshare.net/mtekbir/code-instrumentation):





Binary Instrumentation

Se refiere a la técnica de inyectar código de instrumentación a un proceso en ejecución. El código de instrumentación es totalmente transparente para la aplicación en la que se inyecta. Para este tipo de instrumentación existen diversos frameworks tales como Pin, DynamoRIO, Frida, Valgrind, etc.


Mecanismos de instrumentación

Más allá de la forma de agregar código de instrumentación, existen mecanismos específicos para la captura de datos, los cuales son:

  • Logging: Los logs están dirigidos a administradores que supervisan el funcionamiento normal del sistema. Registro de eventos normales o excepcionales.
  • Tracing: Los traces están dirigidos a desarrolladores que necesitan detalles sobre el flujo de control del software. Se utilizan principalmente para la detección de problemas en sistemas productivos (alternativa al debugging).
  • Exception handling: Medida de precaución para tratar errores en tiempo de ejecución. Útil para el seguimiento y corrección de errores.
  • Performance monitoring: A través de performance counters que permiten el seguimiento del rendimiento de la aplicación.

Buenas prácticas de instrumentación

Finalmente, a modo de listado, algunas recomendaciones útiles para poner en práctica en la instrumentación de nuestras aplicaciones (del libro Hardening Azure Applications):

  • Add logging capability for the most critical, if not all, components of your application.
  • Include elaborate/full exception details.
  • Use counters and log details around retry attempts.
  • Log all failures and retries associated with integration to external service.
  • Monitor current and average response time for all cross-component calls.
  • Determine the root component that is causing any failure condition.
  • Ensure that all instrumentation is configurable for production and test environments.

Webgrafía



Arqueología de Software - Parte 1

El mantenimiento de software y sus desafíos

En el poco tiempo que vengo trabajando en la industria del software, he pasado más tiempo en la extensión y mantenimiento de sistemas existentes (Brownfield Projects) que construyendo sistemas nuevos (Greenfield Projects). Consultando con varios colegas descubro que enfrentan una situación similar. Quizás, este fenómeno podría explicarse con lo que se afirma en el libro Software Architecture in Practice:

La comunidad de desarrollo de software se está enfrentando al hecho de que aproximadamente el 80 por ciento del costo total de un sistema de software típico ocurre después del despliegue inicial. Un corolario de esta estadística es que la mayoría de los sistemas en los que trabaja la gente está en esta fase. Muchos programadores y diseñadores de software nunca llegan a trabajar en nuevos desarrollos; funcionan bajo las restricciones de la arquitectura existente y el cuerpo de código existente.

En base a lo anterior, parece que estamos casi condenados a mantener sistemas existentes. Un escenario común que debemos enfrentar los developers es cuando nos asignan un proyecto para mantener un sistema del que no sabemos nada y con características como:

  1. De miles de líneas de código
  2. Sin documentación de diseño (u obsoleta)
  3. Los creadores (diseñadores/desarrolladores) ya no están presentes

Sin duda, encarar un escenario como este representa un desafío de investigación inicial para entender el sistema. Y es aquí donde viene al rescate la Arqueología de Software. Una disciplina que propone un proceso para recuperar los detalles esenciales para razonar, arreglar y adaptar el sistema existente. Ya que hablamos de arqueología de software ¿que relación tiene esta con la ciencia arqueológica tradicional?

Relación con la arqueología tradicional

Para entender la relación entre la arqueología de software y la ciencia arqueológica tradicional tenemos que entender la definición de esta última:

La arqueología es el estudio de las sociedades humanas del pasado a partir de la recuperación y análisis de sus restos materiales (artefactos útiles y basura) con el objetivo de conocer cómo vivían.

Fuente: Arqueólogos - el lenguaje de los siglos

Según la definición anterior, se desprende que un arqueólogo es netamente un investigador, por tanto, cumple las etapas de un proceso de investigación, buscando información para generar nuevo conocimiento. Es por esto que la ciencia arqueológica tradicional nos ofrece una buena analogía para describir las actividades que un developer realiza cuando investiga el software que desarrollaron otras personas.


Arqueología de software como proceso de investigación de sistemas pobremente documentados

El mantenimiento de software implica actividades orientadas a la modificación o cambio del mismo. El cambio tiene como característica fundamental el hecho de que primero se necesita una comprensión del objeto que se ha de cambiar, para poder hacer efectiva la modificación. Por esto, adoptar la arqueología de software como práctica para encarar el mantenimiento de sistemas que carecen de documentación puede orientarnos en la comprensión de su estructura y comportamiento. 


¿Y cómo se logra esta comprensión a través de la arqueología de software? La idea es seguir un proceso en el cual se analizan diferentes artefactos de software (código fuente, bases de datos, interfaces de usuario, etc.) a través de técnicas y herramientas de ingeniería inversa para obtener modelos que nos permitan entender la estructura y comportamiento de un sistema, así como también los procesos de negocio a los cuales da soporte dentro de la organización.


Con todo este contexto ya podemos explorar las fases, técnicas y herramientas de la arqueología de software, lo cual veremos en un siguiente artículo.

Webgrafía

Bibliografía

  • Working with Legacy Systems. A Practical Guide to the Systems we Inherit and Maintain - Robert Annett.
  • Hunt, A., & Thomas, D. (2002). Software archaeology. IEEE Software, 19(2), 20-22.


 ¡Gracias por llegar hasta aquí! 


Claves del pensamiento arquitectónico

 A diferencia de un desarrollador, un arquitecto debe cultivar un punto de vista arquitectural que le permita tener una visión amplia del sistema que se está construyendo. Según el libro Fundamentals of Software Architecture (by Mark Richards, Neal Ford) existen cuatro aspectos clave para desarrollar el pensamiento arquitectónico:

  1. Entender cuál es el límite entre la arquitectura y el diseño
  2. Tener amplitud técnica
  3. Analizar trade-offs
  4. Entender los requerimientos de negocio
Desarrollar estas destrezas permitirán al arquitecto tomar mejores decisiones arquitectónicas, las cuales influyen en el diseño, producción y entrega de productos software. A continuación veamos brevemente dichas destrezas..

1. Entender cuál es el límite entre la arquitectura y el diseño 

Es común ver una separación vertical entre las responsabilidades de los arquitectos y desarrolladores.

Punto de vista tradicional de la separación entre la arquitectura y el diseño

Sin embargo, no existe un límite entre la arquitectura y el diseño, sino que están integrados y sincronizados. Para que la arquitectura funcione, los arquitectos y desarrolladores deben trabajar juntos. El papel principal del arquitecto es de liderar y capacitar a los desarrolladores del equipo.


Haciendo que la arquitectura funcione a través de la colaboración


2. Tener amplitud técnica

Mientras que un desarrollador debe mantener una profundidad técnica para realizar su trabajo, un arquitecto debe tener una amplitud técnica para pensar desde un punto de vista de la arquitectura. 

Una gran parte del valor de un arquitecto es una amplia comprensión de la tecnología y de cómo utilizarla para resolver problemas concretos. Por ejemplo, como arquitecto, es más beneficioso saber que existen cinco soluciones para un problema particular que tener conocimientos singulares en una sola.

3. Analizar trade-offs

Pensar como arquitecto implica evaluar los trade-offs de cada alternativa para elegir la mejor solución. Los trade-offs se refieren a las ventajas y desventajas que pueda tener una solución determinada.

Todo en arquitectura es un trade-off, por eso es que la respuesta común a una pregunta de arquitectura es un "depende". Pensar arquitectónicamente implica observar los beneficios de una solución dada, pero también analizar los aspectos negativos.


Subir un extremo de la balanza hace bajar el otro

4. Entender los requerimientos de negocio

Pensar como arquitecto requiere entender los requerimientos de negocio para luego traducirlos en características de la arquitectura (escalabilidad, rendimiento, disponibilidad, etc.). Es una tarea compleja porque requiere conocimiento del negocio y buenas relaciones con los principales stakeholders de la empresa.

¡Gracias por llegar hasta aquí!


La modularidad en la arquitectura

La modularidad es un principio organizador. Si un arquitecto diseña un sistema sin prestar atención a cómo se conectan piezas, termina creando un sistema que presenta innumerables dificultades, pues los sistemas de software modelan sistemas que tienden al desorden. Por esto último es indispensable que los arquitectos inviertan energía en asegurar una buena solidez estructural (algo que no se puede dar por accidente).

Utilizamos la modularidad para describir una agrupación lógica de código relacionado, que podría ser un grupo de clases en un lenguaje orientado a objetos o funciones en un lenguaje estructurado o funcional. La mayoría de lenguajes proporcionan mecanismos de modularidad (paquete en Java, espacio de nombre en .NET, etc.)

Medición de la modularidad

Dada la importancia de la modularidad para los arquitectos, necesitan herramientas para entenderla. Los investigadores han creado una variedad de métricas agnósticas de los lenguajes para ayudar a los arquitectos a entender la modularidad. Estas métricas son:

  • Cohesión
  • Acoplamiento
  • Connascence

De módulos a componentes

Los módulos son una colección de código relacionado. Es un nombre genérico para un paquete de código relacionado. Sin embargo, los arquitectos suelen pensar en términos de componentes, la manifestación física de un módulo.

Los desarrolladores empaquetan físicamente los módulos de diferentes maneras, a veces dependiendo de su plataforma de desarrollo. La mayoría de los lenguajes soportan el empaquetamiento físico: archivos jar en Java, dll en .NET, gem en Ruby, etc.

¡Gracias por llegar hasta aquí!

Saturday, November 28, 2020

Educación tecnológica en la industria del Software

Como en cualquier actividad humana, la toma de decisiones es clave durante todo el proceso de desarrollo de software. Por más que intentemos huir de esta responsabilidad tarde o temprano experimentaremos sus consecuencias. No decidir es decidir. 

Personalmente, me interesan mucho aquellas decisiones dentro del contexto del diseño técnico, aquellas que con un trabajo iterativo nos permiten producir las estructuras necesarias para lograr una solución aceptable que satisfaga nuestros objetivos de producto/proyecto. Con diseño técnico me refiero a un diseño estratégico donde las decisiones tomadas son de impacto global sobre nuestro producto/proyecto. 

Considerando la categorización de las decisiones de diseño propuesta en el libro Software Architecture in Practice (Third Edition), hago foco en la categoría Selección de tecnología, de especial importancia, porque casi siempre implementamos nuestras ideas a través de la tecnología.  

La evaluación y elección de tecnología en una industria del software con cambios tecnológicos incesantes nos propone retos que podrían plantearse con las siguientes preguntas:

  • ¿Cómo mantenerse actualizado en una industria en constante evolución?
  •  ¿Qué criterios seguir al evaluar y adoptar una nueva tecnología?
  •  ¿Qué enfoque seguir para que los integrantes de nuestro equipo adopten la nueva tecnología?
  •  ¿Cómo gestionar los atributos de calidad del sistema una vez que se introduzca la nueva tecnología?
  •  Si un vendor anuncia el fin de vida útil de un producto que utilizamos ¿cómo vamos a realizar la migración?
Son muchas cuestiones de interés alrededor de la tecnología que merecen nuestra atención. Sería demasiado pretencioso tratar de abarcar todos estos temas en un sólo artículo, por lo que trataré de responder sólo a la interrogante ¿cómo mantenerse actualizado en una industria en constante evolución? Tema no menor, pues implica estar pendientes de nuestra educación tecnológica que influirá directamente en nuestras decisiones técnicas. 

Estar al día con la nueva tecnología

Poniéndonos el sombrero de un tecnólogo nos toca mantenernos al día con la novedades de la industria. Sin embargo, hay que reconocer que no podemos con todo: hay demasiados cambios como para que una persona pueda dominarlo todo. 

El mejor camino es elegir una o dos áreas que te motiven (con el tiempo puede variar) y profundizar leyendo los textos fundamentales, siguiendo a los líderes de opinión, mirando presentaciones clave, etc. Para lo demás, es suficiente tener una idea general. Esta estrategia nos lleva a desarrollar un perfil "T" que denota un profesional con una habilidad principal (línea vertical de la letra T) con conocimientos generales en otras disciplinas (línea horizontal de la letra T). 

La idea del perfil "T" va en contraposición de mitos como el del famoso full stack developer, un perfil que aparentemente puede hacerlo todo. Pero seamos sinceros, el software es demasiado complejo para eso, pues a medida que las industrian evolucionan, es inevitable que surjan las especializaciones. 

Radar tecnológico

Es fundamental tener un panorama tecnológico de las novedades de la industria, una "big picture" que puede resultar difícil de obtener por la ingente cantidad de nuevos lenguajes, bibliotecas, frameworks y técnicas que pueden confundirnos. Considerando que nuestro tiempo es valioso, la pregunta clave es: ¿cómo centrar nuestra atención en las cosas que realmente importan? ¿cómo realizar un filtro sobre este amplio universo de novedades?

Una solución interesante es consultar fuentes confiables, como el radar tecnológico de ThoughtWorks el cual lo define de la siguiente manera: 

El Radar es un documento que establece los cambios que creemos que son relevantes actualmente en el desarrollo de software — cosas en movimiento a las que creemos que deberían prestar atención y considerar aplicar en sus proyectos. Refleja la opinión idiosincrásica de un grupo de tecnólogos de alto nivel y está basado en nuestras experiencias y trabajo cotidiano. Si bien pensamos que esto resulta interesante, no debería tomarse como un análisis profundo del mercado. https://www.thoughtworks.com/radar
Entonces, un radar tecnológico es un mecanismo para detectar las novedades que valen la pena dedicarle tiempo y atención. Con el mismo fin, podríamos apoyarnos en miembros reconocidos, líderes de opinión dentro de la comunidad del campo del software para orientarnos en donde podríamos invertir tiempo y esfuerzo. 

En conclusión, entender que la selección de tecnología es una decisión de diseño clave en el desarrollo de nuestros productos de software y que nuestra educación tecnológica influye directamente en esta decisión es un buen inicio para aprender a gestionar el cambio dentro de una industria en evolución constante y acelerada.

Gracias por llegar hasta aquí!



Visión técnica en equipos de desarrollo de software (Opinión)

Hace poco, tuve una charla amena y extendida con un amigo que trabaja como líder técnico de un grupo de cinco personas en una consultora de Software en Lima. Compartimos algunas ideas sobre su responsabilidad de dirigir al equipo en el esfuerzo de lograr la visión técnica de equipo. Lindo desafío.

En primer lugar, establecimos una base sobre qué es la visión. Para esto nos apoyamos en John C. Maxwell, que indica que la visión es todo para un líder. Es totalmente indispensable porque establece adonde queremos llegar a través de objetivos que nos marcamos para lograr en el futuro.

Es necesario que a nivel organizacional exista una visión que exprese la razón por la cual existe y en base a ella se planteen las estrategias para lograr dicha visión. Cada líder técnico debe estar en contacto con esta visión empresarial y en consonancia plasmar una visión técnica que sea eficiente tanto para la organización como para los miembros de su equipo. La concepción y plasmación de una visión técnica implica un enfoque multidimensional que incluye personas, negocio, tecnología y liderazgo técnico. 


Por ejemplo, se me ocurre plantear la siguiente visión técnica de equipo:

Ser un equipo que desarrolla productos con altos estándares de calidad, donde sus miembros puedan progresar desarrollando sus habilidades técnicas/humanas y se mantenga actualizado con las tendencias y oportunidades de la Industria IT 

En este sentido, el líder técnico debe invertir tiempo y esfuerzo en ayudar al equipo a comprender la visión técnica, para que el grupo se mueva en la misma dirección. 


Un líder técnico, además de su función de guía, debe esforzarse por conectar la visión personal de cada miembro con la visión técnica plasmada. Entender la visión personal de cada miembro implica conocer sus objetivos profesionales y las razones por las que trabaja en la organización. Lograr esta conexión entre visiones será clave para generar el entusiasmo y compromiso en el equipo.

En definitiva, recuerda que es de vital importancia hacer explícita la visión técnica de equipo para trabajar de manera coordinada y con propósito. Personalmente, considero este tema de gran valor porque apunta a mejorar la forma en que compartimos durante ocho horas con la otra familia nuestro día a día.

¡Gracias por llegar hasta aquí!


Identificar características arquitectónicas

Para crear una arquitectura o determinar la validez de una arquitectura existente se empieza por identificar las características arquitectónicas ("-ilities"). Para lograr esto el arquitecto debe:

  • Comprender el dominio del problema.
  • Trabajar con los stakeholders para establecer lo que es verdaderamente importante desde la perspectiva del negocio.

Un arquitecto extrae las características arquitectónicas de al menos tres fuentes:

  • Requerimientos de negocio
  • Requerimientos funcionales y restricciones
  • Del conocimiento implícito del dominio

En esta oportunidad hablemos sobre lo que implica extraer las características arquitectónicas a partir de los requerimientos de negocio.

Extraer las características arquitectónicas desde los requerimientos de negocio

Los requerimientos de negocio describen las metas de una organización. Un arquitecto debe ser capaz de identificar las características arquitectónicas correctas. Por ejemplo, ¿es la escalabilidad la característica más importante, o es la tolerancia a fallos, la  seguridad o el rendimiento? Tal vez el sistema requiere las cuatro características combinadas.

La comprensión de los objetivos de negocio permite al arquitecto traducirlas en "-ilities", lo que luego constituye la base de decisiones arquitectónicas correctas y justificables. La mayoría de las características arquitectónicas se obtienen  escuchando a los stakeholders y colaborando con ellos para determinar qué es importante desde la perspectiva del negocio.

Aunque esto puede parecer una actividad sencilla, el problema es que los arquitectos y los stakeholders del negocio hablan idiomas  diferentes. Los arquitectos hablan de escalabilidad, interoperabilidad, tolerancia a fallos y disponibilidad. Los  stakeholders del negocio hablan de fusiones y adquisiciones,  satisfacción del usuario, time to market y ventaja competitiva.

Lo que sucede es un problema de "lost in translation" en el que el arquitecto y el stakeholder del negocio no se entienden entre sí. Los arquitectos no tienen ni idea de cómo crear una arquitectura que apoye la satisfacción del usuario, y los stakeholders del negocio no entienden por qué los arquitectos ponen tanta atención y hablan de disponibilidad, interoperabilidad y tolerancia a fallos en la aplicación. Los arquitectos deben a menudo decodificar el lenguaje del dominio en equivalentes de ingeniería.

Afortunadamente, suele haber una traducción de los objetivos del negocio a las características arquitectónicas, tal como se describe en la siguiente imagen:


Recuerda que normalmente un objetivo de negocio implica satisfacer la combinación varias características arquitectónicas y hay que tener cuidado de no caer en la trampa de concentrarnos en uno sólo de ellos.

Particionamiento de la arquitectura

Una de las principales decisiones que un arquitecto debe tomar se refiere a la división de alto nivel de la arquitectura. Para esto, los arquitectos suelen pensar en términos de componentes, la manifestación física de un módulo. Los componentes representan la unidades de construcción básica en la arquitectura, lo que los convierte en una consideración crítica para los arquitectos.

Los componentes se pueden manifestar de diferentes formas:

  • Library
  • Layer
  • Event Processor
  • Distributed service

Por lo general, el componente es el nivel más bajo del sistema de software con el que un arquitecto interactúa directamente. Los componentes consisten en clases o funciones (dependiendo del paradigma de programación), cuyo diseño es responsabilidad de los desarrolladores

Tipos de particionamiento

Cuando un arquitecto realiza la división de alto nivel de la arquitectura, genera componentes utilizando un tipo de particionamiento en particular, que puede ser:
  • Particionamiento técnico
  • Particionamiento por dominio
Tipos de particionamiento de alto nivel

El particionamiento de alto nivel es de particular interés para los arquitectos porque define el estilo de arquitectura a usar, ya sea monolítico o distribuido:
  • Monolithic: Layered architecture, Pipeline architecture, Microkernel architecture
  • Distributed: Service-based architecture, Event-driven architecture, Space-based architecture, Service-oriented architecture, Microservices architecture

Por eso pregúntate ¿qué tipo de particionamiento soporta el estilo arquitectónico que estoy analizando?

Particionamiento técnico

Consiste en dividir la arquitectura en capacidades técnicas. Un ejemplo de esto es la arquitectura en capas, la cual representa una división técnica de alto nivel: presentación, reglas de negocio, servicios, persistencia, etc.

Particionamiento por dominio

Este tipo de particionamiento está inspirado en el libro de Eric Evans Domain-Driven Design (DDD) en donde explica una técnica de modelado para descomponer sistemas complejos. En DDD el arquitecto identifica los dominios o flujos de trabajo independientes y desacoplados entre sí. El estilo arquitectónico de microservicios se basa en este enfoque.

Flujo de identificación de componentes

La propuesta para la identificación de componentes es seguir una serie de pasos bajo un enfoque iterativo. Ya sea para la identificación de componentes candidatos o el refinamiento de los mismos.



  • Identifying Initial Components: Basándose en un tipo de particionamiento de alto nivel, determinar con qué componentes comenzar. Es difícil empezar con algo concreto cuando un arquitecto diseña un sistema desde cero. Para lograr un buen diseño no queda otra opción que iterar.
  • Assign Requirements to Components: Mapear los requisitos funcionales con los componentes. Esto puede implicar la creación de nuevos componentes, la consolidación de los existentes o la separación de los mismos porque tienen demasiada responsabilidad.
  • Analyze Roles and Responsibilities: Pensar tanto en los roles y responsabilidades que la aplicación debe soportar para descubrir la granularidad correcta de los componentes.
  • Analyze Architecture Characteristics: Mientras se asignan los requisitos funcionales a los componentes también se debe observar las características arquitectónicas descubiertas anteriormente. La idea es pensar en cómo las características arquitectónicas podrían afectar a la división y granularidad de los componentes. Por ejemplo, mientras que una parte del sistema pueden ocuparse de la entrada del usuario, la parte que trata con ciento de usuarios concurrentes necesitará diferentes caraterísticas arquitectónicas a diferencia de la otra parte.
  • Restructure Components: Los arquitectos deben iterar continuamente en su diseño de componentes con ayuda de los desarrolladores. A medida que los desarrolladores profundizan en la construcción de la aplicación, se adquiere una comprensión más matizada de dónde deben estar el comportamiento y los roles.
Enlaces:

Mecanismos de gobernabilidad de la arquitectura

Una vez que los arquitectos han establecido las características arquitectónicas y las han priorizado, ¿cómo pueden asegurarse de que los desarrolladores respetarán esas prioridades? La gobernabilidad de las características arquitectónicas es una importante responsabilidad del arquitecto. La finalidad es garantizar la calidad del software, pues su descuido puede dar lugar a problemas de calidad desastrosos.

El libro Building Evolutionary Architectures (O'Reilly) describe una familia de técnicas, llamadas fitness functions, utilizadas para automatizar muchos aspectos del gobierno de la arquitectura.

Fitness Functions

Las fitness functions en arquitectura son mecanismos que proporcionan una evaluación objetiva de la integridad de una característica arquitectónica o de la combinación de características arquitectónicas.

Se pueden utilizar muchas herramientas diferentes para implementar las fitness functions, dependiendo de las características arquitectónicas. Por ejemplo, para probar aspectos de la modularidad existen fitness functions para detectar las dependencias cíclicas, calcular la distancia de la secuencia principal, etc.

Una herramienta de fitness functions interesante es NetArchTest.  Esta herramienta proporciona una variedad de reglas de gobierno predefinidas codificadas como pruebas de unidad y permite a los arquitectos escribir pruebas específicas que abordan la modularidad.

En resumen, las fitness functions permiten a los arquitectos codificar importantes comprobaciones de gobernabilidad para dar soporte a la arquitectura.

Enlaces:

Infraestructura como código y la entrega rápida de valor

Siguiendo con mi ruta de aprendizaje sobre DevOps, en esta oportunidad me gustaría explorar la práctica de Infraestructura como código (IaC). Para dar pie a esta exploración empecemos resaltando el siguiente principio del manifiesto ágil:

Entregamos software funcional frecuentemente...

Como developer, esto es importante tener en cuenta, pues es la razón por la cual nos contratan. No nos pagan sólo por escribir código, sino por entregar software que funcione y de valor al usuario. Entonces, ¿cómo podemos cumplir con este principio ágil? Optimizando nuestro Flujo de Valor.


El Flujo de Valor

Entregar software funcional frecuentemente implica recorrer un flujo, que en términos de Lean Manufacturing  se denomina Flujo de Valor (Value Stream). El Flujo de Valor se refiere a la secuencia de actividades requeridas para diseñar, producir y entregar un bien o dar un servicio a un cliente. 

En el año 2003 los hermanos Poppendieck tradujeron los principios de Lean Manufacturing al mundo del software. En este sentido, podemos ver nuestro trabajo cotidiano como un Flujo de Valor, un proceso donde partimos de una idea y la transformamos en una pieza de software que colocamos en un ambiente productivo para que el usuario la use.


En realidad, lo normal es que dentro de nuestro Flujo de Valor tengamos varios ambientes (environments) por donde nuestra pieza de software debe transitar (Ejemplo: Test,  UAT y production). Y cuando hablamos de ambientes, hablamos de infraestructura. Ya sabes: Operating Systems, servers, storage, networking, etc. Montar todos los ambientes necesarios para el desarrollo de tu proyecto puede implicar demasiado tiempo si se hace manualmente. 

Modelo de infraestructura propuesto por Sjaak Laan 

¿Cómo podemos gestionar nuestra infraestructura de manera efectiva y eficiente? ¿Cómo manejamos nuestros ambientes de cara a optimizar nuestro flujo de valor?

IaC al rescate

La mejor solución para gestionar nuestra infraestructura es eliminar las configuraciones manuales a través de la automatización. Para lograr esto debemos manejar nuestra infraestructura como código. 

La idea es escribir scripts que describan nuestra infraestructura, esto es código que puede ser versionado y ejecutado. De esta forma podemos reutilizar el script múltiples veces, eliminando la necesidad de realizar configuraciones manuales. También podemos replicar la misma configuración para diferentes ambientes (Ejemplo: Test, UAT y production).

Toda esta magia es posible gracias a herramientas como Kubernetes, Ansible, Puppet, Chef, Terraform, Salt, etc.

IaC y la nube

Producto de la aceleración de la transformación digital, ahora más que nunca, las empresas, independientemente de su tamaño, están adoptando Cloud Computing como parte de sus estrategia de TI para ofrecer servicios y productos a sus usuarios.


Transformación digital en los próximos años según IDC


El Cloud Computing nos brinda los recursos de infraestructura para nuestros sistemas y la práctica de IaC nos ayuda en el aprovisionamiento de dicha infraestructura. Un ejemplo de esto es Terraform, una herramienta que tiene soporte para varios proveedores de infraestructura en la nube: Amazon Web Services (AWS), Digital Ocean, Azure, VMware vSphere, son algunos ejemplos.


Finalmente...

En resumen, para optimizar nuestro flujo de valor (y por ende la entrega rápida de valor) es necesario tratar nuestra infraestructura como código para levantar ambientes y tenerlos bajo control. Una vez que tenemos nuestra infraestructura como código, el siguiente paso es hacer que nuestra pieza de software transite por los distintos ambientes hasta llegar a producción cuando el negocio lo necesite. Esta práctica es la denominada Continuous Delivery y será tema de otro artículo.

Enlaces interesantes


¡Gracias por llegar hasta aquí!

Meditaciones sobre seguridad de aplicaciones: explorando las bases

Hace poco tuve la oportunidad de asistir a una charla interesante sobre OAuth2, un mecanismo de autorización basado en un modelo de acceso por delegación. Más allá de cuan interesante fue la charla, lo que realmente me llamó la atención fue algo que dijo el expositor al principio:

La seguridad es a veces un tema complejo o árido de explicar.

Totalmente de acuerdo. Puede que esto sea una opinión rebatible, pero despertó mi curiosidad para explorar más sobre temas de seguridad de aplicaciones. Empecemos por las bases.

En mi trabajo como desarrollador, inevitablemente tengo lidiar con temas de seguridad: autenticación/autorización, hashing, encriptación, etc. Es decir, mis esfuerzos como desarrollador se orientan en implementar mecanismos para proteger datos y procesos computacionales de aplicaciones. Este me parece un buen inicio para seguir razonando sobre la seguridad.

No obstante, sé que mi visión de desarrollador sobre la seguridad puede ser acotada. Así que me gustaría dar un paso más explorando el concepto de la seguridad de la información según ISO 27001: 

La seguridad de la información consiste en la preservación de su confidencialidad, integridad y disponibilidad, así como de los sistemas implicados en su tratamiento, dentro de una organización.

ISO 27001:2013

En otras palabras, la información es segura o fiable cuando hay confidencialidad, integridad y disponibilidad. De esto se deduce que los ataques contra la seguridad de la información son ataques contra estos pilares.


¿Cómo proteger nuestra información contra los ataques? Existe un enfoque denominado defensa en profundidad el cual propone proteger la información a través de múltiples capas. 

Cada capa pone foco en las distintas áreas donde pueden ocurrir ataques. En cada una de estas se aplicarán diferentes controles de seguridad, tecnologías y funcionalidades. El conjunto de capas crea una protección profunda que complicará el trabajo del atacante para llegar a los procesos y datos.

Y para cerrar esta reflexión que va de lo particular a lo general, quisiera englobar todo lo anterior bajo el amplio concepto de Seguridad. Es interesante saber que existe la carrera en Ciencias de la Seguridad, la cual define la seguridad como:

Ciencia interdisciplinaria que está encargada de evaluar, estudiar y gestionar los riesgos que se encuentra sometido una persona, un bien o el ambiente.
Wikipedia

Una definición tan amplia como la vida misma. ¿Para qué evaluar, estudiar y gestionar los riesgos? Para reducirlos a niveles aceptables y así la persona, bien o ambiente pueda cumplir su misión.

Vaya, que amplio es todo esto. Creo que esta pequeña reflexión me sirvió para darme cuenta donde estoy parado respecto a la seguridad. Básicamente, mi trabajo se centra reducir los riesgos de que los atacantes hagan de las suyas rompiendo la integridad, confidencialidad y disponibilidad de datos y procesos de mis aplicaciones. Con esta conclusión creo que ya puedo cerrar este artículo y pensar en los próximos.

¡Gracias por llegar hasta aquí!






Usar Razor desde una aplicación de consola

 Para .NET podemos usar el componente RazorEngine:

Para .NET Core recomiendo revisar los siguientes artículos:


API Gateway with ASP.NET Core

Grandes preguntas: ¿Repites mucho código en cada nuevo microservicio? ¿Haces que tus frontends llamen múltiples endpoints para obtener lo qu...