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.

What is Appium and how to install it

As you can read in http://appium.io/ Appium is an open source test automation framework for use with native, hybrid and mobile web apps. It drives iOS, Android, and Windows apps using the WebDriver protocol. So if you are trying to automate tests for a mobile app, this is a tool you must check.

Appium allow us to interact with the app elements, and it can be used with different languages as Java, JavaScript, Ruby or Python. It is licensed under Apache 2 license, and joined de JS foundation in October 2016.

To install Appium Desktop (server side) you must download the corresponding binary from https://github.com/appium/appium-desktop/releases/ There is a .dmg for your Mac, a .exe for your Windows or a .AppImage for Linux. Take into account in Linux you must run chmod a+x to grant execution permissions, and run ./AppImage to execute it.

Next steps

If you are interested in automating Android apps, you have to install Android Studio, Android SDK (can be easily installed during Android Studio installation) and Java (remember to set JAVA_HOME).

Los 3 factores clave de la productividad

Existe un gran número de acciones y fórmulas encaminadas a mejorar nuestra productividad. De entre lo mucho que he leído entorno a este tema tan importante destacaría los que considero los 3 ingredientes clave.

  • Motivación: Se dedican demasiadas horas al trabajo como para que no te guste. ¿Disfrutas con lo que haces? ¿Qué puedes cambiar para mejorarlo?
  • Objetivos: ¿Qué vas a hacer hoy? ¿Lo tienes claro? Los objetivos son un compromiso que asumimos con nuestro yo. Deben ser concretos y tangibles, realistas y factibles. Revísalos y evalúalos al final del día.
  • Hacer: Empezar, hacer y terminar es el único modo de conseguir las cosas que de verdad quieres. Parece una tontería, pero es así.

Descanso activo

Uno de los principales pilares de la productividad es el descanso. Nuestro cerebro no puede mantener la atención durante mucho tiempo, y al igual que ocurre con nuestros músculos necesita descansar para reponer energías.

Se entiende perfectamente que un atleta tras correr una maratón necesite pasar un tiempo sin forzar sus piernas, pero en ocasiones parece que no interiorizamos que tras una dura jornada de trabajo nuestra cabeza ya no rinde mas y necesita recuperarse.

Una mente que no descansa tendrá mayor estrés, será mas lenta para realizar tareas, dispondrá de un menor rendimiento cognitivo, además de incrementar la posibilidad de sufrir malestares, dolores y quizás enfermedades.

En ocasiones para descansar dedicamos tiempo a leer, a navegar por Internet, a estudiar… pero es un grave error. ¿Creéis que los futbolistas después de un partido se van a jugar al baloncesto? No es buena idea intentar descansar la cabeza con tareas que requieran de un esfuerzo mental.

Aquí es donde entra el juego el descanso activo. Cuando termines tu jornada laboral en lugar de buscar tareas que requieran de un esfuerzo mental busca tareas físicas. Actividades que no requieran pensar como caminar, hacer ejercicios, estiramientos o bailar nos permiten relajarnos y disminuyen nuestro nivel de estrés.

Esto permite finalmente que nuestro cerebro pueda regenerarse y descansar, lo que conlleva una mayor productividad al día siguiente.

¿Por qué me gusta ser productivo?

Desde siempre me ha interesado mucho el tema de la productividad y cómo sacarle más partido a mi tiempo. Hoy te cuento el por qué:

  1. Me hace sentir bien, satisfecho y útil. ¿No te sientes genial el día que te ha cundido?
  2. Me ayuda a centrarme en lo verdaderamente importante. Es sorprendente lo mal que podemos emplear nuestra energía y concentración.
  3. Me ayuda a implantar la dieta de la información. ¿Cuánto tiempo se pierde en redes sociales, blogs o periódicos?
  4. Me permite “sacar” más horas al día. ¿Alguna vez has deseado que el día tuviera más horas? Pues 24 ya están muy bien si sabes aprovecharlas.
  5. Me ayuda a ser más creativo e imaginativo. Al liberar la mente esta se puede dedicar a lo que realmente sabe hacer: crear e imaginar.
  6. Me permite asumir nuevas responsabilidades y retos. Al ser más productivo podemos abarcar más proyectos con el mismo esfuerzo.

Porque no se trata de trabajar más, sino de trabajar mejor.

Mejorar la comunicación por email

Hace unos días escribía acerca de la importancia de la documentación y a raíz de eso he tenido varias conversaciones privadas con personas interesadas. Entre otras cosas comentábamos que la documentación nos permite ser más productivos al disponer de una fuente de conocimiento sólida.

Al hilo de la productividad me viene a la cabeza también el problema de la comunicación y el claro ejemplo del correo electrónico, que mal utilizado hace que perdamos mucho tiempo.

¿Cómo mejorar la comunicación vía correo electrónico?

Cuida el asunto. Una noticia tiene titular y cuerpo. Un correo tiene asunto y contenido. Ambos son importantes y sin embargo muchos no cuidamos el titular. El asunto debe sintetizar el contenido del mensaje. Esto ayudará al receptor a interpretarlo y clasificarlo, así como a buscarlo posteriormente.

Cuida el contenido. En el contenido detallamos la información. No se puede enviar un correo sin contenido aunque coincida con el asunto, puesto que cuando leemos el correo suponemos que en él está toda la información necesaria y no tenemos por qué releer el asunto. El contenido debe ser breve y directo. El correo electrónico debe parecerse más a un telegrama que a una carta. Tardaremos menos en escribirlo, menos en leerlo y mejoraremos nuestra comunicación y productividad.

Cuida la frecuencia de envíos. Envía correos sólo de lo que consideres importante o interesante. Cuando envías un correo le dedicas tiempo tanto tú como todos los destinatarios. Piensa que el tiempo de todos es valioso y que nadie debe perderlo. Ni envíes demasiados correos ni correos sin interés.

Cuida los destinatarios. ¿Están todas los destinatarios que deben recibirlo? ¿Falta o sobra alguno?

Uso de respuestas prediseñadas. ¿Te preguntan constantemente lo mismo? No reescribas una y otra vez la misma contestación; utiliza respuestas prediseñadas.

8 aspectos básicos de la documentación

Soy un obseso de la documentación porque considero que es una parte importantísima del sistema. Una documentación de calidad nos permitirá ganar contexto rápidamente, minimizará el riesgo de cometer errores y de reinvertir tiempo en problemas que ya se solucionaron en el pasado. Es además un medio de comunicación con el resto del equipo, stakeholders y nuestro yo del futuro.

Para mí la documentación debe cumplir estos puntos:

  • Breve, clara y concisa.
  • En un formato legible, común y estándar.
  • Correctamente estructurada. Toda documentación similar debe estructurarse de manera similar.
  • Correctamente redactada. Por favor minimicemos las faltas.
  • Fácil de localizar y consultar.
  • Actualizada y actualizable.
  • No debe estar duplicada.
  • Debe ser interesante o importante.