Home » Escribiendo módulos de Terraform
developing with terraform

Escribiendo módulos de Terraform

En este artículo, explico el paso a paso de cómo crear módulos de Terraform. Si bien es una guía para principiantes, no he pasado por alto las buenas prácticas mínimas que a mi parecer todo programador de Terraform debe incluir en sus módulos.

Quizá, como muchos, ya has deseado estar escribiendo módulos de Terraform pero no tienes ni idea por dónde empezar. En muchos cursos o tutoriales la recomendación es siempre la misma: crea y usa módulos de Terraform.

Llevar esto a la práctica a veces no es tan sencillo, pero aquí estoy para ayudarte y poner las ideas en orden para poder empezar a desarrollar con confianza.

¿Llegaste aquí por casualidad pero aún no sabes qué es Terraform? Si es así, te recomiendo este artículo.

Sin más preámbulos, vamos a empezar.

Introducción

En este punto voy a asumir que ya tienes un concepto básico de Terraform y sabes la teoría sobre qué es un módulo y por qué se usan. Así que no daré mucha explicación detallada al respecto.

Sin embargo, vale resaltar lo más importante: Un módulo de Terraform es un conjunto de archivos organizados dentro de un directorio, bajo un nombre específico, creado para aprovisionar un cierto tipo de recurso o grupo de recursos. Los módulos están pensados para ser reutilizados, por ello deben ser flexibles. Asimismo, deben servir a un propósito específico y no pretender hacer demasiadas cosas, sino solo una o pocas cosas bien hechas.

Escribiendo módulos de Terraform paso a paso

Esta es una secuencia de pasos mínima que recomiendo y que, en base a mi experiencia, te permitirá repetir la misma fórmula con confianza una y otra vez.

Antes de empezar

En este artículo voy a tomar como ejemplo el uso del servicio AWS Secrets Manager, el cual es usado para gestionar secretos de forma segura en la nube de Amazon Web Services.

Por ende, se asume que el lector tiene ya una cuenta en AWS, con privilegios administrativos y credenciales IAM configuradas como variables de entorno (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION).

También es importante recalcar que se debe tener un conocimiento básico de cómo funciona el tipo de recurso cuyo módulo se quiere programar. Es decir, si nunca en la vida has usado el servicio Secrets Manager de AWS, quizá no sea bueno que intentes crear un módulo para el mismo. Antes, es recomendable que aprendas a usarlo, experimentes con él a través de la consola de Amazon y lo complementes con la lectura de documentación del servicio.

Por último, estoy incluyendo configuraciones basadas en las mejores prácticas en la industria, combinado con lo mejor de mi experiencia. Por ello, puede que las recomendaciones de este post difieran de lo aprendido en otro curso u otro recurso de Internet.

Paso 1 – Crear la estructura

Esto consiste en crear un directorio de trabajo, con un nombre que siga este formato:

terraform-PROVIDER-NOMBRE

Donde, PROVIDER es el nombre de un proveedor de Terraform (Ejm: google, aws, hashicorp, etc.) y NOMBRE es el nombre deseado para nuestro módulo. Todo debe estar en minúsculas y usando guiones como separador de palabras.

En nuestro caso, el módulo se llamará terraform-aws-secrets-manager

Una vez creado el directorio, se debe tener los siguientes archivos creados, por ahora en blanco:

  • main.tf
  • variables.tf
  • outputs.tf
  • versions.tf
  • README.md

Paso 2 – Documentar primero

Creo firmemente que la documentación es una parte imprescindible de todo proyecto y que ésta debe ser desarrollada al principio, al menos en un nivel básico como un bosquejo de lo que será el proyecto en el cual se va trabajar.

Y precisamente, de esto se trata RDD (Readme Driven Development), una metodología de desarrollo que enfatiza la creación de documentación clara y completa antes de escribir código, guiando así el proceso de desarrollo.

Sé que con las prácticas de Agilidad de hoy en día, mucho se ha ido dejando de lado la documentación. Pero adoptar RDD tampoco debe significar volver al antiguo modelo Waterfall con metologías como RUP donde se debía hacer una documentación extensiva y muy detallada antes de si quiera empezar a escribir una línea de código. No es necesario llegar a ese extremo, pero tampoco obviar la documentación por el solo hecho de pretender ser “ágiles”. Ningún extremo es bueno, así que en este punto documentaremos lo básico del módulo Terraform con un contenido en Markdown como sigue:

# Modulo Terraform de AWS Secrets Manager

## Descripción

Este modulo tiene por objetivo la creación de secretos en AWS Secrets Manager y gestiona también sus respectivas versiones.

## Observaciones

Este modulo es solo usado para fines prácticos. Tener en cuenta que al usar este modulo, se tendrá que escribir en texto plano el contenido de los secretos que se guardarán en Secrets Manager. Esto conlleva que el contenido del secreto (valor sensible) estará versionado en Git y esto es peligroso, además de ser una mala práctica.


## Recursos

El modulo crea dos recursos: el Secreto y la Versión.
El Secreto es la definición de configuración en Secrets Manager que contendrá los datos sensibles, pero no contiene el dato sensible en sí.
La Version es un texto sensible que se almacena como parte del recurso Secreto antes mencionado. Puede tenerse múltiples versiones en el tiempo.


## Uso

El módulo debe recibir como parámetros las opciones de configuración personalizada para los recursos de tipo Secreto y Version. Estos parámetros son especificados en texto plano.
Opcionalmente, el contenido del recurso Version (valor sensible) puede ser especificado en texto plano o codificado en base64 (lo cual no es sinónimo de cifrado o seguridad).
Además, el secreto debe estar en formato JSON si se desea que contenga diferentes campos como "usuario", "password" u otros atributos personalizados.

...
... (continúa, de ser necesario)

Paso 3 – Leer la documentación de los recursos

Ir al sitio de documentación del proveedor “aws” para Terraform y buscar por palabras clave como “secrets manager”. Se encontrará dos recursos que son estos:

  • aws_secretsmanager_secret
  • aws_secretsmanager_secret_version

Revisar la documentación de cada uno (aquí y acá) y centrarse en:

  1. Descripción breve, para confirmar si el recurso es lo que necesitamos o no
  2. Revisar e intentar entender los ejemplos (Ver aquí para este tipo de recurso específico)
  3. Dar una mirada rápida a todos los argumentos soportados y del tipo que son cada uno (Ver aquí para este tipo de recurso específico)
  4. Enfocarse en los argumentos obligatorios (Required)

Paso 4 – Codificar main.tf

Teniendo un poco más claro los recursos que vamos a empezar a codificar en Terraform, empezaremos con una definición mínima como la siguiente:

resource "aws_secretsmanager_secret" "this" {
  name        = "secret-01"
  description = "Mi secreto de prueba 01"

  tags = {
    creador = "arengifo"
    entorno = "sandbox"
  }
}

Algunos puntos importantes a analizar sobre el código:

  • Argumentos fijos: Temporalmente, es válido poner valores “en duro” mientras se inicia el desarrollo del módulo.
  • Nombre lógico del recurso “this”: Si en el código habrá solo una instancia de este tipo de recurso, o si no hay un mejor nombre que amerite usarse, es válido y recomendable llamarlo simplemente this. Aquí hay una mejor explicación sobre las reglas de nomenclatura de Terraform.

Ahora, vamos a inicializar Terraform dentro del directorio del módulo:

terraform init

Luego, validamos que la sintaxis sea correcta:

terraform validate

Ahora es bueno correr un primer plan:

terraform plan

Y por qué no, animarnos a correr un primer apply:

terraform apply -auto-approve

Verificamos en la consola AWS si se creó el secreto. Luego, procedemos a destruirlo antes de seguir codificando:

terraform destroy -auto-approve

Paso 5 – Codificar variables.tf

El módulo está pensado para ser reutilizado, por ello no es correcto definir los valores de los argumentos”en duro”. Es decir, el ejemplo de main.tf mostrado arriba, al tener argumentos con valores fijos, no permitirá ser reutilizado de forma flexible.

Por ello, es necesario actualizar el archivo main.tf y reemplazar los valores por variables, así:

resource "aws_secretsmanager_secret" "this" {
  name        = var.name
  description = var.description

  tags = var.tags
}

En este punto, puede ser buena idea que el nombre de las variables sea igual al de los argumentos. Por ejemplo, para el argumento name le corresponde var.name (variable de nombre name). Lo mismo para description y tags.

Pero, esas variables aún no existen, así que hay que crear su definición en el archivo variables.tf con este contenido:

variable "name" {
  description = "Nombre del recurso Secrets Manager"
  type        = string
}

variable "description" {
  description = "Descripción del recurso Secrets Manager"
  type        = string
  default     = null
}

variable "tags" {
  description = "Tags a asociar al recurso"
  type        = map(string)
  default     = {}
}

Puntos importantes a analizar de este código:

  • Sobre el tipo de dato: ¿Cómo saber si debe ser string u otro tipo distinto? Revisando la documentación del tipo de recurso Terraform. Usualmente sí dice, otras veces no. Se usa el criterio y la experiencia para intuir el tipo de dato correcto, sino se puede complementar con prueba y error.
  • Sobre el valor por defecto: ¿Cómo saber si debe tener un valor por defecto o no? Según la documentación del tipo de recurso y el criterio+experiencia del programador. ¿Se puede crear un recurso de este tipo sin asignarle un nombre? ¿Se puede crear un recurso de este tipo sin descripción? Nuevamente, la prueba y error será de gran ayuda.
  • Sobre la descripción: No es indispensable, pero sí altamente recomendable que toda variable tenga siempre una descripción. Si quieres hacer las cosas bien, no omitas una descripción clara de todas tus variables.

Ahora, toca volver a probar el código pero esta vez con las variables. Primero, revisamos la sintaxis y luego un plan:

terraform validate
terraform plan

Notarás que Terraform te pide ingresar manualmente el valor de la variable name:

terraform plan con ingreso manual de variable name

Para ahorrarte el trabajo de definir manualmente el valor de las variables en el teclado por cada ejecución de plan mientras desarrollas el módulo, define sus valores con variables de entorno de prefijo TF_VAR_ de este modo:

export TF_VAR_name="secret-002"
export TF_VAR_description="Esta variable podria ser omitida, si gustas"

Ahora, prueba un plan nuevamente.

Paso 6 – Codificar outputs.tf

En la documentación del recurso Terraform de interés, observar los atributos soportados. Para el ejemplo específico en el que trabajamos, puedes ver dicha información aquí.

Los atributos son datos informativos de un recurso que se pueden obtener para ser mostrados por los outputs de Terraform. Usualmente, es para fines informativos al mostrarse en pantalla, pero también para ser usados como entrada de otro tipo de recursos cuando se trabaja dependencias implícitas entre dos tipos de recursos distintos.

Creamos el archivo outputs.tf con un contenido como el siguiente:

output "name" {
  description = "Nombre del recurso Secret Manager creado"
  value = aws_secretsmanager_secret.this.name
}

output "id" {
  description = "ID del recurso Secret Manager creado"
  value = aws_secretsmanager_secret.this.id
}

output "arn" {
  description = "ARN del recurso Secret Manager creado"
  value = aws_secretsmanager_secret.this.id
}

Algunos puntos a resaltar de este código:

  • Descripción: Igual que en las variables, la descripción es opcional pero altamente recomendada.
  • Valor: Se hace una referencia específica al tipo de recurso y su nombre lógico, seguido del nombre del atributo, tal como lo documenta Terraform.
  • Cantidad de outputs: Quizá este tipo de recurso soporta 3, 10 o más atributos. No tenemos necesidad de exponer o mostrar todos ellos en los outputs, sino solo los que por ahora consideremos importantes para informar al ejecutor de Terraform. Con la práctica+experiencia, se sabrá mejor cuándo y cuáles atributos exponer en este archivo.

Volvemos a validar la sintaxis y corremos un plan:

terraform validate

terraform plan

Debemos asegurarnos que ahora se muestra una sección de outputs en pantalla como parte del plan:

salida de terraform plan con outputs incluidos

¿Qué te parece el artículo hasta ahora? ¿Ahora ya te sientes más cómodo escribiendo módulos de Terraform? No te desanimes, aún hay más por aprender. Sigue leyendo.

Paso 7 – Extender codificación e iterar

En este punto, ya tenemos un módulo básico que crea un recurso de tipo Secrets Manager con Terraform. Los valores de configuración del recurso se configuran con argumentos basados en variables y se muestra información en pantalla de los atributos clave tras la creación del recurso con una operación apply.

Ahora es momento de extender el código y hacerlo más funcional, incluir argumentos adicionales para soportar funcionalidades extra e integrarlo con otros recursos necesarios. Por ejemplo, podemos ahora centrarnos en:

  • Agregar soporte para activar el cifrado con KMS
  • Personalizar los días máximos de recuperación del secreto tras su eliminación.
  • Agregar la configuración para crear el recurso Versión que contiene el dato sensible a almacenar en Secrets Manager.
  • Agregar soporte para replicar el recurso Secreto en otra región.

Para lograr estos puntos arriba mencionados, se requiere leer en detalle la documentación de los recursos. Pero, dejaré aquí un ejemplo de cómo luciría el código con las modificaciones solicitadas.

resource "aws_secretsmanager_secret" "this" {
  name                    = var.name
  description             = var.description

  # Plazo de recuperacion tras eliminacion del secreto
  recovery_window_in_days = var.recovery_window_in_days

  # Soporte para cifrado con KMS
  kms_key_id              = var.kms_key_id

  dynamic "replica" {
    for_each = var.replica.enabled ? ["una-vez"] : []

    content {
      kms_key_id = var.replica.kms_key_id
      region     = var.replica.region
    }
  }

  tags = var.tags
}

resource "aws_secretsmanager_secret_version" "this" {
  secret_id      = aws_secretsmanager_secret.this.id
  secret_string  = var.secret_string
  version_stages = var.version_stages
}
# Archivo variables.tf
variable "name" {
  description = "Nombre del recurso Secrets Manager"
  type        = string
}

variable "description" {
  description = "Descripción del recurso Secrets Manager."
  type        = string
  default     = null
}

variable "tags" {
  description = "Tags a asociar al recurso"
  type        = map(string)
  default     = {}
}

variable "recovery_window_in_days" {
  description = "Cantidad de dias despues de la eliminacion de un secreto en que puede recuperarse aun, antes de ser eliminado definitivamente"
  type        = number
  default     = 30
}

variable "kms_key_id" {
  description = "ARN de la llave KMS usada para cifrar el contenido del secreto. Si se deja como null, se usa por defecto la llave de AWS (aws/secretsmanager)"
  type        = string
  default     = null
}

variable "replica" {
  description = "Configuracion de replicacion del secreto a otra region"
  type = object({
    enabled    = optional(bool, false)
    region     = optional(string, null)
    kms_key_id = optional(string, null)
  })
  default = {}
}

variable "secret_string" {
  description = "Contenido del secreto en texto plano"
  type        = string
  default     = null
}

variable "version_stages" {
  description = "Lista de etiquetas staging usadas para identificar versiones unicas del secreto."
  type        = list(string)
  default     = ["AWSCURRENT"]
}
# Archivo outputs.tf
output "name" {
  description = "Nombre del recurso Secret Manager creado"
  value = aws_secretsmanager_secret.this.name
}

output "id" {
  description = "ID del recurso Secret Manager creado"
  value = aws_secretsmanager_secret.this.id
}

output "arn" {
  description = "ARN del recurso Secret Manager creado"
  value = aws_secretsmanager_secret.this.id
}

output "replica" {
  description = "Atributos de la replica del secreto"
  value       = aws_secretsmanager_secret.this.replica
}

output "version_id" {
  description = "Identificador unico de la version del secreto"
  value       = aws_secretsmanager_secret_version.this.version_id
}

En este punto es donde se debe empezar a iterar entre los pasos 4, 5, 6 y 7. Es un proceso continuo que consiste en:

  • Empezar a codificar con funcionalidades mínimas del módulo
  • Revisar sintaxis, probar plan, crear, destruir y seguir codificando
  • Extender más funcionalidades mientras se sigue probando
  • Prueba de ensayo y error
  • Repetir el ciclo

Llegará un punto tal en el que nos sintamos satisfechos con un nivel de funcionalidad y madurez en el módulo como para creer que ya está listo para ser usado en un escenario real, “en la práctica”.

Aquí es preciso recalcar que cuando estemos escribiendo módulos de Terraform no debemos enfocarnos en incluir todas las funcionalidades posibles que soportan los recursos. Algunos de ellos tienen decenas de opciones, con múltiples casos de uso, sintaxis especiales, bloques de código especiales y condiciones que no siempre serán aplicables a nuestro entorno. Y no solo eso, algunas veces la documentación de los recursos no es tan buena y nos puede costar trabajo entenderla. Por todo esto, es recomendable agregar solo las funcionalidades requeridas en el presente. En un futuro, si se necesita, se irán agregando más funcionalidades.

Paso 8 – Codificar versions.tf

Ya nos acercamos al final. Como habrás notado, en poco tiempo ya estás escribiendo módulos de Terraform de una forma ordenada, clara y eficiente. Por ello, es muy importante incluir en el archivo versions.tf la información que indica las versiones mínimas y/o máximas del binario de Terraform y sus providers para garantizar que este módulo funcione bien.

El contenido del archivo versions.tf puede lucir así:

terraform {
  required_version = ">= 1.4, <= 1.5.5"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

Puntos a rescatar de este código mostrado arriba:

  • Binario de Terraform: La versión con la cual se ha probado el código debe ser por lo menos una versión reciente, que tenga quizá no más de 1 año de antigüedad y por lo menos una o dos versiones más antiguas de la última disponible en la Web del fabricante.
  • Provider de Terraform: De modo similar al binario de Terraform, se debe incluir la versión mínima recomendada del provider para garantizar un buen funcionamiento del módulo y con la cual la hayamos probado.

Paso 9 – Crear ejemplo de uso

Se dice que la Infraestructura como Código de por sí es una excelente forma de documentación, pues con un lenguaje claro y simple, se puede entender cómo luce nuestra infraestructura y cómo debe comportarse ante el cambio en uno de sus argumentos. Además, las variables y outputs juegan un papel crucial también al tener argumentos de descripción que complementan la documentación.

Sin embargo, lo antes mencionado no es suficiente. ¿Por qué? La realidad es que un código de Terraform pequeño, como el mostrado en este artículo, quizá se entienda por sí solo. Pero, en la práctica, los módulos de Terraform tienden a aumentar en númeor y tamaño, además de hacerse más extensos y complejos con el paso del tiempo y la necesidad de hacerlos más flexibles para diferentes casos de uso. Si a ello le sumamos el uso de expresiones complejas (for_each, count, data sources, variables de tipo objeto con atributos anidados, dependencias implícitas, funciones, expresiones if-then-else de una sola línea, locales, etc.), entonces las probabilidades que el módulo se deje entender por sí solo son menores.

Por todo lo antes expuesto, es indispensable -por no decir obligatorio- crear ejemplos como parte de la documentación del módulo. Esto se hace dentro de un directorio examples/ y dentro uno o más subdirectorios, cada uno con nombres cortos que expliquen el tipo o propósito del ejemplo. La cantidad de ejemplos lo debe determinar el programador del módulo en función de la cantidad de argumentos y distintas formas de uso que soporte.

Es así que vamos a crear un ejemplo llamado “basic”, en el directorio examples/basic/ donde se cree estos archivos:

  • main.tf (ver contenido debajo)
  • variables.tf (vacío)
  • outputs.tf (ver contenido debajo)
  • versions.tf (ver contenido debajo)
  • README.md (ver contenido debajo)

Este ejemplo “basic” debe mostrarnos cómo usar el módulo con las opciones mínimas. Veamos cómo lucen sus archivos de configuración.

# Archivo examples/basic/main.tf
module "basic_secret" {
  source = "../../"

  name          = "secreto-test-01"
  description   = "Secreto de ejemplo basic"
  secret_string = "zVyA9FkMBjnXVmze4wD4t9HwzT9FYV"
}
# Archivo examples/basic/outputs.tf
output "name" {
  description = "Nombre del recurso Secret Manager creado"
  value       = module.basic_secret.name
}

output "id" {
  description = "ID del recurso Secret Manager creado"
  value       = module.basic_secret.id
}

output "arn" {
  description = "ARN del recurso Secret Manager creado"
  value       = module.basic_secret.arn
}

output "replica" {
  description = "Atributos de la replica del secreto"
  value       = module.basic_secret.replica
}

output "version_id" {
  description = "Identificador unico de la version del secreto"
  value       = module.basic_secret.version_id
}
# Archivo examples/basic/versions.tf
terraform {
  required_version = ">= 1.4, <= 1.5.5"
}
# Ejemplo básico de secreto en Secrets Manager

Este directorio contiene un ejemplo de como crear un recurso Version de secreto en Secrets Manager con su contenido definido en texto plano en el código.

## ¿Cómo se prueba este ejemplo?

Para probar este ejemplo, simplemente aplica los cambios con apply.

#### Aplicando los cambios

Para aplicar los cambios, sigue estos pasos:

1. Instala [Terraform](https://www.terraform.io/)
2. Ejecuta `terraform get`.
3. Ejecuta `terraform plan`.
4. Si el plan luce bien, ejecuta `terraform apply`.

Algunas observaciones importantes del código mostrado arriba:

  • Dado que es un ejemplo, sí se considera válido el usar valores “en duro” dentro de main.tf. Es inclusive recomendado para facilitar la lectura y entendimiento sin tener la necesidad de ir a buscar los valores en variables.tf (razón por la cual se deja vacío dicho archivo).
  • En módulos complejos, podría tener sentido combinar algunos valores “en duro” en main.tf y otros usarlos como variables en variables.tf si es que eso facilita la comprensión de uso del módulo a otra persona.
  • El archivo versions.tf ya no define required_providers porque el main.tf no crea directamente ningún recurso de AWS, sino que solo interactúa con el módulo a través de argumentos.
  • Los outputs son los mismos declarados en el módulo, pero se reemplazó las referencias al recurso con referencias a la instancia de módulo definido en main.tf.

Ahora, dentro del directorio de este primero ejemplo, examples/basic/, se debe ejecutar las mismas operaciones validate, plan, apply y destroy para asegurarnos que todo funciona correctamente.

Luego, podemos pensar en agregar un 2do o 3er ejemplo con variantes de uso del módulo. Por ejemplo, uno llamado “basic-with-replica” (o un nombre en español si se prefiere) donde se configure replicación hacia otra región. Otro más podría llamarse “basic-with-json-data” que muestre cómo crear un secreto con campos de tipo “user” y “password” en un formato JSON.

En resumen, debe realizarse todos los esfuerzos posibles para documentar el módulo teniendo en mente que nosotros no seremos siempre quien mantenga el módulo en el tiempo, ni el único que lo use en el día a día.

Por último y esta es la razón más importante de la creación de ejemplos: Posteriormente, cuando seamos más maduros en el desarrollo de módulos con Terraform, los ejemplos se usarán para alimentar las pruebas o tests que se deben hacer con herramientas como Terratest. Sin embargo, esto será materia de otro artículo separado que publicaré en un futuro.

Paso 10 – Versiona los cambios en Git

Todo el esfuerzo y trabajo que hiciste en este módulo debe versionarse con Git, sí o sí. Para ello, es recomendable crear un repositorio Git dedicado con el mismo nombre del módulo. Es decir, nuestro repositorio se llamaría “terraform-aws-secrets-manager”.

Ya sea que uses GitHub, GitLab, BitBucket o cualquier otra opción, los pasos a seguir deben ser los mismos:

  1. Agrega el contenido del repositorio a un feature branch local.
  2. Confirma y publica los cambios en el servidor remoto de Git.
  3. Crea un Pull Request, pide revisión y aprobación.
  4. Fusiona el branch contra el principal (Ejm: master)
  5. Crea un tag con versionamiento semántico para el módulo (Ejm: 1.0.0)
  6. Asegúrate de que estén activas las reglas de protección del branch master para evitar cambios accidentales o no autorizados al módulo.

Conclusión

“Escribiendo módulos con Terraform” es el primer artículo que escribo con este gran tamaño y creo que lo amerita por el nivel de detalle en las explicaciones y ejemplos incluidos aquí.

Hemos visto una secuencia ordenada, paso a paso, de cómo empezar desde cero a escribir un módulo de Terraform mientras se mantiene en uso las mejores prácticas en cada paso. A pesar de ser una guía de aprendizaje para principiantes, no quise dejar de lado importantes detalles que algunos podrían considerar irrelevantes, pero yo decidí enfocarme en la calidad para que puedas producir un producto excelente. Esto puede requerir un esfuerzo extra (como el adoptar RDD, o documentar ejemplos), pero más temprano que tarde se notará el efecto positivo de tal sacrificio.

Lo anterior no quiere decir que esta guía contiene todas las buenas prácticas para desarrollar módulos, pero sí lo que considero esencial. ¿Qué más hay por agregar? Pues, aspectos como el uso de herramientas de análisis estático, escaneos de seguridad, automatización en la documentación, desarrollo de pruebas, entre otras cosas más. Todo eso será materia de próximos artículos que iré publicando en un futuro cercano.

¿Qué te pareció el artículo? ¿Valió la pena la lectura extensa? Espero que sí. Apóyame compartiendo este post y hazme llegar tus comentarios.

Hasta la próxima

Post navigation

Deja un comentario

Agregue un comentario

Su dirección de correo no se hará público. Los campos requeridos están marcados *