wandres.dev
SNIPPETS · Tu caja de herramientas

Diseñar tu caja de herramientas

Los criterios que separan un snippet que usarás durante años de uno que ejecutarás una vez: idempotencia, limpieza, salida legible y nombres que se encuentran.

⏱ 14 min

La diferencia entre una colección de snippets útil y un cajón de trastos no está en el código sino en cinco decisiones de diseño que se toman al escribirlos. Un snippet que rompe la página cuando lo ejecutas dos veces, o que deja basura, o que devuelve un volcado ilegible, o que no recuerdas cómo se llama, es un snippet que no vas a usar. Estos son los criterios, con las plantillas que los implementan.

🎯 Al terminar esta lección sabrás
  • Escribir snippets idempotentes que se puedan ejecutar repetidamente sin efectos acumulativos.
  • Incluir siempre un mecanismo de limpieza y una forma de invocarlo.
  • Diseñar la salida para que se lea de un vistazo en vez de haber que expandirla.
  • Nombrar y organizar la colección para que se encuentre desde el menú de comandos.

Criterios de comportamiento

Criterio 1: idempotencia

Ejecutar el snippet dos veces debe dejar el mismo estado que ejecutarlo una vez. Es el criterio más importante porque el fallo es silencioso y acumulativo.

Los tres patrones según lo que haga el snippet.

Si solo consulta, es idempotente por construcción y no hace falta nada.

Si instala algo —un observador, una envoltura, un elemento en la página— el patrón es el interruptor: comprobar una clave global, y si existe, desinstalar y salir.

Si modifica la página de forma persistente, conviene que sea reversible o al menos que avise.

// Plantilla de interruptor: instala o desinstala segun el estado
(() => {
  const CLAVE = '__nombreDeLaHerramienta';
  if (globalThis[CLAVE]) {
    globalThis[CLAVE]();
    delete globalThis[CLAVE];
    console.log('%cOFF%c herramienta desactivada', 'background:#f38ba8;color:#11111b;padding:1px 6px;border-radius:3px', '');
    return;
  }

  // --- instalacion ---
  const limpiezas = [];
  // ejemplo: un listener
  const fn = e => console.debug('evento', e.type);
  addEventListener('resize', fn);
  limpiezas.push(() => removeEventListener('resize', fn));

  globalThis[CLAVE] = () => limpiezas.forEach(f => { try { f(); } catch (e) { console.warn('fallo al limpiar:', e); } });
  console.log('%cON%c herramienta activada; vuelve a ejecutar para pararla', 'background:#a6e3a1;color:#11111b;padding:1px 6px;border-radius:3px', '');
})();

El array de limpiezas es lo que hace la plantilla escalable: cada cosa que instales añade su reverso, y la desinstalación es genérica.

Criterio 2: no romper la página

Un snippet de diagnóstico que provoca un error en la aplicación es peor que no tenerlo, porque el error se confunde con el bug que investigabas.

Las tres precauciones.

Envuelve los accesos que pueden fallar. Leer cssRules de una hoja de otro origen lanza. Acceder a contentDocument de un iframe ajeno lanza. Llamar a una API que puede no existir lanza.

const seguro = (fn, porDefecto = null) => { try { return fn(); } catch { return porDefecto; } };
const reglas = [...document.styleSheets].map(h => seguro(() => h.cssRules.length, 0));

Comprueba antes de usar APIs recientes. navigator.storage, cookieStore, PerformanceObserver con tipos concretos: todos pueden no estar. Un encadenamiento opcional o un try evitan que el snippet falle entero por un dato secundario.

Marca lo que insertes en la página. Cualquier elemento que añadas debe tener pointer-events: none, un z-index máximo, y un atributo que lo identifique como tuyo para poder eliminarlo con una consulta.

const marca = document.createElement('div');
marca.dataset.herramienta = 'mias';
marca.style.cssText = 'position:fixed;z-index:2147483647;pointer-events:none';
// Y para limpiar cualquier resto olvidado:
// document.querySelectorAll('[data-herramienta="mias"]').forEach(e => e.remove());

Esa última línea comentada merece ser un snippet propio: la escoba que limpia todo lo que hayas dejado tirado en cualquier página.

Criterio 3: salida legible

Un snippet que devuelve un array de doscientos objetos plegados no ha resuelto nada: ha movido el trabajo de buscar a otro sitio.

Las cuatro reglas de la salida.

Tabula. console.table con las columnas que importan, no el volcado completo.

Ordena por lo que importa. El elemento más grande, el más lento, el más repetido, arriba.

Recorta. Las primeras veinte filas y un contador del total. Nadie lee doscientas.

Resume antes de detallar. Una línea con el titular —cuántos hay, cuánto suman, si hay algo alarmante— antes de la tabla.

// Patron de salida: titular, aviso si procede, tabla recortada
const filas = [];  // ... lo que sea que hayas calculado
const total = filas.reduce((s, f) => s + f.bytes, 0);
console.log(`%c${filas.length} elementos%c, ${(total / 1024).toFixed(1)} kB en total`,
  'background:#89b4fa;color:#11111b;padding:1px 6px;border-radius:3px', '');
if (filas.some(f => f.bytes > 500000)) console.warn('hay elementos por encima de 500 kB');
console.table(filas.slice(0, 20));
if (filas.length > 20) console.log(`... y ${filas.length - 20} mas`);

Y una regla adicional que ahorra mucho: devuelve el resultado. La última expresión de un snippet aparece en la consola y queda en $_, así que se puede seguir trabajando con ella sin volver a calcular.

Criterios de organización

Criterio 4: nombres que se encuentran

Los snippets se invocan escribiendo ! y unas letras en el menú de comandos, así que el nombre es la interfaz.

Usa prefijos por familia. dom-, a11y-, red-, perf-, store-. Escribir !a11y lista todos los de accesibilidad.

Empieza por el verbo o el sustantivo que buscarías. dom-desborde se encuentra buscando desborde; analisis-de-anchura-del-documento no se encuentra buscando nada.

Marca los que instalan algo. Un sufijo como -toggle recuerda que ese snippet es un interruptor y que hay que volver a ejecutarlo para pararlo.

Criterio 5: versionarlos fuera

Los snippets no se sincronizan ni se exportan, así que el navegador no es su sitio definitivo. Tres opciones, de menos a más elaborada.

Un repositorio con un fichero por snippet. Simple, se copia y pega al montar una máquina.

Un solo snippet cargador que instala todas tus herramientas como métodos de un objeto global, visto en la primera lección de este nivel. Ventaja: una sola cosa que pegar.

Un cargador que descarga desde una URL. Un snippet de tres líneas que trae el resto desde un gist o desde tu propio dominio.

// Cargador: trae tus herramientas desde una URL y las instala en globalThis.h
(async () => {
  const URL_HERRAMIENTAS = 'https://ejemplo.com/mis-herramientas.js';
  const codigo = await (await fetch(URL_HERRAMIENTAS)).text();
  (0, eval)(codigo);
  console.log('herramientas disponibles en h:', Object.keys(globalThis.h || {}).join(', '));
})();

Ese (0, eval) no es un adorno: fuerza la evaluación en el ámbito global en vez del local, que es lo que quieres para que las declaraciones del fichero queden accesibles. El coste es que una política de seguridad de contenido estricta bloqueará tanto la descarga como la evaluación, así que en muchos sitios reales no funcionará y habrá que caer en el pegado manual.

La caja de herramientas es una forma de acumular conocimiento que la memoria no consigue

Hay una razón de fondo por la que merece la pena tomarse en serio esta colección, y no es la comodidad. Depurar es una actividad donde el conocimiento se pierde casi por completo entre sesiones. Resuelves un bug difícil, entiendes exactamente por qué ocurría, escribes una consulta ingeniosa que lo demuestra, y tres meses después no recuerdas ni el bug ni la consulta. Lo único que queda es una sensación vaga de haber visto algo parecido. Eso ocurre porque el conocimiento de depuración es procedimental y contextual: no son hechos que se puedan escribir en una nota, son formas de mirar que solo tienen sentido delante del problema. Un snippet es la única forma que conozco de capturar ese tipo de conocimiento, porque no guarda la conclusión sino el procedimiento, y el procedimiento se puede volver a ejecutar sobre un problema nuevo. Cuando dentro de un año te encuentres con una barra de scroll horizontal, no necesitarás recordar la lógica de comparar rectángulos con el ancho del documento: ejecutas !dom-desborde y el pasado te contesta. Multiplicado por veinte herramientas, eso construye algo parecido a una memoria externa de tu propia experiencia técnica. Hay un efecto secundario que resulta ser tan valioso como el principal y que conviene aprovechar: una caja de herramientas es lo mejor que se le puede dar a alguien que empieza en tu equipo. Un desarrollador nuevo no sabe qué comprobar ni en qué orden, y una lista de quince snippets con nombres descriptivos es un currículo implícito de qué preguntas merece la pena hacerse sobre una página. Aprende más ejecutándolos y leyendo su código que con cualquier documento de buenas prácticas, porque cada uno responde a un problema real que alguien tuvo. Compartir la caja es, en la práctica, compartir criterio.

⚔️ Reto práctico

Coge las tres últimas cosas que investigaste en la consola de las que te acuerdes, escríbelas como snippets con la plantilla de interruptor, y ponles nombre con prefijo. Después ejecútalas sobre una página que no sea tuya. Si alguna falla, es que dependía de algo de tu proyecto y no era una herramienta general, y arreglarla es el ejercicio que enseña la diferencia.