Parte 2 — Herramientas, toolchains y anatomía de comandos · ⏱️ Duración estimada: 75 min · Nivel: Fundamentos ✅ Clase construida.
Nadie escribe todo el software desde cero. Un proyecto moderno se apoya en decenas o cientos de bibliotecas de terceros: para parsear JSON, hablar HTTP, cifrar, dibujar. El objetivo de esta clase es que entiendas el mecanismo universal con el que cada lenguaje reutiliza ese código ajeno: un gestor de paquetes que descarga e instala dependencias, un archivo manifiesto donde declaras qué necesitas, y un lockfile que congela las versiones exactas para que tu proyecto sea reproducible en cualquier máquina. Cambian los nombres —pip, pnpm, cargo, composer— pero la trinidad manifiesto/lockfile/gestor es la misma en todos.
El concepto de reproducibilidad que introdujo The Pragmatic Programmer alcanza aquí su expresión más concreta. Un proyecto cuyas dependencias no están fijadas es una bomba de tiempo: funciona hoy y se rompe mañana cuando una biblioteca publique una versión nueva incompatible. El lockfile es la respuesta de ingeniería a ese problema, y entenderlo distingue al que sufre builds impredecibles del que los controla.
Al finalizar, podrás:
Tu código funciona perfecto en tu máquina. Lo subes, tu compañero lo clona, instala las dependencias y falla con un error que tú nunca viste. La causa: tú tienes la versión 2.4 de una biblioteca y él, al instalar «la última», obtuvo la 2.5, que cambió un detalle. Ambos declarasteis «la versión 2.x», que es ambiguo. El lockfile resuelve exactamente esto: registra que se resolvió la 2.4.1 —el número exacto, hasta el parche— y, al haberlo versionado junto al código, tu compañero obtiene esa misma 2.4.1. El clásico «en mi máquina funciona» casi siempre nace de dependencias no fijadas, y la solución casi siempre es hacer commit del lockfile.
El manifiesto es la lista de la compra: declara qué dependencias necesita tu proyecto y, normalmente, con qué rango de versiones aceptables. Es un archivo que tú editas y que expresa intención: pyproject.toml en Python, package.json en JS/TS, Cargo.toml en Rust, go.mod en Go, composer.json en PHP, el .csproj en C#, pom.xml o build.gradle en Java. Ahí escribes «quiero requests, versión 2.x o superior».
El lockfile es el recibo exacto de lo que se compró. Cuando el gestor resuelve tu manifiesto —eligiendo versiones concretas que satisfagan todos los rangos, incluidas las dependencias de tus dependencias— anota el resultado hasta el último dígito en un archivo que no editas a mano: package-lock.json/pnpm-lock.yaml, Cargo.lock, poetry.lock, go.sum, composer.lock. Este archivo es la clave de la reproducibilidad, y por eso la regla de oro es versionar el lockfile junto al manifiesto. El manifiesto dice qué quieres; el lockfile garantiza que todos obtengáis exactamente lo mismo.
El gestor de paquetes es la herramienta que lee el manifiesto, descarga las bibliotecas desde un repositorio central (PyPI para Python, npm para JS, crates.io para Rust, Packagist para PHP, Maven Central para Java, NuGet para C#) y escribe el lockfile. Su verbo típico es install o add: pip install, pnpm add, cargo add. Una precaución que Shotts y la cultura Unix inculcan —desconfiar de lo que traes de fuera— cobra aquí especial peso: cada dependencia es código de terceros que ejecutarás con tus permisos, así que conviene fijar versiones, revisar el lockfile y no depender de latest, que es un blanco móvil.
Compara cómo cada ecosistema añade una dependencia y qué archivos toca. El patrón se repite: un comando que actualiza el manifiesto y regenera el lockfile.
# Python (pip + pyproject.toml, o el clásico requirements.txt)
pip install requests # instala y puedes fijar en requirements.txt
pip freeze > requirements.txt # congela las versiones exactas instaladas
# JavaScript / TypeScript (pnpm + package.json -> pnpm-lock.yaml)
pnpm add zod # añade al package.json y actualiza el lockfile
pnpm install # instala exactamente lo del lockfile
# Rust (cargo + Cargo.toml -> Cargo.lock)
cargo add serde # edita Cargo.toml y resuelve Cargo.lock
cargo build # descarga y compila las dependencias
# Go (go mod + go.mod -> go.sum)
go get github.com/google/uuid # añade al go.mod y fija hashes en go.sum
# Java (Maven: pom.xml / Gradle: build.gradle)
mvn dependency:resolve # resuelve lo declarado en pom.xml
# C# (.NET + .csproj)
dotnet add package Newtonsoft.Json # añade al .csproj y restaura
# PHP (composer + composer.json -> composer.lock)
composer require guzzlehttp/guzzle # añade y escribe composer.lock
Mapa de la trinidad por lenguaje, para tenerlo a mano:
Lenguaje Gestor Manifiesto Lockfile Repositorio
-------- ---------- --------------- ------------------- --------------
Python pip pyproject.toml poetry.lock* PyPI
JS / TS pnpm package.json pnpm-lock.yaml npm
Rust cargo Cargo.toml Cargo.lock crates.io
Go go mod go.mod go.sum proxy de módulos
Java maven/gradle pom.xml (gradle.lockfile) Maven Central
C# nuget proyecto.csproj packages.lock.json NuGet
PHP composer composer.json composer.lock Packagist
*El lockfile de Python depende de la herramienta (poetry, pip-tools); con pip clásico se usa requirements.txt con versiones fijadas.
Verifica la reproducibilidad tú mismo: abre cualquier lockfile con un editor y localiza una dependencia. Verás su versión exacta y, a menudo, un hash criptográfico que garantiza que descargaste ese contenido y no otro suplantado.
Abre un manifiesto real de cualquier proyecto que tengas a mano (package.json, Cargo.toml o pyproject.toml) y localiza la lista de dependencias con sus versiones. Fíjate en la sintaxis de los rangos: un ^2.4.0 o un ~1.2 no es lo mismo que 2.4.1 fijo. Luego busca el lockfile al lado (pnpm-lock.yaml, Cargo.lock…), ábrelo y encuentra esa misma dependencia: comprueba que aquí la versión es un número exacto, sin rangos. Si tienes un ecosistema instalado, crea un proyecto de prueba y añade una dependencia con su comando (cargo add, pnpm add, composer require): observa cómo el manifiesto gana una línea y el lockfile aparece o crece. Comprueba con git status que ambos archivos han cambiado y que ambos deberían ir al commit.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| «En mi máquina funciona» pero en la de otro no | Dependencias no fijadas. Versiona el lockfile para que todos resuelvan lo mismo |
| No commitear el lockfile | Cada máquina resuelve versiones distintas. Añádelo a git junto al manifiesto |
Fijar dependencias a * o latest |
Roturas por actualizaciones inesperadas. Acota rangos y confía en el lockfile |
| Editar el lockfile a mano | Es generado; se corrompe fácil. Cámbialo solo vía el gestor (add, update) |
Versionar la carpeta de dependencias (node_modules, target) |
Es pesada y regenerable. Ignórala; el lockfile basta para reconstruirla |
package.json más lockfile— es idéntico. Lo que aprendes se transfiere a npm y yarn sin cambios.go.mod declara y go.sum fija los hashes exactos de cada módulo, cumpliendo el papel de bloqueo e integridad. Juntos garantizan builds reproducibles.⏮️ Clase 034 · 📂 Parte · 📚 Índice · 🌐 Atlas · Clase 036 ⏭️