Módulo 4: Assumption And Hypothesis Testing
De la suposición a la hipótesis falsable
Descripción
"Los usuarios van a comprar más si ven recomendaciones personalizadas" es una suposición. Suena razonable, tiene datos detrás (risk: 0.6, impact: 5), y probablemente la mayoría del equipo esté de acuerdo con ella. Pero fíjate en un problema que esa frase, tal como está escrita, no resuelve: si en tres semanas las ventas suben, el equipo va a decir "funcionó, las recomendaciones ayudaron". Si las ventas no suben, alguien va a decir "es que todavía es muy pronto", o "el algoritmo necesita más datos", o "fue un mes flojo para todo el sitio". La suposición, como está redactada, no puede perder. Cualquier resultado se puede leer como una confirmación, incluso el resultado que, en el fondo, la contradice.
Una hipótesis es la misma creencia, pero encajada en una forma que sí puede perder. La plantilla es corta y siempre tiene tres partes: creemos que X (la creencia), lo sabremos si observamos Y (la señal que confirmaría X), y estaremos equivocados si observamos Z (la señal que probaría que X es falsa). La tercera parte es la que casi ningún equipo escribe por su cuenta — y es, con diferencia, la más importante de las tres.
Conexión con el módulo. Esta lección instala el objeto que vas a reutilizar sin cambios en el resto del módulo: una hipótesis con tres campos (believe, weWillKnowIf, wrongIf), y isFalsifiable(hypothesis), la función que chequea si esos tres campos están completos. La lección 3 reutiliza exactamente esta función sobre casos más difíciles; la lección 6 la combina con pickTest() en un checklist; y el proyecto del módulo (lección 8) escribe, con esta misma plantilla, la hipótesis real que usa el equipo de Mercado para decidir si vale la pena construir recommendations.
Una analogía cotidiana: tocar la estufa
De niño, probablemente alguien te dijo "la estufa está caliente, no la toques" — una suposición, transmitida de una generación a otra, que tú aceptaste o no sin ninguna evidencia propia. Hay dos formas de relacionarte con esa suposición. La primera: creerla para siempre, sin nunca ponerla a prueba, y vivir con una versión vaga de "probablemente esté caliente" que ninguna experiencia real puede confirmar ni contradecir. La segunda: convertirla en algo comprobable — si toco la estufa y no quema, estoy equivocado — y entonces sí, tocarla (con cuidado) para saber de verdad.
Fíjate en la estructura exacta de esa segunda frase, porque es la plantilla completa de esta lección: creemos que la estufa está caliente; lo sabremos si al tocarla sentimos calor o nos quemamos; estaremos equivocados si la tocamos y no pasa nada. La tercera parte —la condición de fracaso— es lo que convierte "una idea que tengo sobre el mundo" en "algo que puedo poner a prueba de verdad". Sin ella, tocar o no tocar la estufa no cambia nada sobre lo que crees: cualquier sensación se puede racionalizar como "bueno, un poco tibia sí estaba".
Ejemplo trabajado: isFalsifiable(), el primer chequeo
Con la plantilla clara, el siguiente paso es poder verificarla en código: dado un objeto con los tres campos, ¿tiene de verdad una condición de fracaso, o le falta la pieza que la hace útil? isFalsifiable() hace exactamente esa pregunta, sobre tres hipótesis candidatas — la buena, primero de forma correcta, y luego dos versiones defectuosas que representan los dos errores más comunes al escribir una.
// L2: primer chequeo de falsabilidad. Una hipotesis necesita, como minimo,
// una creencia (believe) Y una condicion de fracaso explicita (wrongIf).
function isFalsifiable(hypothesis) {
const hasBelief = typeof hypothesis.believe === 'string' && hypothesis.believe.trim().length > 0;
const hasFailureCondition = typeof hypothesis.wrongIf === 'string' && hypothesis.wrongIf.trim().length > 0;
if (!hasBelief) {
return { ...hypothesis, falsifiable: false, reason: 'no declara una creencia clara (believe) -- no hay nada que probar' };
}
if (!hasFailureCondition) {
return { ...hypothesis, falsifiable: false, reason: 'no declara una condicion de fracaso (wrongIf) -- no se puede refutar' };
}
return { ...hypothesis, falsifiable: true, reason: 'tiene creencia y condicion de fracaso, ambas observables' };
}
const recommendationsHypothesis = {
believe: 'Los usuarios van a comprar mas si ven recomendaciones personalizadas',
weWillKnowIf: 'al menos el 8% de los usuarios que ven una recomendacion la agregan al carrito',
wrongIf: 'menos del 8% de los usuarios que ven una recomendacion la agrega al carrito, incluso despues de dos semanas de exposicion',
};
const noFailureCondition = {
believe: 'A los usuarios les va a gustar ver recomendaciones personalizadas',
weWillKnowIf: 'lo vamos a notar en la reaccion del equipo de soporte',
wrongIf: '',
};
const noBelief = {
believe: '',
weWillKnowIf: 'medimos clics en la seccion nueva',
wrongIf: 'menos del 5% de los usuarios hace clic en la seccion nueva',
};
console.log('=== isFalsifiable() sobre 3 hipotesis candidatas ===\n');
[recommendationsHypothesis, noFailureCondition, noBelief].forEach((h, i) => {
const r = isFalsifiable(h);
console.log('Hipotesis ' + (i + 1) + ':');
console.log(' creemos que: "' + (h.believe || '(vacio)') + '"');
console.log(' lo sabremos si: "' + (h.weWillKnowIf || '(vacio)') + '"');
console.log(' estaremos equivocados si: "' + (h.wrongIf || '(vacio)') + '"');
console.log(' falsifiable: ' + r.falsifiable + ' -> ' + r.reason);
console.log('');
});
Qué esperar. Al correr el archivo con Node, la salida es exactamente esta:
=== isFalsifiable() sobre 3 hipotesis candidatas ===
Hipotesis 1:
creemos que: "Los usuarios van a comprar mas si ven recomendaciones personalizadas"
lo sabremos si: "al menos el 8% de los usuarios que ven una recomendacion la agregan al carrito"
estaremos equivocados si: "menos del 8% de los usuarios que ven una recomendacion la agrega al carrito, incluso despues de dos semanas de exposicion"
falsifiable: true -> tiene creencia y condicion de fracaso, ambas observables
Hipotesis 2:
creemos que: "A los usuarios les va a gustar ver recomendaciones personalizadas"
lo sabremos si: "lo vamos a notar en la reaccion del equipo de soporte"
estaremos equivocados si: "(vacio)"
falsifiable: false -> no declara una condicion de fracaso (wrongIf) -- no se puede refutar
Hipotesis 3:
creemos que: "(vacio)"
lo sabremos si: "medimos clics en la seccion nueva"
estaremos equivocados si: "menos del 5% de los usuarios hace clic en la seccion nueva"
falsifiable: false -> no declara una creencia clara (believe) -- no hay nada que probar
Mira con cuidado la Hipótesis 2, porque es el error más común de los tres: tiene una creencia clara, incluso tiene un weWillKnowIf — pero "lo vamos a notar en la reacción del equipo de soporte" no es una condición de fracaso, es una vaguedad optimista que solo describe cómo se vería el éxito. Nadie escribió qué pasaría si las cosas salen mal, así que isFalsifiable() la marca, con razón, como no falsable: sin importar lo que ocurra, no hay ningún resultado posible que el equipo haya aceptado de antemano como "estábamos equivocados". La Hipótesis 3 es el error contrario, menos común pero igual de real: alguien escribe una condición de medición completa (weWillKnowIf y wrongIf) sin nunca declarar qué es lo que en realidad se cree — un test sin ninguna afirmación real detrás.
Por qué weWillKnowIf y wrongIf casi siempre son el mismo número, visto desde dos lados
Fíjate en la Hipótesis 1: weWillKnowIf dice "al menos el 8%"; wrongIf dice "menos del 8%". No son dos observaciones distintas — son los dos lados de la misma línea, trazada antes de correr el test. Esto no es casualidad ni un detalle de estilo: es la forma correcta de escribir una hipótesis. Si weWillKnowIf y wrongIf apuntan a métricas distintas, o a umbrales que se solapan, queda un espacio intermedio donde cualquier resultado se puede interpretar como "ni confirma ni refuta, pero probablemente estamos bien" — la misma trampa de la suposición original, solo que ahora escondida en la letra chica. Escribe siempre el umbral una sola vez, y describe los dos lados de esa misma línea. El número específico —8%, en este caso— es un umbral pedagógico para el ejemplo; en un caso real, ese número sale de la conversación de negocio (¿cuánto necesitamos que suba la conversión para que valga la pena construir el motor completo?), no de una tabla estadística.
Errores comunes
Una "hipótesis" sin condición de fracaso — no se puede refutar. Qué pasa: el equipo escribe "creemos que a los usuarios les va a gustar ver recomendaciones" y lo presenta como la hipótesis lista para probar, sin ningún wrongIf. Por qué pasa: la creencia por sí sola ya se siente completa — tiene sujeto, tiene predicado, suena a afirmación seria — y falta la parte menos intuitiva: declarar por adelantado qué contaría como fracaso. Cómo detectarlo: exactamente lo que hizo isFalsifiable() con la Hipótesis 2 de hoy — si el campo wrongIf está vacío o falta, no hay hipótesis todavía, solo una expectativa. Cómo corregirlo: no cierres la redacción de una hipótesis hasta escribir su condición de fracaso explícita, en la misma sesión en la que escribes la creencia — nunca después de ver los resultados del test.
Escribir un wrongIf vago que en la práctica nunca podría observarse. Qué pasa: alguien sí llena el campo wrongIf, pero con algo como "si no funciona, lo vamos a notar" — técnicamente hay texto ahí, pero no describe ninguna observación concreta y medible. Por qué pasa: se siente como haber cumplido la regla ("tengo mis tres campos llenos") sin haber hecho el trabajo real de pensar qué observación específica probaría el error. Cómo detectarlo: pregúntate si dos personas distintas, mirando el mismo resultado del test, podrían llegar a conclusiones opuestas sobre si wrongIf ocurrió o no — si la respuesta es sí, el texto es demasiado vago. Cómo corregirlo: la lección 3 de este módulo profundiza en este error específico —el punto ciego de un chequeo automático como isFalsifiable()— y te da el criterio para detectarlo a ojo, no solo con código.
Ejercicios
Ejercicio 1 — Clasifica sin ejecutar Node. Para cada una de estas tres hipótesis, di qué devolvería isFalsifiable() (true o false) y por qué:
- (a)
{ believe: 'El motor de recomendaciones no va a hacer mas lento el sitio', weWillKnowIf: 'el tiempo de carga se mantiene bajo 2 segundos', wrongIf: 'el tiempo de carga sube por encima de 2 segundos' } - (b)
{ believe: 'A los usuarios les va a encantar la nueva seccion', weWillKnowIf: 'recibimos comentarios positivos', wrongIf: '' } - (c)
{ believe: '', weWillKnowIf: '', wrongIf: 'menos del 5% hace clic' }
Ver solución
- (a)
true. Tienebelieveno vacío ywrongIfno vacío — cumple ambas condiciones del código, en ese orden. - (b)
false. Tienebelieve, perowrongIfes una cadena vacía —isFalsifiable()la marca con la razón "no declara una condición de fracaso". - (c)
false. AunquewrongIfsí tiene contenido,believeestá vacío — y el código revisahasBeliefprimero, así que retorna ahí mismo con la razón "no declara una creencia clara", sin siquiera llegar a evaluarwrongIf.
Ejercicio 2 — Escribe tu propia hipótesis falsable. El assumption stack de recommendations tiene otra suposición además de la principal: "a los vendedores no les va a importar que sus productos aparezcan menos en las búsquedas por las recomendaciones". Escribe una hipótesis completa (believe, weWillKnowIf, wrongIf) para esa suposición, y verifica a mano que pasaría isFalsifiable() como true.
Ver solución
Una hipótesis razonable:
{
believe: 'A los vendedores no les va a importar que sus productos aparezcan menos en las busquedas por las recomendaciones',
weWillKnowIf: 'menos del 10% de los vendedores reporta una queja relacionada con visibilidad en las primeras 4 semanas',
wrongIf: 'el 10% o mas de los vendedores reporta una queja relacionada con visibilidad en las primeras 4 semanas',
}
Verificando a mano contra el código: believe no está vacío, wrongIf no está vacío — isFalsifiable() la marcaría true. Fíjate que, igual que en el ejemplo trabajado, weWillKnowIf y wrongIf son los dos lados de la misma línea (el mismo umbral del 10%, visto desde el éxito y desde el fracaso), no dos métricas distintas.
Ejercicio 3 — Explica por qué el orden de los campos importa en el código. Sin ejecutar Node, ¿qué pasaría si isFalsifiable() revisara hasFailureCondition antes que hasBelief? Para el caso noBelief del ejemplo trabajado, ¿cambiaría el resultado final, o solo la razón reportada?
Ver solución
Solo cambiaría la razón reportada, no el resultado final. noBelief tiene believe vacío Y wrongIf no vacío. Con el orden actual del código (hasBelief primero), la función retorna en el primer if con la razón "no declara una creencia clara". Si el orden se invirtiera, el primer if (ahora sobre hasFailureCondition) pasaría de largo porque wrongIf sí tiene contenido, y la función seguiría hasta el segundo if (hasBelief), donde de todos modos retornaría falsifiable: false — pero con una razón distinta si el mensaje también se reescribiera. El resultado booleano (false) es el mismo en ambos órdenes, porque a noBelief le falta una sola condición, no las dos. El orden solo importaría de verdad si un caso fallara ambas condiciones a la vez — ahí el mensaje reportado dependería de cuál if se revisa primero, igual que viste con classifyQuestion() en la guía anterior sobre entrevistas.
Resumen y siguiente paso
En esta lección convertiste una suposición —una frase que ningún resultado puede contradecir— en una hipótesis con estructura: creemos que X, lo sabremos si observamos Y, estaremos equivocados si observamos Z. Escribiste (y corriste) isFalsifiable(), la primera herramienta del módulo, y viste sus dos formas de fallar: una hipótesis sin creencia, y —mucho más común— una hipótesis sin condición de fracaso.
Antes de avanzar deberías poder: escribir la plantilla de tres partes de memoria; identificar, en una hipótesis ajena, si le falta el campo wrongIf; y explicar por qué weWillKnowIf y wrongIf casi siempre describen el mismo umbral, visto desde dos lados.
La lección 3 pone a prueba los límites de isFalsifiable(): vas a ver casos donde el chequeo automático dice true — porque el campo wrongIf técnicamente no está vacío — pero un lector humano, con el criterio de Karl Popper sobre lo que hace que una afirmación sea científica, reconocería que en realidad no se puede refutar.
Recursos
- Jeff Gothelf, "The Lean UX Canvas" — jeffgothelf.com/blog/the-lean-ux-canvas. El origen de la plantilla de hipótesis que usa esta lección: convertir suposiciones de negocio en hipótesis concretas antes de diseñar el experimento que las pone a prueba. En inglés.
- Teresa Torres, "Assumption Testing: Everything You Need to Know to Get Started" — producttalk.org/assumption-testing. Sobre qué es, exactamente, una suposición dentro del vocabulario de discovery, y por qué convertirla en algo comprobable es el primer paso antes de diseñar cualquier test. En inglés.
- Karl Popper, entrada "Karl Popper" en la Stanford Encyclopedia of Philosophy — plato.stanford.edu/entries/popper. La fuente completa del criterio de falsabilidad que sostiene esta lección y la siguiente: una afirmación es comprobable solo si existe una observación posible que la contradiría. En inglés.