Saltar a contenido

Microlecciones

La pieza de Didacta es la unidad: un trozo de materia lo bastante pequeño para que se pueda reutilizar y lo bastante grande para que signifique algo. Una definición con su ejemplo. Un teorema con su demostración. Un problema.

Una unidad es un directorio

content/analysis/normed/conceptos/definition/
├── unit.yaml          id, título, sitio, idiomas, estado
├── es.tex             el contenido, en castellano
├── va.tex             el mismo contenido, en valenciano
└── figures/
    └── bola-unidad.pdf

Que sea un directorio y no un fichero es lo que hace que sus idiomas, sus metadatos y sus figuras se muevan juntos. La carpeta está donde está la lección en la biblioteca --categoría, tema y subtema--, así que reclasificarla --llevarla de analysis/normed/conceptos a analysis/banach/ejemplos-- es mover una carpeta, y no hay ninguna forma de dejarse la mitad detrás.

Se nombra por su id

Lo que usa una unidad --un tema de un curso, el prerrequisito de otra-- no la nombra por su carpeta sino por su id, que no cambia nunca:

structure:
  - unit: u-3fa9c2e1b0d4

Por eso moverla no obliga a reescribir nada: al compilar, Didacta le dice a LaTeX en qué carpeta vive cada id. En la aplicación se ve siempre el título; el id solo se ve si se abre el fichero.

El idioma es el nombre del fichero

va.tex, y no 03VAL-espacios-normados.tex.

Eso no es cosmética. El ordinal que antes llevaba el orden vive ahora en la composición, que es donde el orden pertenece: reordenar un tema ya no implica renombrar ficheros. Y el código de idioma en un sitio fijo es lo que permite que la aplicación conozca el estado de traducción de dos mil unidades sin que nadie lo declare.

El fichero de contenido

\begin{frame}
\didactatitle{Definición de espacio normado}

La métrica usual en $\mathbb{R}$ es $d(x,y) = |x-y|$.

\onlynotes{%
  La idea es quedarse con las propiedades de esa distancia que sirven
  para algo y olvidarse del resto.
}

\begin{definition}[Espacio normado]
Un par $(E, \|\cdot\|)$ donde $E$ es un espacio vectorial y
$\|\cdot\| : E \to \mathbb{R}$ cumple\ldots
\end{definition}

\begin{teaching}[Ritmo]
Quince minutos. Detente en la homogeneidad: es donde se atascan.
\end{teaching}
\end{frame}

Tres cosas de aquí que merecen atención:

\begin{frame} no significa «diapositiva». Es la unidad de contenido. En un perfil de diapositivas sale como una diapositiva; en uno de apuntes, como un bloque de texto seguido. Lo que sostiene ese truco es beamerarticle.

\onlynotes es el mecanismo entero. Hay tres canales --diapositivas, apuntes y profesor-- y cada trozo dice a cuáles pertenece. Lo que no dice nada, sale en todos.

teaching es para ti. Nunca sale en un documento del alumno, en ningún perfil y por ningún descuido, porque el perfil es quien decide si ese canal existe.

Todo lo que se puede escribir

Los metadatos

id: u-3fa9c2e1b0d4
kind: theory
block: theory        # de qué parte de la asignatura forma parte

title:
  es: Espacios normados
  va: Espais normats

category: analysis   # su sitio en la biblioteca, que es también su carpeta
topic: normed
subtopic: conceptos
tags: [norma, banach]  # palabras libres, para buscar

reference: es          # de qué idioma salen los demás

languages:
  es: {status: source}
  va: {status: translated, indent: false}

prerequisites: [u-81c0d5e2aa47]   # por id, como en las composiciones
objectives:
  - Reconocer una norma
  - Distinguir norma de métrica
duration_minutes: 15

Casi todo es opcional. title y kind se usan en toda la aplicación; prerequisites y objectives son para quien los quiera.

kind y block no son lo mismo

Confundirlos fue un error de verdad, y merece la pena decir en qué se diferencian. El kind dice qué es el fichero --una explicación, un ejemplo, un ejercicio-- y el block de qué parte de la asignatura forma parte --la teoría, los problemas, las prácticas--.

Una explicación teórica dentro de una práctica de problemas es kind: theory y block: problems, y las dos cosas son ciertas: va con la hoja, y no tiene resultado ni solución que rellenar.

Los bloques los declara cada repositorio en su taxonomy.yaml, con un id y un nombre por idioma:

blocks:
  - id: theory
    title: {es: Teoría, va: Teoria, en: Theory}
  - id: practicas
    title: {es: Prácticas de ordenador}

Sin declarar ninguno valen los dos de siempre --theory y problems--, que es lo que hace que un repositorio de antes de que esto existiera se vea exactamente igual. Y una lección que nombra un bloque que nadie declara no desaparece: se ve entera, con el bloque por su id.

Gestionarlos desde la aplicación

status se calcula, no se declara

Que una traducción esté al día no lo dice nadie escribiéndolo: se deduce comparando cuándo cambió el original con cuándo cambió la traducción. Una marca escrita a mano diría que sí el día que se escribió y seguiría diciéndolo cinco revisiones después.

indent: false, y cuándo hace falta

Al guardar un .tex desde la aplicación se le pasa el beautify --con latexindent si está instalado, y si no con el indentador propio, que hace menos y siempre funciona--. Hace tres cosas: pone cada \\begin, \\end e \\item en su línea, sangra por niveles, y junta cada párrafo para volver a cortarlo a 80 columnas.

Lo único que cambia es el espacio en blanco, nunca dentro de un verbatim, y nunca por dentro de una fórmula o de unas llaves.

Un fichero escrito antes de que esto existiera se queda como está hasta que alguien lo guarde. Para ordenarlo sin tocarlo, pulsa la palabra «Beautify» de la barra del editor --o su botón en la barra de formato--: deja el cambio sin guardar, para poder mirarlo.

Aun así hay ficheros que hay que dejar quietos, y por eso se puede apagar desde la casilla de la barra del editor, en cada idioma por separado:

  • Un entorno de código propio, que el indentador no conoce y por tanto no protege. Ahí el espacio en blanco es el contenido: reindentarlo cambia lo que sale impreso sin tocar una letra.
  • Un .tex generado por otra herramienta y que se vuelve a generar: sangrarlo convierte cada regeneración en un diff contra todo el fichero, y el historial deja de servir para ver qué cambió de verdad.
  • Un fichero con un \\begin sin cerrar --material recién migrado lo tiene--. LaTeX lo compila igual porque es indulgente; el contador de niveles no lo es, y a partir de ahí sale todo corrido.

Es por idioma porque el motivo vive en un fichero concreto: que el castellano venga generado no dice nada del inglés escrito a mano.

La misma lección, en varios sitios

flowchart TD
  U["analysis/normed/definition"]
  U --> A["Análisis I · 2024-2025<br/>Tema 3"]
  U --> B["Análisis I · 2025-2026<br/>Tema 1"]
  U --> C["Máster · 2025-2026<br/>Repaso"]

Corriges una errata en la unidad y queda corregida en los tres. No hay tres copias que sincronizar, porque no hay tres copias.

Dos preguntas que la biblioteca contesta y el repositorio no

Estas dos exigen recorrer todas las composiciones a la vez, así que un grep no las contesta:

¿Dónde se usa esta unidad? Que es la forma práctica de «¿puedo cambiar esto?». Sale en el panel de cada unidad, con el curso, el año y el documento.

¿Qué unidades no usa nadie? Material que existe y no se está dando. Después de migrar un sistema anterior, eso es una lista larga y muy útil.

Cómo se crea una unidad

Desde la aplicación, con Nueva lección en la biblioteca o Crear una nueva… al añadir en una composición. Para empezar a partir de una que ya existe, Duplicar… en su icono de información.

O desde el terminal:

didacta new unit analysis/normed/dual-space
didacta new unit analysis/series/convergence --kind problem
didacta new unit analysis/series/ratio --from analysis/series/convergence

Crea el directorio, el unit.yaml con los campos puestos y el fichero del idioma de referencia.