Solucionando el problema de las preguntas en conferencias

En general, dentro del tiempo estipulado para las charlas por la organización de una conferencia se incluye unos minutos de preguntas y respuestas.

Esos minutos pueden ser más o menos, pero en general están ahí, excepto quizás para charlas ultracortas, como las Lightning Talks. Pero en una charla de 25 o 40 minutos, siempre habrán entre 3 y 10 minutos para que la gente pueda hacerle preguntas a les charlistas.

Entonces, cuando termina la charla, les charlistas agradecen, se avisa que arranca el espacio de preguntas y respuestas, y ahí aparece un momento de incertidumbre donde se espera a ver si en efecto hay alguna pregunta! La gente arranca (o no), y luego se utiliza todo el tiempo (o no), y termina el ciclo.

Más allá de sus ventajas obvias, que hacen que siempre haya de estos espacios en casi todas las charlas de casi todas las conferencias, esta dinámica tiene algunos problemas bien conocidos.

Entre ellos:

  • Romper barreras: no es fácil animarse a hacer preguntas en una conferencia, por múltiples razones. Podemos pensar que la pregunta es muy tonta, o que ya estuvo contestada pero no la entendimos. Quizás no querramos exponernos porque pertenecemos a alguna minoría y no sabemos si es un ambiente "seguro" (ver diversidad). Quizás nos dé vergüenza hablar en el idioma de les charlistas porque no lo manejamos del todo bien. Quizás tengamos directamente alguna dificultad en el habla.
  • Preguntas, no disertaciones: es bastante molesto (para les charlistas y para el público en general) cuando el que va a hacer una pregunta NO hace una pregunta, sino que se pone a exponer opiniones, dar sus puntos de vista, contestar otras preguntas anteriores, y en general toda disertación que no sea, efectivamente, una pregunta para las personas que acaban de dar la presentación.
  • No se escucha: la mayoría de las veces cuesta que todo el público escuche bien la pregunta que se está haciendo, especialmente si el ambiente es grande, o la persona habla en voz baja. A veces hay un micrófono que se puede acercar a la persona que hace la pregunta, pero tiene que haber alguien corriendo de un lado para el otro; a veces hay algún micrófono central al que nos podemos acercar para hacer la pregunta, pero eso incrementa la barrera que hablaba antes. Y si la charla se está filmando, y la pregunta no se hace por micrófono, directamente se pierde.

¿Cómo solucionamos esto? A mí se me ocurrió algo: el cuabot.

Un bot de preguntas y respuestas

El cuabot es un botcito de Telegram que se activa durante la conferencia y permite solucionar (al menos en parte) algunos de estos problemas.

La dinámica es la siguiente...

  • cualquier persona puede hablar con el bot, en cualquier momento, tiene sólo comandos para mandar preguntas
  • al conectarse por primera vez informa esos comandos, y hay uno por sala de la conferencia (ej: /salaA, /sala8, /plenaria); esto está obviamente configurado distinto por conferencia
  • entonces asistimos a una conferencia, vamos a una charla, y si queremos hacer una pregunta en cualquier momento, ejecutamos el comando que corresponda del bot según la sala en que estemos
  • el bot va a replicar esta pregunta en un grupo privado donde está el responsable de la sala y un par más (no todo el mundo)
  • cuando termina la charla propiamente dicha, el responsable de la sala va a tener N preguntas YA hechas (aunque la gente puede escribir también en ese momento), elige cual(es) preguntas valen la pena o entran en el tiempo, y las comunica

Esto soluciona los problemas antedichos:

  • Romper barreras: es mucho más fácil animarse a escribir algo que decirlo en voz alta en un salón lleno de gente, especialmente si es en un idioma en el que no estamos muy habituados.
  • Preguntas, no disertaciones: el responsable de la sala puede ignorar tranquilamente algo que NO sea una pregunta, aunque también puede decidir qué es lo mejor para el cierre de la charla (elegir las mejores 3 preguntas de muchas, si hay poco tiempo, o si casi no hay preguntas pero hay un par de comentarios, también puede leer eso para llenar el tiempo); de cualquier manera el poder lo tiene el responsable de la sala, en vista de todo lo que haya mandado el público
  • No se escucha: el responsable de la sala puede hablar directamente en uno de los micrófonos habilitados, al que no hace falta llevarlo a las corridas por toda la sala.

Obviamente trae algunos detalles a la conversación: la gente tiene que tener un dispositivo en la mano para poder mandar el mensaje (algo que sucede con altísima frecuencia), este dispositivo tiene que estar conectado a internet (lo cual es una buena suposición), y la persona tiene que tener Telegram instalado/configurado (que es bastante normal para personas técnicas).

De cualquier manera, como último recurso siempre se puede hacer la pregunta de la forma clásica (moviendo aire con nuestros pulmones y modulando ese flujo de aire con nuestras cuerdas vocales).

Comentarios Imprimir

Matemática: de las gaseosas a Python

El sábado hago un asado por el cumple de Felu, así que estamos comprando vituallas. Entre ellas, gaseosas; Moni las compró ayer a la noche, y como era tarde quedaron en el living.

Esta mañana, las fui llevando de a 3 (fácil de agarrarlas) hasta la cocina, no me sobró ninguna botella (o sea, la cantidad era múltiplo de 3). A la tarde las llevé al quincho, pero las agarré de a 4 (más lío, pero valía la pena porque el "viaje" es más largo): me sobró una botella (o sea, hice un último viaje con una botella sola).

Me quedé pensando: ¿cómo calcularía uno qué numero de botellas moví? Debería ser una de las soluciones a algo como (si x es la cantidad de botellas) x % 3 = 0 y x % 4 = 1.

Lo tiré en twitter.

Roberto al toque propuso algunas cosas, pero aunque quedaba como un paso más cerca de la resolución, yo no terminaba de entender como dar el paso final.

Interesante, porque al menos hasta este yo ya me estaba dando cuenta de que ese problema que me parecía difícil de generalizar en verdad lo era (más allá de mis limitaciones matemáticas), escuché por primera vez ecuaciones diofánticas, e incluso me di cuenta que estaba rozando el 10° problema de Hilbert.

El décimo problema de Hilbert, NO de Dilbert!

Luciano entró en el juego, y luego de un poco de charla alrededor del problema, y vislumbró por donde podía venir la mano.

Efectivamente, terminó confirmando que el problema se podía resolver mediante el teorema chino del resto, e incluso pasó un video que lo explica (en inglés), que me marqué para ver en algún momento.

Y no sólo es, también mostró cómo resolverlo en Python! Miren:

$ fades -d sympy
Python 3.6.8 (default, Jan 14 2019, 11:02:34)
...
>>> from sympy.ntheory.modular import crt
>>> x, N = crt([3,4], [0,1])   # 3 y 4 son los divisores, 0 y 1 los restos correspondientes
>>> [x + i * N for i in range(10)]
[9, 21, 33, 45, 57, 69, 81, 93, 105, 117]

En mi caso, había movido 21 botellas. Un espectáculo.

Comentarios Imprimir

Perlitas Python

Estas últimas semanas estuve bastante a full, especialmente con un montón de pequeñas cositas de Python, las tiro como popurrí...

El 28 de Agosto hubo un meetup en oficinas de Virtualmind (Socia Benefactora de la Asociación Civil. Fue el primero ahí y estuvo muy bueno, gracias Nariné por la coordinación por parte de la empresa y todo. Tuvimos las charlas de "Cómo publicar una biblioteca en PyPI (y todo lo que conlleva)" por Agustín Scaramuzza y "Testing basado en propiedades con Hypothesis" por Sasha, y después un espacio social mientras picábamos y tomábamos algo. Y después un grupito ya reducido nos fuimos un rato más por ahí...

El 30 de Agosto di mi ya clásica charla de Introducción a Python en el curso de posgrado Herramientas Computacionales para Científicos de la Universidad de La Plata. Esta vez como novedad invité a Yanina a que hable de la comunidad de Python y Python Argentina. Y después como siempre Manu y familia nos agasajaron en su casa (espectaculares pizzas caseras!).

Mañana viernes doy una charla, también de Intro a Python, en la Universidad Nacional de Hurlingham. Está bueno empezar a hacer cosas en Universidades, ojalá tuviera más tiempo para empujar esto más fuerte.

Este sábado, ya ya también, se realiza el PyDay de Rosario, al que lamentablemente no voy a poder asistir. Vayan que las charlas pintan buenísimas!!

Por suerte el 27 de Septiembre me desquito y voy (a Rosario, justamente) un meetup que hace rato estamos tratando de organizar en la sede de San Cristobal, que es Socia Benefactora de la Asociación Civil. Y tengo ganas de dar una charla ahí,. Así que si están por la zona y quieren pasar a saludar, bienvenides :) (especialmente si por algún motivo se pierden el PyDay de este sábado!!).

Charlas, charlas, charlas

Además de todo eso, muy a full con la PyConAr de Diciembre, preparando todo, coordinando a un grupo copado que están laburando un montón. En un par de días cierra el Call for Charlas, y ya estamos viendo el nuevo logo, vamos a hacer remeras (estén atentes a la preventa para comprarlas baratas!), ya tenemos confirmado a un keynote (nos falta una), y montón más de detallitos... o más bien, detallotes! :)

También, lo que me lleva bastante carga horaria (nos lleva, realmente, a Leandro (tesorero) y a mí), estoy ayudando al PyData Córdoba y el PyDay de Rosario recién mencionado, en esto de la Asociación Civil Python Argentina como paraguas de organización (básicamente, ayudar a la gente a hacer eventos, con cobertura institucional y manejo de dinero).

Y finalmente, a punto de terminar de renovar el logo de PyAr, ya tendremos novedades :D

Comentarios Imprimir

Series (y películas) a todo ritmo

Buena racha de ver pelis! Entre viajes, ratos libres, pelis que vi de casualidad, metí un montón estos últimos meses! Por otro lado, no anoté tantas nuevas para ver, así que ahí vamos bajando los pendientes.

En lo que también avancé bastante fue con las series...

  • Girls: bleh, pero me dió para terminarla; me gustó mucho la actuación de Adam Driver, un descubrimiento.
  • The Kaminsky Method: es MUY buena, especialmente si estás envejeciendo :p.
  • The Strain: una de vampiros, pero con una vuelta de tuerca "realista", muy explícito todo, Guillermo del Toro en su máxima expresión.
  • Louie: la corté, le dí cinco capítulos, pero es un humor que no me mueve un pelo. O sea, la comedia se basa en un humorista, sus monólogos, y vida, y lo que hace no me divierte. Seguro a otros le gustará.
  • Love, Death & Robots: la disfruté mucho. Hay algunos que bleh, pero como son cortitos, no pasa nada. Hay otros que son geniales.
  • The Bletchley Circle: está bien, bastante mejor la primer temporada que la segunda, pero son cortas así que zafa.

Ahora estoy con:

  • Vikings: promete, es larga, veremos como la llevan; por lo pronto me molesta la estúpida dicotomía de "violencia sí sexo no". O sea, está bien mostrar como a uno le cortan la cabeza y la sangre salpica todo, pero está mal mostrar una teta incluso al amamantar, ni hablemos de desnudos eróticos, o sexo!
  • True Detective: la primera temporada es MUY BUENA; creo haber escuchado que las otras dos no están relacionadas, ojalá no decaiga demasiado el nivel.
Carla Gugino en Gerald's Game

En fin, ¡películas!

  • A Scanner Darkly: -0. La historia está buena, tiene sus giros interesantes, pero se me hizo muy cuesta arriba el tipo de imagen (animada, todo el tiempo como "temblando").
  • Amateur: No la pude encontrar para ver :(.
  • Blind: +0. Una historia de amor, no mucho más, incluso un poco menos, pero está bien.
  • Bright: +0. Sobre-explicada, y con demasiados "rosas" en la historia, pero me gustó el acercamiento distinto a un tema clásico, y cómo maneja el "siempre hay un excluido".
  • Counterpart: Era una serie! La saqué de la lista de películas, entonces, la anoté en mi otra lista :)
  • Deadpool 2: +0. Entrega todo lo que promete, que no es demasiado: acción, humor negro, algunos chistes decentes, y no mucho más.
  • Distorted: -0. Tiene algunas partes interesantes, pero a nivel técnico / explicaciones, es todo demasiado "por encima", y constantes malas decisiones de les protagonistas aburre un poco. NO es un buen otro punto de vista sobre un tema ya trillado.
  • El faro de las orcas: +0. Muy linda película, los paisajes son imponentes, vale la pena incluso siendo tan leeenta.
  • Gerald's Game: +1. Me gustó mucho. Basada sobre un libro de Stephen King, el único libro en mi vida que lo tuve que cerrar en un momento porque me dio miedo (y estaba en el subte a las seis de la tarde). No recuerdo tanto la historia como para decir si fue bien llevada al cine, pero me gustó mucho como está hecha (la dificultad estructural de la conversión libro/peli reside en que la mitad de todo pasa estando una persona sola).
  • Infancia clandestina: +1. Muy buena, muy dura; vale la pena.
  • It: +1. Me gustó un montón, la peli asusta y tensiona, y aunque es un toque larga hay un montón de detalles de dirección y fotografía que la hacen super disfrutable. Falta la segunda mitad, claro.
  • Julie & Julia: +0. Una linda película sobre la historia de dos cocineras y sus pasiones.
  • La reina del miedo: -0. Me pareció entre sosa y tirada de los pelos.
  • Le vache: +0. Linda historia, interesante ver un tipo de vida al que no estamos acostumbrados, me gustaría verla visto en idioma original y subtitulada, la conseguí solamente doblada al castellano.
  • Los decentes: -1. Está bien expresada las diferencias de clase y la evolución de la piba en su descubrimiento. Pero es insoportablemente lenta. Hay una escena donde a una mujer se la ve por un pasillo y luego entra a la cocina, en el medio pasan 19 segundos de nada, de NADA. Es LENTA.
  • Marjorie Prime: -0. Está buena como uso experimental de una tecnología, pero es demasiado lenta, y un poco sin un "tema" o "sentido".
  • Mission: Impossible - Fallout: +0. Positivo si te gusta más o menos la saga. Me llamó la atención que me pareciera que las escenas de piñas/patadas/tiros no saturaban el resto de la película (por eso mi voto positivo), cuando eso es lo primero que me cansa. Una más de misión imposible, pero zafa.
  • Mother!: +1. Tiene una forma de llevarte por la historia MUY rara, pero efectiva, de transportarte por situaciones que no son sencillas de contar cinematográficamente. No tiene nada que ver, pero me dejó con ganas que ese director filme The Dark Tower como corresponde.
  • Replicas: -0. Demasiada fantasía y poca discusión sobre qué significa ser humano, "qué somos", etc. Keanu Reeves empieza a restarle a las películas, es el nuevo Nicolas Cage (?).
  • Solo: A Star Wars Story: +0. Está bien la historia en sí, se sostiene, la peli entretiene. Es una pochoclera más, pero mezclada con el resto de la historia, funciona.
  • Suburbicon: -0. La historia (aunque sorprende, tiene sus giros y te lleva) es bleh, y por un buen rato la película no va a ningún lado.
  • Surviving the 70's: +0. Excelentes las actuaciones de Alejandro Awada y Patricio Contreras, incluso Romina Ricci está a la altura. A la otra chica le falta un poco, pero no llega a restar. Muy "teatral", la historia está bien.
El coso

Más películas anotadas para ver:

  • Captain Marvel: (2019; Action, Adventure, Sci-Fi) Carol Danvers becomes one of the universe's most powerful heroes when Earth is caught in the middle of a galactic war between two alien races. [D: Anna Boden, Ryan Fleck; A: Brie Larson, Samuel L. Jackson, Ben Mendelsohn]
  • El cuento de las comadrejas: (2019; Comedy, Drama) A group of four old friends conformed by a film director, a film writer, an actress and her husband share a big house in the country. Their coexistence is menaced by a young couple who resourcefully and deceitfully seek to get them to sell the house to develop a real estate project of their own. [D: Juan José Campanella; A: Graciela Borges, Oscar Martínez, Luis Brandoni]
  • El increíble finde menguante: (2019; Drama) It's not a loop, it's a countdown: Alba is trapped in her weekend, forced to relive it over and over again, but each repetition gets a bit shorter. [D: Jon Mikel Caballero; A: Iria del Río, Adam Quintero, Nadia de Santiago]
  • La odisea de los giles: (2019; Adventure, Comedy, Crime, Drama, History, Thriller) Based on the book from Eduardo Sacheri "The Night of the Heroic Losers" (Alfaguara Novel Prize 2016). In a far-flung town in the province of Buenos Aires, many things are about to die out. During the economic crisis that led to the traumatic bank freeze of 2001, a group of men decides to gather the amount of money necessary to acquire some abandoned silos on an agro-industrial property. But even before they can carry out the project, a scam makes them hit rock bottom and react in the face of injustice. Now it's about robbing the thief. This novel narrates the story of a well-deserved collective revenge carried out during a legendary night that will never be forgotten.::chepevm [D: Sebastián Borensztein; A: Ricardo Darín, Luis Brandoni, Chino Darín]
  • Lucy in the Sky: (2019; Drama, Sci-Fi) Astronaut Lucy Cola returns to Earth after a transcendent experience during a mission to space, and begins to lose touch with reality in a world that now seems too small.::Fox Searchlight Pictures [D: Noah Hawley; A: Natalie Portman, Dan Stevens, Jon Hamm]
  • Empowered: (2018; Comedy) After to visit a Hindi guru healer, Paz loses control over what she says and starts speaking out everything that comes to her mind.::Chockys [D: Santiago Segura; A: Maribel Verdú, Diego Martín, Toni Acosta]
  • The Old Man & the Gun: (2018; Biography, Comedy, Crime, Drama, Romance) Based on the true story of Forrest Tucker and his audacious escape from San Quentin at the age of 70 to an unprecedented string of heists that confounded authorities and enchanted the public.::Fox Searchlight Pictures [D: David Lowery; A: Robert Redford, Casey Affleck, Sissy Spacek]
  • Yucatán: (2018; Comedy) Two white collar thieves compete fiercely against the other trying to steal millions from an old baker, that he won in the lotto.::Chockys [D: Daniel Monzón; A: Luis Tosar, Rodrigo De la Serna, Joan Pera]
  • Ad Astra: (2019; Adventure, Drama, Mystery, Sci-Fi, Thriller) An astronaut travels to the outer edges of the solar system to find his father and unravel a mystery that threatens the survival of our planet. He uncovers secrets which challenge the nature of human existence and our place in the cosmos. [D: James Gray; A: Brad Pitt, Liv Tyler, Ruth Negga]
  • Terminator: Dark Fate: (2019; Action, Adventure, Sci-Fi) Sarah Connor has returned from far away, and she's gearing up with a team of agents who will fight against T-1000. [D: Tim Miller; A: Arnold Schwarzenegger, Edward Furlong, Mackenzie Davis]
El escenario de Mother

Finalmente, el conteo de pendientes por fecha:

(Dic-2013)    4
(Abr-2014)    3
(Jul-2014)   10   5   1
(Nov-2014)   22  22   7
(Feb-2015)   13  13  10
(Jun-2015)   16  15  13  11   1
(Dic-2015)   21  19  19  18   6   1
(May-2016)       26  25  23  21   9
(Sep-2016)           19  19  18  14   1
(Feb-2017)               26  25  23  21   9   1
(Jun-2017)                   23  23  21  18   5
(Dic-2017)                       19  19  18  16   5
(May-2018)                           22  22  22  17
(Sep-2018)                               12  12  12
(Mar-2019)                                   13  13
(Ago-2019)                                       10
Total:       89 100  94  97  94  89  84  79  69  57
Comentarios Imprimir

Complejidad, performance, y expresiones regulares

Hace algunos meses (sí, este post me había quedado en el tintero) se presentó en el laburo una tarea particular: había que evitar algunas búsquedas que se estaban haciendo en el Snap Store que no tenían realmente sentido (y algunas complicaban al buscador), como por ejemplo 123333333333333333333. En estos casos es útil contestar "vacío" directamente sin hacer laburar al sistema.

Cuando me comentaron del inconveniente me ofrecí a agarrar la tarea, porque ya había hecho esto mismo. Es más, hice un poco de arqueología y encontré un código muy similar, que en su momento había escrito para el buscador de scopes. Entre otras restricciones a las búsquedas, estaba la de "detectar ráfagas de letras iguales".

O sea que si en una búsqueda cualquier letra se repetía más de N veces sin otra cosa en el medio, esa búsqueda no tiene sentido. Como ejemplo, para N=3 la búsqueda foxxbarxxxdox es correcta, pero monroooose no. En el primer caso no importa que la x aparezca muchas veces, nunca aparece ininterrumpidamente más que 3, y en el segundo caso la o aparece en una ráfaga de 4 veces: alpiste.

Buscar palabras en servicios web es más sencillo que buscar el destino (?)

El código que rescaté (y usé en el nuevo servicio) era exactamente este:

# detect a "lot of same letter in a row"
cnt = 1
prev = None
for char in term:
    if char == prev:
        cnt += 1
        if cnt > MAX_REPEATED_IN_A_ROW:
            return True
    else:
        cnt = 1
        prev = char

La variable term es justamente la palabra buscada, y MAX_REPEATED_IN_A_ROW es una constante del módulo que indica el N que hablábamos arriba (pero mejor descripto, je).

Cuando propuse el branch, la persona que hizo el review le pareció que se podía mejorar ese algoritmo. O mejor dicho, reemplazarlo totalmente por una expresión regular, y propuso lo siguiente:

for char in term:
    if re.search(r"{char}{times,}".format(char=char, times=MAX_REPEATED_IN_A_ROW), term):
        return True

Casi enseguida, se dio cuenta que hacer una regex (apócope en inglés para "expresión regular") por cada caracter no iba a estar bueno, y mejoró (?) la misma para hacer solamente una regex en total:

if re.search(r"(\w)\1{{{times},}}".format(times=MAX_REPEATED_IN_A_ROW - 1), term):
    return True

¿Valía la pena ir a algo más complejo? ¿O no era tanto más complejo? El loop original no me gustaba del todo, realmente, pero me parecía más fácil de entender que una expresión regular como las propuestas... y también más sencilla de modificar a futuro si los requerimientos cambiaban sutilmente.

Por otro lado, las expresiones regulares parecían funcionar en las pruebas que había realizado a mano (y en los test cases que tenía. Y quizás fuese más rápido, después de todo estamos cambiando un algoritmo hecho en Python por una regex (cuyo motor está hecho en C). Pero no me convencía hacer el cambio.

Para agregar elementos en el análisis, me propuse medir tiempos. La mejor forma era simular la realidad, así que pedí los logs de alguno de los servidores, agarre toneladas de búsquedas reales de un par de semanas anteriores (176 mil), y me puse a medir cuanto tardaba tanto el loop original como las dos regexes propuestas como reemplazo (todos pensábamos que la segunda era más rápida que la primera, pero no costaba nada comprobarlo).

Al comenzar este análisis encontré rápidamente que la regex "lenta" no servía del todo: explotaba por el aire con búsquedas como ter$. La descarté para hacer foco en los otros dos códigos y no irme por las ramas.

Ya desconfiando, armé un programita que no sólo analice los tiempos del loop y la regex rápida, sino que también compare los resultados... y vi que no daban lo mismo siempre! Exploré un poquito y encontré que la regex "rápida" daba resultados erróneos para búsquedas como loch,,,,,,,,,,.

Mejoramos entonces la regex, y nos quedó:

if re.search(r"(\.)\1{{{times},}}".format(times=MAX_REPEATED_IN_A_ROW - 1), term):
   return True

Esta funcionó, al menos para todos los ejemplos que yo tenía para medir los tiempos. Pero cuanto podía confiar que no íbamos a encontrar otro caso en el futuro que la haga romper?

¿Y si yo no hacía correr todos los ejemplos y metíamos la anterior, que no funcionaba del todo?

Hay una frase en modo de chiste (pero más o menos verdad) que dice que "si tenés un problema, y para resolverlo usás expresiones regulares, ahora tenés dos problemas".

Por otro lado, ¿valía la pena el cambio a nivel de velocidad?

Pongámonos a medir tiempos, pasame el cronómetro

Los resultados del análisis de tiempos me terminó dando que la última expresión regular tardaba (en promedio, para cada búsqueda) 1.5056µs, mientras que el loop tardaba 1.456µs.

La regex era más lenta, por casi 50 nanosegundos.

Dejé el loop.

Comentarios Imprimir