Vim-golf y drills de eficiencia
El golf como práctica de maestría: quince retos concretos con antes y después, solución contada pulsación a pulsación y presupuesto, desde xp hasta :g, cgn, macros, marcas y registros. Cómo contar teclas con honestidad, y cuándo el golf deja de entrenar y empieza a estorbar.
El vim-golf es un juego con una regla: dado un texto inicial y uno final, llegar en el mínimo número de pulsaciones. Como deporte tiene su comunidad y sus campeonatos; como herramienta de entrenamiento es otra cosa, y más seria: es la forma más barata de descubrir la distancia entre lo que sabes y lo que tu mano elige bajo presión. Sabes que existe daw desde el Nivel 0; el golf mide si lo tecleas cuando toca o si tu mano sigue prefiriendo ocho pulsaciones de x. Esta lección es una ronda completa: quince retos ordenados de calentamiento a final, cada uno con su texto, su presupuesto y su solución contada tecla a tecla.
- Situar el golf donde corresponde: práctica de recuperación para lo ya aprendido, no método para aprender cosas nuevas.
- Contar pulsaciones con las reglas estándar, que es lo que da sentido al presupuesto y a la ★ del repaso.
- Jugar una ronda de quince retos que cubre la gramática del Nivel 0 y las herramientas del Nivel 1: objetos, bloque visual, registros, marcas,
:g,cgny macros. - Reconocer las tres situaciones en que el golf es contraproducente, y dejar de contar teclas en ellas.
Práctica de maestría, no de aprendizaje
Conviene decirlo antes del primer reto, porque el golf tiene mala fama precisamente entre quienes lo usan mal: el golf no enseña nada nuevo. Si no conoces cgn, ningún reto de golf te lo va a revelar; te vas a frustrar contra un muro que la lección 1.3 derriba en diez minutos. El orden correcto es siempre lección primero, golf después.
Lo que el golf sí hace, y no lo hace nada más, es forzar la recuperación. Leer la lección 1.2 y asentir no demuestra que sepas registros; demuestra que la explicación era buena. Resolver el reto 10 de esta ronda sin mirar la solución —traer "0p de la memoria, sin pista, con el reloj de tu paciencia corriendo— es un acto distinto, y es el que fija. Cada reto de esta ronda es una pregunta de examen sobre una lección concreta que ya cursaste, y por eso la ronda entera alimenta el repaso: estos drills entran en tu cola de repaso espaciado y volverán a preguntarte dentro de tres, siete y veintiún días, que es cuando de verdad se decide si los sabías.
Juega cada reto así: lee el antes y el después, resuélvelo tú primero en el drill —tecleando de verdad, no mentalmente—, cuenta tus pulsaciones, y solo entonces abre la solución. Si tu solución es distinta pero iguala el presupuesto, es tan buena como la de la lección; en golf no hay soluciones oficiales, hay pulsaciones.
Cómo contar pulsaciones
Las reglas de conteo son las estándar de la comunidad, y las mismas que usa el presupuesto de los drills del repaso:
- Cada tecla pulsada cuenta una: letras, dígitos, símbolos, espacios.
Esccuenta una.Entercuenta una.- Un acorde con modificador cuenta una:
Ctrl-ves una pulsación, no dos. - El texto que escribes en Insertar o en la línea de comandos cuenta carácter a carácter: escribir
hola mundoson diez.
Un ejemplo contado entero, que además es el reto 7 de la ronda: ci"hola mundo y Esc son c+i+" (3) más diez caracteres de texto (10) más Esc (1): 14 pulsaciones. Fíjate en la moraleja del conteo: cuando hay texto nuevo que escribir, el texto domina el total y la diferencia entre una solución buena y una mala está en las tres o cuatro teclas de alrededor. Cuando no hay texto que escribir, cada tecla cuenta el doble y ahí es donde el golf se pone interesante.
En el repaso, la ★ de un drill significa exactamente esto: resuelto sin pista y dentro del presupuesto. El presupuesto de cada reto de esta ronda es la solución de la lección; igualarlo demuestra dominio, y superarlo —pasa más de lo que crees— merece que lo compartas.
La ronda: calentamiento
Cinco retos de gramática pura, Nivel 0. Si alguno se te resiste, la lección 0.4 es tu casa.
Reto 1 · par 2. El error tipográfico más viejo del mundo.
antes: mejor teh que nunca ↑ cursor en la edespués: mejor the que nuncax borra la e (y la deja en el registro sin nombre); p la pega después de la h. Dos pulsaciones: x+p. El intercambio de caracteres adyacentes es un solo gesto, no una sesión de Insertar.
Reto 2 · par 3. Eliminar un elemento de una lista sin romper el espaciado.
antes: uno dos tres ↑ cursor en cualquier parte de dosdespués: uno tresdaw (3): delete a word, la palabra con su espacio. Con diw quedarían dos espacios seguidos, y con dw dependerías de estar al principio exacto de la palabra. daw funciona desde cualquier punto de ella.
Reto 3 · par 3. Intercambiar la línea actual con la de abajo.
antes: segunda primeradespués: primera segundadd (2) corta la línea; p (1) la pega debajo de la actual. Tres pulsaciones y las líneas quedan intercambiadas. El registro sin nombre trabaja para ti sin que lo nombres.
Reto 4 · par 4. Pasar una palabra a mayúsculas.
antes: -- nivel: dios ↑ cursor en la palabradespués: -- nivel: DIOSgU es un operador como cualquier otro, así que compone: gUiw (4) = uppercase inside word. Reescribirla a mano son ocho pulsaciones y una oportunidad de equivocarte que antes no existía.
Reto 5 · par 3. Indentar el cuerpo de un bloque, sin seleccionar nada.
antes: function f() { let x = 1 return x } ↑ cursor en cualquier línea del interiordespués: function f() { let x = 1 return x }> (operador de indentado) + i{ (objeto: dentro de las llaves): 3 pulsaciones para el bloque entero, esté donde esté el cursor dentro de él. La versión con Visual —seleccionar líneas y >— cuesta más y no se beneficia de . para repetir.
La ronda: los objetos trabajan por ti
Tres retos donde el texto nuevo domina el conteo y la gramática decide el resto.
Reto 6 · par 13. Cambiar los argumentos de una llamada.
antes: fetch(a, b) ↑ cursor dentro de los paréntesisdespués: fetch(url, opts)ci( (3) vacía el interior y entra en Insertar; url, opts son 9; Esc (1). Total 13. La posición dentro de los paréntesis no importa: el objeto la resuelve.
Reto 7 · par 14. Reemplazar el contenido de un string.
antes: let saludo = "helo wrld";después: let saludo = "hola mundo";ci" (3) + hola mundo (10) + Esc (1) = 14. Detalle que vale oro: los objetos de comillas buscan hacia delante en la línea, así que ci" funciona incluso con el cursor antes de la primera comilla (:h i'). Es el único objeto que hace eso.
Reto 8 · par 8. Comentar cuatro líneas de golpe.
antes: a = 1 b = 2 c = 3 d = 4 ↑ cursor en la primera columna de la primera líneadespués: // a = 1 // b = 2 // c = 3 // d = 4Ctrl-v (1) + 3j (2) marca el bloque; I (1) inserta al principio; // son 3; Esc (1) lo replica en las cuatro líneas. Total 8. Con gc3j serían 4 y ganaría el golf —pero solo si el fichero tiene un tipo con commentstring; el bloque visual funciona en cualquier parte, incluido este drill.
La ronda: registros y marcas
Nivel 1, lección 1.2. Aquí es donde el golf empieza a distinguir a quien leyó la lección de quien la entrenó.
Reto 9 · par 8. Copiar un valor de un string a otro.
antes: version = "2.1.0" ↑ cursor dentro del primer string fallback = "0.0.1"después: version = "2.1.0" fallback = "2.1.0"yi" (3) copia el interior y deja el cursor al principio de lo copiado; j (1) baja —y aterriza sobre el segundo string—; vi" (3) selecciona su interior; P (1) pega encima. Total 8. La P mayúscula en Visual es la fina: pega sin machacar el registro, así que podrías seguir pegando el mismo valor en diez sitios más. Con p minúscula, el registro pasaría a contener 0.0.1 y el segundo pegado sería basura.
Reto 10 · par 8. Pegar lo copiado después de borrar por el camino.
antes: plantilla ↑ cursor aquí bórrame objetivodespués: plantilla objetivo plantillayy (2), j (1), dd (2) —que machaca el registro sin nombre—, y aquí está el reto entero: "0p (3) pega del registro 0, que solo guarda yanks y al que los borrados no llegan. Total 8. Si tu instinto fue p a secas y pegaste bórrame, la lección 1.2 te espera.
Reto 11 · par 8. Borrar un bloque delimitado por marcas.
antes: intro BORRAR desde aquí ← dejaste ma al pasar ...muchas líneas... hasta aquí BORRAR ← dejaste mb al pasar finaldespués: intro final:'a,'bd (7 caracteres) + Enter (1) = 8 (12 si cuentas las cuatro de dejar ma y mb al pasar). Las marcas como límites de un rango Ex son el uso que casi nadie entrena: no hace falta ver el bloque ni contar líneas, porque lo delimitaste cuando lo tenías delante. Cualquier comando de rango las acepta: :'a,'by, :'a,'b>, :'a,'bs/….
La ronda: edición en masa
Los pesos pesados del Nivel 1: :g, cgn y macros. Presupuestos altos, rendimiento por pulsación altísimo.
Reto 12 · par 8. Eliminar todas las líneas en blanco.
antes: uno ␣ dos ␣ ␣ tresdespués: uno dos tres:g/^$/d (7) + Enter (1) = 8, y el conteo es idéntico con seis líneas que con seis mil: ahí está la gracia de :g. El patrón ^$ —principio y final pegados— es la definición exacta de línea vacía. Su hermano :v/ERROR/d (el que borra lo que no casa) resuelve el filtrado de logs con el mismo esquema.
Reto 13 · par 13. Renombrar revisando, sin :s.
antes: let data = load(); ↑ cursor sobre data check(data); return data;después: let result = load(); check(result); return result;* (1) busca la palabra bajo el cursor; cgn (3) cambia la siguiente coincidencia; result (6); Esc (1); y cada . (1+1) busca y cambia a la vez. Total 13. La virtud sobre :%s//result/g no es el conteo, que queda parecido: es que entre punto y punto puedes pulsar n para saltarte una ocurrencia. Es el reemplazo con derecho a veto de la lección 1.3.
Reto 14 · par 14. Transformar una lista en literales de string.
antes: rojo verde azul negro blancodespués: "rojo", "verde", "azul", "negro", "blanco",La grabación: qa (2), I" (2), Esc (1), A", (3), Esc (1), j (1), q (1) = 11. La reproducción: 4@a (3). Total 14. La j final dentro de la macro es lo que la hace repetible: cada ejecución deja el cursor lista para la siguiente. Con quinientas líneas, el total sube exactamente una pulsación (499@a) — y con 99@a ni cuentas: la j falla en la última línea y detiene la repetición sola.
Reto 15 · par 10. Reunir las líneas TODO al final del fichero.
antes: codigo // TODO: uno mas codigo // TODO: dos findespués: codigo // TODO: uno mas codigo // TODO: dos fin // TODO: uno // TODO: dos:g/TODO/t$ (9) + Enter (1) = 10: para cada línea que casa, t$ la copia al final. Y cuando el destino no es este fichero, la variante con registros de la 1.2: qaq limpia el registro, :g/TODO/y A acumula cada línea en él (la A mayúscula añade en vez de reemplazar), y "ap pega la colección donde quieras — en otro buffer, en otra ventana, donde sea. Un aviso de campo: el primer añadido sobre el registro recién vaciado cuela una línea en blanco al principio del pegado; un dd la despacha. Más pulsaciones, cero opciones en golf — y aun así es la variante que gana en la vida real.
Cuándo el golf es contraproducente
El golf es una herramienta de entrenamiento con tres modos de fallo conocidos, y conviene tenerlos delante porque los tres son tentadores.
Contar teclas durante el trabajo real. El coste dominante de editar código nunca es teclear: es decidir qué escribir. Si en mitad de un refactor te paras a buscar la solución de siete pulsaciones en vez de ejecutar la de doce que ya te sabes, has cambiado dos segundos de teclado por veinte de deliberación, y encima has salido del problema que importaba. La regla es limpia: en el repaso se cuenta; en el trabajo, jamás. El objetivo del entrenamiento es precisamente que la solución corta se vuelva la automática, para que en el trabajo no haya nada que decidir.
Confundir corto con bueno. En vimgolf.com verás soluciones ganadoras que parecen ruido de módem: explotan carambolas del texto concreto —un salto que aterriza de chiripa donde conviene, un p que funciona por el estado accidental de un registro—. Son divertidas y no enseñan nada, porque no se transfieren: la solución que quieres entrenar es la que haría lo correcto también en el fichero de mañana. Recuerda la prueba de repetibilidad de la 0.4: ¿esta misma frase funcionaría en la línea de abajo? El golf de campeonato responde que no y le da igual; a ti no debería.
Golfear lo que no has aprendido. Ya lo dijimos arriba, pero es el error más caro: usar retos como método de descubrimiento. Fallar un reto de cgn sin haber cursado la 1.3 no produce aprendizaje, produce la sensación de que Vim es arbitrario. El fallo útil —la dificultad deseable de la lección 6.1— es el que ocurre al borde de lo que sabes, no en territorio sin mapa.
El efecto testing: por qué preguntarse gana a releer
La razón de que esta lección sean quince preguntas y no quince explicaciones tiene nombre propio en la ciencia del aprendizaje: el efecto testing, o efecto de la práctica de recuperación, documentado experimentalmente por Henry Roediger y Jeffrey Karpicke con un resultado que sigue sorprendiendo a todo el mundo: recuperar algo de la memoria fija ese algo mucho más que volver a estudiarlo, y la ventaja crece con el tiempo transcurrido. Releer produce una fluidez engañosa —el texto «suena» conocido y el cerebro confunde reconocerlo con saberlo—; el intento de recuperación, incluso cuando falla, fortalece la ruta de acceso de un modo que la relectura no toca.
La generalización vale para cualquier cosa que quieras retener, y desmonta cómo estudia casi todo el mundo. Releer apuntes y subrayar: fluidez, no memoria. Taparlos e intentar reproducir el argumento: memoria. Ver la solución del problema y asentir: nada. Intentar el problema antes de mirar la solución: casi todo. Explicarle a un colega el sistema que acabas de entender, sin mirar el diagrama: la forma más barata de descubrir que no lo habías entendido. Los exámenes tienen mala prensa como instrumento de medición, pero como instrumento de aprendizaje son de lo mejor que hay, y las mejores herramientas de estudio del mundo —de las flashcards al método socrático— son formas de convertir el estudio en examen continuo.
Por eso el orden de esta guía es lección → drill → repaso, y no lección → lección → lección. Y por eso la instrucción de «resuélvelo tú primero» no era una formalidad: el valor del reto está antes de abrir la solución. Un drill mirado es una relectura; un drill intentado es un test. Solo el segundo te cambia.
Tu tarjeta de resultados
- Juega la ronda entera en orden, resolviendo cada reto antes de abrir su solución, y apunta tus pulsaciones en cada uno.
- Suma tu total y compáralo con el par del campo: 119 pulsaciones. Hasta 135 es una gran ronda; si bajas del par en algún reto, documenta tu solución.
- Los retos donde te pasaste del par son tu diagnóstico: identifica qué lección del Nivel 0 o 1 cubre cada uno y ponla en tu lista de repaso.
- Estos quince drills ya están en tu cola de el repaso: el objetivo de la quincena es ★ en al menos diez —sin pista y dentro del par— cuando el repaso espaciado te los vuelva a servir.
- Diseña un reto de golf propio con el protocolo de la 6.1: un antes y un después de tu trabajo de esta semana, tu mejor solución contada tecla a tecla como par, y al repaso.