Netflix explica dónde y cómo utiliza Python: desde aprendizaje automático hasta automatización, pasando por seguridad

03/05/2019
Artículo original

Netflix explica dónde y cómo utiliza Python: desde aprendizaje automático hasta automatización, pasando por seguridad

En lo que a lenguajes de programación se refiere, Python es una de las estrellas del momento. Dependiendo del índice que consultemos, es el más usado o está cerca, pero en cualquier caso, su relevancia en el desarrollo ya no puede infravalorarse. Es un lenguaje fenomenal para Devops, desarrollo web, aprendizaje automático o Data Science, y las proyecciones apuntan a que si sus competidores se van a permanecer estables en cuánto a búsquedas relacionadas, las de Python van a crecer exponencialmente.

Netflix ha sido la última gran compañía en abrirse para explicar cómo gestiona a nivel de desarrollo todos los procesos, y según cuentan, a lo largo de todos los apartados del servicio, desde los implicados en garantizar la seguridad hasta los algoritmos de recomendación, pasando por su red de distribución de contenido Open Connect. El artículo ha sido publicado en el blog de tecnología de Netflix en Medium, de cara a la Pycon, la conferencia de Python que tiene lugar desde ayer hasta el 9 de mayo en Cleveland.

Ser intuitivo para resolver problemas de red, la clave del uso de Python en Netflix

Python Que se usen estas carátulas y no otras depende de herramientas escritas en Python.

Según el artículo, coordinado por Amjith Ramanujam, una forma sencilla aunque imprecisa de pensar cómo funciona Netflix es pensar que todo lo que ocurre antes de que pulsemos Play ocurre en los servidores de Amazon en Amazon Web Services, mientras que todo lo que pasa después, como la propia reproducción del vídeo, pasa en la red Open Connect Network. Así, el contenido está situado lo más cerca posible del usuario, para reducir los costes de operación de Netflix y de los ISP y mejorar la experiencia final.

El funcionamiento de Netflix suele ser ejemplar independientemente del momento en que se utilice

Para diseñar, construir y operar esta compleja infraestructura, Python juega un gran papel, pues mucho del software interno está escrito con el lenguaje. Según la visión de Netflix, que sea tan intuitivo lo hace ideal en el área de las redes, porque permite solucionar los problemas rápidamente.

Otro departamento de la compañía cuyas herramientas están escritas en Python es el de Ingeniería de demanda, que se encarga de asignar y distribuir recursos en función del tráfico y la conmutación por error regional. El servicio que lidia con ello también está basado en Python, y utiliza numpy, scipy, boto3 o rq para ejecutar análisis numéricos, para hacer cambios en ARS o para ejecutar cargas de trabajo asíncronas.

Algunas de estas librerías matemáticas, junto a otras como ruptures o pandas, se utilizan para alertas y en trabajo de análisis estadístico de manos del equipo CORE, que también utiliza Python para automatizar tareas, para explorar datos y limpieza, junto a otros usos de visualización. Otra gran área donde Python resulta imprescindible es en entrenamiento para aprendizaje automático, en algoritmos de recomendación, algoritmos para la elección del arte que muestra o algoritmos de marketing.

Además de en estos, Netflix también hace uso de aprendizaje automático en cientos de casos a lo largo de muchas divisiones de la compañía, con muchas de las aplicaciones potenciadas por Metaflow, un framework de Python que facilita la labor de ejecutar proyectos de aprendizaje automático desde la etapa de prototipado hasta la de producción, y que "lleva Python a sus límites".

Las preguntas de las entrevistas de programación son demasiado difíciles y demasiado cortas

03/05/2019
Artículo original

Nota: este artículo es una traducción de "Programming Interview Questions Are Too Hard and Too Short" por Charles Treichler en el blog de la empresa de selección TripleByte, traducido y publicado aquí con su autorización expresa.

TL;DR: las preguntas de entrevistas de trabajo de programación pueden resultar innecesariamente difíciles. A veces realmente lo son. Y esto no sólo es porque hacen que las entrevistas sean demasiado estresantes. Nuestros datos revelan que las preguntas sobre programación más difíciles en realidad empeoran la predicción final sobre la idoneidad de los candidatos que en el caso de las más fáciles.


Programar bajo la presión del tiempo es difícil. Esto es especialmente cierto durante las entrevistas de trabajo. Un ejercicio de programación que parecería simple en circunstancias normales se convierte de alguna manera en un desafío imponente bajo las luces brillantes de una oficina en la que se realizan entrevistas. Las hormonas del estrés nublan el pensamiento durante las entrevistas (aunque, lamentablemente, ni luchar ni huir es una respuesta válida ante un problema de programación amenazante). Y casi puede parecer que las preguntas están diseñadas para ser perversamente difíciles. De hecho, creo que esto es más que un simple presentimiento.

Las preguntas de las entrevistas están diseñadas para ser difíciles. Debido a que el coste de contratar a un mal programador es mucho más alto que el coste de descartar a un buen programador, las empresas se ven incentivadas a establecer un listón alto. Y para la mayoría de las organizaciones esto significa hacer preguntas difíciles. Intuitivamente, esto parece tener sentido porque las preguntas más difíciles parecen dar lugar a un proceso de selección más riguroso. Pero la intuición resulta ser un mal consejero en este caso. Nuestros datos muestran que las preguntas más difíciles son en realidad menos fiables que las que son relativamente más fáciles.

Las preguntas de las entrevistas son demasiado difíciles

Las preguntas difíciles sí filtran a los malos profesionales, pero también filtran a los buenos (es decir, tienen una alta tasa de falsos negativos). Por el contrario, las preguntas fáciles producen menos falsos negativos pero más falsos positivos (ya que más programadores aciertan). Equilibrar estas dos variables es el problema principal al que te enfrentas al seleccionar el nivel de dificultad óptimo para las preguntas de la entrevista. Las empresas que buscan evitar falsos positivos a toda costa tienden a inclinarse hacia el extremo más difícil de este espectro.

Sin embargo, el hecho de que un candidato responda o no correctamente a una pregunta no es la única fuente de información en el transcurso de una entrevista. También se pueden evaluar los procesos de los candidatos, por ejemplo, observando cuánto tiempo tardan en terminar, cuán limpio es el código y cuánto les cuesta encontrar una solución. Nuestro análisis muestra que esta segunda fuente de información (los procesos) es casi tan predictiva como la primera (los aciertos).

Pero en este punto hay una concesión más. Las preguntas que transmiten la mayor parte de la información sobre los procesos son mucho más fáciles que las preguntas que transmiten la mayor parte de la información sobre los aciertos. Esto se explica con claridad cuando se analizan los procesos hasta el punto de determinar hasta qué punto un candidato se esfuerza mientras encuentra una solución (el aspecto del proceso más directamente relacionado con la dificultad de la pregunta). Si una pregunta es lo suficientemente difícil como para transmitir mucho valor al acierto, entonces todos los candidatos tendrán dificultades con ella (incluso aquellos que a la larga la terminen acertando). Por lo tanto, el nivel de esfuerzo no trasladará mucha información sobre el candidato.

Por el contrario, las preguntas que transmiten información sobre los procesos serán lo suficientemente fáciles para que la mayoría de los candidatos las respondan correctamente, por lo que tendrán poco que ofrecer en términos de información sobre el candidato cuando lo evaluamos en función de si la respuesta es correcta o no. Una pregunta óptimamente difícil es aquella que equilibra "proceso" y "acierto" para extraer la información máxima de la combinación de estos dos factores (y que no tiene que ser la información de 10 sobre 10 para ninguno de los dos).

Hemos entrevistado a miles de ingenieros y evaluado sus respuestas a lo largo de múltiples dimensiones, incluyendo el proceso y el acierto, y hemos comparado estas puntuaciones con el rendimiento posterior. Y, después del análisis de regresión (considerando tanto los indicadores de proceso como los de acierto), nuestros datos mostraron que las preguntas más predictivas eran en realidad mucho más fáciles de lo que esperábamos (y más fáciles que las preguntas que hacen muchas de las empresas).

En última instancia, las preguntas más difíciles descartan a demasiados candidatos capacitados para ser óptimos. Por lo tanto, si quieres que tu proceso de contratación sea más preciso, probablemente deberías hacer preguntas más fáciles.

Quiero dejar claro, sin embargo, que esto no significa que debas bajar el listón y pasar a más gente. Hacer preguntas más fáciles no implica necesariamente que las entrevistas sean más fáciles. El nivel de dificultad de las preguntas que se hacen y dónde se establece el umbral de corte son decisiones independientes. Se puede implementar un proceso de contratación extremadamente riguroso haciendo preguntas relativamente fáciles y evaluándolas de manera exigente. Nuestro hallazgo es sencillamente que las preguntas más fáciles proporcionan más información. Pero lo que se haga con esa información depende de cada empresa.

Las preguntas más fáciles de responder también son menos estresantes, lo cual es una ventaja importante. El estrés causa que los candidatos tengan un desempeño inferior. Sin embargo, cuando los candidatos se sienten más cómodos, dan lo mejor de sí mismos, lo que en realidad hace que las entrevistas sean más reveladoras. Creo que los entrevistadores tienden a subestimar los efectos del estrés en los candidatos y a sobreestimar sus propias habilidades. Cuando eres tú quien hace las preguntas, es fácil olvidar lo difícil que es conseguir una programación real en 30-60 minutos. Para contrarrestar este sesgo, hemos adoptado una regla en Triplebyte que establece que los entrevistadores tienen que dar a los candidatos 3 veces más tiempo para responder a una pregunta de lo que piensan que les llevaría resolverla a ellos mismos. Por lo general, esta simple norma resulta dar con el tiempo adecuado para contrarrestar los efectos del estrés y los nervios.

Las preguntas en las entrevistas se hacen cortas

Las preguntas fáciles también son beneficiosas por otra razón importante. Te permiten incluir más contenido en tus entrevistas. Esto significa que se pueden utilizar problemas más largos, con varias partes, que tienen beneficios adicionales en términos de pronosticar la valía de los candidatos. Uno puede hacer preguntas que aumenten en dificultad a medida que pasa el tiempo, y estas preguntas más largas y reales son más reveladoras que las de sus parientes más cortas y más difíciles <sup>*</sup>.

<sup>*</sup> "El mejor predictor acerca del desempeño de alguien en un trabajo es un ejercicio de ejemplo de trabajo real (29%). Esto conlleva darle a los candidatos un trabajo de prueba, similar a lo que van a hacer en el puesto, y evaluar su desempeño en éste" - Wired Magazine

Esto se debe en parte a que las preguntas más largas ofrecen una mejor aproximación a cómo sería la programación del candidato en un entorno de trabajo real. Una programación productiva requiere trabajar con una base de código relativamente grande durante un largo período de tiempo, y las preguntas más largas simplemente logran una mejor aproximación a esta realidad.

Además, las preguntas más largas permiten dar pistas cuando un candidato se atasca. Creo que esto es vital porque incluso los mejores ingenieros pueden tropezar durante un problema con el código. Hacer preguntas más largas da a los candidatos la oportunidad de reponerse de los errores y mostrar sus habilidades durante el ejercicio. Un solo paso en falso no debería arruinar toda una entrevista. Finalmente, el hecho de poder ofrecer ayuda hace que las entrevistas sean menos estresantes, lo que, una vez más, resulta en resultados más fiables a la hora de evaluar a los candidatos.

Conclusión

Las empresas pueden quedar atrapadas en un círculo vicioso a la hora de fijar la dificultad de una prueba. Comienzan haciendo preguntas que de por sí son demasiado duras y cortas, lo que les lleva a tomar malas decisiones de contratación basadas en indicadores difusos. Cuando experimentan resultados deficientes, pueden intentar corregirlos haciendo de su proceso una experiencia aún más rigurosa (lo que generalmente significa hacer preguntas aún más difíciles). Pero esto sólo hace que sus entrevistas sean menos precisas. Y así sucesivamente. Tanto las empresas como los candidatos se ven afectados por este ciclo. En mi opinión, las empresas pierden talento y los candidatos pierden puestos de trabajo, y todos se estresan más de lo necesario.

Espero que los entrevistadores acepten estos hallazgos descritos. Esto no solamente puede hacer que el trabajo sea más conciso, sino también más fácil. Es mucho menos intensivo en términos de tiempo encontrar problemas sencillos y con múltiples pasos que los retos cortos y sumamente difíciles.

Así que, aquí está nuestro consejo, si realmente quieres hacer que tus entrevistas sean más precisas, probablemente necesites empezar a hacer preguntas de programación más fáciles. Esto no significa bajar el listón. Sólo significa obtener mejores indicadores para poder contratar a las personas adecuadas.

Netflix explica dónde y cómo utiliza Python: desde aprendizaje automático hasta automatización, pasando por seguridad

02/05/2019
Artículo original

Netflix explica dónde y cómo utiliza Python: desde aprendizaje automático hasta automatización, pasando por seguridad

En lo que a lenguajes de programación se refiere, Python es una de las estrellas del momento. Dependiendo del índice que consultemos, es el más usado o está cerca, pero en cualquier caso, su relevancia en el desarrollo ya no puede infravalorarse. Es un lenguaje fenomenal para Devops, desarrollo web, aprendizaje automático o Data Science, y las proyecciones apuntan a que si sus competidores se van a permanecer estables en cuánto a búsquedas relacionadas, las de Python van a crecer exponencialmente.

Netflix ha sido la última gran compañía en abrirse para explicar cómo gestiona a nivel de desarrollo todos los procesos, y según cuentan, a lo largo de todos los apartados del servicio, desde los implicados en garantizar la seguridad hasta los algoritmos de recomendación, pasando por su red de distribución de contenido Open Connect. El artículo ha sido publicado en el blog de tecnología de Netflix en Medium, de cara a la Pycon, la conferencia de Python que tiene lugar desde ayer hasta el 9 de mayo en Cleveland.

Ser intuitivo para resolver problemas de red, la clave del uso de Python en Netflix

Python Que se usen estas carátulas y no otras depende de herramientas escritas en Python.

Según el artículo, coordinado por Amjith Ramanujam, una forma sencilla aunque imprecisa de pensar cómo funciona Netflix es pensar que todo lo que ocurre antes de que pulsemos Play ocurre en los servidores de Amazon en Amazon Web Services, mientras que todo lo que pasa después, como la propia reproducción del vídeo, pasa en la red Open Connect Network, estando el contenido situado lo más cerca posible del usuario, para reducir los costes de operación de Netflix y de los ISP y mejorar la experiencia final.

El funcionamiento de Netflix suele ser ejemplar independientemente del momento en que se utilice

Para diseñar, construir y operar esta compleja infraestructura, Python juega un gran papel, pues mucho del software está escrito con el lenguaje. Que sea tan intuitivo lo hace ideal en el área de las redes, porque permite solucionar los problemas rápidamente. Otro departamento de la compañía cuyas herramientas están escritas en Python es el de Ingeniería de demanda, que se encarga de asignar y distribuir recursos en función del tráfico y las conmutación por error regional. El servicio que lidia con ello está escrito en Python, y utiliza numpy, scipy, boto3 o rq para ejecutar análisis numéricos, para hacer cambios en ARS o para ejecutar cargas de trabajo asíncronas.

Algunas de estas librerías matemáticas, junto a otras como ruptures o pandas se utilizan para alertas y en trabajo de análisis estadístico de manos del equipo CORE, que también utiliza Python para automatizar tareas, para explorar datos y limpieza, junto a otros usos de visualización. Otro gran uso de Python es en entrenamiento para aprendizaje automático, en algoritmos de recomendación, algoritmos para la elección del arte que muestra o algoritmos de marketing.

Además de ahí, también emplea aprendizaje automático en cientos de casos a lo largo de toda la compañía, con muchas de las aplicaciones potenciadas por Metaflow, un framework de Python que facilita la labor de ejecutar proyectos de aprendizaje automático desde la etapa de prototipado hasta la de producción, y que "lleva Python a sus límites".

JavaScript: por qué obtengo fechas diferentes por consola y por pantalla

02/05/2019
Artículo original

Hoy una curiosidad rápida y simple pero puede que de interés, surgida a partir de la pregunta de un alumno...

Si tienes una fecha en una variable de JavaScript, por ejemplo, la fecha de hoy (recuerda que los meses comienzan a contarse en 0, por eso un 4 como segundo argumento del constructor):

var base = new Date(2019, 4, 2);

y la muestras por pantalla, por ejemplo con un alert(), verás esto:

que es justo lo que cabría esperar ya que estamos en España en horario de verano y por lo tanto, al no especificar la hora, supone las 12 de la noche (00:00) y GMT+2.

Sin embargo, si abrimos Firefox y vamos a su consola y mostramos la misma fecha veremos esto:

Lo que vemos es una fecha anterior, el 1 de mayo a las 10 de la noche... ¿Pero no es la misma fecha?

Para acabar de liar la cosa, si repetimos lo mismo en Chrome, veremos esto:

o sea, lo mismo que en el alert() de antes.

¿A qué se deben estas diferencias?

La explicación es muy sencilla. console.log es una instrucción pensada para el uso de programadores y que además es capaz de mostrar otras muchas cosas aparte de texto. Por ejemplo, si tenemos un elemento en una variable y lo mostramos por consola en Firefox, no solo nos muestra el contenido HTML del elemento, sino que podemos interactuar con él, resaltándose en la página al pasarle por encima, pudiendo seleccionarlo y desplegándolo para ver todo su contenido:

Pero si lo mostramos por pantalla, por ejemplo con un alert(),  veremos simplemente esto:

¿Te da ya alguna pista?

Efectivamente: la consola muestra objetos y nos permite interactuar con ellos, mientras que un alert() y cualquier función que se dirija a la interfaz de usuario no tiene esa capacidad. Además, la consola puede funcionar de manera diferente según el navegador, de ahí la diferencia entre Firefox y Chrome.

En el caso concreto de alert() lo que ocurre es que siempre llama implícitamente al método toString() de lo que se pretende mostrar para asegurarse de que es una cadena de texto. Si es una fecha, toString() por defecto siempre la muestra en el formato definido por ECMA-262 2018 (antes de eso era dependiente de cada implementación, aunque era bastante consistente y ahora está ya estandarizado, aquí tienes un resumen más digerible), que resulta en lo que se veía en una de las figuras anteriores y que, sino se indica otra cosa, supone que la fecha está en la zona horaria actual del usuario y no en UTC.

En el caso de Chrome, al mostrar la fecha por consola ésta se muestra también como una cadena y no como un objeto, ya que ningún estándar determina cómo debe hacerse esto y en este caso la gente de Google ha optado por hacerlo de manera diferente a Firefox, usando también el toString() para mostrarlo por consola. Sin embargo si lo que mostramos en la consola de Chrome es un elemento del DOM lo mostrara de la misma manera que lo hacía Firefox, pudiendo también interactuar con él y demás.

El resumen es: lo que se muestra por consola y lo que se muestra por pantalla no tienen por qué coincidir ni tampoco tienen porque qué coincidir lo que se ve por consola en dos navegadores diferentes. En el caso de las fechas, que en JavaScript son bastante complicadas de gestionar en cuanto entran en juego las zonas horarias, la cosa se complica más aún.

En fin, es más una curiosidad que otra cosa, pero puede que te resulte útil en alguna ocasión saberlo...

Agregando estado

01/05/2019
Artículo original

Estado en React

React es por asi decirlo, una maquina de estados, reacciona a cambios de estado y define todo un ciclo de eventos que suceden cada vez que cambia el estado, el proceso simple es que vuelve a renderizar el componente, es decir, crea el DOM virtual del componente hace la comparacion de diferencias y actualiza el DOM, esto lo hace a una velocidad mas que decente.

Hooks

Hablar de React despues del 06 Febrero del 2019 es hablar de Hooks, no podemos ser mas afortunados de por fin librarnos de ese mal concepto de Clases en javascript, que ni son clases reales porque son instancias y confunden mucho tanto a desarrolladores js como a los que no lo son.
Vamos a realizar un pequeno contador que muestre cuantos segundos han pasado desde que cargamos una pagina. Hooks nos ayudara a escribir el codigo en React.

Dependencias

- La unica dependencia es haber realizado el ejercicio del post anterior.

Actualizando el componente

Solo vamos a actualizar el archivo index.tsx, debera quedar asi:

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

const Hello: React.SFC<{
  text: string

leer más

Cómo crear operadores personalizados para clases propias en C#

30/04/2019
Artículo original

Imagen ornamental. Base CC0 de Kelly Sikkerma

Al igual que ocurría con las conversiones, el ecosistema .Net viene preparado con una serie de operaciones que es posible realizar entre los tipos del propio framework. Un ejemplo trivial es una suma:

int total = 10 + 11;

En cambio, al igual que pasaba con las conversiones, cuando definimos nuestras propias clases tenemos que definir también sus operaciones (si es que las tiene). En caso contrario, vamos a ver un error que nos dice que no se puede aplicar un determinado operador:

La imagen muestra un error de operación entre clases definidas por el usuario para las que no se ha sobrescrito el operador correspondiente

A simple vista, puede parecer que estas operaciones tienen poca utilidad. Yo mismo he tenido que pensar bastante en un ejemplo cristalinamente claro con el que explicarlo. Pero hay uno que lo es. De hecho, es todo un campo: ¡las matemáticas!. Y más en concreto, el manejo de fracciones.

Para este articulo he elegido las fracciones por ser algo fácil de entender, aunque el modo de trabajo sería igual para matrices, números imaginarios, etc...

El framework no nos provee de ningún tipo nativo para trabajar con fracciones, así que podemos definir nuestro propio tipo. Podría ser algo así:

class Fraccion
{
  public Fraccion(int Numerador, int Denominador)
  {
    this.Numerador = Numerador;
    this.Denominador = Denominador;
  }
  public int Numerador { get; }
  public int Denominador { get; }
}

Aunque las fracciones se pueden operar calculando su valor decimal, eso puede generarnos un error por la precisión de la división que se va a acumular en cada operación. Por esa razón es habitual trabajar con ellas y solo calcular la división como último paso. Siguiendo esta filosofía de mantener la fracción hasta el final, podríamos ir operando las fracciones de esta manera. Por ejemplo, para multiplicar dos fracciones tan solo se deben multiplicar los numerados y los denominadores entre sí:

Fraccion frac1 = new Fraccion(1,2);  //Representa 1/2, o sea 0.5
Fraccion frac2 = new Fraccion(1,4);  //Representa 1/4, o sea 0.25
Fraccion Multiplicacion = new Fraccion((frac1.Numerador * frac2.Numerador),(frac1.Denominador * frac2.Denominador));

Este código es perfectamente válido, pero si lo que queremos es sumarlas, la cosa se complica ya que hay que sacar factor común y luego sumar los numeradores:

Fraccion frac1 = new Fraccion(1,2);
Fraccion frac2 = new Fraccion(1,4);
Fraccion Suma = new Fraccion((frac1.Numerador * frac2.Denominador + frac2.Numerador * frac1.Denominador),(frac1.Denominador * frac2.Denominador));

Nota: en este caso no hacemos la simplificación final de la fracción, sacando común denominador, para no complicar la explicación. En el ejemplo final sí lo tienes añadido.

Es aquí donde entra la sobrecarga de operadores. Con esta posibilidad que nos ofrece el framework podemos crear nuestras propias operaciones entre tipos sin ningún problema. Por ejemplo, el caso anterior podríamos definir el operador de suma de fracciones así:

class Fraccion
{
  public Fraccion(int Numerador, int Denominador)
  {
    this.Numerador = Numerador;
    this.Denominador = Denominador;
  }
  public int Numerador { get; }
  public int Denominador { get; }

  public static Fraccion operator +(Fraccion frac1, Fraccion frac2)
  {
    var nuevoNumerador = frac1.Numerador * frac2.Denominador + frac2.Numerador * frac1.Denominador;
    var nuevoDenominador = frac1.Denominador * frac2.Denominador;
    return new Fraccion(nuevoNumerador, nuevoDenominador);
  }
}
//---------
Fraccion frac1 = new Fraccion(1,2);
Fraccion frac2 = new Fraccion(1,4);
Fraccion Suma = frac1 + frac2;

Como vemos, se definen de manera similar a una función. Deben ser métodos estáticos y se utiliza la palabra clave operator delante del operador que vamos a sobrecargar. Como argumentos tomarán tantos como operandos, es decir, como elementos con los que se va a operar. Generalmente serán 2, pero no te olvides de que existen también operadores unarios con un solo operando.

Hay que decir también, que es necesario que definamos cada operación que queremos soportar. Esto incluye cada uno de los parámetros de la operación y su orden, por ejemplo, con la clase anterior, no podríamos sumar la fracción con un escalar (sumarle un número entero):

La imagen muestra un error de operación al multiplicar la fracción por un escalar

Para que el código anterior pueda funcionar, tendremos que escribir otras 2 sobrecargas del operador + (ponemos solo las nuevas sobrecargas, no la clase entera):

class Fraccion
{

  //...

  public static Fraccion operator +(int escalar, Fraccion frac)
  {
    var nuevoNumerador = escalar * frac.Denominador + frac.Numerador;
    return new Fraccion(nuevoNumerador, frac.Denominador);
  }
  public static Fraccion operator +(Fraccion frac, int escalar)
  {
    var nuevoNumerador = escalar * frac.Denominador + frac.Numerador;
    return new Fraccion(nuevoNumerador, frac.Denominador);
  }
}

Es necesario sobrescribir las dos porque hay operaciones donde el orden sí importa. La resta es un buen ejemplo.

La lista de operadores que se pueden sobrecargar es bastante grande, y no es necesario sobrecargar más de los que nuestra aplicación necesita o los que queramos soportar si estamos creando una librería.

En resumen

La posibilidad de sobrecargar los operadores combinada con la de definir nuestras propias conversiones dota de una gran potencia al lenguaje y nos permite adaptarnos a las necesidades que tengamos en cada momento. Es precisamente la unión de estas dos opciones la que más potencia nos ofrece.

Siguiendo con nuestro ejemplo de fracciones, podemos aprovechar las conversiones personalizadas para evitar tener que escribir un montón de código y poder usar operadores como >, <, >=, <=, ==, !=, etc. sin tener que definirlos, aprovechando la conversión desde Fraccion a double, y en sentido contrario de int a Fraccion.

Te dejo un repl.it a continuación con el código completo de la clase y ejemplos para todos los operadores y conversiones, de modo que puedas probarlo:

Este ejemplo es, por supuesto, mejorable y se le pueden añadir más cosas, pero nos aporta una idea clara de la potencia que nos ofrece el framework al poder escribir nuestras conversiones y sobrecargar operadores y a efectos de ilustrar lo que necesitábamos creo que te será de gran utilidad.

Termina el soporte para Ruby 2.3

28/04/2019
Artículo original

Anunciamos que todo soporte para la serie Ruby 2.3 ha terminado.

Después de la publicación de Ruby 2.3.7 el 28 de Marzo de 2018, el soporte para la serie Ruby 2.3 estaba en fase de mantenimiento de seguridad. Ahora, un año después, esa fase ha concluido. Por tanto, desde Marzo 31 de 2019, cesa todo soporte para la serie Ruby 2.3. Las correcciones de seguridad y de fallas a versiones más recientes de Ruby ya no se retro-portarán a 2.3. Tampoco habrá más parches para 2.3. Recomendamos que actualice a Ruby 2.6 o 2.5 tan pronto como le sea posible.

Sobre las versiones de Ruby actualmente soportadas

Serie Ruby 2.6

Actualmente en fase de mantenimiento normal. Retroportaremos correcciones a fallas y publicaremos nuevas versiones con las correcciones cuando sea necesario. Y, si se encuentra alguna falla de seguridad crítica, publicaremos un arreglo urgente para la misma.

Serie Ruby 2.5

Actualmente en fase de mantenimiento normal. Retroportaremos correcciones a fallas y publicaremos nuevas versiones con las correcciones cuando sea necesario. Y, si se encuentra alguna falla de seguridad crítica, publicaremos un arreglo urgente para la misma.

Serie Ruby 2.4

Actualmente en fase de mantenimiento de seguridad. No retroportaremos correcciones a fallas a 2.4 excepto correcciones de seguridad. Si se encuentra alguna falla de seguridad crítica, publicaremos un arreglo urgente para la misma. Planeamos terminar el soporte para serie Ruby 2.4 en Marzo 31 de 2020.

Publicado por antonpaisov el 2019-03-31
Traducción de vtamara

Publicado Ruby 2.4.6

28/04/2019
Artículo original

Se ha publicado Ruby 2.4.6.

Esta versión incluye cerca de 20 correcciones a fallas desde la versión anterior, y también incluye varias correcciones a fallas de seguridad. Por favor vea detalles en los temas siguientes.

Vea detalles en las bitácoras de cambios.

Después de esta versión, terminaremos la fase de mantenimiento normal de Ruby 2.4, y comenzaremos su fase de mantenimiento de seguridad. Esto significa que después de la versión 2.4.6 no retro-portaremos correcciones a fallas a 2.4 excepto correcciones a fallas de seguridad. La vigencia de la fase de mantenimiento de seguridad es de un año. Al final de ese año, se terminará el soporte oficial de Ruby 2.4. Por esto le recomendamos comenzar a planear la actualización a Ruby 2.6 o a 2.5.

Descargas

  • https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.6.tar.bz2

    SIZE:   12623913 bytes
    SHA1:   b44b5c6637a69b3b95971b1937ecb583dc1de568
    SHA256: 909f360debed1f22fdcfc9f5335c6eaa0713198db4a6c13bab426f8b89b28b02
    SHA512: 292802984e5cff6d526d817bde08216fe801d255c4cede0646e450f22d4a3a81ae612ec5d193dcc2a888e3e98b2531af845b6b863a2952bcf3fb863f95368bcf
    
  • https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.6.tar.gz

    SIZE:   15880585 bytes
    SHA1:   3bc2d9ab3381887c57e0fb7937dc14e9f419f06c
    SHA256: de0dc8097023716099f7c8a6ffc751511b90de7f5694f401b59f2d071db910be
    SHA512: 7eb7720961e98e22e4335c38eeead9db96d049ef3ac1da437769b98fee7a10feb092643ce75822a2fe3bd5fd94938417ab5c2de7c6056afe0abf6e4cf03ca282
    
  • https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.6.tar.xz

    SIZE:   10005544 bytes
    SHA1:   86a4fa22cb3547005ec4bfcf77489a4254226187
    SHA256: 25da31b9815bfa9bba9f9b793c055a40a35c43c6adfb1fdbd81a09099f9b529c
    SHA512: eafb2257747f99e2ed262af142e71175b70f7cceaa4d1253b92c8337f075a9a58a2d93b029d75e11a9b124f112a8f0983273b2b30afc147b5cf71a8dbb5fa0ba
    
  • https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.6.zip

    SIZE:   17469891 bytes
    SHA1:   0e55d231c0e119304e077e42923ce6a1c3daa1d1
    SHA256: c5de9f11d4b7608d57139b96f7bc94899bb2fc9dee2e192c8951f6647a9d60f7
    SHA512: cfa779cdb970dfd35dc2a97951310cb3cde1d380b040c283fda6609c591039817a2847ab7174f7a9ee7f7adbb610709b57914bb26e5c015a20d5fe880c569855
    

Comentarios de la versión

Disculpenos por hacerlo esperar tanto tiempo. Gracias a todos los que nos ayudaron con esta versión.

El mantenimiento a Ruby 2.4, incluyendo esta publicación, se basa en el “Acuerdo para versiones estables de Ruby” de la Asociación Ruby.

Publicado por usa el 2019-04-01
Traducción de vtamara

Publicado Ruby 2.6.3

28/04/2019
Artículo original

Se ha publicado Ruby 2.6.3.

Esta versión añade soporta para la nueva Era Japonesa “令和” (Reiwa). Actualiza la versión de Unicode a 12.1 beta (#15195) y actualiza la librería date (#15742).

Esta versión también incluye algunas correcciones a fallas. Ver detalles en la bitácora de cambios.

Descargas

  • https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.gz

    SIZE:   16784748 bytes
    SHA1:   2347ed6ca5490a104ebd5684d2b9b5eefa6cd33c
    SHA256: 577fd3795f22b8d91c1d4e6733637b0394d4082db659fccf224c774a2b1c82fb
    SHA512: 8503b86da60e38da4f1a1553b2570d4125c1823280e6fb6d07825a0e92dd7b628e13147ebde085702cbf5c5eddfe7fa5a2445996bc29164196a53bc917b02112
    
  • https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.zip

    SIZE:   20611578 bytes
    SHA1:   85e9ffe707fb1c1eb4131c953530bb01105a5948
    SHA256: 5ef6b8e5b5f242d41e4b3d9ab21a40d3f494dfca42b00b25ab8fd3122325fe2d
    SHA512: 5c87e1eda0002e95684c08ea4eb55b5ce1941dd6304806117647c0bd44ab0714d50fe3b24c322a4f5978286a5442ceaa2d141ebe7cfe07198e0a0b876af6c004
    
  • https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.bz2

    SIZE:   14509165 bytes
    SHA1:   aed3bd3c5346b3b85a6b184bb320465d98994fe3
    SHA256: dd638bf42059182c1d04af0d5577131d4ce70b79105231c4cc0a60de77b14f2e
    SHA512: c63c3f527bef88922345f4abb4b9ad467117b63f2132e41722ea6b4234cec3446626c3338e673065a06d2894feee92472807c284cbe613a442c8fda234ea7f88
    
  • https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.3.tar.xz

    SIZE:   11904360 bytes
    SHA1:   ee231856cee812cfc67440d643f7451857a760c9
    SHA256: 11a83f85c03d3f0fc9b8a9b6cad1b2674f26c5aaa43ba858d4b0fcc2b54171e1
    SHA512: 959a613f5cf5b3185a1d7a7ba0e1921166b3930f30461b391b1c9fcfe396f56dc3c736123dfc7b4e72c32a97dc5a1eb1fd7f09bcc3793a3c5526f6644ba421c8
    

Comentarios de la versión

Muchos contribuyentes, desarrolladores y usuarios que enviaron reportes de fallas nos ayudaron a hacer esta versión. Gracias por sus contribuciones.

Publicado por naruse el 2019-04-17
Traducción de vtamara

Hello World x4

23/04/2019
Artículo original

Hace poco estuve en un curso relativo a Kafka, la verdad la capacidad que tiene esa herramienta es muy fuerte, sobre todo cuando aplicamos programación funcional en medio. Aunque este post no es relativo a Kafka, si lo es relativo a la programación funcional y será bastante sencillo.

Haremos un ejemplo de curry f(x)(y) = f(x, y) en tres lenguajes Kotlin, Typescript y Javascript.

Kotlin

fun main() {
    val sendAll = { content: String ->
        { content2: String ->
            content + content2
        }
    }

    val a = sendAll("Hello")

    println(a(" World"))
}

Typescript

const sendAll = (content: string) =>
  (content2: string) => content + content2;

const a = sendAll("Hello”);

console.log(a(" World”));

Javascript

const sendAll = content => content2 => content + content2;

const a = sendAll("Hello”);

console.log(a(" World”));

Conclusiones

leer más

Página Anterior Página Siguiente