Autoscaling for AWS EMR Clusters

Allow EMR Clusters to Auto Scale based on cluster usage, allowing our applications to be more reactive and cost-efficient.

Estimated Impact

  • Better performance and reaction to load spikes.
  • Cost savings on EMR resource usage.

Measurement

  • Measurement can be done by comparing the overall number of deployed instances before/after Autoscaling is enabled everywhere possible.
  • Also, it might be possible that by enabling AutoScaling, some EMR Instance Types may be changed to less powerful ones.

What we know so far

About EMR Auto-scaling

  • EMR allows auto-scaling only on TASK node types. You can set any instance type, which is going to be used for new servers.
  • You can set the minimum and maximum instances there can be. (I have gone with 0 and 6 respectively)
  • You can set the thresholds for scaling out and in on instance count. Available metrics are the same as CloudWatch.
  • You need to specify an Autoscaling role. There’s a default AWS creates for you: `EMR_AutoScaling_DefaultRole`.
  • All this can be configured via CloudFormation using the InstanceGroupConfig type.
  • There is an issue where a cluster/stack with this configuration will fail to delete the regular way. More info HERE.
"FeedingAutoScale": {
       "Type" : "AWS::EMR::InstanceGroupConfig",
       "Properties" : {
         "AutoScalingPolicy" : {
           "Constraints": {
             "MaxCapacity": {
               "Ref": "AutoScalingInstanceMax"
             },
             "MinCapacity": {
               "Ref": "AutoScalingInstanceMin"
             }
           },
           "Rules": [
             {
               "Name": "Scale-out",
               "Description": "Scale-out policy",
               "Action": {
                 "SimpleScalingPolicyConfiguration": {
                   "AdjustmentType": "CHANGE_IN_CAPACITY",
                   "ScalingAdjustment": 1,
                   "CoolDown": 300
                 }
               },
               "Trigger": {
                 "CloudWatchAlarmDefinition": {
                   "Dimensions": [
                     {
                       "Key": "JobFlowId",
                       "Value": {
                         "Ref": "FeedingCluster"
                       }
                     }
                   ],
                   "EvaluationPeriods": 1,
                   "Namespace": "AWS/ElasticMapReduce",
                   "Period": 300,
                   "ComparisonOperator": "LESS_THAN",
                   "Statistic": "AVERAGE",
                   "Threshold": {
                     "Ref": "AutoScalingScaleOutYarnMAP"
                   },
                   "Unit": "PERCENT",
                   "MetricName": "YARNMemoryAvailablePercentage"
                 }
               }
             },
             {
               "Name": "Scale-in",
               "Description": "Scale-in policy",
               "Action": {
                 "SimpleScalingPolicyConfiguration": {
                   "AdjustmentType": "CHANGE_IN_CAPACITY",
                   "ScalingAdjustment": -1,
                   "CoolDown": 300
                 }
               },
               "Trigger": {
                 "CloudWatchAlarmDefinition": {
                   "Dimensions": [
                     {
                       "Key": "JobFlowId",
                       "Value": {
                         "Ref": "FeedingCluster"
                       }
                     }
                   ],
                   "EvaluationPeriods": 1,
                   "Namespace": "AWS/ElasticMapReduce",
                   "Period": 300,
                   "ComparisonOperator": "GREATER_THAN",
                   "Statistic": "AVERAGE",
                   "Threshold": {
                     "Ref": "AutoScalingScaleInYarnMAP"
                   },
                   "Unit": "PERCENT",
                   "MetricName": "YARNMemoryAvailablePercentage"
                 }
               }
             }
           ]
         },
         "Name": "AutoScaling TASK",
         "InstanceCount": {
           "Ref": "AutoScalingInstanceCount"
         },
         "InstanceRole" : "TASK",
         "InstanceType": {
           "Ref": "AutoScalingInstanceType"
         },
         "JobFlowId": {
           "Ref": "FeedingCluster"
         }
       }
     }

About Dynamic Allocation

For AutoScaling to work correctly, no fixed set of executors need to be configured. Instead, Spark needs to be able to allocate resources dynamically. This concept has been around for a while. It uses previous job metrics to calculate a dynamic load. There exists two relevant settings for this:

  • `spark.dynamicAllocation.enabled`  – Since Spark 1.5
  • `spark.streaming.dynamicAllocation.enabled`  – Since Spark 2.0.0

As our Feeding application is a Spark streaming one, we need the latter. However, EMR automatically sets `spark.dynamicAllocation.enabled` to true behind doors in an attempt to optimize apps for you. As these two settings are incompatible (They can’t be both enabled), we need to explicitly disable it. More info on Spark settings EMR changes automatically can be found HERE.

Other spark configs that don’t play well with StreamingDynamicAllocation are:

  • `spark.executor.cores`
  • `spark.executor.instances`

Those need to be left out.

On upgrading EMR (and Spark) versions

For Spark Streaming Dynamic Allocation, it is recommended to use Spark version > 2.0.1. Currently, our setup uses EMR release version 5.0.0, which comes with Spark 2.0.0. An EMR release upgrade is needed in order to use Dynamic Allocation and Auto-scaling working. I’ve decided to go straight for the most recent EMR release version, which as of February 2018 is EMR 5.11.1

To know more on EMR release versions, and see details, go HERE.

What changed on Spark?

Mainly, two things are different on Spark 2.2.1 in our scenario:

  • Spark stopped distributing Kinesis API’s because of licensing/legal issues. Jira HERE.
  • AWS deprecated a method we used on our streaming API to get the region based on the Kinesis endpoint. Javadoc HERE. Changes needed for SparkFeeding HERE.

To solve the first, we can use --packages org.apache.spark:spark-streaming-kinesis-asl_2.11:2.1.0 to add spark-streaming-kinesis-asl and its dependencies into the classpath automatically, rather than building the assembly jar by ourselves. However, for SBT to don’t fail on artifact building, it is required to use the %provided keyword for that library on `build.sbt`.

To solve the second issue, the `getRegion` method o the same class can be used. That one takes a string with the name of the region, which can be easily set on the spark config with the following CloudFormation property:

«spark.search.region»: {
«Ref»: «AWS::Region»
},

Getting YARN Logs on EMR

All this investigation was possible, by taking a look at the YARN error logs. If there is a need to take a look at the reason of a failed Spark Application.

Having trouble troubleshooting a failed Spark Application like Spark_Feeding? EMR will gather stderr and controller logs and upload them to S3, but most of the time the provided information will not be enough. So, here’s how you can get it:

  1. Go to the EMR cluster’s page in AWS
  2. In the summary page, note the Master’s public DNS.
  3. Fix the URL (i.e. ip-172-00-0-00.ec2.internal: … => 172.00.0.00: …)
    1. Tip: There is an add-on for Chrome that fixes it for you!
  4. SSH as hadoop to that address, providing the team’s SearchInfra_Search credentials file.
  5. You can now issue YARN commands to list applications and get the complete logging

Example commands

  • Get active applications details: yarn application --list
  • Get failed applications details: yarn application --list -appStates FAILED
  • Get an application full logs: yarn logs --applicationId <applicationID>

Infrastructure as Code – AWS Redshift (Boto3)

The following is an example/template of Infrastructure as Code (IAC) for deploying an AWS Redshift cluster using Python and Boto3. Here’s the target architecture:

Target Redshift AWS Architecture

For this to work, you will need to create an AWS account and IAM user with appropriate permissions to Redshift and S3. After that, just input your own user secret and key into the attached notebook.

You can download the ipynb notebook. Or just check the Jupyter notebook below:

On the next post, we will discuss how to Extract, Transform and Load (ETL) data into this Redshift Database via parallel imports using S3.

Cómo seleccionar un algoritmo de ML

Si es nuevo en #Analytics, #MachineLearning y #AI, probablemente se haya preguntado cómo elegir el algoritmo de aprendizaje automático adecuado para el problema. Recopilé este PDF de referencia rápida de un par de recursos para ayudarlo a tomar una decisión.

Contraflujo – Seo para WordPress

SEO Para WordPress

ContraflujoHoy revisaremos SEO para WordPress, en nuestra nueva  sección llamada Contraflujo donde conseguiremos los mejores métodos funcionales para avanzar rápido, minimizar su tiempo de implementación de cualquier modulo o proyecto.

El SEOSearch Engine Optimization o posicionamiento web puede ser muy sencillo o tremendamente complicado. Y la plataforma de distribución de los contenidos,   tiene un papel  importante en el posicionamiento en los motores de búsqueda.

Instalaremos:

Icono de Yoast

  • Yoast Seo:  El mejor plugin SEO a contratar, si tu portal es profesional, es posible aportar unas monedas para que te ayude mucho más para una posición profesional.  Esto sucede con portales que tiene muchos competidores.  Pero igual su versión gratuita te ayudara hacer el trabajo esencial, su instalación es igual a otros plugins de wordpress y su configuración es muy sencilla: en su página principal esta una sección paso a paso, luego tendrás que configurar  las herramientas de webmasters google console, bing y yandex. Son importante las tres, nunca obvies un paso de las configuraciones, completa todo lo que sugiere Yoast SEO. Recuerda un desarrollador siempre desarrolla algo para que puedas usarlo. Hay muchos vídeos para configurarlo, no hay secretos allí, lo importante es revisar y entender el significado de cada función.
  • WP SuperCache: Cuando nuestro portal es visitado muchas veces por la misma persona, es posible ayudarle a guardar su cache, para que los elementos que no cambien  no sean recargados cada vez que entren.
  • Google Analytics: Necesitaremos un plugin de WordPress que no permita ver desde nuestro sitio el comportamiento del portal.

Después de esto no hemos hecho todo, tenemos que empezar a evaluar el comportamiento de nuestro portal, no debes esperar terminar el portal, para poder  instalar las herramientas de SEO o nos costara trabajo arreglarlo. La estructura del portal debe estar lista antes de alimentarlo con los posts. Si ya tiene los posts, solo te tocara un re-trabajo ajustar categorías, páginas y posts.

Algunas cosas importantes:

  • No anexes, no subas imágenes o archivos pesados, una parte importante en tu posicionamiento es la velocidad, reduce las imágenes que puedas  con herramientas gráficas.
  • En cada entrada o post siempre Yoast Seo, tendrás sugerencias, que tendrás que corregirlas, esto con el fin de ayudarte a  posicionarte.

Sugerencias Yoast

  • Usa herramientas como Keyword PlannerUbersuggest o Keyword Shitter para conseguirlas de forma gratuita o SEMrush para robarlas a tu competencia pagando la herramienta.
  • Cuidado con el Keyword Stuffing: poner demasiadas palabras claves ya no funciona,  todo lo expresado debe ser en forma natural, escribe para que te puedan leer.
  • Cambia la estructura de los enlaces en wordpress: Por defecto WordPress te seleccionará una estructura, categorías y fechas. Verifica, que tus enlaces sean adecuados ejemplo:  http://blog.leonelatencio.com/ejemplos-de-hadoop-mapreduce/ ‎ .
  • Enlaza todo lo que puedas: Mientras más quieras posicionar tus post, conseguir enlaces y ponlo en tus post,  los otros portales sentirán curiosidad de donde vienen estas entradas y  pasaran a ver tu post, comentarán, compartirán y en algún momento te enlazarán .

Es importante ver, hasta donde quieres llevar tu página o blog,  plantearte un objetivo con una página parecida o blog, seguir estas estrategias y otras que vamos a plantear más adelante como lista de chequeo para tu blog o página.  Esta es la estrategia mínima, a medida que leas nuestro blog y nos sigas, podrás ir subiendo de nivel.

Esperamos tus comentarios.

Hadoop – Ejemplos de hadoop-mapreduce-examples.jar

Hadoop MapReduce Una de las formas tradicionales de asegurarnos que un ambiente de Hadoop recién instalado funciona correctamente, es ejecutando el siempre presente jar de ejemplos map-reduce incluido con toda instalación de hadoop. Hablamos del hadoop-mapreduce-examples.jar.

 

En este tutorial, haremos un ejercicio que consiste en encontrar todas las apariciones de una palabra usando una expresión regular. Para hacerlo, crearemos un directorio llamado input en nuestro directorio de inicio y copiaremos los archivos de configuración (los xml) de Hadoop para usar esos archivos como nuestros datos de entrada.

Nota: la tilde (~) es un atajo muy útil en Bash para no tener que escribir la ruta de nuestra carpeta de usuario.

mkdir ~/input
cp /usr/local/hadoop/etc/hadoop/*.xml ~/input

A continuación, podemos usar el siguiente comando para ejecutar el programa (jar) hadoop-mapreduce-examples, un archivo Java con varias opciones. Invocaremos grep, uno de los muchos ejemplos incluidos en hadoop-mapreduce-examples, seguido por el directorio de entrada inputy el directorio de salida grep_example. El programa MapReduce grep contará las coincidencias de una palabra literal o expresión regular. Finalmente, proporcionaremos una expresión regular para encontrar ocurrencias de la palabra principaldentro o al final de una oración declarativa. La expresión distingue entre mayúsculas y minúsculas, por lo que no encontraríamos la palabra si estuviera en mayúscula al comienzo de una oración:

/usr/local/hadoop/bin/hadoop jar /usr/local/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.0.1.jar grep ~/input ~/grep_example 'principal[.]*'

El comando consta de las siguientes partes:

  1. /usr/local/hadoop/bin/hadoop Es el directorio donde esta el ejecutable de hadoop en el sistema.
  2. jar Le indica a hadoop que deseamos ejecutar una aplicacion empaquetada de Java. (Jar)
  3. /usr/local/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.0.1.jar Es la ruta donde esta el Jar que deseamos ejecutar. Note que la versión del jar depende de la versión de hadoop instalada.
  4. grep Es un parámetro de los muchos que se le pueden pasar al Jar de ejemplos que trae Hadoop. grep sirve para encontrar y contar ocurrencias de strings haciendo uso de expresiones regulares. Para ver una lista de los ejemplos que trae, click aquí.
  5. ~/input El directorio de entrada. Es donde el programa va a buscar los archivos de entrada a la tarea de map-reduce. Aquí copiamos unos archivos de prueba en un comando anterior.
  6. ~/grep_example El directorio de salida. Es donde el programa va a escribir el resultado de la corrida de la aplicación. En este caso, la cantidad de veces que la palabra del parámetro siguiente, aparece en los archivos de entrada.
  7. ‘principal[.]*’ Es la expresión regular que deseamos buscar. Esta expresión regular en particular coincide con la palabra ‘principal’ y ‘principal.’ (con y sin punto al final). Si desean saber un poco mas de expresiones regulares, les recomiendo este sitio web.

Cuando la tarea finaliza, proporciona un resumen de lo que se ha procesado y los errores que ha encontrado, pero esto no contiene los resultados reales.

. . .
 File System Counters
 FILE: Number of bytes read=1247674
 FILE: Number of bytes written=2324248
 FILE: Number of read operations=0
 FILE: Number of large read operations=0
 FILE: Number of write operations=0
 Map-Reduce Framework
 Map input records=2
 Map output records=2
 Map output bytes=37
 Map output materialized bytes=47
 Input split bytes=114
 Combine input records=0
 Combine output records=0
 Reduce input groups=2
 Reduce shuffle bytes=47
 Reduce input records=2
 Reduce output records=2
 Spilled Records=4
 Shuffled Maps =1
 Failed Shuffles=0
 Merged Map outputs=1
 GC time elapsed (ms)=61
 Total committed heap usage (bytes)=263520256
 Shuffle Errors
 BAD_ID=0
 CONNECTION=0
 IO_ERROR=0
 WRONG_LENGTH=0
 WRONG_MAP=0
 WRONG_REDUCE=0
 File Input Format Counters
 Bytes Read=151
 File Output Format Counters
 Bytes Written=37

Nota: Si el directorio de salida ya existe, el programa fallará, y en lugar de ver el resumen, la salida se verá algo así como:

 . . .
 at java.lang.reflect.Method.invoke(Method.java:498)
 at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
 at org.apache.hadoop.util.RunJar.main(RunJar.java:136)

Los resultados se almacenan en el directorio de salida (~/grep_example/) y se pueden verificar ejecutando caten el directorio de salida:

cat ~/grep_example/*
 6 principal
 1 principal.

La tarea MapReduce encontró una aparición de la palabra principal seguida de un punto y seis apariciones en las que no estaba el punto. La ejecución del programa de ejemplo ha verificado que nuestra instalación autónoma (standalone, un solo servidor) funciona correctamente y que los usuarios no privilegiados del sistema pueden ejecutar Hadoop para su exploración o depuración.

Otros Ejemplos de Hadoop MapReduce

Vale la pena probar otros ejemplos contenidos en el jar, como por ejemplo:

  • Terasort: Se usa normalmente para hacer Benchmarking en clusters de hadoop.
  • PI: Calcula los decimales de PI usando MapReduce!

Branding Personal: Su importancia para los desarrolladores.

Todos tienen una historia. Aquí está la mía:

Hola, soy Leonel, y soy Ingeniero Senior de Software Venezolano en Panamá. Soy desarrollador Big Data, con inclinación a la ciencia de datos y experiencia en desarrollo móvil. Mi trabajo es tomar aquello que imaginas y hacerlo realidad, diseñar aquello que visionas, comunicar a aquellos que están alejados y resolver eso que te preocupa.

En mi vida, no solo soy Leonel, el ingeniero de software, o Leonel el padre, sino que también soy la marca ‘Leonel’, desarrollador Big Data que asiste a charlas, dicta cursos que puedes encontrar en Internet y tiene una introducción intencionalmente hecha a medida. Eso resume lo que hago.

La idea del personal branding de convertirte en una marca es bastante extraña. Algunas personas se rehúsan porque tiene la mala reputación de estar asociado con «vender un producto» o de que usted, como persona, es un producto o pertenece a una entidad. En esta época en la que todo el mundo odia a los fanfarrones más humildes, o no le gustan las tareas que se llevarán a cabo, es fácil ver por qué algunas personas no hacen nada con respecto a su marca personal.

Sin embargo, es imposible negar el poder de la marca. Desde lo que elegimos comprar hasta nuestras creencias y valores fundamentales, nuestras vidas están determinadas por la marca de alguien o de alguna compañía de alguna manera. Las decisiones que tomamos sobre las cosas, las ideas o las personas como resultado de las impresiones que tenemos se encuentran en el núcleo mismo de cómo los humanos interactúan con el mundo. Del mismo modo que usamos estas impresiones para guiar nuestra toma de decisiones, debemos ser conscientes de lo que nosotros, como desarrolladores y personas, ofrecemos al mundo y lo que forma nuestra propia marca.

Como desarrolladores o programadores, cuando vamos de un lugar a otro, generalmente no tenemos activos tangibles, como un artista tiene una cartera o un periodista tiene clips. El código, a menos que pertenezca a la comunidad Open Source (Código Abierto), es el dominio privado de los clientes o de la organización de la que forma parte y, como resultado, nos queda poco para diferenciarnos, además de un título y algunos puntos sobre un resumen. Esa falta de propiedad es lo que hace que la marca sea tan crucial, especialmente cuando es una de las únicas cosas que te diferencia.

Pero a medida que fui tomando experiencia como desarrollador de software, empecé a darme cuenta de lo importante que era desarrollar una marca personal. Esta práctica de definir mi marca personal no solo me ha permitido exhibir por completo el trabajo que hago como ingeniero, sino que también me ha ayudado a cultivar y descubrir quién quiero ser para el mundo.

La marca personal: Un cultivo a largo plazo.

Para mí, cultivar una marca es como hacer crecer una planta. Por defecto, una marca es como un par de raíces en el suelo, con algo de altura y hojas que han crecido hasta lo que es ahora. A diferencia de una planta real -que requiere que existan elementos establecidos de agua, luz solar y oxígeno-, una marca y la persona a la que está adherida no tienen ningún elemento establecido que necesite para tener éxito y no existen restricciones.

Puedes poner lo que quieras en tu marca y crecerá en lo que quieras que sea. A dónde va su marca, qué tan grande o pequeña es, qué tan rápido crece, eso depende de uno mismo. Incluso se puede cambiar de dirección a la mitad, lo cual es algo que no se puede decir sobre las plantas.

Ya sea que esté programando, trabajando o pensando en mi marca personal, me aseguro de seguir estos cuatro pasos: Definir, Crecer, Curar y Aprender.

Definir

La marca no se trata de lo que sientes o piensas acerca de ti, sino más bien de lo que otras personas sienten, piensan y dicen sobre ti. Esto fue bastante aterrador para mí al principio, pero rápidamente me di cuenta de que puede ser un alivio. La marca no se trata de ti, se trata de todos los demás y de cómo te perciben.

Para comenzar a definir su marca, hágase la pregunta «¿Por qué me conoce la gente?» Si tiene problemas con esto (lo cual hice), acérquese a sus colegas para obtener comentarios.

Curar

Después de recibir retroalimentación de sus compañeros y colegas, el siguiente paso en el proceso de desarrollo de la marca es la curaduría. La clave de este paso es comprender por completo lo que quiere que se sepa y evaluar si coincide con lo que la gente piensa de usted en su trabajo, proyectos o cualquier otra cosa y utilizar esta información como su modelo final. Otra forma de conceptualizar este paso es pensar: Si pudieras comenzar desde cero, ¿quién me gustaría ser?

Crecer

Una vez que haya establecido quién va a ser su «futuro», el siguiente paso es hacer crecer la marca de esa persona. Una pregunta importante que debe hacer durante este paso es cómo va a pasar del presente al futuro.

Así es como lo hice: tomé las tres cosas por las que quería ser conocido desde el paso anterior y encontré tres objetivos para cada uno, estos objetivos se relacionaron con una visión de lo que quería para mi yo futuro.

Aprender

El cuarto paso en el desarrollo de una marca personal es aprender analizando sus métricas de éxito y comprendiendo cómo lo ha hecho. Este es un paso simple que a menudo se olvida, pero es crucial para todo el proceso de desarrollo de la marca. Por lo general, solo pongo una cita en mi agenda y reflexiono internamente o en voz alta con un amigo o colega de confianza. Encuentro que siempre puedo aprender algo nuevo de la reflexión y descubrir qué puedo incorporar en la próxima iteración de mi marca.

Introduciendo: M.U. Tutors Licensing

M.U. Tutors es un mercado de tutores y estudiantes online, que permite buscar rápidamente al tutor ideal para ese examen o asignación próxima.

Como colaborador activo del proyecto, me complace anunciar un modelo de licenciamiento para el producto, ideal para universidades, escuelas y academias que manejan clases particulares o programas de tutorías. Esto significa que la institución dueña de la licencia, lo es también de los datos y la plataforma donde corre el sistema, originalmente ideado como SAAS.

Puede visitar https://licensing.mututors.com/ para conocer mas detalles de la licencia.

Firefox Quantum y el lenguaje Rust

Rust es un lenguaje de programación compilado, de propósito general y multiparadigma que está siendo desarrollado por Mozilla.​ Ha sido diseñado para ser «un lenguaje seguro, concurrente y práctico».​​

El Logo de Rust

El nuevo Firefox Quantum incluye Stylo, un motor de CSS escrito en Rust, que aprovecha al máximo la «Concurrencia Libre de Miedo» de Rust para acelerar el estilizado de la página. Es el primer componente principal de Servo que se integra con Firefox y representa un hito importante para Servo, Firefox y Rust. Reemplaza aproximadamente 160,000 líneas de C ++ con 85,000 líneas de Rust.

Firefox Quantum

 

Se puede leer mas al respecto de Rust y su «Fearless Concurrency» en el blog de Rust: https://blog.rust-lang.org/2017/11/14/Fearless-Concurrency-In-Firefox-Quantum.html

 

Mi franela del HacktoberFest ya llegó!

Cada octubre, Digital Ocean y GitHub envían camisetas gratuitas del Hacktoberfest a miles de personas en el mundo.

El diseño de este año.

El año pasado me quedo corto por un PR (Pull-Request), pero este año califique, y debo decir que la camiseta se ve GENIAL! Obtener una es sencillo: Debes realizar 4 solicitudes de extracción (PR, Pull-Requests) a proyectos Open Source en GitHub. Aquí lo resumo en 3 pasos:

  1. Registrarse en el Hacktoberfest:
    Necesitas una cuenta de GitHub. Si todavía no tienes uno, puedes crear uno gratis en solo unos minutos. Luego hay que ir a la página de registro del Hacktoberfest y seguir las instrucciones. Sólo toma un minuto.
  2. Realizar 4 PR’s:
    Se deben realizar cuatro Pull Requests a proyectos de Software libre. Pueden ser cosas tan sencillas como el archivo Readme.md de un repositorio publico cualquiera. Si no conoces ninguno, dejo a la orden mis repositorios. Aquí hay una guía más detallada para contribuir al código abierto, si te sientes aventurero.
  3. Verificar si has calificado:
    Una vez que se haya registrado, puede verificar su progreso en el sitio web de Hacktoberfest.

Python, primero en el ranking de la IEEE

Fuente: IEEE

Python ha continuado su trayectoria ascendente desde el año pasado y saltó dos lugares a la ranura N º 1, aunque los cuatro primeros (Python, C, Java y C++) – siguen estando muy cerca de popularidad.

Sin embargo, por segundo año consecutivo, no se han introducido nuevos idiomas en el ranking:

Parece que hemos entrado en un período de consolidación en la codificación como programadores digerir las herramientas creadas para atender a la explosión de la nube, móviles y grandes aplicaciones de datos.

Fuente: https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2017