Saltar al contenido principal

Roles y Ansible Galaxy 📦

Hasta ahora has escrito playbooks lineales. Cuando un proyecto crece, esos ficheros se vuelven inmanejables. En este capítulo aprendes a modularizar tu código con roles, reutilizar trabajo de la comunidad con Ansible Galaxy y aplicar buenas prácticas que mantendrán tu repositorio sano a largo plazo.

Los roles usan templates Jinja2 para generar configuraciones dinámicas — si necesitas repasar la sintaxis de Jinja2, vuelve al módulo 4.

📋 Contenido del capítulo

  1. Roles y modularidad — Estructura de un rol, cómo crearlos y consumirlos.
  2. Ansible Galaxy y Collections — Compartir y consumir contenido de la comunidad.

Roles y modularidad 📦

Organiza tu código como un profesional usando la estructura de roles.

Video pendiente de grabación

Introducción: ¿por qué roles?

Hasta ahora, hemos escrito playbooks que son listas largas de tareas. Esto funciona bien para 10 o 20 tareas, pero ¿qué pasa cuando tienes 500? ¿O cuando quieres configurar Nginx en 10 proyectos diferentes?

🍝 La analogía: código espagueti vs. librerías

Imagina un libro de 1000 páginas sin capítulos ni índice. Eso es un playbook gigante. Es difícil de leer, difícil de mantener y casi imposible de reutilizar.

Los roles son como las "habilidades" en un videojuego.

  • Tienes un personaje (servidor).
  • Quieres que sepa hacer magia (servidor web).
  • En lugar de enseñarle los movimientos uno a uno cada vez, le equipas el libro de hechizos "Mago de Fuego" (rol webserver).
  • ¡Pum! Ahora sabe lanzar bolas de fuego (instalar nginx, configurar vhosts, abrir puertos) automáticamente.

La estructura de un rol

Ansible espera una estructura de carpetas muy específica. Si la respetas, la magia ocurre sola (autoloading).

🌳 Anatomía visual

Diccionario de carpetas

  • tasks/: Aquí van los módulos (apt, copy, service). Es lo que antes tenías en la sección tasks: del playbook.
  • handlers/: Los disparadores (restart nginx).
  • templates/: Tus archivos .j2.
  • files/: Archivos que se copian tal cual (certificados, imágenes).
  • defaults/: Variables con la prioridad más baja. Están hechas para ser sobrescritas fácilmente por el usuario del rol.
  • vars/: Variables con prioridad alta. Úsalas para constantes que rara vez cambian.
  • meta/: Metadatos del rol: información del autor, licencia y dependencias de otros roles.

Manos a la obra: creando tu primer rol

Vamos a refactorizar. Tomaremos el "código espagueti" de un servidor web y lo convertiremos en un rol elegante.

Paso 1: inicializar la estructura

Ansible tiene un comando para crear el esqueleto por ti:

ansible-galaxy init webserver

Paso 2: mover las piezas (refactorización)

Supongamos que tenías este playbook espagueti que despliega varios contenedores:

# old_playbook.yml (espagueti) ❌
- hosts: servers
become: true
tasks:
- name: Desplegar PostgreSQL
community.docker.docker_container:
name: postgres
image: postgres:16-alpine
state: started
restart_policy: unless-stopped
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: changeme
POSTGRES_DB: quotes

- name: Desplegar quotes API
community.docker.docker_container:
name: quotes
image: pabpereza/quotes:latest
state: started
restart_policy: unless-stopped
ports:
- "8000:8000"
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: changeme
POSTGRES_HOST: postgres
POSTGRES_DB: quotes

Cuando necesitas desplegar quotes en tres entornos distintos, copias y pegas esas tareas cada vez. Cuando quieres cambiar la versión de la imagen, buscas en 10 ficheros. Eso es espagueti.

Ahora, "descuartizamos" las tareas de Nginx y ponemos cada cosa en su lugar dentro de la carpeta webserver/:

1. roles/webserver/tasks/main.yml

- name: Desplegar contenedor web
community.docker.docker_container:
name: "{{ container_name }}"
image: "{{ container_image }}"
state: started
restart_policy: unless-stopped
ports:
- "{{ container_port }}:80"
volumes:
- "{{ html_root }}:/usr/share/nginx/html:ro"
notify: Recrear contenedor

2. roles/webserver/handlers/main.yml

- name: Recrear contenedor
community.docker.docker_container:
name: "{{ container_name }}"
image: "{{ container_image }}"
state: started
restart_policy: unless-stopped
recreate: true

3. roles/webserver/defaults/main.yml

container_name: web
container_image: nginx:1.27-alpine
container_port: 80
html_root: /srv/web/html

Paso 3: el resultado final (limpio y profesional)

Tu playbook principal (site.yml) ahora queda así de minimalista:

# site.yml (modular) ✅
- hosts: servers
roles:
- webserver

¡Y si mañana quieres usar una imagen distinta, cambias container_image en un sitio y listo! Puedes usar el rol webserver en cualquier proyecto simplemente añadiéndolo a tu requirements.yml.

Dependencias entre roles

Los roles pueden depender de otros roles. Por ejemplo, si tu rol quotes necesita que primero esté corriendo el contenedor de base de datos y el proxy inverso, puedes declarar estas dependencias en el archivo meta/main.yml.

🔗 Ejemplo de dependencias

roles/quotes/meta/main.yml

dependencies:
- role: postgres
vars:
postgres_password: "secreto123"
db_port: 5432

- role: webserver
vars:
container_image: pabpereza/quotes:latest
container_port: 8000

¿Cómo funciona?

  1. Cuando ejecutas el rol quotes, Ansible primero levanta database_container y luego webserver.
  2. Los roles se ejecutan solo una vez, aunque múltiples roles los tengan como dependencia.
  3. Puedes pasar variables específicas a cada dependencia usando vars:.

Usar roles en playbooks con dependencias

# site.yml
- hosts: servers
roles:
- quotes # Ejecutará postgres → webserver → quotes

💡 Buenas prácticas

  • No abuses: Si tienes 10 niveles de dependencias, algo está mal en tu diseño.
  • Documenta: Siempre indica en el README qué roles son prerequisitos.
  • Versiona: Si usas roles de Galaxy, fija las versiones en requirements.yml.

Ansible galaxy y collections

No reinventes la rueda. Probablemente alguien ya ha creado el rol perfecto para instalar Docker, Kubernetes o MySQL.

🌌 Ansible galaxy (el "app store")

Es el repositorio oficial de contenido comunitario.

  • Buscar roles: ansible-galaxy search elasticsearch
  • Instalar un rol: ansible-galaxy install geerlingguy.elasticsearch

📦 Content collections (el nuevo estándar)

Antiguamente, Galaxy solo tenía roles. Ahora, con la complejidad de la nube, usamos collections. Una collection es un paquete que incluye: roles + módulos + plugins.

Por ejemplo, la collection amazon.aws incluye módulos para EC2, S3, Lambda, etc.

Comandos esenciales
# Instalar una colección
ansible-galaxy collection install amazon.aws

# Listar lo que tienes instalado
ansible-galaxy collection list
Usando collections en un playbook
- hosts: localhost
collections:
- amazon.aws # Declaramos que usaremos esta colección
tasks:
- name: Crear instancia EC2
ec2_instance: # Módulo que viene dentro de la colección
instance_type: t2.micro

Resumen

  1. Divide y vencerás: Usa roles para separar responsabilidades.
  2. Estandariza: Respeta la estructura de carpetas (tasks, vars, templates) para que cualquiera entienda tu código.
  3. Reutiliza: Antes de escribir código, busca en Ansible Galaxy. Si tienes que escribirlo, hazlo pensando en que sea un rol genérico para el futuro.
  4. Declara dependencias: Usa meta/main.yml para especificar qué roles necesita tu rol antes de ejecutarse.

Ansible Galaxy y Collections 🌌

Aprende a reutilizar código de la comunidad y a compartir tus propios roles con el mundo.

¿Qué es Ansible Galaxy?

🌟 La analogía: el "App Store" de Ansible

Imagina que necesitas configurar un servidor con Docker. Podrías escribir todas las tareas desde cero (instalar dependencias, añadir repositorios, configurar el daemon, etc.), o simplemente descargar un rol ya probado y mantenido por la comunidad.

Ansible Galaxy es el repositorio oficial donde miles de desarrolladores comparten roles, collections y plugins listos para usar.

🎯 Ventajas de usar Galaxy

  • Ahorro de tiempo: No reinventes la rueda. Usa roles probados en producción.
  • Calidad: Los roles populares tienen miles de descargas y están bien mantenidos.
  • Estandarización: Aprende buenas prácticas viendo código de expertos.
  • Comunidad: Contribuye con mejoras y reporta bugs.

🌐 Galaxy vs Collections

  • Galaxy (tradicional): Repositorio de roles individuales.
  • Collections (moderno): Paquetes que incluyen roles + módulos + plugins + documentación.

Buscando roles en Galaxy

🔍 Búsqueda desde línea de comandos

# Buscar roles relacionados con "docker"
ansible-galaxy search docker

# Buscar con un término más específico
ansible-galaxy search mysql --author geerlingguy

# Ver detalles de un rol específico
ansible-galaxy info geerlingguy.docker

📊 Output de ejemplo

$ ansible-galaxy search nginx

Found 523 roles matching your search:

Name Description
---- -----------
geerlingguy.nginx Nginx installation for Linux
jdauphant.nginx Install and configure nginx
nginxinc.nginx Official NGINX role
...

🌐 Búsqueda en la web

La forma más cómoda es buscar en galaxy.ansible.com:

  • Filtros: Por plataforma (Ubuntu, CentOS, etc.), categoría, autor.
  • Métricas: Descargas, estrellas, fecha de última actualización.
  • Documentación: README, dependencias, versiones compatibles.

💡 Criterios para elegir un buen rol

Criterio¿Qué buscar?
PopularidadMás de 1000 descargas, estrellas altas
MantenimientoÚltima actualización reciente (< 6 meses)
CompatibilidadSoporta tu distribución y versión de Ansible
DocumentaciónREADME completo con ejemplos
LicenciaOpen source (MIT, Apache, BSD)

Instalando roles desde Galaxy

📥 Instalación básica

# Instalar un rol (se guarda en ~/.ansible/roles/)
ansible-galaxy install geerlingguy.docker

# Instalar en una ruta específica
ansible-galaxy install geerlingguy.nginx -p ./roles/

# Instalar una versión específica
ansible-galaxy install geerlingguy.mysql,3.4.0

📦 Usando requirements.yml

Para proyectos profesionales, nunca instales roles manualmente. Usa un archivo requirements.yml para documentar todas las dependencias.

requirements.yml

# Roles desde Galaxy
roles:
- name: geerlingguy.docker
version: 6.1.0

- name: geerlingguy.nginx
version: 3.1.4

- name: geerlingguy.mysql
version: 4.3.3

- name: geerlingguy.redis
version: 1.8.0

# Collections
collections:
- name: community.general
version: 8.1.0

- name: ansible.posix
version: 1.5.4

- name: amazon.aws
version: 7.1.0

🚀 Instalación desde requirements.yml

# Instalar todos los roles y collections del archivo
ansible-galaxy install -r requirements.yml

# Forzar reinstalación (útil para actualizar)
ansible-galaxy install -r requirements.yml --force

# Instalar en ruta específica
ansible-galaxy install -r requirements.yml -p ./roles/

🔗 Instalando desde Git

Puedes instalar roles directamente desde repositorios Git (GitHub, GitLab, etc.):

requirements.yml

roles:
# Desde GitHub
- src: https://github.com/usuario/mi-rol.git
name: mi_rol_custom
version: main # Branch, tag o commit

# Desde GitLab
- src: git@gitlab.com:empresa/rol-interno.git
name: rol_interno
scm: git

# Desde Galaxy con nombre personalizado
- src: geerlingguy.apache
name: apache_role
version: 3.2.0

Usando roles instalados en playbooks

Una vez instalados, los roles se usan como cualquier otro rol local:

📝 Ejemplo: playbook con roles de Galaxy

site.yml

- name: Configurar servidor web con roles de Galaxy
hosts: servers
become: true

vars:
# Variables para geerlingguy.docker
docker_users:
- deployer
- jenkins

# Variables para geerlingguy.nginx
nginx_vhosts:
- listen: "80"
server_name: "ejemplo.com www.ejemplo.com"
root: "/var/www/ejemplo"

roles:
- geerlingguy.docker
- geerlingguy.nginx
- geerlingguy.certbot

post_tasks:
- name: Verificar que Docker está corriendo
service:
name: docker
state: started

🔧 Sobrescribiendo variables de roles

Los roles de Galaxy suelen tener muchas variables configurables. Revisa su documentación:

# Ver variables disponibles de un rol
cat ~/.ansible/roles/geerlingguy.docker/defaults/main.yml

# O en GitHub:
# https://github.com/geerlingguy/ansible-role-docker#role-variables

Ejemplo de sobrescritura:

- hosts: servers
roles:
- role: geerlingguy.mysql
vars:
mysql_root_password: "secreto123"
mysql_databases:
- name: wordpress
encoding: utf8mb4
mysql_users:
- name: wpuser
password: "pass123"
priv: "wordpress.*:ALL"

Collections: el nuevo estándar

📦 ¿Qué es una Collection?

Una collection es un paquete que puede incluir:

  • Roles: Como los tradicionales
  • Módulos: Nuevas funcionalidades (aws_ec2, docker_container)
  • Plugins: Filtros, callbacks, inventarios
  • Documentación: Guías y ejemplos

🌍 Collections oficiales importantes

CollectionDescripciónEjemplo de uso
community.generalMódulos generales de la comunidadtimezone, snap, git_config
ansible.posixHerramientas POSIX/Unixmount, sysctl, firewalld
amazon.awsServicios de AWSec2, s3, rds, lambda
azure.azcollectionMicrosoft Azureazure_rm_virtualmachine
google.cloudGoogle Cloud Platformgcp_compute_instance
community.dockerGestión de Dockerdocker_container, docker_image
community.mysqlBase de datos MySQLmysql_db, mysql_user
community.kubernetesKubernetes/K8sk8s, helm

📥 Instalando collections

# Instalar una collection
ansible-galaxy collection install community.general

# Instalar versión específica
ansible-galaxy collection install amazon.aws:7.1.0

# Instalar desde requirements.yml
ansible-galaxy collection install -r requirements.yml

# Listar collections instaladas
ansible-galaxy collection list

# Ver información de una collection
ansible-galaxy collection info community.docker

🗂️ Ubicación de collections

Las collections se instalan en:

  • Sistema: /usr/share/ansible/collections/
  • Usuario: ~/.ansible/collections/ansible_collections/
  • Proyecto: ./collections/ansible_collections/

📝 Usando collections en playbooks

Opción 1: Declarar a nivel de play

- name: Gestionar AWS EC2
hosts: localhost
collections:
- amazon.aws # Todos los módulos de esta collection están disponibles

tasks:
- name: Crear instancia EC2
ec2_instance: # Módulo de amazon.aws
name: target1
instance_type: t3.micro
image_id: ami-0c55b159cbfafe1f0
region: us-east-1
key_name: mi-llave
state: running

Opción 2: Usar FQCN (Fully Qualified Collection Name)

- name: Gestionar Docker
hosts: servidores
tasks:
- name: Crear contenedor Nginx
community.docker.docker_container: # FQCN completo
name: nginx
image: nginx:latest
ports:
- "80:80"
state: started

- name: Configurar timezone
community.general.timezone: # FQCN completo
name: Europe/Madrid

Recomendación: Usa FQCN para evitar conflictos si dos collections tienen módulos con el mismo nombre.

Creando y publicando tu propio rol

🛠️ Paso 1: Inicializar el rol

# Crear estructura del rol
ansible-galaxy init webserver

# Estructura generada:
# webserver/
# ├── README.md
# ├── defaults/
# │ └── main.yml
# ├── files/
# ├── handlers/
# │ └── main.yml
# ├── meta/
# │ └── main.yml
# ├── tasks/
# │ └── main.yml
# ├── templates/
# ├── tests/
# │ ├── inventory
# │ └── test.yml
# └── vars/
# └── main.yml

📝 Paso 2: Escribir el código del rol

tasks/main.yml

- name: Desplegar contenedor web
community.docker.docker_container:
name: "{{ container_name }}"
image: "{{ container_image }}"
state: started
restart_policy: unless-stopped
ports:
- "{{ container_port }}:80"
volumes:
- "{{ html_root }}:/usr/share/nginx/html:ro"
env: "{{ container_env | default({}) }}"
notify: Recrear contenedor

defaults/main.yml

container_name: web
container_image: nginx:1.27-alpine
container_port: 80
html_root: /srv/web/html
container_env: {}

handlers/main.yml

- name: Recrear contenedor
community.docker.docker_container:
name: "{{ container_name }}"
image: "{{ container_image }}"
state: started
restart_policy: unless-stopped
recreate: true

📄 Paso 3: Documentar en meta/main.yml

meta/main.yml

galaxy_info:
author: Tu Nombre
description: Despliegue de Nginx como contenedor Docker
company: Tu Empresa (opcional)
license: MIT
min_ansible_version: "2.14"

platforms:
- name: Ubuntu
versions:
- focal
- jammy
- name: Debian
versions:
- bullseye
- bookworm

galaxy_tags:
- docker
- containers
- web
- nginx

dependencies: []

✍️ Paso 4: Escribir README.md completo

README.md

# Rol Ansible: webserver

Despliega Nginx como contenedor Docker en servidores Linux.

## Requisitos

- Ansible >= 2.14
- Colección `community.docker` instalada (`ansible-galaxy collection install community.docker`)
- Docker instalado en los hosts destino

## Variables

| Variable | Default | Descripción |
|----------|---------|-------------|
| `container_name` | `web` | Nombre del contenedor |
| `container_image` | `nginx:1.27-alpine` | Imagen Docker |
| `container_port` | `80` | Puerto externo |
| `html_root` | `/srv/web/html` | Directorio con el HTML estático |
| `container_env` | `{}` | Variables de entorno del contenedor |

## Ejemplo de uso

```yaml
- hosts: servers
roles:
- role: webserver
vars:
container_name: mi_sitio
container_port: 8080
html_root: /data/html

Licencia

MIT

Autor

Tu Nombre (@tu_usuario)


#### 🧪 Paso 5: Probar el rol localmente

```bash
# Ejecutar el test incluido
ansible-playbook tests/test.yml -i tests/inventory

# O crear un playbook de prueba
cat > test-rol.yml <<EOF
- hosts: localhost
become: true
roles:
- webserver
EOF

ansible-playbook test-rol.yml

📤 Paso 6: Publicar en Galaxy

6.1. Subir a GitHub

cd webserver
git init
git add .
git commit -m "Versión inicial"
git remote add origin https://github.com/tu_usuario/ansible-role-webserver.git
git push -u origin main

# Crear un tag de versión
git tag 1.0.0
git push origin 1.0.0

6.2. Importar en Galaxy

  1. Ve a galaxy.ansible.com
  2. Inicia sesión con GitHub
  3. Ve a "My Content" → "Add Content"
  4. Selecciona tu repositorio ansible-role-apache
  5. Galaxy importará automáticamente tu rol

6.3. Actualizar versiones

# Hacer cambios en el código
git add .
git commit -m "Añadida compatibilidad con SSL"
git tag 1.1.0
git push origin main --tags

# Galaxy detectará el nuevo tag automáticamente

Buenas prácticas con Galaxy

✅ DO:

  • Fija versiones en requirements.yml: Evita sorpresas con actualizaciones.
  • Lee el README antes de instalar: Entiende qué hace el rol.
  • Revisa el código: Especialmente en roles con pocos downloads.
  • Contribuye con issues y PRs: Ayuda a mejorar los roles que usas.
  • Usa FQCN en collections: Mayor claridad y evita conflictos.

❌ DON'T:

  • No uses roles sin mantenimiento: Busca alternativas activas.
  • No instales sin probar primero: Usa --check mode.
  • No expongas credenciales: Usa Ansible Vault para secretos.
  • No dependas de un solo rol: Ten un plan B si el autor lo abandona.

🔒 Seguridad

# Verificar el código antes de ejecutar
cat ~/.ansible/roles/nombre_rol/tasks/main.yml

# Ejecutar en modo dry-run
ansible-playbook site.yml --check

# Limitar a un host de pruebas primero
ansible-playbook site.yml --limit test-server

Creando tu propia collection

🎯 Cuándo crear una collection

Crea una collection cuando tengas:

  • Múltiples roles relacionados
  • Módulos personalizados
  • Plugins o filtros custom
  • Documentación extensa

🛠️ Inicializar collection

# Crear estructura de collection
ansible-galaxy collection init mi_namespace.mi_collection

# Estructura generada:
# mi_namespace/
# └── mi_collection/
# ├── README.md
# ├── galaxy.yml # Metadatos de la collection
# ├── docs/
# ├── plugins/
# │ ├── modules/ # Tus módulos custom
# │ ├── inventory/
# │ ├── lookup/
# │ └── filter/
# ├── roles/ # Roles incluidos
# └── playbooks/ # Playbooks de ejemplo

📝 Configurar galaxy.yml

galaxy.yml

namespace: mi_namespace
name: mi_collection
version: 1.0.0
readme: README.md
authors:
- Tu Nombre <email@ejemplo.com>

description: Collection para gestión de infraestructura web

license:
- MIT

tags:
- web
- infrastructure
- automation

dependencies: {}

repository: https://github.com/tu_usuario/mi_collection
documentation: https://docs.ejemplo.com
homepage: https://ejemplo.com
issues: https://github.com/tu_usuario/mi_collection/issues

📦 Build y publicar

# Construir la collection (crea un .tar.gz)
ansible-galaxy collection build

# Publicar en Galaxy (necesitas API key)
ansible-galaxy collection publish mi_namespace-mi_collection-1.0.0.tar.gz --api-key=TU_API_KEY

# Instalar localmente para pruebas
ansible-galaxy collection install ./mi_namespace-mi_collection-1.0.0.tar.gz

Ejemplo completo: proyecto con Galaxy

Estructura del proyecto:

mi-proyecto/
├── ansible.cfg
├── requirements.yml
├── inventory/
│ └── hosts.yml
├── group_vars/
│ └── all.yml
├── playbooks/
│ └── site.yml
└── roles/ # Roles locales custom
└── mi_rol/

ansible.cfg

[defaults]
roles_path = ./roles:~/.ansible/roles
collections_path = ./collections:~/.ansible/collections
inventory = inventory/hosts.yml

requirements.yml

roles:
- name: geerlingguy.docker
version: 6.1.0
- name: geerlingguy.nginx
version: 3.1.4

collections:
- name: community.general
version: 8.1.0
- name: community.docker
version: 3.4.11

Workflow:

# 1. Instalar dependencias
ansible-galaxy install -r requirements.yml

# 2. Ejecutar playbook
ansible-playbook playbooks/site.yml

# 3. Actualizar dependencias cuando sea necesario
ansible-galaxy install -r requirements.yml --force

Comandos de referencia rápida

# === ROLES ===
# Buscar roles
ansible-galaxy search <término>

# Instalar rol
ansible-galaxy install <autor>.<rol>

# Instalar desde requirements
ansible-galaxy install -r requirements.yml

# Listar roles instalados
ansible-galaxy list

# Eliminar rol
ansible-galaxy remove <autor>.<rol>

# Ver información de un rol
ansible-galaxy info <autor>.<rol>

# === COLLECTIONS ===
# Buscar collections
ansible-galaxy collection search <término>

# Instalar collection
ansible-galaxy collection install <namespace>.<collection>

# Listar collections instaladas
ansible-galaxy collection list

# Ver información
ansible-galaxy collection info <namespace>.<collection>

# === CREACIÓN ===
# Inicializar rol
ansible-galaxy init <nombre_rol>

# Inicializar collection
ansible-galaxy collection init <namespace>.<collection>

# Build collection
ansible-galaxy collection build

# Publicar collection
ansible-galaxy collection publish <archivo.tar.gz> --api-key=<KEY>

Resumen

En este capítulo has aprendido:

Qué es Ansible Galaxy: El repositorio oficial de contenido de la comunidad. ✅ Buscar e instalar roles: Cómo encontrar y usar roles de calidad. ✅ Requirements.yml: Gestión profesional de dependencias. ✅ Collections: El nuevo estándar que incluye roles, módulos y plugins. ✅ Publicar tu contenido: Comparte tus roles con la comunidad. ✅ Buenas prácticas: Seguridad, versiones fijas y documentación.

💡 Puntos clave

  1. No reinventes la rueda: Usa roles de Galaxy cuando sea posible.
  2. Fija versiones: requirements.yml es tu mejor amigo.
  3. Lee el código: Especialmente de roles con pocos usuarios.
  4. Contribuye: Reporta bugs, envía PRs, mejora la comunidad.
  5. Usa FQCN: Claridad y compatibilidad a largo plazo.