Guía de 0 a 1 · Software con criterio

Cuaderno de software de Alexandra

Aprender a construir sistemas como se corre un experimento: reproducible, versionado, con controles y explicado.

Esto no es un curso de Python. Python lo vas a aprender de paso. La meta es que sepas decidir: qué construir, cómo partirlo, cuándo está terminado, qué no hacer, y cómo verificar lo que la IA escribe por ti. La sintaxis se busca; el criterio no se delega.

Para Alexandra · bioingeniera · sabe R y Biopython Mentor Rodrigo · revisa cada PR Ritmo sugerido 2 sesiones de 2 h por semana Duración estimada 5–7 meses
Antes de empezar

Las reglas del cuaderno

Seis reglas. Si en algún momento no sabes qué hacer, vuelve a esta lista.

  1. Criterio antes que sintaxis.

    Cómo se escribe un for lo resuelve la documentación o la IA en segundos. Decidir si ahí va un for, un dict o una consulta a la base de datos, no. Cada proyecto te enseña una decisión, no un comando.

  2. Un concepto nuevo por proyecto.

    Todo lo demás del proyecto usa cosas que ya dominas. Si un proyecto te obliga a aprender tres cosas nuevas a la vez, está mal partido: se divide.

  3. Terminado tiene una definición.

    Un proyecto está listo cuando: está en GitHub, tiene README, los tests pasan, corre en Docker en otra máquina, y puedes explicar cada archivo en dos minutos. Sin eso, no está listo, está avanzado.

  4. Leer más que escribir.

    La IA va a escribir la mayoría del código. Tu trabajo es leerlo todo, entenderlo y decidir si entra. Nada que no puedas explicar se mergea. Nunca.

  5. Aburrido es bueno.

    Herramientas maduras, estándar, con documentación grande. Lo nuevo y brillante lo pruebas cuando ya sepas qué problema resuelve.

  6. Pequeño y terminado vale más que grande y a medias.

    Un CLI de 80 líneas con tests y README enseña más que una plataforma de 3.000 líneas que "casi funciona".

Por qué ahora es distinto

Hace cinco años aprender a programar era aprender a escribir. Hoy la IA escribe bien y rápido, así que lo escaso es otra cosa: saber qué pedir, verificar lo que llega, notar cuando algo está mal aunque "funcione", y tener el modelo mental para partir un problema. Esta guía está armada para eso: vas a usar Claude Code desde el día uno, pero como tutor y par de programación, no como máquina expendedora de proyectos.

De dónde partes

No partes de cero. Ya piensas en protocolos, controles, reproducibilidad y datos. Ya has escrito código en R y usado Biopython. Casi todo lo que sigue tiene un equivalente en algo que ya haces.

Ya lo haces en el lab / en REn software se llamaLo ves en
Bitácora de laboratorio: qué hiciste, cuándo, por quéGit: historial de cambios con mensajeHábitos, P0
Control positivo y negativo de un ensayoTests: casos donde sabes la respuestaHábitos, P0
Medio de cultivo estandarizado, mismo lote de reactivosDocker: el mismo entorno en cualquier máquinaHábitos, P0
Protocolo escrito para que otro lo repitaREADME + código legibleTodos
data.frame, dplyr, ggplot2pandas, polars, matplotlibP2
Script .R que corres línea a líneaMódulo .py con funciones y un punto de entradaFase 1, P1
RStudio · CRAN · install.packagesVS Code · PyPI · uv addFase 0
Objetos Seq, SeqRecord de BiopythonClases y tipos: datos con forma conocidaFase 1, P1
Hoja de Excel compartida con el inventarioBase de datos con esquema y clavesP3
Muestra que llega, se procesa, sale un resultadoRequest → response de una APIP4
Un resultado que "salió raro" y no sabes por quéLogs y observabilidadP6, P7

Lo que sí es nuevo: pensar en sistemas (varias piezas hablándose), en estado (qué cambia y quién lo cambia), en fallos (qué pasa cuando la red se cae) y en costo (de tiempo, memoria, dinero). Los proyectos están ordenados para meter esas ideas de a una.

Fase 0 · 1 sesión

El laboratorio: herramientas y por qué cada una

Instalar todo de golpe y entender para qué sirve cada cosa. No hay que dominarlas; hay que saber qué problema resuelven.

Terminal (zsh)

Donde viven las herramientas. Diez comandos bastan: cd ls pwd mkdir cat less mv cp rm --help. Aprende a leer el prompt: en qué carpeta estás y en qué entorno.

Python 3.12 + uv

uv instala Python, crea el entorno virtual y maneja dependencias. Un entorno por proyecto, igual que un medio por cultivo: nunca mezclas.

VS Code + extensión Python

Editor. Lo importante desde la semana 1: el debugger (breakpoints, ver variables) antes que aprender a poner print.

git + GitHub

Historial local y copia remota. Cuenta en GitHub, llave SSH, tu primer repo. Todo proyecto de esta guía vive ahí.

Docker Desktop

Empaqueta tu programa con su entorno para que corra igual en cualquier lado. Desde el proyecto 0, aunque sea un CLI.

Claude Code

Tu tutor y par. Configúralo con un CLAUDE.md por proyecto que diga las reglas (ver Trabajar con IA).

pytest + ruff

Correr tests y mantener el código limpio y con formato uniforme. Los dos corren con un comando; se corren siempre antes de commitear.

Cuaderno de decisiones

Un archivo DECISIONES.md por proyecto: qué decidiste, qué alternativas había, por qué. Es lo que un revisor (o tú en 3 meses) más agradece.

Cómo termina la fase 0

Con el Proyecto 0 hecho: un repo con una función, un test que pasa, un Dockerfile que corre ese test, y un README. Si eso corre en la laptop de Rodrigo sin que él instale nada más que Docker, la fase 0 está cerrada.

Fase 1 · 2–3 semanas

Fundamentos de Python, en paralelo con los proyectos 0 y 1

Esto no se estudia aparte: se aprende mientras haces P0 y P1. La lista está para que sepas qué es "lo básico" y no te saltes nada. Cada punto tiene un ejercicio de 20 minutos que le puedes pedir a Claude que te plantee y luego te corrija.

ConceptoIdea en una líneaEjercicio
Tipos y estructurasint str float bool, y las cuatro colecciones: list (orden), dict (clave→valor), set (únicos), tuple (fijo). Elegir la estructura correcta es la mitad del diseño.Contar bases de una secuencia con dict; luego con collections.Counter.
Funciones y type hintsUna función hace una cosa, recibe entradas, devuelve salida, no toca nada más. def gc(seq: str) -> float:Escribir gc_content, reverse_complement. Con hints.
Módulos e importsUn archivo = un módulo. Se separa lógica de entrada/salida. from seqtool.core import gc_contentPartir un script en core.py + cli.py.
Errores y excepcionesFallar temprano, con mensaje claro. raise ValueError("secuencia vacía"). Capturar solo lo que sabes manejar.Leer un traceback de arriba a abajo y explicarlo en voz alta.
Archivos y rutaspathlib.Path, abrir con with, codificación explícita. Nunca rutas absolutas de tu laptop en el código.Leer un FASTA a mano, sin Biopython, y luego con Biopython. Comparar.
Iteración y comprensionesfor, enumerate, zip, [x for x in ...]. Generadores para no cargar todo en memoria.Procesar un FASTA grande línea a línea sin cargarlo entero.
Clases (solo cuando hace falta)Datos con forma + comportamiento. @dataclass primero. Si no tienes estado que proteger, una función basta.@dataclass class Reactivo con validación en __post_init__.
Entorno y dependenciaspyproject.toml declara qué necesita el proyecto; uv.lock fija versiones exactas. Reproducibilidad de verdad.Agregar biopython con uv add, ver qué cambió en el repo.
Leer código ajeno50 % del oficio. Abrir un repo pequeño y explicar qué hace sin correrlo.Leer Bio/SeqUtils/__init__.py y encontrar cómo calcula GC.
Trampa de la fase 1

Quedarse "estudiando" Python por semanas. A la tercera semana, aunque sientas que te falta, arrancas P1. Lo que falte se aprende con el proyecto en la mano.

Los cuatro hábitos del día 0

Se practican desde el proyecto 0 y en todos los que siguen. No son "para después, cuando el proyecto sea grande". Son el equivalente de etiquetar tubos y anotar en la bitácora: se hace siempre, y por eso nunca cuesta.

GitLa bitácora versionada

Cada cambio con sentido es un commit; el mensaje dice por qué, no qué (el qué se ve en el diff). Trabajas en una rama por cambio, subes, abres un Pull Request y Rodrigo lo revisa. Aunque seas la única que programa: el PR es donde ocurre la enseñanza.

  • Commits pequeños y frecuentes. Si el mensaje necesita "y", son dos commits.
  • .gitignore desde el inicio: nunca entran .env, datos crudos, .venv, ni archivos generados.
  • Flujo: git switch -c feat/gc-content → commits → git push → PR → revisión → merge.
  • Aprende a leer git log, git diff, git blame. Es leer la bitácora.

Comandos que bastan por meses: status add commit push pull switch log diff restore. Lo demás cuando lo necesites.

TestsLos controles del ensayo

Un test es un caso donde ya sabes la respuesta: control positivo (con esta entrada sale esto) y negativo (con esta entrada inválida, falla así). Sin controles no sabes si el ensayo funcionó; sin tests no sabes si el código funciona, y menos aún si lo escribió la IA.

  • Toda función con lógica tiene al menos un test feliz y uno de borde (vacío, inválido, enorme, duplicado).
  • Cuando encuentres un bug: primero escribe el test que lo reproduce (falla), luego arréglalo (pasa). Ese test se queda para siempre.
  • No se testea lo trivial ni las librerías ajenas. Se testea tu lógica.
  • pytest corre en un comando y en CI (GitHub Actions) en cada PR. Un PR con tests rojos no se mergea.
DockerEl medio estandarizado

"En mi máquina funciona" es el equivalente a un resultado que nadie puede reproducir. Docker empaqueta tu programa con su Python, sus dependencias y su sistema, y lo corre igual en tu laptop, en la de Rodrigo o en la nube.

  • Conceptos: imagen (la receta congelada) vs contenedor (una corrida de esa receta). Dockerfile es la receta.
  • Desde P0: docker build -t hola . && docker run hola corre los tests. Desde P3, docker compose levanta app + base de datos.
  • Lo entiendes cuando puedas responder: ¿por qué el contenedor no ve mis archivos? ¿por qué la DB se borra al reiniciar? (volúmenes) ¿por qué localhost no es lo mismo adentro? (redes)
DocumentarEl protocolo escrito

El README es el protocolo: qué es esto, cómo lo corro, cómo lo pruebo, qué decisiones tomé. Se escribe para la persona que llega mañana sin contexto, que casi siempre eres tú misma.

  • README con: propósito en dos líneas, cómo correr, cómo testear, estructura de carpetas, decisiones y pendientes.
  • DECISIONES.md: una entrada por decisión no obvia. "Elegí SQLite y no Postgres porque…".
  • Los comentarios en el código explican por qué, nunca qué. Si necesitas explicar qué hace, el código está mal escrito.
Proyectos

Once proyectos, un concepto cada uno

Todos giran alrededor de datos que reconoces: secuencias, placas, reactivos, protocolos y papers. Los proyectos 3 al 10 construyen sobre el mismo sistema (un inventario de laboratorio) para que veas cómo crece un sistema real: primero datos, luego API, luego clientes, luego automatización, luego inteligencia.

Cada ficha tiene: qué construyes, el concepto nuevo (el único), las buenas prácticas que se practican en esa etapa, la trampa típica y el criterio de listo. Las casillas se guardan en tu navegador; márcalas cuando de verdad se cumplan.

Criterio de listo común a todos

Repo en GitHub con README · tests en verde con pytest · corre con Docker · PR revisado y aprobado por Rodrigo · puedes explicar cada archivo en dos minutos · DECISIONES.md actualizado. Las fichas solo agregan lo específico.

0

Hola, reproducibleValidar que el laboratorio funciona de punta a punta

concepto · la cadena de herramientas1 sesióngit · pytest · docker · uv

Qué construyes

Un repo hola-alexandra con una sola función (gc_content(seq)), su test, un Dockerfile que corre el test, y un README. Nada más.

Concepto nuevo

El ciclo completo: escribir → probar → versionar → empaquetar → compartir. Es el mismo ciclo que vas a repetir cien veces; aquí lo haces con algo trivial para que la única dificultad sea el ciclo.

Buenas prácticas de esta etapa

  • Estructura mínima: src/hola/core.py, tests/test_core.py, pyproject.toml, Dockerfile, README.md, .gitignore.
  • Primer commit antes de escribir código: la estructura vacía. Segundo: la función y el test. Tercero: el Dockerfile.
  • El test se escribe antes que la función. Corre, falla, escribes la función, pasa.
Trampa · Querer que la función haga algo interesante. Aquí lo interesante es la tubería, no la función.

Listo cuando

1

seqtoolUn CLI de secuencias que harías igual en Biopython, hecho a mano a propósito

concepto · programa = funciones puras + entrada/salida3 sesionesargparse/typer · pathlib · pytest

Qué construyes

seqtool stats archivo.fasta imprime longitud, %GC y conteo por base de cada secuencia; seqtool revcomp, seqtool find --motif GAATTC. Lee FASTA sin Biopython.

Concepto nuevo

Separar la lógica (funciones puras: entran datos, salen datos, sin leer archivos ni imprimir) de la entrada/salida (leer el archivo, parsear argumentos, imprimir). La lógica se testea fácil porque no toca el mundo; la I/O es delgada y aburrida.

Buenas prácticas de esta etapa

  • Funciones cortas con nombre que dice qué devuelven: parse_fasta, gc_content, find_motif.
  • Tests con un FASTA de 3 secuencias en tests/data/, incluyendo una con minúsculas y una con N.
  • Errores claros: archivo inexistente, FASTA malformado, motivo vacío. Con código de salida ≠ 0.
  • Primer contacto con complejidad: find_motif recorre la secuencia; ¿cuánto crece el tiempo si la secuencia es 10× más larga? Mídelo con time.
Trampa · Un solo archivo de 300 líneas con la lógica mezclada con prints. Se nota porque los tests son imposibles de escribir.

Listo cuando

2

Reporte de placaDe un Excel real de tu trabajo a un reporte que le ahorra una hora a alguien

concepto · datos sucios y validación en el borde4 sesionespandas · openpyxl · pytest fixtures · CI

Qué construyes

Un script que toma un export real (placa de qPCR, curva de crecimiento, lectura de espectro: lo que uses), lo limpia, calcula lo que calculas a mano hoy (ΔΔCt, tasas, promedios por réplica) y produce un reporte (Markdown/HTML/xlsx) con tablas y un gráfico.

Concepto nuevo

Los datos reales vienen sucios: celdas vacías, unidades mezcladas, nombres con espacios, filas de comentarios. El 80 % del código serio es validar en el borde (al entrar) y fallar temprano y claro. Adentro, la lógica asume datos limpios.

Buenas prácticas de esta etapa

  • Tres capas: load (lee y valida) → transform (calcula, sin efectos) → report (escribe). Cada una testeable sola.
  • Nunca modificas el archivo original. El crudo es inmutable; todo se deriva.
  • Fixtures de test: un CSV mínimo de 6 filas que cubre los casos raros. No el archivo real de 4.000 filas.
  • Esquema explícito: qué columnas espero, de qué tipo. Si falta una, error con nombre de la columna. (pandera o validación a mano.)
Trampa · "Arreglar" el dato malo a mano en Excel y seguir. La corrección va en código, con un test que la documenta. Y la otra: dejar toda la lógica en un notebook; el notebook es para explorar, el módulo es el producto.

Listo cuando

3

Inventario de reactivos en SQLiteEl sistema que vas a hacer crecer hasta el proyecto 10

concepto · persistencia, esquema y claves4 sesionessqlite3 · SQLModel/SQLAlchemy · migraciones · docker compose

Qué construyes

Un CLI para el inventario de un laboratorio: reactivos, lotes (con vencimiento y cantidad), ubicaciones (congelador, estante), movimientos (entra/sale). inv add, inv take, inv expiring --days 30.

Concepto nuevo

Persistencia con estructura. Un esquema dice qué existe y cómo se relaciona (un reactivo tiene muchos lotes; un lote está en una ubicación). Claves primarias, foráneas, restricciones y transacciones. Es lo que Excel nunca te dio: garantías.

Buenas prácticas de esta etapa

  • Diseña el esquema en papel antes de escribir código. Tres tablas bien pensadas > una tabla de 40 columnas.
  • Migraciones desde el inicio (alembic): el esquema cambia, y el cambio se versiona como el código.
  • Nunca SQL armado con f-strings. Parámetros siempre. Aquí aprendes qué es una inyección SQL con un ejemplo que tú misma escribes.
  • Tests contra una DB en memoria que se crea y destruye en cada test.
  • Complejidad de nuevo: buscar un lote por código en una lista de 100.000 vs con un índice. Créalo, mide, entiende qué es un índice (spoiler: un dict).
Trampa · Guardar el inventario en un CSV "porque es más simple". Lo es hasta que dos personas escriben a la vez o alguien borra una fila sin querer. Y: usar el ORM sin saber leer el SQL que genera.

Listo cuando

4

API del inventario con FastAPIEl mismo inventario, ahora accesible por HTTP para otros programas

concepto · HTTP y el contrato cliente–servidor5 sesionesFastAPI · Pydantic · TestClient · códigos HTTP

Qué construyes

GET /reactivos, POST /lotes, POST /movimientos, GET /lotes/por-vencer?dias=30. Documentación automática en /docs. La lógica de P3 se reutiliza; solo cambia la puerta de entrada.

Concepto nuevo

El contrato. Un cliente manda un request (método, ruta, cuerpo); el servidor responde (código, cuerpo). El servidor no recuerda nada entre requests (stateless): todo lo que importa vive en la DB. Los códigos HTTP son parte del contrato: 201 creado, 404 no existe, 422 entrada inválida, 409 conflicto.

Buenas prácticas de esta etapa

  • Capas: routers/ (HTTP) → services/ (reglas de negocio) → repositories/ (DB). El router no sabe de SQL; el servicio no sabe de HTTP.
  • Pydantic valida en el borde. Un cuerpo inválido nunca llega a tu lógica.
  • Un error se responde con el código correcto, nunca 200 {"error": "…"}.
  • Tests con TestClient contra DB en memoria. Un test por endpoint por caso (feliz, no existe, inválido).
Trampa · Meter la regla "no puedes sacar más de lo que hay" dentro del endpoint. Mañana la necesitas desde el CLI y desde el vigía y ya la tienes copiada tres veces.

Listo cuando

5

Cliente y tableroUn programa que consume tu API, y una pantalla de "reactivos por vencer"

concepto · el otro lado: latencia, fallos y desconfianza3 sesioneshttpx · Streamlit o HTMX · timeouts · reintentos

Qué construyes

Un cliente Python (InventarioClient) que habla con la API, y un tablero mínimo (Streamlit o HTMX + Jinja) con la lista de lotes por vencer y un botón para registrar salida.

Concepto nuevo

La red falla. El servidor puede estar caído, lento, o responder algo inesperado. El cliente decide qué hacer: timeout, reintento, mensaje claro. Y el servidor nunca confía en el cliente: valida todo de nuevo. Aquí entiendes por qué la validación de P4 estaba en el servidor.

Buenas prácticas de esta etapa

  • La URL de la API viene de una variable de entorno. Nunca localhost:8000 en el código.
  • Timeout explícito en cada request. Reintentos solo en operaciones idempotentes (GET sí, POST de movimiento no, o con clave de idempotencia).
  • Tests del cliente con la API simulada (respx) incluyendo el caso "servidor caído".
  • Docker compose con dos servicios: api y web. Descubres que localhost dentro de un contenedor no es tu laptop.
Trampa · Que el tablero muestre una pantalla en blanco o un traceback cuando la API no responde. El usuario debe ver "no pude conectar con el inventario, reintenta".

Listo cuando

6

Auth, secretos y deployLa API sale de tu laptop y queda accesible en internet, con llave

concepto · entornos, secretos y "funciona en prod"4 sesionesAPI keys/JWT · .env · Postgres · Cloud Run o Fly.io · logs

Qué construyes

La API con autenticación (API key por usuario, o JWT si quieres ir un paso más), configuración por variables de entorno, Postgres en lugar de SQLite, y desplegada en Cloud Run o Fly.io desde GitHub. Logs que se pueden leer desde afuera.

Concepto nuevo

Entornos. Lo que corre en tu laptop (dev) y lo que corre en la nube (prod) es el mismo código con distinta configuración. La configuración viene del entorno; los secretos nunca del repo. Y en prod no se prueba: se observa (logs, health, versión).

Buenas prácticas de esta etapa

  • .env local ignorado por git; .env.example commiteado con las claves sin valores.
  • La respuesta de /health incluye la versión (commit) que corre. Siempre sabes qué está desplegado.
  • Logs estructurados (JSON) con nivel: qué pasó, cuándo, con qué request. Sin datos sensibles.
  • Migración de SQLite a Postgres solo cambiando la URL de conexión: si duele, tu capa de repositorio filtraba SQL específico.
  • Deploy automático desde main con GitHub Actions, después de que los tests pasen.
Trampa · Pegar el token en el código "un ratito para probar" y commitearlo. Los bots de GitHub lo encuentran en minutos. Si pasa: rotar la llave, no solo borrar el commit.

Listo cuando

7

Vigía de vencimientosUn proceso que corre solo, revisa el inventario y avisa por Telegram

concepto · procesos en segundo plano e idempotencia5 sesionescron / Cloud Scheduler · Telegram bot · logs · backoff

Qué construyes

Un job que corre cada mañana, consulta /lotes/por-vencer, y manda un mensaje por Telegram con lo que vence en 30 días. Extensión: un scraper que revisa el precio de un reactivo en la web de un proveedor y avisa si baja.

Concepto nuevo

Nadie está mirando. Un proceso automático falla en silencio, se ejecuta dos veces, o se queda colgado. Tres preguntas nuevas: ¿es idempotente (correrlo dos veces = correrlo una)? ¿cómo sé que sigue vivo? ¿qué pasa si el paso 3 falla después del paso 2?

Buenas prácticas de esta etapa

  • El job registra qué avisos ya mandó (en la DB), y no repite. Correrlo cinco veces seguidas manda un solo mensaje.
  • Reintentos con backoff exponencial para fallos de red. Límite de reintentos. Después, alerta.
  • Un "latido": el job escribe cuándo corrió por última vez; algo (o alguien) mira que ese dato no envejezca.
  • Logs con contexto: cuántos lotes vio, cuántos avisos mandó, cuánto tardó.
Trampa · try: … except: pass. Silencia el error y el vigía "funciona" mientras no avisa nada hace tres semanas. Y la otra: 40 mensajes iguales porque el cron corrió cada minuto en vez de cada día.

Listo cuando

8

Asistente de laboratorio con LLMUn chat que responde sobre tus protocolos usando la API de Claude

concepto · el LLM como función no determinista con costo4 sesionesClaude API · prompts versionados · evals · tokens

Qué construyes

Un endpoint POST /preguntar que recibe una pregunta ("¿cuánto tiempo centrifugo en el paso 4?") y responde usando un protocolo que le pasas en el prompt. Interfaz mínima en el tablero de P5.

Concepto nuevo

Hasta ahora, misma entrada → misma salida. Un LLM no: es una función probabilística, cuesta dinero por token, tarda segundos, y a veces se equivoca con seguridad. Eso cambia cómo se prueba (evaluaciones sobre muchos casos, no un test exacto), cómo se controla (temperatura, límites, formato) y cómo se presenta al usuario (con fuente, con duda).

Buenas prácticas de esta etapa

  • El prompt es código: vive en un archivo, se versiona, tiene tests. Cambiar una palabra puede cambiar todo.
  • Un set de evaluación: 20 preguntas con respuesta conocida. Antes de cambiar el prompt, mides; después, mides. Se decide con números.
  • Registras tokens y costo por request. Sabes cuánto cuesta cada pregunta y cuánto costó el mes.
  • Salida estructurada (JSON con respuesta, confianza, fuente) validada con Pydantic. Si el modelo no cumple el formato, se maneja.
  • Límites: máximo de tokens, timeout, y nunca un bucle que llame al modelo sin tope.
Trampa · Probar con tu única pregunta de ejemplo, ver que responde bien y darlo por listo. Y: meter datos confidenciales o de pacientes en el prompt sin pensar dónde van.

Listo cuando

9

RAG de protocolos y papersEl asistente ahora busca en tus PDFs antes de responder, y cita la fuente

concepto · búsqueda semántica y por qué el modelo no sabe tus documentos6 sesioneschunking · embeddings · sqlite-vec / pgvector · evaluación de recuperación

Qué construyes

Dos partes separadas: ingesta (PDF → texto → trozos → embeddings → DB) y consulta (pregunta → embedding → los 5 trozos más parecidos → prompt con esos trozos → respuesta con cita). Sobre 20–50 protocolos y papers tuyos.

Concepto nuevo

Recuperar antes de generar. El modelo no sabe tus documentos; se los das en el momento. Un embedding convierte texto en un vector donde "cercano" significa "parecido en significado". El sistema es tan bueno como su recuperación: si los trozos correctos no llegan al prompt, la mejor respuesta del mundo es inventada.

Buenas prácticas de esta etapa

  • Ingesta y consulta son programas separados con la DB en medio. La ingesta es idempotente (re-ingestar el mismo PDF no duplica).
  • Cada trozo guarda su origen: archivo, página, posición. La respuesta cita eso. Sin cita, no vale.
  • Mide la recuperación antes que la respuesta: 20 preguntas donde sabes en qué documento está la respuesta. ¿En cuántas el trozo correcto está en el top-5? Ese número es tu métrica; el prompt viene después.
  • Tamaño de trozo y solape son decisiones: pruébalas con la métrica, no a ojo.
  • Complejidad: comparar la pregunta contra 100.000 trozos uno por uno es O(n). Un índice vectorial lo hace mucho más rápido a cambio de aproximar. Entiende el trade-off.
Trampa · Trozos gigantes (una página entera) que "funcionan" con la pregunta de ejemplo. Y saltarse la métrica de recuperación e ir directo a retocar el prompt.

Listo cuando

10

Servidor MCP del inventarioTu API expuesta como herramientas para que un agente (Claude) la use por ti

concepto · herramientas, agentes y permisos4 sesionesMCP SDK · tools · Claude Desktop / Claude Code · auditoría

Qué construyes

Un servidor MCP con herramientas: buscar_reactivo, lotes_por_vencer, registrar_salida, preguntar_protocolo (P9). Lo conectas a Claude Desktop o Claude Code y le pides: "¿qué debería pedir esta semana?" y el agente consulta el inventario y arma la lista.

Concepto nuevo

Un agente decide qué llamar. Tú describes herramientas (nombre, para qué sirve, qué parámetros); el modelo elige cuándo usarlas y con qué. Es una integración entre sistemas donde una parte es no determinista, así que los permisos importan: qué puede leer, qué puede cambiar, qué necesita confirmación.

Buenas prácticas de esta etapa

  • Herramientas pequeñas, con una descripción que un humano entendería sin ver el código. La descripción es la interfaz.
  • Lectura por defecto. Cualquier herramienta que modifica datos pide confirmación o está detrás de un permiso explícito.
  • Registro de auditoría: qué herramienta llamó el agente, con qué parámetros, qué respondió. Si algo sale mal, sabes qué hizo.
  • Las herramientas reutilizan la capa de servicios de P4. El MCP es otra puerta de entrada, como el CLI y la API.
Trampa · Una herramienta eliminar_lote sin confirmación. El agente la va a usar cuando menos lo esperes. Y: exponer toda la API como está, en vez de diseñar herramientas para lo que el agente realmente necesita hacer.

Listo cuando

Después del 10

Ya no necesitas fichas. Opciones, en orden de lo que más enseña:

  • Un proyecto tuyo, de cero, sin guía. Algo de tu trabajo. Tú escribes las fichas: concepto, criterio de listo, decisiones. Rodrigo solo revisa PRs.
  • Contribuir a Biopython. Un issue etiquetado good first issue. Leer código ajeno grande, seguir sus reglas, pasar su CI, recibir revisión de desconocidos. Es el mejor examen de criterio que existe.
  • Frontend de verdad (React o similar) para el tablero, si te interesa. Es un mundo aparte con sus propios antipatrones.
  • Un pipeline bioinformático reproducible con Nextflow o Snakemake y Docker. Une lo que ya sabes de biología con lo que ahora sabes de sistemas.
Transversal

Complejidad algorítmica, lo que hay que saber

La pregunta es una sola: si la entrada crece 10×, ¿cuánto crece el tiempo (o la memoria)? No necesitas demostrar nada; necesitas reconocer la forma cuando la ves en tu código y saber cuál es la salida.

FormaSi n crece 10×…Lo ves enEjemplo tuyo
O(1)el tiempo no cambiaBuscar en dict o set; índice de DB por clave¿Está este código de lote en el inventario? → set
O(log n)+1 paso, más o menosBúsqueda binaria; índice B-tree en DBBuscar un lote por fecha con índice
O(n)10× más tiempoUn for sobre los datos; leer un archivo enteroCalcular %GC de una secuencia; recorrer un FASTA
O(n log n)~13× más tiempoOrdenar (sorted)Ordenar lotes por vencimiento
O(n²)100× más tiempoUn for dentro de otro sobre los mismos datos; comparar todos contra todosBuscar duplicados comparando cada secuencia con cada otra
O(2ⁿ)olvídaloProbar todas las combinacionesTodos los subconjuntos posibles de primers

El patrón que más aparece

Buscar en una lista dentro de un bucle. Es O(n²) disfrazado. La solución casi siempre es convertir la lista a set o dict una vez, antes del bucle.

# lento: O(n·m)
for lote in lotes:
    if lote.codigo in codigos_lista: ...

# rápido: O(n + m)
codigos = set(codigos_lista)
for lote in lotes:
    if lote.codigo in codigos: ...

Por qué BLAST no compara todo contra todo

Alinear cada secuencia contra cada una de una base de millones sería O(n²) sobre números enormes. BLAST indexa k-mers (trozos cortos) en algo parecido a un dict y solo alinea donde hay coincidencia. Es la misma idea que el índice de tu DB en P3 y el índice vectorial en P9: pagar una vez para buscar rápido muchas veces.

Reglas prácticas

  • Mide antes de optimizar. time, timeit, cProfile. La intuición sobre dónde está lo lento suele fallar.
  • La mayoría del código no necesita optimizarse. El que sí, se nota: tarda minutos, se queda sin memoria, o el usuario espera.
  • Sospecha de un bucle dentro de otro sobre el mismo dato. Sospecha de x in lista repetido. Sospecha de cargar un archivo entero cuando podías leerlo por partes.
  • En bases de datos: si una consulta es lenta, la respuesta casi siempre es un índice, no más CPU.
  • La memoria también cuenta: un generador procesa un FASTA de 10 GB con 10 MB de RAM; una lista, no.
  • Legibilidad primero. Un O(n²) claro sobre 200 filas le gana a un O(n) ingenioso que nadie entiende. Cuando n crezca, cambias.
Transversal

Antipatrones: lo que no se hace

Cada uno de estos lo vas a ver en código ajeno, en código que la IA propone, y en tu propio código a las 11 de la noche. La lista sirve para reconocerlos rápido. Junto a cada uno, qué hacer en su lugar.

En el código

La función que hace todo200 líneas que leen, calculan, imprimen y guardan. Imposible de testear, imposible de reusar.Una función, una responsabilidad. Si necesitas "y" para describirla, son dos.
Nombres que no dicen nadax, df2, temp, final_v3, data.El nombre dice qué es: lotes_por_vencer, gc_por_secuencia. Si cuesta nombrarlo, no sabes qué es todavía.
Copiar y pegar con cambios chicosEl mismo bloque tres veces con una variable distinta. Cuando corrijas un bug, lo corriges en una y olvidas dos.Una función con parámetro. Regla de tres: la primera vez escríbelo, la segunda cópialo, la tercera abstrae.
Números mágicosif dias < 30, timeout=7. ¿Por qué 30? ¿Por qué 7?Constante con nombre o parámetro de configuración: DIAS_AVISO_VENCIMIENTO = 30.
except: passSilencia todo. El programa "funciona" y está roto hace semanas.Captura la excepción específica que sabes manejar; las demás que exploten. Y siempre log.
Estado global mutableVariables al tope del archivo que cualquier función cambia. Nadie sabe quién puso qué valor.Pasa lo que necesitas como parámetro; devuelve lo que produces. Estado explícito.
Comentarios que repiten el código# incrementa i en 1. Ruido. Y código comentado "por si acaso".Comentarios para el porqué. El código muerto lo guarda git; bórralo.
Rutas y URLs de tu laptop/Users/ale/datos/…, localhost:8000 dentro del código.Parámetros, variables de entorno, rutas relativas al proyecto.
Clases porque síUna clase con un solo método y sin estado. O una jerarquía de herencia para tres cosas.Empieza con funciones. Clase cuando hay estado que proteger. Composición antes que herencia.
Fechas sin zona horariadatetime.now() en un servidor que está en otra zona. Todo lo que pasa después de las 7 pm cae "mañana".Siempre con zona (datetime.now(timezone.utc)), y convertir a local solo para mostrar.

Con los datos

Secretos en el repoAPI keys, contraseñas, tokens en el código o en un commit viejo.Variables de entorno, .env ignorado, gestor de secretos en prod. Si se filtró: rotar.
Modificar el dato crudoAbrir el CSV original y "arreglar" una celda.El crudo es inmutable. Toda corrección es código, con test.
Confiar en la entradaAsumir que el archivo tiene las columnas, que el request trae los campos, que el usuario mandó un número.Validar en el borde. Adentro, asumir limpio.
SQL con f-stringsf"SELECT … WHERE codigo = '{codigo}'". Alguien manda ' OR 1=1 -- y lee todo.Consultas parametrizadas. Siempre.
Contraseñas o datos personales sin cuidadoGuardar contraseñas en claro, mandar datos de pacientes a un servicio externo sin pensarlo.Contraseñas siempre con hash. Datos sensibles: mínimo necesario, y saber a dónde van.
Sin respaldo, sin migraciónCambiar el esquema a mano en la DB de prod. Sin backup.Migraciones versionadas. Backup probado (que se restaure, no solo que exista).

En el proceso

El commit "cambios"Un commit de 40 archivos con mensaje "cambios" o "fix".Commits chicos, mensaje con el porqué. Un PR = un cambio revisable.
"Es chiquito, no necesita tests"Todo empieza chiquito. Cuando crezca ya no sabrás por dónde empezar.Tests desde la primera función. Es más barato al inicio que nunca.
Optimizar antes de medirReescribir algo "para que sea más rápido" sin saber si era lento.Medir. Casi siempre lo lento está en otro lado.
Construir para el futuro que no llega"Por si algún día necesitamos soportar tres bases de datos…"YAGNI: no lo vas a necesitar. Construye lo de hoy bien; el cambio de mañana será más fácil por eso.
Reinventar la librería maduraEscribir tu propio parser de CSV, tu propio cliente HTTP, tu propio hash.Usa lo estándar. Reinventa solo para aprender (como P1) y dilo.
Probar en producción"Voy a cambiar esto directo en el servidor a ver si funciona".Se prueba local y en tests; en prod se observa. Y todo cambio pasa por git.
El notebook como productoUn Jupyter de 80 celdas que hay que correr en orden y que solo funciona en tu máquina.Notebook para explorar; la lógica migra a un módulo con tests.
Lo nuevo y brillanteAdoptar el framework que salió el mes pasado porque lo vio en un video.Herramientas aburridas y maduras. Lo nuevo, cuando sepas qué problema resuelve que lo aburrido no.

Con la IA

Aceptar sin leerPegar lo que propuso, correr, "funciona", commit.Cada línea se lee y se entiende. Lo que no puedas explicar, no entra.
Pedir el proyecto entero"Hazme el inventario con API y tablero". Sale algo grande, opaco y con decisiones que no tomaste.Una cosa a la vez, del tamaño de un commit. Tú diriges.
Iterar el mismo error 20 vecesPegar el traceback, probar lo que dice, pegar el nuevo, sin leerlo.Leer el traceback tú, formular hipótesis, y recién preguntar con la hipótesis.
Dependencias que aparecen solasLa IA agregó tres librerías que no conoces "para hacerlo más fácil".Cada dependencia es una decisión tuya. Pregunta por qué; busca si la estándar ya lo hace.
Sin tests, sin verificaciónSi no hay tests, no tienes forma de saber si lo que la IA escribió hace lo que crees.Los tests son tu instrumento de medición sobre el código de la IA. Sin ellos estás a ciegas.
Compartir lo que no debesPegar el .env, datos de pacientes, código propietario del trabajo.Antes de pegar, pregunta: ¿esto puede salir de aquí?
Transversal

Trabajar con IA: el modo tutor

Vas a usar Claude Code desde el proyecto 0. La regla es simple: la IA propone, tú dispones. Al inicio la usas más como tutor que como escritora; con el tiempo escribirá más, pero el criterio de qué entra sigue siendo tuyo.

  1. La primera vez, a mano.

    Cada concepto nuevo lo escribes tú la primera vez (tu primer test, tu primer endpoint, tu primer Dockerfile). Después, que la IA lo repita. Si nunca lo escribiste, no sabrás cuando lo escribe mal.

  2. "Explícame" antes que "hazme".

    Pide que te explique el código, las alternativas, los trade-offs. Cuando ya entiendas, pide que lo haga. Y después, que te explique lo que hizo.

  3. Una cosa a la vez, del tamaño de un commit.

    "Agrega validación de secuencia vacía en gc_content con su test" sí. "Haz el proyecto 3" no.

  4. Lee el diff completo antes de aceptar.

    Todo. Si es demasiado para leer, el pedido era demasiado grande.

  5. Test primero, luego que la IA implemente.

    Tú escribes el test que describe lo que quieres (o lo revisas línea por línea si lo escribe ella). Recién ahí la implementación. El test es tu contrato con la IA.

  6. Cuando falle, primero tú.

    Lee el traceback de arriba a abajo. Formula una hipótesis. Después pregunta con la hipótesis incluida: "creo que falla porque X, ¿es así?".

  7. Pide alternativas y decide tú.

    "Dame dos formas de hacer esto y sus trade-offs". Elegir es lo que estás aprendiendo. Anota la elección en DECISIONES.md.

  8. Un CLAUDE.md por proyecto.

    Con las reglas: correr pytest y ruff antes de proponer terminado, no agregar dependencias sin preguntar, no tocar tests para que pasen, explicar cada cambio. Es tu protocolo para la IA.

Cómo pedir

Así noHazme una API de inventario con FastAPI.Demasiado grande, sin criterio tuyo, sale opaco.
Así síAntes de escribir código: ¿cómo organizarías las carpetas de una API FastAPI chica con capa de servicios y repositorio? Dame dos opciones y sus trade-offs.Tú decides la estructura; después pides cada pieza.
Así noMe sale este error: [traceback]. Arréglalo.No aprendiste nada y aceptaste un cambio a ciegas.
Así síEste traceback dice que lote es None en la línea 42. Creo que es porque busco un código que no existe y no manejo ese caso. ¿Es correcto? ¿Dónde lo manejarías: en el repositorio o en el servicio?Hipótesis, pregunta de diseño, decisión tuya.
Así noHaz que los tests pasen.Va a cambiar el test si es más fácil que arreglar el código.
Así síEl test test_take_more_than_available falla. No modifiques el test. Explícame por qué falla y propón un cambio en services.py solamente.Delimitas qué puede tocar.
Así noOk, dale.Sin haber leído.
Así síAntes de aplicar: ¿por qué agregaste tenacity? ¿Se puede hacer con la librería estándar? Muéstrame el diff.Cada dependencia y cada línea son tuyas.
La medida de que va bien

Con el tiempo, la IA escribe cada vez más y tú lees cada vez más rápido. Pero el examen no cambia: Rodrigo abre un archivo cualquiera del repo, señala una función, y tú explicas qué hace, por qué está ahí y qué pasaría si se borra. Si puedes, va bien, sin importar quién tecleó.

Transversal

Claude fuera del código: en el trabajo diario y para lo que no está aquí

Lo que practicas con la IA en los proyectos (pedir chico, dar contexto, verificar contra algo que sabes, decidir tú) sirve igual para el resto de tu trabajo. Y esta guía se va a quedar corta: van a aparecer herramientas, técnicas y problemas que no están en ninguna ficha. Aquí está el método para las dos cosas.

El protocolo para aprender algo que no sabes

Sirve para Nextflow, Postgres, un framework de frontend, Terraform, una técnica estadística o lo que aparezca el año que viene. Son las mismas fichas de arriba, pero las escribes tú con ayuda de la IA.

  1. Pide el mapa, no el tutorial.

    "Voy a tener que usar X para Y. Dame los cinco conceptos que necesito entender, en orden, y qué problema resuelve cada uno. Todavía nada de código." Un mapa de cinco conceptos cabe en la cabeza; un tutorial de tres horas no.

  2. Pide el proyecto mínimo.

    "¿Cuál es el proyecto más chico que me obliga a usar los cinco? Con criterio de listo." Si te propone algo de dos semanas, pide que lo parta.

  3. Hazlo con las mismas reglas.

    Repo, tests, Docker, PR, DECISIONES.md. Aunque sea "solo para aprender". Es lo que convierte un tutorial en algo que recuerdas.

  4. Pide que te examine.

    "Hazme cinco preguntas de criterio sobre X, del tipo ¿qué pasa si…?, y corrige mis respuestas con dureza." Si no pasas, todavía no sabes; vuelve al paso 3 con otro proyecto mínimo.

  5. Escribe la ficha.

    Con el mismo formato que las de esta guía: concepto, buenas prácticas, trampa, listo cuando. Guárdala en tu propio cuaderno. La próxima persona que aprenda X en tu equipo la va a agradecer, y esa persona sueles ser tú en seis meses.

Recetas de trabajo

Situaciones reales de un laboratorio o una oficina técnica. En cada una: cómo pedirlo y, sobre todo, qué verificas tú, porque la IA se equivoca con seguridad y en tu trabajo el error cuesta.

Un export nuevo de un instrumento

Pega 20 filas (sin datos que no puedan salir) y pide: "explícame qué es cada columna, en qué unidades, y qué se ve raro". Después: "escribe un script que valide y resuma esto" (es el P2 aplicado).

Verificas: tres filas calculadas a mano contra la salida del script.

Escribir un SOP o protocolo

Dale tus notas crudas más un SOP existente como plantilla de formato. Pide estructura, checklist de pasos críticos y puntos donde suele haber error. Tú escribes lo técnico.

Verificas: cada número, tiempo, temperatura y volumen. Todos.

Leer papers más rápido

Sube el PDF y pide un resumen con forma fija: pregunta, método, resultado principal, limitación, qué aplica a mi caso. Luego contrasta: "¿qué diría un revisor escéptico de la figura 3?".

Verificas: vas a la figura o tabla clave y la lees tú. El resumen no reemplaza eso.

Análisis exploratorio (R o Python)

Claude Code abierto en la carpeta de datos: "haz un análisis exploratorio: distribución por grupo, faltantes, outliers; guarda las figuras en figs/ y explícame qué ves". Pide el código, no solo la conclusión.

Verificas: los n por grupo cuadran con lo que sabes; una figura la rehaces a mano.

Estadística que no dominas

"Tengo este diseño (grupos, réplicas, medidas repetidas o no): ¿qué test aplica, por qué, y qué supuestos tengo que verificar? Dame el código y el gráfico para cada supuesto." Pide dos opciones y sus riesgos.

Verificas: los supuestos con tus gráficos; y que el test lo aceptaría el revisor de tu área.

Automatizar lo repetitivo

"Cada lunes junto cuatro Excel y saco un resumen": descríbelo paso a paso, pide un script (P2) y luego que corra solo (P7). Empieza por lo que te toma más de una hora al mes.

Verificas: un lunes lo haces a mano y con el script; deben coincidir.

Informe o presentación

Dale los resultados y el público ("gerencia sin formación técnica", "comité científico"). Pide estructura, no texto: qué va primero, qué figura sostiene cada punto, y "tres preguntas incómodas que me van a hacer".

Verificas: cada afirmación tiene un dato tuyo detrás.

Depurar un pipeline ajeno

Pega el comando, el error completo y la versión de la herramienta. Pide "hipótesis en orden de probabilidad, y cómo descarto cada una". No pidas "arréglalo".

Verificas: descartas una hipótesis a la vez, con evidencia; anotas la que fue.

Correo técnico difícil

Un reclamo a un proveedor, una respuesta a un revisor, un pedido a otra área. Da el contexto y el tono que quieres; pide dos borradores. Tú eliges y editas.

Verificas: que dice lo que tú dirías, ni más ni menos. Lo firmas tú.

Claude Code sin escribir software

Claude Code no es solo para repos: funciona sobre cualquier carpeta. Una carpeta de datos, de papers, de documentos del proyecto. Las mismas ideas de los proyectos aplican:

  • Un CLAUDE.md en la carpeta que diga: qué hay aquí, qué no se toca (los datos crudos son de solo lectura), dónde van las salidas, qué formato quieres. Es el protocolo para la IA, igual que en un repo.
  • Conectar herramientas por MCP (Google Drive, Slack, la base de datos del laboratorio, tu propio inventario del P10). En P10 construiste una herramienta; aquí las consumes. Es la misma idea desde el otro lado.
  • Guardar los pedidos que funcionaron. Un archivo prompts.md con "resumen de paper", "revisión de SOP", "EDA estándar", listos para reusar. Con el tiempo se vuelven skills: instrucciones reutilizables que llamas por nombre.
  • Un chat largo no es una herramienta. Si haces lo mismo tres veces, es un script o un prompt guardado (la regla de tres de nuevo).
Lo que no cambia, sea código o no

Pedir chico. Dar contexto (quién eres, para qué es, en qué formato, un ejemplo). Verificar contra algo que ya sabes. Nunca compartir lo que no puede salir. Y decidir tú: la IA propone, tú firmas.

Transversal

Criterio: las preguntas que hay que hacerse

El criterio no es una lista de reglas, es el hábito de hacerse ciertas preguntas antes de decidir. Estas son las que más rinden.

Antes de construir

  • ¿Qué problema resuelve esto, para quién, y cómo sabré que lo resolvió?
  • ¿Cuál es la versión más chica que sirve?
  • ¿Ya existe algo maduro que lo hace?
  • ¿Qué es lo que no sé todavía y debería averiguar primero?

Al diseñar

  • ¿Dónde vive el estado y quién lo cambia?
  • ¿Qué pasa con entrada vacía, duplicada, enorme, malformada?
  • ¿Qué pasa si esto se corre dos veces? ¿Si se corta a la mitad?
  • ¿Qué pasa si la red / el archivo / el servicio no está?
  • ¿Cuánto crece si los datos crecen 10×?

Al elegir

  • ¿Qué tan caro es deshacer esta decisión? (lo reversible se decide rápido; lo irreversible, despacio)
  • ¿Cuál es la opción aburrida?
  • ¿Lo necesito hoy o "por si acaso"?
  • ¿Cuál voy a poder explicar en tres meses?

Al terminar

  • ¿Puede otra persona correrlo sin preguntarme?
  • ¿Los tests describen lo que hace?
  • ¿Qué decidí y por qué está anotado?
  • ¿Qué dejé pendiente y está escrito?

Principios que resumen lo anterior, para tener a mano: KISS (lo simple gana), YAGNI (no lo vas a necesitar), DRY con cuidado (tres veces antes de abstraer), fallar temprano y claro, separar I/O de lógica, medir antes de optimizar, lo aburrido es bueno, pequeño y terminado.

Transversal

El ritual semanal con Rodrigo

Una sesión fija por semana, 45–60 minutos, siempre con la misma forma. La forma importa: es lo que hace que la enseñanza sea de criterio y no de sintaxis.

1 · DemoAlexandra muestra lo que corre. Desde Docker, no desde su editor. Cinco minutos.
2 · Revisión del PRRodrigo lee el PR en voz alta y comenta como lo haría con un colega: qué está bien, qué cambiaría, por qué. Alexandra defiende o cede, con argumentos.
3 · La pregunta del porquéRodrigo elige una función cualquiera y pregunta: ¿por qué está aquí? ¿qué pasa si la borro? ¿qué pasa si la entrada es X?
4 · Siguiente pasoSe acuerda qué se hace la próxima semana, del tamaño de uno o dos PRs. Se anota.
Para Rodrigo

Corregir menos, preguntar más. Cuando algo está mal, no digas la solución: pregunta qué pasaría si… y deja que ella llegue. Y de vez en cuando manda un PR con un error a propósito para que ella lo revise; revisar código ajeno enseña más rápido que escribir el propio.

Transversal

Recursos, pocos y elegidos

No hace falta leer todo. Cada uno tiene su momento; están ordenados por cuándo entran.

Libros, si te gustan los libros: The Pragmatic Programmer (criterio, ameno) y A Philosophy of Software Design (Ousterhout; corto, sobre complejidad y diseño). Ninguno urgente; los dos valen a partir del P4.