Compañía neutra en carbono

No sé si es por la edad o por qué pero cada vez veo más necesarias estas iniciativas. No es que antes las viera mal, pero sí que podía pensar que eran fruto del márketing más que de la necesidad. Sin embargo, de un tiempo a esta parte considero muy importante formar parte de una empresa que tiene en cuenta el medio ambiente.

Cabify es una compañía neutra en carbono gracias a que se compensan todas las emisiones a través de iniciativas en todos los países donde opera. Además está realizando una gran inversión electrificando la flota e invirtiendo en energías renovables.

Y quizás porque me hago mayor, o porque cada vez es más patente el tema de la contaminación… o por ambas cosas, para mí formar parte de un proyecto que lucha activamente contra el cambio climático es un punto clave a tener en cuenta.

Más información en:

Mejorar la comunicación oral

La comunicación oral es una de las herramientas más importantes que usamos diariamente para relacionarnos con las personas de nuestro entorno. Bien sea en la máquina de café, a través de Zoom o en un pasillo de la oficina, surgirán conversaciones en las que se nos comunicarán dudas, necesidades, inquietudes…

Debemos dedicar esfuerzos en mejorar nuestras habilidades en este campo, realizando una escucha activa que evite los siguientes obstáculos:

  • Oír solamente aquello que nos interesa.
  • Tener prejuicios sobre la otra persona o sobre lo que nos quiere comunicar.
  • Barreras del entorno.
  • Sentimientos “a flor de piel”.
  • Quejas constantes.
  • Fingir que escuchamos.
  • Pensar en la respuesta en lugar de atender.

Para ello lo mejor es tener en cuenta los consejos listados a continuación:

  • Tómate tiempo para escuchar.
  • Establece un clima agradable.
  • Acepta a la otra persona tal y como es.
  • No te distraigas.
  • Prepárate el tema que quieres tratar.
  • Escucha y resume.
  • Estructura el mensaje.
  • No adelantes conclusiones.
  • Escucha con empatía.
  • Pregunta.
  • Anota los datos que estimas necesarios.

Luchar contra las interrupciones

¿Cómo podemos luchar contra las interrupciones?

  • Elimina los interruptores: Quita alarmas, notificaciones de WhatsApp, Telegram, Slack… Elimínalas de raíz.
  • Ojo con el móvil: ¿Esperas una llamada de vida o muerte? Pues siléncialo y ponlo boca abajo. Revísalo cada cierto tiempo en lugar de con cada notificación.
  • Enfócate: Recuerda el propósito de la tarea y prepárate para comenzarla.
  • Aísla la tarea: Si te piden algo ¿es obligatorio y vital que pares y lo hagas ya? Siempre es preferible apuntarlo para más adelante y volver a la tarea inicial.
  • Trabaja en bloques cortos: Es más fácil bloquear completamente las interrupciones si trabajas en tareas de menos de 30 minutos. Divide y vencerás.
  • Comunica tus rutinas: Si no se te puede llamar hasta las 10.00 que todo el mundo lo sepa.
  • Frena a la gente pesada: Siempre hay una persona que le gusta interrumpir sin miramiento. Ponle límites.
  • Comunicación concisa: Responde de manera breve y directa. Estructura tu mensaje para reducir la llamada actual, y dejarlo todo claro para que no sea necesaria una nueva llamada futura.
  • ¡No interrumpas tú! Si no te gusta que te interrumpan, no te dediques a interrumpir.

Pon en marcha cuanto antes estos puntos y verás que es más fácil de lo que esperabas.

Evita las interrupciones

El mayor enemigo de la productividad son sin duda las interrupciones. Debemos evitarlas a toda costa pues son el ladrón más voraz de nuestro tiempo. Las interrupciones:

  • Rompen nuestro ritmo laboral.
  • Hacen nuestro trabajo más lento y torpe, perdiendo tiempo en cualquier cosa.
  • Son fuente de estrés y ansiedad, y nos separan de objetivos y tareas.
  • Desgastan nuestra motivación, creatividad y energía.
  • Corroen nuestro ánimo, optimismo y buen humor.
  • Producen insatisfacción.

Porque para causar más impacto no hay que trabajar más horas, sino aprovechar mejor las que dedicamos.

Sistema de tipos de datos

En los lenguajes de programación llamamos tipo de datos o sencillamente tipo, a un atributo de los datos que indica al sistema la clase de datos que se va a manejar. Ejemplos típicos son los números enteros, números en coma flotante, caracteres, cadenas de caracteres y lógicos.

Llamamos sistema de tipos al sistema formal que define las reglas que asignan un tipo de datos a los distintos constructos del código como variables, expresiones o funciones. Su principal cometido es reducir la posibilidad de errores en nuestros programas, al haber definido un contrato entre las distintas partes que permite comprobar que se conectan de manera consistente. También permite expresar reglas de negocio y habilitar optimizaciones del compilador.

Los sistemas de tipos (type system en inglés) se clasifican en varias categorías según su comprobación:

Estáticos vs dinámicos

Se dice que un lenguaje de programación usa tipado estático si la comprobación de tipos se realiza durante la compilación. Claros ejemplos son C, C++, Java y Go. Por el contrario se dice que es de tipado dinámico si la comprobación se realiza en tiempo de ejecución, como ocurre en Perl, Python y Ruby.

Manifiestos vs inferidos

El tipado manifiesto es aquel que identifica explícitamente en nuestro código el tipo de la variable declarada. Por el contrario el tipado inferido, también conocido como tipado implícito, es aquel en el que el tipo de la variable se detecta.

Algunos lenguajes como Go mezclan ambos tipados. Por ejemplo en el siguiente código la primera línea declara explícitamente el tipo de la variable i, mientras que en la segunda línea el tipo de j es inferido.

var i int
j := i // j es un entero

Fuertemente tipados vs Débilmente tipados

Por regla general un lenguaje fuertemente tipado tiene reglas estrictas de tipado en tiempo de compilación. Cabe destacar que un lenguaje dinámicamente tipado puede ser fuertemente tipado. Por el contrario en un lenguaje débilmente tipado no hay reglas estrictas y se pueden producir resultados erróneos o impredecibles cuando se realiza una conversión de tipos en tiempo de ejecución.

Tipado nominal vs Tipado estructural

En lenguajes de computación se dice que un sistema de tipos es de tipo nominal si la compatibilidad y equivalencia entre los tipos de datos se determina por declaraciones explícitas y/o el nombre de los tipos. En contraste se considera un tipado estructural a aquel en el que las comparaciones se basan en la estructura de los tipos en cuestión sin necesitar declaraciones explícitas.

Lenguajes como C++, C#, Java o Delphi son considerados como lenguajes de tipado nominal. Por el contrario Go usa un tipado estructural ya que con que un tipo implemente los métodos indicados por una interfaz se considera que la cumple sin necesidad de indicar nada explícito.

Evita interrumpir a otras personas

En nuestro trabajo diario surgen muchas dudas que han de ser resueltas por otras personas, que deberán interrumpir su flujo de trabajo para atender a nuestras peticiones. Es importante gestionar correctamente nuestras solicitudes para evitar al máximo cortar su trabajo. Para ello ten en cuenta:

  • ¿Eres capaz de resolverlo sin ayuda? ¿Has dedicado el tiempo necesario a la resolución?
  • ¿Tienes autoridad para tomar esa decisión? ¿O necesitas consenso?
  • ¿Puedes esperar a tener la respuesta o debes obtenerla de manera inmediata?
  • Estudia en primer lugar el problema para realizar todas las preguntas en una sola conversación evitando múltiples interrupciones.
  • Busca claridad y precisión a la hora de exponer tus ideas, opiniones, consultas o quejas.
  • Dirige la conversación, buscando una respuesta y evitando diálogos interminables. Evita frases vacías:
    • En lugar de «¿quedamos para ver unas cosas?» es mejor «¿tienes tiempo para ver un problema desplegando tal servicio?».
    • En lugar de «tenemos un problema» es mejor «los últimos cambios en la librería X han roto interfaces. He revisado todos los puntos en los que nos afecta y propuesto un borrador que me gustaría revisar contigo».

Preguntar es muy útil y nos permite ganar contexto rápidamente y desbloquearnos. Tan malo es resistirse a preguntar como preguntar indiscriminadamente. Pero ten en cuenta que las interrupciones son caras y no debemos cortar constantemente a la gente.

How Cabify speed up backend development

Every time a rider asks for a journey, a driver performs a drop off, or a corporate client books for a ride at Cabify, a lot of pieces that compose our technical puzzle start to interact among them. These pieces are called microservices, and all of them create an interconnected ecosystem that allows us to provide service to our customers. In order to develop them we mainly use Golang, Elixir and Ruby, being the first one the most widely adopted language.

In their daily job our developers must face a lot of different problems that can be grouped in two different categories: those related with the business domain, and those related with the technical infrastructure. Middleware, the team I belong to, is in charge of tackling the accidental complexity of the infrastructure so other teams can focus on addressing problems in their own domain.

One of our main missions is to find a way the teams in charge of developing the microservices do not spend time trying to fit them into the Cabify’s platform. As Golang is the most widely adopted language, we have been focused on finding tools and libraries for this language to abstract the integration of the services in the platform.

As you might know there is no industry-standard framework to build services in Golang (aka Go). While Ruby has Ruby on Rails and Java has Spring, Go has a rich ecosystem compound by many loosely coupled libraries. The Go official libraries provide us a standard way of handling basic HTTP communications, data encoding/decoding, time management, etc. But many other decisions are left to the programmers. As no tool satisfied our necessities we made a new one. And we called it Servant.

Servant is not a framework but the integration of multiple libraries and tools properly configured to facilitate their setup to match the infrastructure we have at Cabify. It tries to hide as many irrelevant details as possible so developers can focus on their domain logic, instead of infrastructure problems. This internal library allows us to speed up the backend development. Do you want to know how it works? Let’s do a quick tour.

This is the smallest microservice we can write thanks to Servant.

package main

import "gopkg.cabify.tools/servant"

func main() {
    service := servant.NewService()
    service.Run()
}

The servant.NewService() returns a new service that we’ll use as an entry point for almost every interaction. It will read the configuration from the environment variables, and will use it to initialize the internal machinery. The service.Run() executes the service in an infinite loop.

Let’s execute it:

{"appname":"main","appversion":"","level":"info","msg":"Creating a new service","time":"2022-04-01T09:49:48+02:00"}
{"level":"info","msg":"Initializing default Gin server","time":"2022-04-01T09:49:48+02:00"}
{"level":"info","msg":"Configuring HTTP server healthcheck route","path":"/status","time":"2022-04-01T09:49:48+02:00"}
{"level":"info","msg":"Configuring HTTP server healthcheck route","path":"/status/liveness","time":"2022-04-01T09:49:48+02:00"} 
{"level":"info","msg":"Configuring HTTP server healthcheck route","path":"/status/readiness","time":"2022-04-01T09:49:48+02:00"}
{"level":"info","msg":"Configuring HTTP server Prometheus metrics route","path":"/metrics","time":"2022-04-01T09:49:48+02:00"}  
{"level":"info","msg":"Configuring HTTP server middleware to obtain HTTP metrics","time":"2022-04-01T09:49:48+02:00"}
{"address":":8080","level":"info","msg":"Starting task","task-name":"http-server","time":"2022-04-01T09:49:48+02:00"}
{"level":"info","msg":"Service is up and running","time":"2022-04-01T09:49:48+02:00"}

Structured logging.

Servant configures the log backend according to the Cabify standards, using the Logrus library. It is written in JSON and it provides several normalized fields as levelmsg or time. Having those normalized fields will do easier to dive into the logs via Kibana as all the services use the same name for the same purpose, and will avoid the cardinality explosion we would have if every service would name them in their own (we could have msgmessagememoreport, etc).

Health checks.

Take a look to:

{"level":"info","msg":"Configuring HTTP server healthcheck route","path":"/status","time":"2022-04-01T09:49:48+02:00"}
{"level":"info","msg":"Configuring HTTP server healthcheck route","path":"/status/liveness","time":"2022-04-01T09:49:48+02:00"} 
{"level":"info","msg":"Configuring HTTP server healthcheck route","path":"/status/readiness","time":"2022-04-01T09:49:48+02:00"}

Three endpoints have been created:

  • /status
  • /status/liveness
  • /status/readiness

These endpoints are called health checks, and are used by our container orchestrators and load balancers to determine if the service container is up and ready to receive traffic, and if it’s not alive and must be restarted. To test how they work we can do:

$ curl -w "\n" http://localhost:8080/status
{"status":"ok"}

Nice. Our service is alive and ready to work.

Metrics.

The next interesting line is:

{"level":"info","msg":"Configuring HTTP server Prometheus metrics route","path":"/metrics","time":"2022-04-01T09:49:48+02:00"}

It explains to us that a route for /metrics has been configured in our HTTP server in order to export metrics to a Prometheus server. Why do we do that? Because we need to collect, aggregate and analyze different metrics to be able to evaluate the response time of our application, the memory usage, CPU consumption, bandwidth, availability, error rate, etc.

Let’s see how many requests have been handled:

$ curl -w "\n" http://localhost:8080/metrics | grep promhttp_metric_handler_requests_total
# HELP promhttp_metric_handler_requests_total Total number of scrapes by HTTP status code.
# TYPE promhttp_metric_handler_requests_total counter
promhttp_metric_handler_requests_total{code="200"} 7
promhttp_metric_handler_requests_total{code="500"} 0
promhttp_metric_handler_requests_total{code="503"} 0

Awesome. No error has been handled.

Bootstrap and shutdown.

Let’s check now these lines:

{"appname":"main","appversion":"","level":"info","msg":"Creating a new service","time":"2022-04-01T09:49:48+02:00"}
[...]
{"level":"info","msg":"Service is up and running","time":"2022-04-01T09:49:48+02:00"}

As you see our service is up and running. Servant provides a way of starting the different parts of our service following a given order. And if we kill our app using Ctrl+C, what will happen?

{"delay":"2s","level":"info","msg":"Termination started, waiting before shutting down resources","time":"2022-04-01T09:54:39+02:00"}
{"address":":8080","level":"info","msg":"Shutting down task","task-name":"http-server","time":"2022-04-01T09:54:41+02:00"}

Servant is listening for the SIGHUPSIGINT and SIGTERM signals. When one of them is captured the shutdown sequence is started so our program is terminated in a graceful manner. First, Servant waits a few seconds to let ongoing actions finish before the program is terminated, being terminated in the opposite order they were started. After that, the HTTP server is closed, and the program exits with a status code of 0.

Servant in a nutshell.

As a summary, what we have shown to you is the essence of Servant. This code represents a minimum service that can be deployed in the Cabify platform. It provides health checks to be used by our container orchestrators and load balancers to determine if the service container is up and ready to receive traffic, or must be restarted. It also provides Prometheus instrumentation to be scrapped and served by our monitoring infrastructure. It shows the log of the application in a normalized way so we can easily dive into it via Kibana. The service lifecycle is managed by the library to perform graceful bootstraps and shutdowns.

All this without worrying our developers about the current infrastructure. All of that with just two lines of source code.

But that is not all: Servant provides a lot of useful functionalities and tools, and facilitates their integration and configuration. Thanks to it the developers will have HTTP and gRPC clients and servers, integration with caching services and MySQL databases, distributed tracing, recoverers, circuit-breakers, retriers, sane default configuration, and many more.

Cabify Tech.

This post was originally published by me in the blog of Cabify Tech:

3 puntos clave para formar hábitos productivos

Formar hábitos productivos no es una tarea sencilla. Nuestras rutinas están cada vez más marcadas y es difícil alterarlas. Por ello si quieres formar hábitos productivos te recomiendo que sigas estos puntos:

  1. Pasos pequeños. Un solo cambio a la vez, pequeño y sencillo. No intentes cambiar demasiadas cosas en poco tiempo.
  2. Cambios medibles. Fíjate cambios concretos, medibles y palpables, que sean asumibles y con plazos razonables. Comprueba cada cierto tiempo si estás llevándolos a cabo y si surten el efecto deseado.
  3. Repite y repite. Con regularidad diaria y constante. Cambiar no es fácil. Debes ser constante y apoyarte en la rutina.

5 pasos para completar mis tareas

No es la primera vez que hablo de la productividad, y seguro que tampoco será la última, porque es un tema que me interesa muchísimo. Durante estos últimos años he estado siguiendo principalmente 5 pasos para completar mis tareas en el menor tiempo posible y hoy quería compartirlos.

  1. Preparo las tareas claves del día. A primera hora identifico cuáles son las tareas clave que voy a realizar ese día. Su importancia y repercusión hacen que me prepare y me predispone a hacerlas adecuadamente, eligiendo bien el momento en el que las abordaré, cuidando el entorno, eliminando las distracciones, mentalizándome antes, etc.
  2. Me concentro en terminar antes de empezar. Tengo tendencia natural a dispersarme en varias actividades. Es bastante natural empezar una tarea dejando a medias otras. Para evitarlo me concentro en completar la tarea en la que estoy trabajando, siendo consciente de no empezar otra nueva.
  3. Elimino la multitarea a toda costa. La multitarea me crea una falsa sensación de productividad. La combato activamente para evitar dispersarme. Por ejemplo divido la tarea en pasos pequeños, cierro el paso a las distracciones externas y recuerdo la importancia y valor de terminarla.
  4. Valoro la importancia de la tarea. Antes de hacer una tarea pienso en el valor que aporta. Siendo consciente de su importancia me predispongo a dar lo mejor de mí. Si es insignificante me ayuda a ser consciente que he de reducir el tiempo que le dedico.
  5. Recopilo todo el material antes de empezar. Es muy frecuente que a mitad de tarea me dé cuenta que me falta un documento, cierta información, etc. Esto me obliga a parar para pedirlo, o buscarlo en Internet, por lo que rompo por completo mi ritmo de trabajo.

Existe un sexto paso que aunque no sea una manera activa de afrontar las tareas es tan importante como los puntos anteriores. Así que de bonus:

  1. Hago frecuentes descansos entre tareas. No soy de los que se sientan orgullosos por haber estado infinidad de horas con el culo pegado a la silla. Considero que los descansos entre tareas son totalmente necesarios. Con ellos refresco la mente, cambio de actividad con eficacia, reprogramo mi nivel de atención y recargo las pilas. Un descanso es la recompensa a una tarea bien hecha. Me levanto, camino, salgo a tomar el sol y el aire…

¿Y tú? ¿Tienes algún truco para completar tus tareas eficientemente?

Appium error: bundletool.jar cannot be found

I’ve installed Appium in Linux and MacOS and once I finished the installation I’ve ran appium-doctor to do a diagnostic for necessary dependencies. In both computers I got the same problem:

  • bundletool.jar cannot be found

I’ve tried a bunch of solutions proposed via Stack Overflow and similar sites, but I got no solutions. So investigating and doing different tests I was able to solve it using these steps:

  • Download bundletool.jar` from https://github.com/google/bundletool/releases
    • At this moment is bundletool-all-0.10.3.jar`
  • Rename it to bundletool.jar
  • Create folder ~/Library/Android/sdk/bundle-tool in Mac
    • ~/Android/Sdk/bundle-tool in Linux
  • Move bundletool.jar to this path and make it executable with chmod +x bundletool.jar
  • Add $ANDROID_HOME/bundle-tool to the path editing .bash_profile or .bashrc

Finally when you run appium-doctor you can see bundletool.jar is properly installed at found.