Roberto Alsina: Coffee As a Service Architecture

Coffee As A Service Architecture


Today I was in a meeting with recruiters (yes, really) because they want to be better at technical recruiting and they had the idea that talking to me would help them (oh, sweet summer children).

A nice time was had by all (I hope) and at one point I was asked about what architecture was, and more specifically, about the difference between microservices and a monolith.

Which I tried to explain using what I had at hand: coffee cups, sugar dispensers, a spoon and so on. It didn't quite work out but I kept thinking about it on my way home and ... let's try again.

What is Architecture?

Architecture, when it comes to software, can be defined in many ways, but one way I like is to say that architecture involves:

  • What the components of your system are
  • How they are done
  • How they talk to each other

There is a lot more, but you start with that, and that is more or less enough to explain monoliths and microservices.

The Coffee Service

One thing of massive importance about systems is that they are meant to do something. They exist for a purpose. So, let's suppose the purpose of our system is to make coffee and put it in a cup.

We can call the cup the "coffee client" and whatever we use to make the coffee is the "coffee system" or "coffee service"

So, assuming you have a can full of cofee beans and a cup, how do you make coffee?

The Coffee Monolith

This is my very own coffee machine. Not only is it monolith-shaped, it's functionally monolithic (it's also large enough to deserve its own table, as you can see).

It has two buckets on top. On one you put water, in the other you put coffee beans. Then, you put a cup under the spigot and press a button or two.

It will:

  • Grind the beans
  • Put the ground coffee in the right place and apply the "right" pressure
  • Heat the water to the "right" temperature
  • Run water through the coffee grounds
  • Pour the coffee into the cup
  • Discard the grounds into a hidden deposit

Sounds awesome, right? It is!

It takes all of 30 seconds to go from coffee beans to a nice cup of coffee! It tastes good!

And it's important to keep that in mind. IT IS GREAT.

Monoliths, when they done correctly and you are not expecting anything out of their operating parameters, are awesome.

The problem with monoliths is not that they can't be done right, it's that it's hard to do them right, and that even when you do get it right, in our industry the meaning of "right" is not fixed.

So, because the whole point is to ride this analogy into the ground, let's consider all the things about this awesome machine.


It grounds the coffee. What happens if you want it ground finer? Or coarser?

It turns out that if you have the right tool you can adjust the mill's output (it's not in the manual).

In a microservice-based coffemaker I would replace the grinder.

How about water temperature?

It has three settings. Want anything else? No luck.

In a microservice-based coffee service I would just use an adjustable kettle.

How about the amount of coffee per cup?

It has three settings. Want anything else? No luck.

In microservice-cofee I would just transmit as much coffee as I wanted.

How about changing the bean variety between cups?

The bean hopper takes half a pound of beans. It's not easy to get them out. So, no.

In microservice-coffee heaven I could have multiple hoppers providing beans of all varieties and just connect to the one I want today!

Cup size?

It does two sizes (but you reprogram those sizes)

In microservice-cofee I would just pour as much water as I liked.

A monolith has the flexibility its designers thought of adding, no more, no less. And changing it is ... not trivial.

I could use a vacuum cleaner to remove the beans from the hopper and change varieties. I would consider that a hack. I have also done it. I regret nothing.

Unused Features

It has a thing that lets you setup a credit system for coffee cups I will never use. A milk foamer I use once a week. Why? Because "we may need this and it's hard to add it later, so let's just do it from the beginning" ground coffee.

Sometimes yes, it's useful (capuccino!) but sometimes it's just something I paid for and will never use (coffee credits!)

In a microservice architecture I would just get a new milk foamer, use both for a while and then keep using the one I like.

Hard to Improve

How do I add a better foaming thingie?

By buying one and putting it in the table.

How do I add a more flexible coffee grinder?

I can't because this machine is incompatible with pre-ground coffee. There is a newer, more expensive model that can take that but this one? You need to throw it away.

Modifying a monolithic system is difficult because the pieces are tightly coupled. I can't use a separate grinder because the system requires the coffee grounds to arrive via a specific internal duct at a specific point in the coffee-making cycle, there is just no way to insert my grind-o-matic-3000 in there without a saw and duct tape.

In a modular system I would unplug the grinder and insert a compatible-but-different grinder, in a microservice architecture I would just use whatever grinder and put the coffee grounds in a message and have the next piece in the system pick it from there.


This coffee machine is expensive. It's much more expensive than buying a grinder, a coffee machine a kettle and a milk foamer.

What it provides in exchange for the extra money (and reduced flexibility and so on) is performance. I don't boil water, I don't grind coffee, I don't pour, I just press a damned button and enjoy coffee.


You can buy pre-ground coffee and effectively outsource that part of the process to some external provider.

I can't! I am doomed to ground my own coffee forever.


I have a lubrication schedule, or else my expensive machine will break.

I have to disinfect the coffee ground bin or else it will have maggots.

I have to empty the water waste tray before it overflows.

I have to have a thing to dump the bits of dirty water it uses to clean itself when it turns on/off.

I have to buy special acid to periodically remove scale from its innards or it will stop working. That costs actual money and takes half an hour.

I need to cleanup coffee crud from all the internal springs, levers and thingies every couple of weeks.

Now, you, readers with normal coffee making things? How is your coffee machine maintenance routine? What, you don't have one? Thought so.


So, that's why nowadays most people prefer to pay the performance penalty of a microservice architecture instead of using an awesome monolith.

This is not exhaustive, there is still separation of concerns, encapsulation, rigidity of contracts and a lot more, but it should be convincing enough without being dogmatic :-)

Facundo Batista: A todo Python, noticias, eventos


Hace unas semanas anunciaba por acá (y por otros lados) que iba a dar un Seminario Python nivel medio/avanzado con apoyo de Onapsis, abierto a la comunidad.

Explotó, en cuatro días tenía el 80% de las vacantes con la reserva confirmada, en siete días estaba todo cerrado. No esperaba un éxito tan rotundo, pero estoy muy contento. El lado gris es que un par se me enojaron porque no llegaron a entrar en el curso porque se demoraron en pagar (la mayoría lo entendió perfectamente).

Seguramente haré otros cursos durante el año. SPOILER ALERT: quizás algo introductorio primero y medio/avanzado luego, pero no sólo teoría sino también práctica, en conjunto con otro docente. Ya habrán novedades.


Ayer sábado fui invitado por Ana Vélez Rueda a dar una charla de introducción a la programación primero e introducción a Python luego, en la Universidad de Quilmes, para futuros docentes de Python. Luego de pensarlo bastante estos últimos días mezclé un poco ambas charlas, y creo que salió muy bien. La gente estuvo super interesada, y aunque fue largo y cansador (¡sábado a la tarde!) se la bancaron.

Próximos eventos de PyAr

Hay dos juntadas planeadas a futuro. La primera, bastante confirmada y que será anunciada estos días es el martes 21 a la tarde/noche, en J.P. Morgan, y va a ser una charla/taller sobre testing, más la parte social de siempre.

La segunda, todavía en etapa de "ver qué forma le damos" va a ser en Trocafone, el sábado 15 de Junio. Como es sábado, la idea es hacer algo más tipo sprint. O sea, ponernos a trabajar en algo (puntual o no), aunque seguramente abriremos el día con un par de charlas, quizás trabajar a la tarde luego del almuerzo, etc. Como les decía, todavía hay que definir la dinámica de ese día, pero está bueno volver cada tanto a la juntada de sábado, para hacer cosas :)

Anunciaremos detalles sobre ambas juntadas tanto en mi tuiter como en el de Pyar, pero la coordinación la haremos a través del meetup de Buenos Aires así que también se pueden sumar ahí.

Facundo Batista: Seminario Python, nivel medio/avanzado

Por segunda oportunidad voy a dar un Seminario de Python abierto al público en general, coordinado con Onapsis, aunque esta vez no va a ser introductorio sino que va a tener un nivel de medio a avanzado.

El contenido apunta a aquelles que ya tienen una base de Python y buscan formalizar conocimientos y terminar de establecer una estructura que les permita explorar temas más avanzados. De esta manera sólo voy a hacer un repaso rápido de los temas más simples, y haré foco en cuestiones más avanzadas o poco conocidas del lenguaje.

En otras palabras, asumiré un conocimiento de las estructuras más simples y usadas del lenguaje (que voy a repasar de forma breve) y voy a profundizar en otros temas del lenguaje y sus bibliotecas. El programa es super variado, me entusiasmé y metí un montón de temas, así que el ritmo de las clases va a ser interesante. Vengan despiertes :p

Algunos títulos (¡no todos!) son:

  • Generadores
  • Scopes
  • Closures y decoradores
  • Clases, y métodos especiales
  • Virtualenvs
  • Unit testing, logging, serialización
  • Concurrencia y paralelismo, threading y async
  • Context managers

Les decía que el Seminario es abierto al público en general, y será de 16 horas en total, cuatro sábados de Junio, durante la mañana, en CABA.

El costo es súper accesible, $1400, ya que parte lo cubre Onapsis, y la idea es hacerlo barato para que pueda venir la mayor cantidad de gente posible, y encima van a haber algunas becas. Ojo que los cupos son limitados (la oficina tiene un límite), por lo que cuanto antes consigan reserva la posición, mejor... tengan en cuenta que para la primera edición hubo gente que quedó afuera.

Al final del Seminario entregaré un certificado de asistencia y la totalidad del curso en formato electrónico.

Para realizar la reserva deben enviarme un mail así les confirmo disponibilidad y les paso los datos necesarios para realizar el pago (que podrá ser por depósito, transferencia bancaria, tarjeta de crédito, débito, etc.).

Acá están todos los detalles del curso.

Facundo Batista: Sincronizando (una historia de "soltar")

En una charla nerds con amigos surgió el tema de cómo guardar "pequeñas notas" de forma piola (que se replique, que sea posible buscar, que sea más o menos simple, etc.). En su momento barajamos varias opciones, y a mí me quedó dando vueltas en la cabeza un clientito que se instala y trabaja contra Nextcloud.

Nextcloud es una suite de servicios alrededor de sincronizar archivos, notas, tareas, etc, y ofrece formas de armar grupos de colaboración para trabajar con todo eso. Yo puntualmente estaba interesado en lo que es sincronización de archivos, y potencialmente notas.

Para mí es todo un viaje, porque tomé la decisión de que si Nextcloud funcionaba correctamente dejaba de usar Magicicada (ex Ubuntu One). Aunque estoy emocionalmente atado a ese pedazo de software, y todo lo que representó en mi carrera laboral y como evolución en Python, en algún punto entendí que NUNCA voy a tener tiempo de agregarle los features que quería para que cumpla con todo lo que quiero tener, en parte porque el tiempo que sí tengo prefiero (o preferiría) dedicárselo a otras cosas, incluso a otros proyectos de software, u otros hobbies no tan relacionados con la informática.

La decisión

Entonces, me voy de Magicicada. Cuando internamente terminó de madurar ese proceso adentro mío, me puse a laburar seriamente con Nextcloud. Lo instalé en mi servercito casero, y funcionó. Luego, toda la fase de cómo usarlo desde cada computadora. Quise probar que sincronice archivos desde el desktop, y a priori no anduvo.

Investigué un poco, creo que es por algo de la URL, y para dejar 100% como dice el manual del server le tengo que instalar SSL. Puedo para eso usar el servicio de LetsEncrypt, pero para que funcione (según entendí y probé) tengo que tener el puerto 80 accesible desde afuera. El tema es que Claro (mi proveedor de internechi) no me enruta más puerto por puerto, con lo que tendría que armar una DMZ acá en mi intranet, lo cual no es trivial (y asumiendo que el cambio de config de Claro no me rompa otra cosa y me deje en pelotas y en la vía).

Pero... pero.... pero.... pero... Me dí cuenta que NO tengo ganas de crear todo un universo sólo para finalmente tener una tarta de manzana :)

Alta tarta de manzanas

Y, pensé en Dropbox...

Hasta ahora venía esquivando Dropbox porque es una empresa yanqui, y meter todos mis datos ahí siempre me dio escozor. Como uno no tiene control sobre la encriptación de los archivos (se encriptan al transmitirse, y teóricamente cuando están guardados, pero Dropbox posee la clave para abrirlos) pueden ver todo lo que tengo. ¿En qué me jodía? Por un lado tengo mucha música en mp3, y aunque toda esa música la bajé de CDs que legalmente compré (!) no quiero que el día de mañana me rompan las pelotas porque les parezca que estoy infringiendo copyright. Por otro lado, tengo un montón de datos sensibles que no me gustaría que queden expuestos al mundo en caso de un fallo de seguridad de Dropbox.

Pero, estos dos aspectos ahora no me joden tanto. Con respecto a la música, es un riesgo que puedo correr. Con respecto a mis datos privados, hoy por hoy los tengo todos bajo KeePassX, así que todo bien ahí.

Por otro lado, al mismo tiempo NO quiero todo encriptado, porque ahí ya no podría acceder a mis archivos desde el teléfono o desde la web directamente, en caso de necesitarlo, y este es un feature que sí quiero... y una de las razones fuertes para irme de Magicicada.

El nuevo mundo

Habiendo sopesado estas variables, terminé de tomar la decisión. Me voy a Dropbox. La cuenta gratuita no me alcanza, pero la más barata sí, porque me ofrecen un terabyte de almacenamiento (puedo meter todas mis fotos y videos caseros, entre los cuales no llego a los 300GB), y cuesta USD 8.25, que por todo lo que yo uso este servicio, se justifica.

Igual, antes de "tirarme a la pileta", tenía que hacer otra verificación. Dropbox, ¿funciona?

Ejecuté una batería de pruebas desde mi computadora de escritorio. Funciona bien con Vim, que es complicado porque mueve/graba/mueve todo el tiempo. Funciona bien con LibreOffice, que maneja cada documento como un directorio comprimido con montón de archivitos adentros. También le abrí un archivo .tar de pocos archivos inmensos, y otro de montonazo de pequeños archivos en una árbol grandote de directorios, y se la bancó.

Y después ya en el baile le puse toda mi música, y todos mis archivos "simples" (en otras palabras, todo lo que sincronizo normalmente, excepto fotos y videos).

En todos los casos, fui comprobando los hashes de todo contra lo que el mismo Dropbox bajaba en la laptop. Se la bancó.

Yo, tirándole cosas a Dropbox hasta asegurarme que funca

Bien, ¡funciona! ¿Tiene algunos puntos débiles o negativos? Encontré tres grandes cosas que me molestan...

Por un lado, tenés que tener todo dentro del directorio $HOME/Dropbox. Con Ubuntu One y Magicicada yo siempre tuve el directorio default de cada uno, más una de Música, una de video, y una de fotos, que eran externas. Pero Dropbox no te deja hacer eso, tiene que estar todo adentro de la misma raíz.

La solución/parche que implementé es tener un .externals en ese directorio raíz, y ahí adentro la de música, fotos y videos, y desde los otros lugares hice un enlace simbólico. No es lo que más lindo queda, pero funciona. Un enlace simbólico al revés NO funciona, ya que Dropbox sincroniza el archivo del symlink en sí, y no el directorio al que apunta.

Otro punto negativo que me pareció HORRIBLE al principio pero luego no me pegó tanto (aunque tuve que tocar un par de archivos) es que Dropbox no respeta diferencias entre mayúsculas y minúsculas. O sea, que si vos tenés un archivo barco y otro Barco, Dropbox NO te sincroniza ambos, sino que uno de los dos te lo renombra para indicarte la colisión. Entiendo que se debe a que algunos sistemas de archivos de Windows tienen este mismo problema, pero Dropbox debería ser más inteligente y como yo tengo en todos lados Linux, no exponerme a esa limitación.

Finalmente, Dropbox es bastante flojo con respecto a sus notificaciones y data que tira al usuario. En mi sistema operativo (KDE Neon sobre Ubuntu Bionic) me pone un ícono en el systray que tiene un tilde verde, y cuando está sincronizando titila algo azul. Si lo abro, junto con otra info me dice en qué estado está: normalmente en "Actualizado", a veces mostrando la operación actual, pero de forma bastante resumida.

Desde linea de comandos puedo hacer dropbox status que me muestra esa misma info, pero me es más accesible. También es útil el dropbox ls o dropbox filestatus pero le falta información realmente sobre qué hizo, algo detallado que muestre en qué estado está con cada cosa, o donde poder revisar qué pasó media hora atrás... o sea, logs.

Quiero ver qué está haciendo, dejame ver qué está haciendo, mostrame qué está haciendo

Entiendo que a la mayoría de los usuarios finales no les importe más información que esa, pero yo en algunos casos necesito tener más control de lo que está haciendo o pasó.

¿Y las pequeñas notas?

Para cerrar el ciclo con el arranque del artículo, ¿qué onda sincronizar notas? Mariano me dijo que usaba bastante Zim Wiki, que es 100% texto y guarda las cosas en archivos sincronizados por, claro, Dropbox.

Él lo usa con el cliente que proveen en Linux y Windows, o directamente tocando el archivo de texto correspondiente en el teléfono. Me comentó también que tiene un "buscar" que funciona, y permite agregarle etiquetas (tags) a las notas.

Lo voy a probar.

Facundo Batista: Películas, duda, series

De nuevo vi bastante más que las que anoté para ver. Pero no le estoy dedicando mucho tiempo a ver películas (aunque aproveché bastante los vuelos largos en el último viaje), con lo cual creo que lo que pasa es que estoy anotando pocas nuevas.

¿Por qué? Creo que porque no hay mucho que me interese de lo que está saliendo (por ejemplo, ignoro todo lo que sean películas basadas en guerra, o de terror "normal" (o sea, aburrido), o la trigésimo novena de los avengers, etc...).

¿O quizás estoy perdiéndome de ver trailers que están buenos? ¿Hay películas que están por salir que piensan que están buenas y NO estoy anotando? ¿Mejores lugares para buscar trailers que IMDb? Propongan.

Por otro lado, estuve arrancando y cerrando un par de series. Recomiendo fuerte Borgen, enterita. Es muy buena. La primera temporada de Fargo es genial, la segunda pinta muy bien (estoy en eso). También estoy viendo Girls, que zafa. Y para que vean que no son todas rosas, tenía bajadas para ver y no pude pasar del primer capítulo (y picoteos de otros capítulos, para asegurarme de no llevarme una impresión equivocada) de Flight of the Conchords (no es mi tipo de humor, no me da nada, muy aburrida) y Dark Net (odio las series medio en primera persona onda "yo soy un muchacho tranquilo, crecí en oklahoma, conocí mi chica online" mientras lo muestran llevarle pasto a una vaca o una boludez así).

Bueno. A los bifes...

  • Absolutely Anything: +0. Una idea no nueva, pero encarada de un lado interesante y divertida.
  • Atomic Blonde: +0. No deja de ser una de espías en la época de la guerra fría, pero atrapa, divierte, y convence (si es que te interesa ese tipo de películas).
  • Atomica: -0. El contexto y parte de la historia eran interesantes, pero las actuaciones bleh, la peli en general no suma.
  • Black Snow: -0. La historia zafa y las actuaciones están buenas, pero es muy lenta por partes, y no te deja gran cosa.
  • Elle: -0. Es una historia chata, en el sentido que va contando cosas que poquito a poquito suma un relato, pero nunca te das cuenta cual es el nudo de la cuestión, entonces como que no vas entendiendo mucho, pero algo se forma; más allá de eso, no me entusiasmó nada.
  • Frank & Lola: +0. La película está bien, no es gran cosa pero cierra y se pasa un buen rato. Compensan que sí me gustan las películas "de chefs" y que no me gustan las películas donde las parejas tienen relaciones tóxicas.
  • Future Man: No es una peli, sino una serie! Ahí la reencolé donde corresponde, sacándola de acá.
  • MindGamers: -0. Tiene partes muy interesantes, pero el estilo de filmación la hace medio insoportable, y aunque una notable suma de sinsentidos parece acomodarse luego, no llega a funcionar.
  • Murder on the Orient Express: -0. No me terminó de enganchar... No sé exactamente qué es lo que hizo que la peli se me haga muy anodina.
  • Passengers: +0. Divertida, con efectos interesantes, con una trama liviana pero dinámica y se la pasa bien.
  • Ready Player One: +0. Está buena por los efectos y por todas las referencias... luego la historia no me llamó demasiado la atención.
  • Rooster's Blood: +0. Casi la saco cuando habían pasado veinte minutos y la historia no apuntaba a ningún lado, pero terminó zafando y está buena. Hay que bancarse algunos planos lentos interminables, pero va.
  • The Assignment: -0. Me gustó la forma gráfica de contar y mostrar la historia, y la historia misma no está mal, con un par de vueltas que sorprenden y te llevan hasta el final. Pero está armada como si fuese el suceso épico del cine y se queda muy corta, y eso hace que le reste un montón.
  • The Autopsy of Jane Doe: +1. Con la base de la historia muy conocida (se trató miles de veces), la peli logra darle un giro totalmente "real" pero sorprendente, lo cual más allá de que la peli es en sí de terror, tiene ese misterio que te lleva hasta al final y vale la pena.
  • The Circle: +0. La historia zafa, los paralelos con la realidad son evidentes; es una muy buena película para que muchos tomen conciencia de a donde nos dirigimos.
  • The Comedian: -0. La historia zafa, pero no va a ningún lado, las actuaciones están bien, pero a la peli le falta como "consistencia"...
  • The Discovery: +0. El concepto base de la historia está bueno, la trama alrededor también, y la vuelta del final es inesperada. Está bien.
  • The Little Hours: +0. Muy divertida, muy atípica. Ligeramente basada en el Decamerón, es una excusa para hilar una historia que lleva bien la peli.
  • The Recall: -1. Es muy mala. Así y todo la terminé de ver, porque no es que haya algo que sea insoportable, sólo es muy mala de forma parejita :).
  • The Whole Truth: +0. Está bien, se nota que la trama es más compleja y está resuelta con la voz en off, pero se sigue bien y se arma todo bien, con un desenlace no esperado y que cambia un poco la perspectiva de lo anterior.
  • Unlocked: +0. No deja de ser una de espías/acción, pero las idas y vuelta que tiene la hacen interesante. Pierde un poco la gracia el final como apostando a secuelas, pero bueh, la primera zafa, si hacen una continuación no me anoto...
  • What Happened to Monday: +0. Muy rara, pero entretenida. Lo que labura la actriz con los múltiples papeles es loable.
  • Zero Days: -1. No la pude terminar de ver de lo embolante que era. Hay toda una parte interesante que es, justamente, el tema del virus. Y todo lo relacionado con la planta atómica también está bueno. Pero si estirás eso a casi dos horas de película, encima en ese formato de "entrevistas", se hace insoportable.
Jane Doe

De las pocas nuevas...

  • Hellboy: (2019; Action, Adventure, Fantasy, Sci-Fi) Based on the graphic novels by Mike Mignola, Hellboy, caught between the worlds of the supernatural and human, battles an ancient sorceress bent on revenge.::Dominic Henriott AND ABDUL [D: Neil Marshall; A: David Harbour, Milla Jovovich, Ian McShane]
  • Yesterday: (2019; Comedy, Drama, Fantasy, Music, Musical, Romance) A struggling musician realizes he's the only person on Earth who can remember The Beatles.::a_clockwork_alpaca [D: Danny Boyle; A: Ana de Armas, Lily James, Kate McKinnon]
  • All Inclusive: (2018; Comedy) Pablo and Lucia live together. Pablo buys an All-Inclusive in Brazil online as a surprise for Lucia but his boss firing him, so Pablo tries to cancel the trip but he can't. They travel anyway, but Brazil waits with nothing but trouble.. [D: Diego Levy, Pablo Levy; A: Alan Sabbagh, Julieta Zylberberg, Mike Amigorena]
  • Aniara: (2018; Drama, Sci-Fi) A spaceship carrying settlers to Mars is knocked off course, causing the consumption-obsessed passengers to consider their place in the universe. [D: Pella Kagerman, Hugo Lilja; A: Emelie Jonsson, Bianca Cruzeiro, Arvin Kananian]
  • Asher: (2018; Drama, Thriller) An aging hitman's last job goes sideways, forcing him to redeem himself. [D: Michael Caton-Jones; A: Famke Janssen, Ron Perlman, Richard Dreyfuss]
  • Brexit: (2019; Biography, Drama, History) Political strategist Dominic Cummings leads a popular but controversial campaign to convince British voters to leave the European Union from 2015 up until the present day. [D: Toby Haynes; A: Benedict Cumberbatch, Sarah Belcher, Malcolm Freeman]
  • Escape Room: (2019; Action, Adventure, Drama, Horror, Mystery, Sci-Fi, Thriller) Six strangers find themselves in a maze of deadly mystery rooms, and must use their wits to survive. [D: Adam Robitel; A: Taylor Russell, Logan Miller, Jay Ellis]
  • Green Book: (2018; Biography, Comedy, Drama, Music) A working-class Italian-American bouncer becomes the driver of an African-American classical pianist on a tour of venues through the 1960s American South. [D: Peter Farrelly; A: Viggo Mortensen, Mahershala Ali, Linda Cardellini]
  • Incontrol: (2017; Drama, Sci-Fi, Thriller) 4 university students hook up to a machine allowing them to become one of their fellow students - e.g. allowing them each to party as one of the rich and beautiful. The long hook-ups start seriously affecting their normal selves.::Scott Filtenborg [D: Kurtis David Harder; A: Sarah Troyer, Anja Savcic, Valerie Planche]
  • Pet Sematary: (2019; Horror, Thriller) Louis Creed, his wife Rachel, and their two children Gage and Ellie move to a rural home where they are welcomed and enlightened about the eerie 'Pet Sematary' located nearby. After the tragedy of their cat being killed by a truck, Louis resorts to burying it in the mysterious pet cemetery, which is definitely not as it seems, as it proves to the Creeds that sometimes, dead is better. [D: Kevin Kölsch, Dennis Widmyer; A: John Lithgow, Jason Clarke, Amy Seimetz]
  • Spider-Man: Into the Spider-Verse: (2018; Animation, Action, Adventure, Family, Sci-Fi) Teen Miles Morales becomes Spider-Man of his reality, crossing his path with five counterparts from other dimensions to stop a threat for all realities.::Chockys [D: Bob Persichetti, Peter Ramsey, Rodney Rothman; A: Shameik Moore, Jake Johnson, Hailee Steinfeld]
  • The Irishman: (2019; Biography, Crime, Drama, History, Thriller) A mob hitman recalls his possible involvement with the slaying of Jimmy Hoffa. [D: Martin Scorsese; A: Anna Paquin, Robert De Niro, Al Pacino]
  • Get Her... If You Can: (2019; Comedy) Roberto (Javier Rey) and Daniela (Amaia Salamanca) are siblings, both wealthy business people, with very different styles. Roberto's plot to return her sister her sense of humour gets unexpectedly out of hand. [D: Inés de León; A: Amaia Salamanca, Hugo Silva, Javier Rey]

Finalmente, el conteo de pendientes por fecha:

(Jun-2013)    2
(Sep-2013)    8
(Dic-2013)   12   4
(Abr-2014)    8   3
(Jul-2014)   10  10   5   1
(Nov-2014)   22  22  22   7
(Feb-2015)   13  13  13  10
(Jun-2015)   16  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
(May-2018)                               22  22  22
(Sep-2018)                                   12  12
(Mar-2019)                                       13
Total:       91  89 100  94  97  94  89  84  79  69

Facundo Batista: PyCamp 2019

Se nos fue el PyCamp 2019, el doceavo, el primero en San Rafael, Mendoza. Más precisamente en Los Reyunos, en instalaciones de la Universidad Tecnológica Nacional.

El lugar estuvo bien, aunque no 100% preparado para cómo lo íbamos a usar, lo acondicionamos al toque y funcionó sin problemas. Era lejos a nivel viaje, pero estaba buenísimo, mucho verde, super cómodo, y aunque no estaba cerrado para nosotros, estábamos bastante aislados (excepto cuando nos metíamos en la pileta, claro, porque era compartida con gente que visitaba el predio para pasar el día). Creo que fue el PyCamp con mejor paisaje de toda la historia:

Más o menos el atardecer

Sí fue seguro el PyCamp donde la internet funcionó sin problemas (casi perfecto, más allá de un par de cortecitos).

Y teníamos el plus de que había un proyector que usamos un montón. Deberíamos analizar comprar un microproyector para que PyAr tenga en este tipo de eventos, porque es evidente que cuando se lo tiene, se lo aprovecha.

El pasto que se ve atrás de la pile está varios metros abajo

A nivel proyectos, le metí bastante tiempo a un experimento para tener sistemas de gestión automáticos alrededor de procesos que sean lineales o máquinas de estados finitas (django-flow), y al sitio de gestión de socies de la Asociación Civil.

También trabajé con fades (principalmente ayudando/mentoreando a otres que laburaron en el proyecto), participé en una charla que nos dio Fisa sobre pytest (¡me encantó!), y además llevé adelante un juego grupal que es una especie de coding dojo rotativo rápido, algo que seguramente repetiremos en el futuro porque estuvo buenísimo.

El primer día nos levantamos tempranito, no había gente "externa" todavía

Obvio también tuvimos los clásicos juegos de mesa, luego de cenar (menos la primer noche, que nos recontracolgamos con José Luis, Sofi, Matu y Leandro laburando hasta las cuatro de la mañana en ese experimento que mencionaba antes, cuando ya no entendíamos ni lo que pensábamos.

Juegos de mesa, decía. Volví a disfrutar el Galaxy Trucker (me encanta, debería conseguirlo), perdí un par de veces en el Resistance, y estuve rondando/ayudando bastante en una partida de Munchkin.

Jugando al Galaxy Trucker

También conocí juegos nuevos: uno 100% de interacción humana, el "Psicólogo" (me gustó, es un toque bizarro, al estilo Mao, no es para cualquier grupo), y dos de mesa: el Aquarius que no me entusiasmó mucho, y el Bohnanza, que me pareció bárbaro.

Y claro que hubo actividades "externas". No sólo nos metimos varias veces a la pileta, sino que hicimos malabares, y además una de las noches fuimos al observatorio que está en el predio donde además de recibir una charla informativa que me gustó bastante, pudimos tener la experiencia de observar un grupito de estrellas alrededor de Hatysa a través de un telescopio que en general sólo está disponible para estudios científicos, fue genial.

Trabajando, pensando, mirá que gente concentrada

En fin. No, no voy a repetir que es el mejor evento del año. Pero sí que sí voy a afirmar que el PyCamp es el "vine por el lenguaje, me quedé por la comunidad" en su máxima expresión.

Todas las fotos (mías y algunas choreadas del grupo de Telegram que tuvimos), acá, y les dejo también estas que compartieron muches otros asistentes al evento.

Facundo Batista: Empezando el año a todo trapo

Menos mal que salió descanso unos días a fin de Diciembre, porque el año empezó con ritmo bastante movidito.

Por un lado, la actividad de les peques, que hicieron "colonia" a la tarde, con lo cual los tenía a la mañana en casa, les preparaba el almuerzo, los llevaba al club, y muchas veces también los iba a buscar.

Aprovechaba ese par de horas bien temprano en la mañana, más la tarde solo, para meterle duro y parejo al laburo. Después hacía malabares. Pero ellos lo disfrutaban un montón, así que valía la pena.

Por otro lado, a Febrero lo tuve partido en dos porque viajé por laburo. A Malta, destino al que ya había ido en 2014, pero que ahora revisité en un contexto muy cambiado, ya que a nivel trabajo estoy en algo muy diferente, y a nivel equipo es casi todo distinto... es más, considerando un par de faltazos por razones de fuerza mayor, tendría que ver realmente si hubo alguien que se repitiera en el equipo de aquella vez y la de esta. Los tiempos cambian.

Callecita interna de Valleta, la capital de Malta

Más allá de eso, aproveché a pasear por lugares que no había conocido :). Todas las fotos acá.

Encima, esta semanita, que acabo de volver, la tengo saturada de reuniones (en la escuela de les peques y un par más), y el viernes muy temprano ya parto para San Rafael donde hacemos el PyCamp de este año.

El mismo termina el martes, y yo a diferencia de otras veces donde me quedo bien hasta el final, viajo el mismo martes a la tarde de regreso porque el miércoles arrancan las clases, y quiero estar ahí.

El hotel tenía muy buena vista

A nivel agenda lo bueno es que ya los horarios se normalizan a partir de esa primer semana de Marzo, o casi: más allá de un par de semanas de horarios especiales para Male para adaptarse al doble turno, después ambos peques pasan a tener el mismo horario y eso me simplifica bastante la operatoria diaria.

Lo cual es esencial para poder encarar el resto del año e ir haciendo todo lo que tengo ganas de hacer :)

Facundo Batista: Reponiendo la patente

El año pasado nos fuimos unos días con la familia a Ostende, entre Navidad y Año Nuevo. En general tuvimos buen tiempo (aunque mucho viento, no pudimos hacer mar), pero hubo un par de lluvias complicadas.

Uno de los chaparrones, de especialmente alta intensidad en poco tiempo, nos encontró pegando una vuelta por Valeria del Mar. Cuando empezaron a caer las gotas (cada una como un baldazo de agua) apuntamos para volver al hotel.

En la vuelta pasamos por tres zonas inundadas. Las primeras dos era sólo cuestión de tomársela con calma. Pero la tercera y última estaba tan complicada que dudé mucho en pasar: para el caso aunque camionetas grandes pasaban bien, muchos autos pegaban la vuelta.

Pero le calculé bien y me mandé. Pasamos, aunque el agua llegó al parabrisas al bajarse la trompa del auto en un badén en la mitad de lo inundado. Llegamos al hotel, y cuando me bajé del auto, me di cuenta que habíamos perdido la patente de adelante!

Hice algunas averiguaciones, y no había mucha opción: hay que hacer un duplicado de las chapas y ponérselas al auto (lo cual tarda unas semanas, pero mientras tanto se lleva pegado al vidrio un papelito de trámite provisorio). Pero para eso hay que ir al Registro Automotor, y nosotros habíamos perdido la patente un sábado al mediodía, y el domingo volvíamos a casa, así que no había chance.

No todos los días llovió, eh, hicimos playa también

Fui a la policía, para hacer una declaración de que había perdido la patente. Luego de renegar un poco me la hicieron, pero la verdad es que a la hora de circular esa declaración no me servía para nada: no se puede circular sin patente. Pero tampoco iba a mandar el auto en grúa y a la familia en colectivo hasta casa. Así que me arriesgué, puse adelante la patente de atrás, y volvimos a casa.

Por suerte la caminera nunca me paró, y un par de días después ya hice el trámite en el registro número 3 de Olivos (un placer hacer trámites ahí, siempre te ofrecen más soluciones que trabas o inconvenientes).

A los quince días llamé para ver si estaban las chapas, y no. Tres días después volví a intentar, tampoco. Al otro día me llamaron del registro y me dijeron que les habían avisado que las chapas están demoradas, así que antes de que se venza el mes tenía que pasar a que me "renueven" el papelito provisorio que te permite circular mientras tanto.

El jueves pasado finalmente me llamaron para avisarme que las placas estaban listas, así que al otro día las fui a buscar (y obvio las puse al toque, porque como uno entrega los papelitos provisorios, sino no se puede circular).

Pero al ponerlas me di cuenta que los tornillos de adelante no agarraban bien. Les puse unos más gruesos que tenía por ahí, pero igual no quedaron bien, ¡es que las patentes en la Renault Stepway van agarradas al paragolpes, y el mismo es de plástico! Mejor prevenir que curar, pensé, entonces le puse poxipol a los agujeritos y puse los tornillos, para que queden mejor agarrados.

Pero soy porfiado, y quiero evitar tener el mismo quilombo la próxima vez que cruce un charco (o evitar en lo posible que me las roben, que también es una posibilidad), así que le puse algunos remaches (dos atrás, abajo, para que la chapa no se levante, y cuatro adelante, dos abajo y dos arriba).

La próxima que pierda la patente será porque perdí el paragolpes :p

Le puse varios remaches, no se sale más

Marcos Dione: customizing-the-python-language

Programming languages can be viewed as three things: their syntax and data model, their standard library and the third party libraries you can use. All these define the expressiveness of the language, and determine what can you write (which problems you can solve) and how easily or not. This post/talk is about how expressive I think Python is, and how easy it is or not to change it.

I said that we solve problems by writing (programs), but in fact, Python can solve several problems without really writing a program. You can use the interpreter as a calculator, or use some of the modules a programs:

$ python3 -m http.server 8000

With that you can serve the current directory via HTTP. Or do this:

$ python3 -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 30.2 usec per loop
$ python3 -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 27.5 usec per loop
$ python3 -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 23.2 usec per loop

to check which method is faster. Notice that these are modules in the standard library, so you get this functionality out of the box. Of course, you could also install some third party module that has this kind of capability. I find this way of using modules as programs very useful, and I would like to encourage module writers to consider providing such interfaces with your modules if you think it makes sense.

Similarly, there are even programs written in Python that can also be used as modules, which I think should also be considered by all program writers. For instance, I would really like that ssh was also a library; of course, we have paramiko, but I think it's a waste of precious developer time to reimplement the wheel.

The next approach I want to show is glue code. The idea is that you take modules, functions and classes, use them as building blocks, and write a few lines of code that combine them to provide something that didn't exist before:

import centerlines, psycopg2, json, sys, shapely.geometry, shapely.wkt, shapely.wkb

tolerance = 0.00001

s =
data = json.loads(s)
conn = psycopg2.connect(dbname='gis')

ans = dict(type='FeatureCollection', features=[])

for feature in data['features']:
    shape = shapely.geometry.shape(feature['geometry'])

    shape = shape.simplify(tolerance, False)
    skel, medials = centerlines.skeleton_medials_from_postgis(conn, shape)
    medials = centerlines.extend_medials(shape, skel, medials)
    medials = shapely.geometry.MultiLineString([ medial.simplify(tolerance, False)
                                                 for medial in medials ])


s = json.dumps(ans)

This example does something quite complex: it takes a JSON representation of a polygon from stdin, calculates the centerline of that polygon, convert is back to a JSON representation and outputs that to stdout. You could say that I'm cheating; most of the complexity is hidden in the shapely and centerlines modules, and I'm using PostgreSQL to do the actual calculation, but this is what we developers do, right?

Once the building blocks are not enough, it's time to write our own. We can write new functions or classes that solve or model part of the problem and we keep adding glue until we're finished. In fact, in the previous example, centerlines.skeleton_medials_from_postgis() and centerlines.extend_medials() are functions that were written for solving this problem in particular.

But the expressiveness of the language does not stop at function or method call and parameter passing; there are also operators and other protocols. For instance, instead of the pure OO call 2.add(3), we can simply write 2 + 3, which makes a lot of sense given our background from 1st grade. Another example which I love is this:

file = open(...)
line = file.readline()
while line:
    # [...]
    line = file.readline()


file = open(...)
for line in file:
    # [...]

The second version is not only shorter, it's less error prone, as we can easily forget to do the second line = file.readline() and iterate forever on the same line. All this is possible thanks to Python's special methods, which is a section of the Python reference that I definitely recommend reading. This technique allowed me to implement things like this:

command1(args) | command2(args)

which makes a lot of sense if you have a shell scripting background; or this:

with cd(path):
    # this is executed in path

# this is executed back on the original directory

which also will ring a bell for those of you who are used to bash (but for those of you who don't, it's written as ( cd path; ... )). I can now even write this:

with remote(hostname):
    # this body excecutes remotely in hostname via ssh

Following this same pattern with the file example above, we can even simplify it further like so:

with open(...) as file:
    for line in file:
        # [...]

This has the advantage that not only relieves us from closing the file, that would happen even if an unhandled exception is raised within the with block.

Special methods is one of my favorite features of Python. One could argue that this is the ultimate language customization, that not much more can be done. But I'm here to tell you that there is more, that you can still go further. But first let me tell you that I lied to you: the pipe and remote() examples I just gave you are not (only) implemented with special methods. In fact, I'm using a more extreme resource: AST meddling.

As any other programming language, Python execution goes through the steps of a compiler: tokenizing, parsing, proper compilation and execution. Luckily Python gives us access to the intermediate representation between the parsing and compilation steps, know as Abstract Syntax Tree, using the ast.parse() function. Then we can modify this tree at our will and use other functions and classes in the ast module to make sure this modifications are still a valid AST, and finally use compile() and exec() to execute the modified tree.

For instance, this is how I implemented |:

class CrazyASTTransformer(ast.NodeTransformer):
    def visit_BinOp(self, node):
        if type (node.op) == BitOr:
            # BinOp( left=Call1(...), op=BitOr(), right=Call2(...) )
                           keyword(arg='_out', value=Name(id='Pipe', ctx=Load())))
                           keyword (arg='_bg', value=Name(id='True', ctx=Load())))
            update_keyword(node.right, keyword(arg='_in', value=node.left))
            node = node.right
            # Call2(_in=Call1(...), _out=Pipe, _bg=True)

        return node

I used Call1 and Call2 to show which is which; they're really ast.Call objects, which represent a function call. Of course, once I rewrote the tree, most of the code for how the commands are called and how the pipe is set up is in the class that implements commands, which is quite more complex.

For remote() I did something even more extreme: I took the AST of the body of the context manager, I pickle()'d it, added it as an extra parameter to remote(), and replaced it with pass as the body of the context manager, so the AST becomes the equivalent of:

with remote(hostname, ast_of_body_pickled):

When the context manager really executes, I send the AST over the ssh connection together with the locals() and globals() (its execution context), unpickle in the other side, restore the context, continue with the compile()/exec() dance, and finally repickle the context and send it back. This way the body can see its scope, and its modifications to it are seen in the original machine.

And that should be it. We reached the final frontier of language customization, while maintaining compatibility, through the AST, with the original interpreter...

Or did we? What else could we do? We certainly can't[1] modify the compiler or the execution Virtual Machine, and we already modify the AST, can we do something with Python's tokenizer or parser? Well, like the compiler and the VM, they're written in C, and modifying them would force us to fork the interpreter, with all the drawbacks of maintaining it. But can we make another parser?

On one hand, the Python standard library provides a couple of modules to implement your own parsers: tokenize and parser. If we're inventing a new language, this is one way to go, but if we just want a few minor changes to the original Python language, we must implement the whole tokenizer/parser pair. Do we have other options?

There is another, but not a simple one. pypy is, among other things, a Python implementation written entirely in (r)Python. This implementation runs under Python legacy (2.x), but it can parse and run current Python (3.x) syntax[4]. This implementation includes the tokenizer, the parser, its own AST implementation[2], and, of course, a compiler and the VM. This is all free software, so we can[3] take the tokenizer/parser combination, modify it at will, and as long as we produce a valid (c)Python AST, we can still execute it in the cPython compiler/VM combination.

There are three main reasons to modify this code. First, to make it produce a valid cPython AST, we will need to modify it a lot; cPython's compile() function accepts only ASTs built with instances of the classes from the ast module (or str or bytes[5]), it does not indulge into duck-typing. pypy produces ASTs with instances of its own implementation of the ast module; rewriting the code is tiresome but not difficult.

Second, on the receiving side, if we're trying to parse and execute a particular version of Python, we must run it at least under the oldest Python version that handles that syntax. For instance, when I wanted to support f-strings in my language, I had no option but to run the language on top of Python-3.6, because that's when they were introduced. This meant that a big part of the modifications we have to do is to convert it to Py3.

Finally, we must modify it so it accepts the syntax we want; otherwise, why bother? :)

So what do we get with all this fooling around? Now we can modify the syntax so, for instance, we can accept expressions as keyword argument names, or remove the restriction that keyword and positional arguments must be in a particular order:

grep(--quiet=True, 'mdione', '/etc/passwd')

After we modify the parser, it's able to generate an AST, but this AST is invalid because the compiler will reject it. So we still have to recourse to more AST meddling before passing it to the compiler. What I did for the parameter meddling was to create a o() function which accepts a key and a value, so --quiet=True becomes the AST equivalent of o('--quiet', True). Once we've finished this meddling, the original, official, unmodified interpreter will happily execute our monster.

All of these techniques are used in ayrton in some way or another, even the first one: I use python3 -m unittest discover ayrton to run the unit tests!

[1] Well, technically we can, it's free software, remember!

[2] The cPython AST, while being part of the standard library, is not guaranteed to be stable from versions to version, so we can't really consider it as part of the API. I think this is the reason why other implementations took the liberty to do it their own way.

[3] ... as long as we respect the license.

[4] In fact some of the work is implemented in the py3.5 branch, not yet merged into default. I'm using the code from this branch.

[5] This would also be another avenue: feed compile() the definite bytecode, but that looks like doing a lot of effort, way more than what I explain here.

python ayrton

Facundo Batista: Encarando el nuevo año

No soy de hacer esas "promesas de fin de año" (¿o son de año nuevo?) en las que la gente dice "este año adelgazo", "este año aprendo surf", "este año salgo del closet", etc. Pero me agarraron ganas de planificar un poco los siguientes doce meses y ponerme como grandes objetivos en los que me gustaría invertir principalmente esfuerzo, como una forma de arrancar más ordenado.

Hay una frase que leí hace poco en un texto de Forn, de Primo Levi, que indica que "Los objetivos de la vida son la mejor defensa contra la muerte". No es que a mí me falte cosas para hacer: La idea es solamente ordenar un poco el futuro a corto plazo.

A nivel de desarrollo de software me gustaría empujar fades como proyecto que lidero con alguien más, seguir puliendo mi blog, y más allá de quizás agarrar algún otro con baja prioridad, quiero lanzar este año una especie de mezcla entre grupo de tareas y grupo de aprendizaje (para newbies y diverso) alrededor de CDPedia.

No digo que no trabajaré para nada en otra cosa de software, pero seguro que mi construcción de la agenda día a día y planificación normal de semanas subsiguientes va a estar fuertemente condicionados por estos proyectos que me "anoté".

Do I really look like a guy with a plan?

A nivel Python Argentina lo tengo separado como dos partes. Una es el grupo en sí mismo, y lo que tengo ganas de empujar este año es por un lado la migración conceptual a Discourse (conceptual, digo, porque no vamos a "migrar" realmente, es una nueva herramienta, que apunto a que termine reemplazando la vieja lista de mailman), la creación de un nuevo logo (cumplimos 15 años, es hora, ¿no?) y empujar a que Eventol gane características para ser usado como plataforma de juntadas recurrentes (como, pero sin lock-in ni límite de asistentes) para la coordinación de juntadas en todo el país.

La otra es el laburo en la Asociación Civil. Estoy metiéndole detalles y detalles a medida que lo uso al sistema de Socies, y esperando que vuelva Gilga de vacaciones para ponerlo online: mi idea a este respecto es seguir agregándole features y pequeñas mejoras pero muy puntuales en función de que vaya surgiendo las distintas necesidades. Por otro lado, necesitamos un sistema para Soporte de Eventos (que básicamente maneje todo lo que es entrada y salida de dinero alrededor de un evento nuestro o de terceros), pero la idea ahí es armar una definición y que lo haga alguien más.

A nivel de evento propiamente dicho, por otro lado, tengo en vista dos o tres. Dos seguro, que es el PyCamp 2019, el cual ya pagué y compré pasajes (lo organiza Matu Varela, con el soporte de la Asociación Civil, claro), y la PyCon Argentina 2019, que todavía tenemos que disparar la organización propiamente dicha. Digo "dos o tres" porque tenía ganas de ir a la PyCon USA, pero justo cae durante mi cumpleaños, entonces me frenó un poco eso... para colmo me di cuenta de eso luego que propuse algunas charlas, entonces tomé la decisión de que si me aprueban alguna charla voy, pero si no aprovecho y me quedo con mi familia :)