Quantcast
Channel: Planeta Código
Viewing all 2715 articles
Browse latest View live

Variable not found: Índices y rangos en C# 8 (1 de 2)

$
0
0
.NET Core Seguimos analizando las novedades que traerá C# 8, y esta vez vamos a detenernos en una característica que aportará algo más de agilidad a la hora de trocear o acceder a elementos de arrays y algunos tipos de colecciones similares, como Span<T>.

Como muchas otras características del lenguaje, se trata de algunos azucarillos sintácticos creados en torno a dos nuevos tipos añadidos a las bibliotecas básicas del framework: las estructuras System.Index y System.Range. Por esta razón, para utilizar estos elementos no sólo es necesario disponer de nuevos compiladores, sino también de nuevas versiones del framework.
Recordad que a día de hoy ya se puede probar C# 8 en Visual Studio 2019 o directamente desde la interfaz de línea de comandos de .NET Core.

Índices de arrays con System.Index

Hasta esta versión de C#, la forma natural de acceder a un elemento específico de un array era indicando el entero que representaba su posición en el mismo. Por ejemplo, con arr[0] podíamos acceder al primer elemento de la colección, o con arr[arr.Length-1] al último.

La nueva estructura Index proporciona una fórmula para almacenar y gestionar índices usando tipos específicamente diseñados para ello, lo que permite añadir algo más de flexibilidad al resultado. Su uso básico, que no parece demasiado útil, es el siguiente:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };

Index i0 = new Index(0);
Index i1 = new Index(1);
Index i7 = new Index(7);

Console.WriteLine(primes[i0]); // 2
Console.WriteLine(primes[i1]); // 3
Console.WriteLine(primes[i7]); // 19
Así al vistazo no parece algo que valga demasiado la pena, ¿verdad? Bueno, pues como aportación interesante, a la hora de crear un índice podemos indicar si la referencia la hacemos desde el principio o desde el final de la secuencia:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };

Index fromStart3 = new Index(3); // Por defecto, 'fromEnd' es falso
Index fromEnd1 = new Index(1, fromEnd: true);
Index fromEnd8 = new Index(8, fromEnd: true);

Console.WriteLine(primes[fromStart3]); // 7
Console.WriteLine(primes[fromEnd1]); // 19
Console.WriteLine(primes[fromEnd8]); // 2
¡Alto ahí! Fijaos en un detalle sumamente importante: cuando comenzamos por el final, el índice 1 es el primer elemento. O en otras palabras, un acceso desde el final al índice 0 daría un error, porque este elemento sería posterior al último item de la colección; sin embargo, cuando contamos desde el principio, el índice cero es el primero.
var ceroFromStart = new Index(0);
var ceroFromEnd = new Index(0, fromEnd: true);
Console.WriteLine(primes[ceroFromStart]); // 2
Console.WriteLine(primes[ceroFromEnd]); // Error: IndexOutOfRangeException
Por último, cabe añadir que la estructura Index dispone de algunos métodos estáticos para agilizar la creación de índices, como Index.FromStart() o Index.FromEnd(), o para obtener referencias al comienzo y final (recordad, ¡fuera del array!) con Index.Start e Index.End respectivamente:
Index fromEnd3A = Index.FromEnd(3);
Index fromEnd3B = new Index(3, fromEnd: true);
Console.WriteLine(fromEnd3A.Equals(fromEnd3A)); // True

var start = Index.Start;
var alsoStart = Index.FromStart(0);
Console.WriteLine(start.Equals(alsoStart)); // True

Conversiones implícitas y el operador hat ^

Anteriormente hemos visto lo fácil que es crear índices y utilizarlos para acceder a los elementos de una colección. Pero, obviamente, esto no podía quedar ahí.

En primer lugar, el tipo Index dispone de conversiones implícitas hacia y desde int, lo que quiere decir que normalmente podremos utilizar estos dos tipos indistintamente, como se muestra en el siguiente ejemplo:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };
Index fromStart3a = new Index(3);
Index fromStart3b = 3;
int fromStart3c = 3;

Console.WriteLine(primes[fromStart3a]); // 7
Console.WriteLine(primes[fromStart3b]); // 7
Console.WriteLine(primes[fromStart3c]); // 7
Console.WriteLine(fromStart3a.Equals(fromStart3c)); // True
Vale, esto simplifica la codificación de índices comenzando por el principio, igual que lo hemos hecho siempre con enteros, pero, ¿qué ocurre con la indexación desde el final?

Y aquí es donde entra en juego el nuevo uso del operador hat (sombrero) ^ de C# 8. Este operador es un mero azucarillo sintáctico para facilitar la creación de índices desde el final, como hacíamos con Index.FromEnd(), pero de forma más compacta. Veamos unos ejemplos:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };
var fromEnd2A = Index.FromEnd(2);
var fromEnd2B = ^2; // = Index.FromEnd(2)

Console.WriteLine(primes[fromEnd2A] == primes[fromEnd2B]); // True
Console.WriteLine(primes[fromEnd2B]); // 17
En el siguiente post veremos cómo la nueva estructura Range permite especificar rangos o extraer porciones de colecciones indicando los límites superiores e inferiores, y cómo se vale de Index para ello.

Publicado en: www.variablenotfound.com.

Picando Código: NotPinkCon 2019 – vuelve la conferencia de seguridad informática en Buenos Aires, Argentina

$
0
0

NotPinkCon

NotPinkCon es un evento gratuito y abierto a todo público, donde se brindan conferencias técnicas en seguridad informática, impartidas por mujeres y dirigidas a estudiantes, profesionales y entusiastas del tema. Las charlas serán de nivel técnico variado, útiles tanto para quienes recién comienzan o aún no lo han hecho pero tienen interés en aprender, como para quienes tienen más experiencia.

El evento se realiza el 30 de agosto,  en Buenos Aires, Argentina.

El team de NotPinkCon está compuesto por un grupo de mujeres especialistas en seguridad informática, reconocidas tanto por sus investigaciones, como por sus presentaciones en diversos eventos alrededor del mundo y su gran ambición en lograr la igualdad de género en el área de la tecnología. Conocé al staff

Si querés ser oradora en NotPinkCon, está abierto el llamado a charlas con fecha límite el 15 de julio. Los temas para los que están buscando oradoras son: seguridad ofensiva y defensiva en todas las áreas de infosec. Por ejemplo: Seguridad en apps web, hacking móvil, hacking IoT, Reversing, escribir exploits, seguridad wireless, hacking de hardware, malware, ataques criptográficos y así. Ofrecen a las oradoras cubrir los gastos por el viaje hasta USD 1.500 y dos noches de alojamiento, entrada VIP, cena de oradoras y acceso a fiestas.

Ya podés registrar tu entrada, el evento es abierto a todo público, pero tiene una capacidad limitada.

Pueden seguir a @NotPinkCon en Twitter para estar al tanto de todas las novedades.

Objetivo de NotPinkCon

El principal objetivo de NotPinkCon es incentivar a más mujeres a participar como speakers en los eventos de seguridad informática. Creemos que todas tienen investigaciones interesantes para contar y queremos romper las barreras que les impidan hacerlo.

Para ello proponemos un escenario más confortante, que funcione como un escalón intermedio antes de dar el salto de presentarse en un escenario mixto, el cual -por la desafortunada desigualdad de género- podría resultar algo intimidante para comenzar.

Asimismo también queremos contar en nuestro escenario con oradoras experimentadas. Sin lugar a dudas, su experiencia en el escenario no solo será de ayuda para las nuevas speakers sino también de gran inspiración para la audiencia.

Nuestro segundo objetivo es incentivar a las mujeres a unirse al fascinante mundo de la seguridad informática. Hemos notado que el hecho de que las oradoras sean mujeres incrementa el interés del género, lo cual se ve reflejado positivamente en una audiencia de gran paridad entre hombres y mujeres.

En resumen, NotPinkCon tiene los siguientes objetivos:

  • Incentivar la participación de mujeres como speakers en los eventos.
  • Incrementar el interés de las mujeres por la Seguridad Informática.

Visitá el sitio web para ver más.

Picando Código: Actualización del validador de Cédula de Identidad Uruguaya

$
0
0

Hace unos años creé mi primera gema en Ruby: Un validador de cédulas de identidad uruguaya. Poco más de un año después, escribí una versión en JavaScript. Desde entonces han surgido un montón de versiones más del validador de cédulas de identidad en distintos lenguajes. Recientemente actualicé el sitio web del proyecto: Validación Cédula Identidad Uruguaya

Validador de Cédulas de Identidad Uruguaya

La idea principal de las bibliotecas en Ruby, JavaScript y demás, es validar números de cédula ingresador por un usuario en un sitio/aplicación. La motivación de escribir la primera versión fue la cantidad de sitios uruguayos que lo hacen mal (ver entrada). Así que este sitio web utiliza el JavaScript y sirve para:

  • Ver si un número de cédula es válido
  • Obtener el dígito verificador de un número de cédula
  • Generar números de cédula al azar.

Además de una lavada de cara (o CSS y markup) al sitio, agregué las dos versiones más recientes del validador de cédulas: PHP y Go. La versión de Go la escribí el año pasado como ejercicio mientras aprendía Go para el trabajo. Qué lenguaje que no me gustó… Tanto que me había olvidado que escribí el validador de cédulas en Go, hasta que me puse a escribir esto.

Así que por el momento hay implementaciones open source para: Ruby, Python, JavaScript, jQuery, Node, PHP, y Go.
Si falta la versión en su lenguaje de programación favorito, y se animan a escribirlo y publicarlo bajo código libre ¡contáctenme que lo agrego!

Blog Bitix: Teses unitarios parametrizados con JUnit

$
0
0

Hay múltiples lenguajes y librerías donde cada una publica nuevas versiones. Una vez elegida una esa decisión no tiene que ser para siempre si las circunstancias de un proyecto cambian o una nueva versión incorpora las funcionalidades por las que se eligió otra. Si se reconsideran de nuevo el conjunto de todos los parámetros la decisión puede ser distinta. Esto me ha ocurrido al evaluar de nuevo JUnit comparándolo con Spock, teniendo en cuenta que en JUnit 5 han incorporado los teses parametrizados y el lenguaje que utiliza cada una de ellas.

JUnit
Java

En mis preferencias de herramientas que elegiría para un proyecto basado en la plataforma Java estaba Spock, por la legibilidad de los teses con su lenguaje específico de dominio o DSL con sus diferentes secciones given, when, then. Otro motivo era la posibilidad de ejercitar un mismo test pero con diferentes parámetros para ejecutar todas las condiciones del sujeto bajo prueba con la sección where y las posibilidades de mocking incorporadas. Pero Spock usa el lenguaje Groovy. Es menos verboso, es dinámico pero que no posee igual la asistencia de código de los IDEs y por su naturaleza dinámica con posibilidad de errores de compilación no detectados hasta en tiempo de ejecución. En mis preferencias está el lenguaje Java así que he revisado si estás características de Spock son ofrecidas por JUnit desde la última vez que lo use.

El primer motivo de usar Spock sobre la legibilidad del test se puede suplir añadiendo un comentario de línea con la sección. El segundo motivo es que en JUnit también se pueden crear teses parametrizados con varios casos de prueba. Para los teses parametrizados se puede usar la anotación @ParameterizedTest con una serie de valores que en el test se reciben como un parámetro.

Aqui se compara el mismo test usando Spock y luego JUnit.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
importspock.lang.SpecificationclassStringLengthCalculator{intlength(Stringstring){returnstring.length()}}classStringLengthCalculatorSpockextendsSpecification{def"calculate string length"(){given:defcalculator=newStringLengthCalculator()expect:defresult=calculator.length(a)then:expected==resultwhere:a|expected""|0"java"|4"groovy"|5"go"|2}}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.DisplayName;importorg.junit.jupiter.api.Test;importorg.junit.jupiter.params.provider.Arguments;publicclassStringLengthCalculator{publicintlength(Stringstring){returnstring.length()}}publicclassStringLengthCalculatorTest{@ParameterizedTest@DisplayName("calculate string length")@ValueSource(strings={"","java","groovy","go"})voidlengthOfStrings(Stringa)throwsException{// given
StringLengthCalculatorcalculator=newStringLengthCalculator();// expect
intresult=calculator.length(a);// then
Assertions.assertEquals(expected,result);}}

O si la parametrización es más compleja usando un método que devuelve una lista de parámetros en Junit.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
importspock.lang.SpecificationclassCalculator{intadd(inta,intb){returna+b}}classCalculatorSpockextendsSpecification{def"calculate sum"(){given:defcalculator=newCalculator()expect:defresult=calculator.add(a,b)then:expected==resultwhere:a|b|expected1|3|42|-1|10|6|6}}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
importorg.junit.jupiter.api.Assertions;importorg.junit.jupiter.api.DisplayName;importorg.junit.jupiter.api.Test;publicclassCalculator{publicintadd(inta,intb){returna+b;}}publicclassCalculatorTest{@ParameterizedTest@DisplayName("calculate sum")voidlengthOfStrings(inta,intb,intexpected)throwsException{// given
Calculatorcalculator=newCalculator();// when
intresult=calculator.add(a,b);// then
Assertions.assertEquals(expected,result);}staticStream<Arguments>lengthOfStrings(){returnStream.of(Arguments.arguments(1,3,4),Arguments.arguments(2,-1,1),Arguments.arguments(0,6,6),);}}

Con estas posibilidades de JUnit y para hacer mocking con Mockito realmente los dos motivos que tenía para usar Spock no son imprescindibles además de disponer de un lenguaje con buena asistencia de código en los IDEs. También para los teses igualmente se aplican las 10 razones que tengo para seguir usando Java.

Arragonán: KPIs para equipos de desarrollo de software

$
0
0

Como parte de mi trabajo en el último año, he intentado empujar la cultura de mejora continua en los diferentes equipos con los que he ido trabajando. Tanto en cuestiones de herramientas y habilidades técnicas, como en las de comunicación y coordinación, con ciertas restricciones y dependencias que caen fuera de nuestro margen de influencia.

Partimos del supuesto de que cuanto mejores sean las prácticas del equipo, mejor capacidad de entrega tendrá. Eso se traduce en una mayor adaptabilidad a los cambios, una mejor mantenibilidad del software con el paso del tiempo y posiblemente una mayor motivación del equipo con su trabajo.

Además de las típicas sensaciones subjetivas de efecto de mejora, teníamos que pensar en indicadores que nos permitieran ir observándolo realmente. En algún momento, también se empezaría a querer tener visibilidad desde fuera de los equipos, así que tocaba darle una vuelta y ordenar ideas.

Estuve preparando una presentación para explicar internamente cómo estábamos trabajando, hacia dónde creía que debíamos ir a través de una mejora continua, los distintos KPIs que podríamos observar y las necesidades que se cubrirían con una buena capacidad de entrega.

Diapositiva de una presentación con la visión de lo que, como equipo deberíamos cubrir: adaptabilidad respecto a negocio, entregar pronto, evitar retrabajo, una buena UX y evitar bugs en lo posible

“Dime cómo me mides y te diré cómo me comporto”

Desconozco el origen, pero con estas cosas siempre me acuerdo de este dicho. Hay que andar con ojo con qué indicadores (que no objetivos) vamos a medir. Además, tendremos que usar varios para compensar el fomento de comportamientos extraños que falsean esas métricas.

Con el uso normal de las herramientas, sólo acordando algunas convenciones, se puede facilitar la explotación de datos posterior para extraer métricas. Los orígenes de datos para los indicadores son:

  • El código
  • El repositorio y servidor de automatización
  • Las herramientas de gestión
  • El propio producto

Indicadores del código

Las herramientas de análisis estático de código nos dan números sobre deuda técnica que existe. No debemos perder de vista estos indicadores y dedicar tiempo en analizar y hacer limpieza específica de vez en cuando. Unas veces se resuelven con soluciones simples y otras esconden problemas de diseño que no resultan tan evidentes.

La cobertura de test es uno de los indicadores más habituales, lo más interesante en este caso es ver qué NO está cubierto. Y como se suele comentar, hay que andar con cuidado porque es un indicador fácil de falsear si se busca como objetivo.

En un momento dado, además, se podría utilizar mutation testing (comprobar que se rompe algún test al modificar código de producción) para tener un indicador de la calidad de los tests unitarios.

Indicadores del repositorio y servidor de automatización

Hay bastantes indicadores interesantes que se pueden sacar de los repositorios y servidores de automatización, aunque en su mayoría son dependientes de las convenciones de uso.

Sin embargo, un indicador siempre válido y que pienso que debería observarse es la frecuencia de integración.

La integración continua es una práctica (que no herramienta) tan popular como malinterpretada, ya que hasta que no se une el trabajo que ha hecho o está haciendo una persona con la rama principal de desarrollo y se completa una build, no la estamos realizando.

Hasta que no ha terminado correctamente la construcción de un artefacto de software, no sabemos si todo está correcto. A mayor frecuencia, feedback más temprano y menor incertidumbre.

En caso de usar ramas, también es interesante ver la duración de vida de las ramas. A más tiempo, mayor riesgo de conflictos u otros problemas al integrar.

Y si se utilizan pull/merge requests, también hay un puñado de indicadores que en un momento dado puedan sacarnos olores relacionados con la capacidad de entrega: cantidad de comentarios, tiempo que quedan abiertas, cantidad de rechazos…

Indicadores de las herramientas de gestión

Las herramientas de gestión, además de servir como radiador de información para saber la situación actual de la construcción del producto y ayudar a coordinar el trabajo, son una buena fuente de información de indicadores del proceso de trabajo.

Para observar la capacidad de todo el equipo en conjunto de hacer vertical slicing es muy útil conocer el tiempo de ciclo. A menor tiempo de ciclo, mayor es nuestra capacidad de entrega. Es el tiempo que se tarda desde que se empieza a trabajar en algo que aporte valor (por ejemplo, una historia de usuario) hasta que pasa a estar hecho.

Es habitual que en algún punto de las herramientas de gestión se pueden observar los distintos despliegues que se han realizado, donde podamos obtener la frecuencia de despliegue. Evidentemente a mayor frecuencia, mejor.

Aunque nuestro tiempo de ciclo fuera corto y la frecuencia de despliegue alta, sería posible que nuestro producto fuera frágil debido a bugs. Por eso el indicador de bugs detectados y resueltos por versión/despliegue es otra métrica a tener siempre en cuenta.

Dependiendo del momento y escenario en el que se encuentre un producto, también me parece muy interesante el indicador del lead time, el tiempo que pasa desde que se pide algo nuevo hasta que está desplegado en producción. Que vendría a ser consecuencia de los 3 anteriores indicadores y del tamaño de la pila de producto.

Como supongo que haya quien pueda echarlo de menos, omito intencionadamente los indicadores al respecto de las estimaciones, tipo story points por iteración. En mi opinión, tienen un componente muy subjetivo y variable para ser utilizado como indicador de cambio en la capacidad de entrega de un equipo.

Indicadores del propio producto

Además de otro tipo de instrumentación mucho más minuciosa que necesitan los miembros del equipo de gestión de producto o diseño, el equipo de desarrollo debería poder observar el número y porcentaje de uso por funcionalidad, que al final define el éxito o no del trabajo de todos.

Lo más interesante de este indicador es que combinado con otras métricas puede ayudar a tomar decisiones sobre la evolución del producto. Como por ejemplo, este escenario:

  1. Detectamos problemas muy graves de rendimiento en una parte del producto.
  2. Observamos que el porcentaje de uso de la funcionalidad afectada por esos problemas es residual.
  3. Decidimos no resolverlo de momento, pero lo reflejamos en la pila del producto como algo poco prioritario.
  4. Configuramos una alerta para detectar cierto aumento en el porcentaje de uso de esa funcionalidad.

Otro indicador importante es el crash rate del producto, cuántas veces se detecta un fallo o error por cantidad de uso, que nos permite saber lo estable que es un producto. Y mezclado con el indicador de números de uso por funcionalidad, nos permite detectar los puntos problemáticos.

Dependiendo del contexto del producto y del negocio, posiblemente podamos sacar también otros indicadores relevantes de operaciones y soporte que sean consecuencia del uso del producto.

Medir sin perder el foco

Estos son muchos KPIs distintos. Es interesante observarlos porque nos pueden servir para detectar olores sobre problemas y oportunidades de mejora, pero son demasiados para tratar de mejorar todo a la vez.

Para evitar diluirnos y no terminar mejorando en nada, deberíamos elegir y enfocarnos en un par de esos indicadores cada vez, dependiendo de la situación de cada equipo.

Y aunque sea tentador hacerlo, evitaría usar alegremente estos indicadores para marcar objetivos, así como para evaluar a equipos distintos.

No olvidemos que el propósito de medir estos indicadores es observar la evolución en el tiempo de un equipo trabajando en un producto y contexto determinado.

Variable not found: Enlaces interesantes 365

$
0
0
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET / .NET Core

ASP.NET / ASP.NET Core

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

Variable not found: Índices y rangos en C# 8 (2 de 2)

$
0
0
.NET CoreEn el post anterior vimos que la estructura Index, junto con alguna cortesía del compilador, permitía la especificación de índices en arrays de forma muy sencilla. Veíamos cómo podíamos acceder a elementos concretos utilizando su posición en la colección, tanto contando desde el principio como desde el final:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };
Index fromStart = 2; // = Index.FromStart(2) - conversión implícita
Index fromEnd = ^2; // = Index.FromEnd(2)

Console.WriteLine(primes[fromStart]); // 5
Console.WriteLine(primes[fromEnd]); // 17
Sin embargo, puede que a Index por sí mismo tampoco le veáis demasiada utilidad... y así es. De hecho, su finalidad es más bien el dar soporte a rangos, una nueva característica de C#8 que nos permitirá referirnos a "porciones" de arrays o colecciones similares usando una sintaxis compacta e integrada en el lenguaje.

La estructura Range

La estructura Range ofrece una vía para la especificación de rangos en colecciones indexadas mediante el almacenamiento de sus índices iniciales y finales. O en otras palabras, Range permite definir un rango del interior de un array o similar mediante la indicación de un Index inicial y un Index final.

Veamos un ejemplo de uso:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };

var firstTwoItemsRange = new Range(Index.FromStart(0), Index.FromStart(2));
// O Más simple, utilizando conversiones implícitas:
// var firstTwoItemsRange = new Range(0, 2);
var firstTwoItems = primes[firstTwoItemsRange];
Console.WriteLine(string.Join(",", firstTwoItems)); // 2,3
Un aspecto sumamente importante en este punto, del que seguro que algunos os habéis dado cuenta, es el índice final en un objeto Range es no inclusivo (¡ojo con esto!). Por esa razón, el resultado mostrado por consola es "2,3" y no "2,3,5", a pesar de haber indicado como índices iniciales y finales 0 y 2, respectivamente.

Si quisiéramos incluir el último elemento, deberíamos especificar un índice superior por encima del mismo, como en el siguiente código, donde utilizamos Index.From() para obtener el índice del elemento que se encuentra virtualmente más allá del último ítem del array:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };

var lastThreeItemsRange = new Range(5, Index.FromEnd(0));
var lastThreeItems = primes[lastThreeItemsRange];
Console.WriteLine(string.Join(",", lastThreeItems)); // 13,17,19
Como ya sabemos gracias al post anterior, podemos utilizar el edulcorante sintáctico que nos ofrece C# para crear rangos de forma más compacta efectiva, gracias al uso de las conversiones implícitas y el hat operator:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };

var lastThreeItemsRange = new Range(^3, ^0);
var lastThreeItems = primes[lastThreeItemsRange];
Console.WriteLine(string.Join(",", lastThreeItems)); // 13,17,19

var allPrimesRange = new Range(0, ^0);
var allPrimes = primes[allPrimesRange];
Console.WriteLine(string.Join(",", allPrimes)); // 2, 3, 5, 7, 11, 13, 17, 19
Y como ocurría con la estructura Index, Ranage también ofrece algunos miembros estáticos para simplificar la codificación de rangos frecuentes, como Range.StartAt(), Range.EndAt() o Range.All:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };

var firstTwoItemsRange = Range.EndAt(2);
var firstTwoItems = primes[firstTwoItemsRange];
Console.WriteLine(string.Join(",", firstTwoItems)); // 2,3

var lastThreeItemsRange = Range.StartAt(5);
var lastThreeItems = primes[lastThreeItemsRange];
Console.WriteLine(string.Join(",", lastThreeItems)); // 13, 17, 19

var allPrimesRange = Range.All;
var allPrimes = primes[allPrimesRange];
Console.WriteLine(string.Join(",", allPrimes)); // 2, 3, 5, 7, 11, 13, 17, 19

Añadimos más edulcorante: el operador rango ".."

Con lo que sabemos hasta este momento, ya podríamos definir rangos de una forma bastante efectiva y fácil de leer, pero, de nuevo, los diseñadores de C# no podían dejarlo ahí y han añadido un atajo para hacerlo aún más sencillo.

El operador ".." permite definir rangos de forma más compacta, usando índices separados por estos caracteres para determinar los límites de éstos. Como vemos en el siguiente código, estos índices son opcionales, lo que permite especificar muy fácilmente los límites superiores e inferiores del rango:
var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };

var thirdAndFourthItems = primes[2..4];
Console.WriteLine(string.Join(",", thirdAndFourthItems)); // 5,7

var firstTwoItems = primes[..2];
Console.WriteLine(string.Join(",", firstTwoItems)); // 2,3

var lastThreeItems = primes[^3..];
Console.WriteLine(string.Join(",", lastThreeItems)); // 13, 17, 19

var allPrimes = primes[..];
Console.WriteLine(string.Join(",", allPrimes)); // 2, 3, 5, 7, 11, 13, 17, 19

Pero... ¿qué estamos haciendo realmente a obtener un rango de una colección?

Hasta ahora hemos visto cómo se definen los rangos, y cómo podemos usarlos para "extraer" un subconjunto de elementos de un array.

Pero en realidad no nos hemos detenido a pensar qué es lo que estamos haciendo realmente cuando obtenemos un rango. Es decir, la pregunta es: ¿estamos creando un nuevo array copiando los elementos del anterior? ¿O quizás estamos obteniendo un puntero a los elementos existentes inicialmente? Pues, como suele ocurrir, la respuesta es que depende.

Cuando obtenemos un rango desde un array, internamente se copiarán los elementos a un nuevo array. Esto podemos comprobarlo fácilmente con el siguiente código, donde podemos observar que la modificación de un elemento del rango no afecta a la colección original:
var primes = new [] { 2, 3, 5, 7, 11, 13, 17, 19 };

var firstTwoItems = primes[..2];
firstTwoItems[0] = 666;
Console.WriteLine(string.Join(",", firstTwoItems)); // 666,3

var allItems = primes[..];
Console.WriteLine(string.Join(",", allItems)); // 2, 3, 5, 7, 11, 13, 17, 19
Sin embargo, si lo aplicamos sobre zonas de memoria como las referenciadas por Span<T>, el rango representará un subconjunto indexado de las mismas, pero apuntando a los contenidos originales (es decir, no se creará una copia de los datos):
string ToCommaString(Span<int> values) => string.Join(",", values.ToArray());

var primes = new[] { 2, 3, 5, 7, 11, 13, 17, 19 };
var span = primes.AsSpan();

var thirdAndFourthItems = span[2..4]; // Points to ...[5,7]...
thirdAndFourthItems[0] = 666;
Console.WriteLine(ToCommaString(thirdAndFourthItems)); // 666,7

var allItems = span[..];
Console.WriteLine(ToCommaString(allItems)); // 2, 3, 666, 7, 11, 13, 17, 19

var allOriginalItems = primes[..];
Console.WriteLine(string.Join(",", allOriginalItems)); // 2, 3, 666, 7, 11, 13, 17, 19
Toolbelt. Picture by Bert MarshallBueno, y creo que con esto ya hemos dado un buen repaso a Index y Range, así que lo dejamos aquí :)  Espero que os haya resultado interesante para comprender estos nuevos tipos y añadirlos como herramientas a nuestro cinturón de desarrollador.

Publicado en: www.variablenotfound.com.

Fixed Buffer: La potencia de la Reflexión (Parte 1)

$
0
0

¡Ya estamos de vuelta por estos lares! Hoy vengo a contaros un problema que he tenido en el trabajo y como lo he solucionado con una herramienta no muy visible pero muy potente que nos ofrece .Net, la reflexión. Antes de nada, ¿qué es eso de la reflexión y como puedo usarla en C#?

Si nos fijamos en la definición:

La reflexión proporciona objetos (de tipo Type) que describen los ensamblados, módulos y tipos. Puede usar la reflexión para crear dinámicamente una instancia de un tipo, enlazar el tipo a un objeto existente u obtener el tipo desde un objeto existente e invocar sus métodos, o acceder a sus campos y propiedades. Fuente: Reflexión (C#)

Dicho con otras palabras más sencillas, la reflexión en C# es la capacidad que tenemos para desde el código, conseguir información sobre tipos (clases, librerías, objetos, etc…) y usar esa información para crear objetos dinámicamente y/o acceder a sus miembros sin crear una instancia tipada.

Vale, ¿con lo que he dicho no he conseguido aclararlo mucho más verdad? La verdad es que personalmente creo que es un concepto avanzado del lenguaje y que eso es lo que echa para atrás a muchos programadores. De hecho, si vemos su página de MSDN, vamos que tiene varias opciones:

Seguramente después de esto te sigas preguntando en que me ha podido valer la reflexión de c#. Vale, en mi caso, yo tenia una serie de clases que heredaban todas de una clase base, pero cada una tenia sus particularidades, algo como por ejemplo esto:

public class BaseClass
{
    public string ModeloMotor { get; set; }
}

public class Coche : BaseClass
{
    public bool Descapotable { get; set; }
}

public class Moto : BaseClass
{
    public bool Motor2Tiempos { get; set; }
}

public class Camion : BaseClass
{
    public bool EsVehiculoLargo{ get; set; }
}

Todo ello son posibles clases que recibimos de un método o una api, la cual nos devuelve un «BaseClass», si nos fijamos, todas están relacionadas entre ellas, pero cada una de las clases tiene sus particularidades. Aquí, tendríamos una opción clara, aprovecharnos del poliformismo y tener una clase base que lo contenga todo:

public class BaseClass
{
    public string ModeloMotor { get; set; }
    public bool Descapotable { get; set; }
    public bool Motor2Tiempos { get; set; }
    public bool EsVehiculoLargo{ get; set; }
}

public class Coche : BaseClass
{
    //...
}

public class Moto : BaseClass
{
    //...
}

public class Camion : BaseClass
{
    //...
}

De este modo, desde cada una de las clases hijas tendremos acceso a todas las propiedades. Pero claro, tampoco tiene mucho sentido hablar de un camión con un motor de dos tiempos o una moto que sea un vehículo largo.

Otra opción posible, es hacer casting a absolutamente todas las posibles clases hijas para ver si alguna coincide:

var moto = claseBase as Moto;
if (!(moto is null))
    Console.WriteLine(moto.Motor2Tiempos);
var coche = claseBase as Coche;
if (!(coche is null))
    Console.WriteLine(coche.Descapotable);
var camion = claseBase as Camion;
if (!(camion is null))
    Console.WriteLine(camion.Tara);
//.....

¿Os imagináis lo larga que se puede hacer la lista si tengo 20 clases diferente que heredan de clase base?

Aquí es donde entra en juego la reflexión, desde un objeto de tipo «BaseClass», mediante la reflexión de C#, podemos iterar las propiedades del objeto encapsulado y obtener su valor, por ejemplo, vamos a crear un método de extensión que nos permita obtener desde la clase base si es un vehículo largo:

static class Extensiones
{
    public static bool? EsVehiculoLargo(this BaseClass clase)
    {
        //Obtenemos todas las propiedades de la clase que nos pasan
        var properties = clase.GetType().GetProperties();
        //Iteramos las propiedades
        foreach (var propertyInfo in properties)
        {
            //Si alguna se llama 
            if (propertyInfo.Name == "EsVehiculoLargo")
            {
                //Retornamos el valor
                return Convert.ToBoolean(propertyInfo.GetValue(clase));
            }
        }
        //Si ninguna coincide, retornamos null
        return null;
    }
}

Si nos fijamos en el código, estamos creando un método extensor para «BaseClass». En él, lo que vamos a hacer es obtener todas las propiedades, pero no de «BaseClass», sino de la clase hija encapsulada dentro. Dentro de las propiedades, vamos a buscar la que tenga el nombre que nos interesa, y si hay alguna, vamos a obtener el valor pasándole al objeto PropertyInfo la instancia de donde tiene que obtener el valor.

Con esto, no solo podemos leer la propiedad, también podríamos escribirla llamando al método «SetValue»:

propertyInfo.SetValue(clase, true);
propertyInfo.SetValue(clase, false);

Pero eso no es todo lo que podemos conseguir, también podemos obtener información sobre su tipo, obtener el método get o set, los atributos que tiene, si es de lectura y/o escritura …

De este modo tan elegante, podemos acceder a la información de la clase hija sin tener que conocer el tipo exacto de la clase hija. En mi caso, pude conseguir consumir la api sin tener que hacer casting individuales (en mi caso yo tenía más de 60 clases hijas).

Pero no se queda ahí, ¡la reflexión da para mucho más! Si con este ejemplo te ha picado el gusanillo sobre lo que puede ofrecer la reflexión, en las próximas entradas vamos a profundizar en diferentes casos, como crear un objeto de una clase de manera dinámica, buscar entre los atributos de un objeto, o llamar a métodos de objetos dinámicamente. De momento, dejo un enlace al código para poder probarlo y lo iremos ampliando.

**La entrada La potencia de la Reflexión (Parte 1) se publicó primero en Fixed Buffer.**


Blog Bitix: Pruebas de carga y rendimiento de un servicio web con Apache Bench

$
0
0

En algunos que un servicio devuelva los datos esperados no es suficiente, otros requisitos no funcionales o de términos de servicio son que sus tiempos de respuesta sean menores al especificado en sus requisitos, que sea capaz de soportar cierto número de peticiones concurrentes o de atender un número de peticiones por minuto. Para asegurar que el servicio es capaz de cumplir estos requisitos funcionales hay que utilizar herramientas que permitan evaluar su desempeño, una de ellas muy fácil de utilizar y que proporciona valiosa información es Apache Bench.

Apache

Para hacer pruebas de carga o medir el rendimiento de cualquier servicio que funcione mediante el protocolo HTTP hay multitud de herramientas. Una de las más sencillas de utilizar y con un informe con información interesante es Apache Bench o simplemente ab. Este comando se puede utilizar con simplemente tres parámetros el endpoint a probar, el número de peticiones en total a realizar (-n) y cuantas peticiones concurrentes al mismo tiempo (-c). Otos parámetros son los datos POST a enviar, cabeceras (-H) y cookies (-C) de las peticiones, tiempos de timeout (-s) o cerficado de cliente (-E) entre algunos otros. En vez limitar las pruebas a un número de peticiones las pruebas se pueden limitar a un tiempo determinado por ejemplo 60 segundos (-t).

Es una herramienta que se utiliza para medir el rendimiento de el servidor Apache pero utilizable para cualquier otro servicio por ejemplo una web o una API REST o GraphQL. Está disponible por supuesto para GNU/Linux pero también para macOS y para Windows.

Si quisiese medir el rendimiento en mi blog alojado en GitHub Pages podría hacerlo lanzando 1000 peticiones para que sea una muestra suficientemente amplia con 20 usuarios de forma concurrente que son los que en los momentos de más tráfico tiene mi blog. Mi conexión de internet es un ADSL que no llega a 1 MB/s de subida por lo que la conexión en cierta medida limite el test.

1
$ ab -n 1000 -c 20 https://picodotdev.github.io/blog-bitix/

El informe de resultado que ofrece ab al finalizar la prueba incluye el tiempo dedicado en la conexión, en el procesado, esperando y en total con los valores para cada uno de ellos con mínimo y máximo, de media y la mediana. El tiempo total empleado por la prueba, el protocolo SSL/TLS usado, los bytes devueltos en la petición, el número de peticiones servidas por segundo, el tiempo de media empleado de media por cada petición y de media teniendo en cuenta la concurrencia, la tasa de transferencia en la respuesta y finalmente el tiempo de respuesta según percentil que van que desde el 50 al 100, es decir, que el 50% de las peticiones se han respondido en el tiempo en milisegundos indicado. Si las hubiera también muestra las peticiones fallidas y las que han devuelto un código de respuesta distinto de 200.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking picodotdev.github.io (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: GitHub.com
Server Hostname: picodotdev.github.io
Server Port: 443
SSL/TLS Protocol: TLSv1.2,ECDHE-RSA-AES128-GCM-SHA256,2048,128
Server Temp Key: X25519 253 bits
TLS Server Name: picodotdev.github.io
Document Path: /blog-bitix/
Document Length: 28389 bytes
Concurrency Level: 20
Time taken for tests: 29.220 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 29007394 bytes
HTML transferred: 28389000 bytes
Requests per second: 34.22 [#/sec] (mean)
Time per request: 584.404 [ms] (mean)
Time per request: 29.220 [ms] (mean, across all concurrent requests)
Transfer rate: 969.45 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 149 349 149.7 303 1361
Processing: 122 225 75.5 207 586
Waiting: 53 122 68.8 108 481
Total: 329 574 174.0 512 1612
Percentage of the requests served within a certain time (ms)
50% 512
66% 534
75% 555
80% 744
90% 832
95% 915
98% 1104
99% 1171
100% 1612 (longest request)

Esta herramienta puede ser utilizada para par medir el rendimiento de cualquier servicio web. Un blog de Wordpress, una página de una organización, un endpoint de un servicio REST o GraphQL, etc… Es muy sencilla de utilizar y genera un informe corto pero con interesante información sobre el rendimiento. Si se hacen cambios se puede medir el antes y el después y comparar los resultados para observar de que modo han afectado al redimiento si de forma positiva o negativa y en que grado.

Blog Bitix: Metadatos e introspección en GraphQL

$
0
0

Una API REST no ofrece introspección y por tanto hay que recurrir a un sistema de documentación que puede estar desactualizado y hay que mantener para conocer como usar la API y cuales son sus tipos y parámetros. Por el contrario GraphQL incorpora un sistema de introspección que permite conocer sus tipos y campos, a través del editor GrapiQL o si fuese necesario de forma automtizada con código.

GraphQL

Una de las cosas que me gustan de GraphQL sobre REST es que la API de un servicio se define en un esquema. Tanto las operaciones de consulta, de modificación con sus nombres de parámetros, tipos y si son requeridos o no. Esta información es básica para hacer un buen uso de esa API y conocer cual es su contrato. Además con la herramienta GraphiQL se pueden crear y realizar consultas con un pequeño IDE con asistencia de código. GraphQL genera los metadatos e ofrece la instrospección a partir únicamente de la definición del esquema del servicio sin ningún esfuerzo adicional por parte del creador del servicio.

En el ejemplo de esta serie de artículos sobre GraphQL he usado el siguiente esquema que utiliza como modelo de datos el de una librería.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
scalar LocalDate
type Book {
id: Long
title: String
author: Author
isbn: String
date: LocalDate
comments(after: String, limit: Long): CommentsConnection
batchedIsbn: String
batchedComments(after: String, limit: Long): CommentsConnection
}
type Magazine {
id: Long
name: String
pages: Long
}
type Comment {
id: Long
text: String
}
type Author {
id: Long
name: String
}
input BookFilter {
title: String
}
type CommentsConnection {
edges: [CommentEdge]
pageInfo: PageInfo
}
type CommentEdge {
node: Comment
cursor: String
}
type PageInfo {
startCursor: String
endCursor: String
hasNextPage: Boolean
}
union Publication = Book | Magazine
type Query {
books(filter: BookFilter): [Book]!
publications: [Publication]!
book(id: Long): Book!
authors: [Author]!
author(id: Long): Author!
}
type Mutation {
addBook(title: String, author: Long): Book
}
schema {
query: Query
mutation: Mutation
}

Si no se conoce el esquema qué operaciones, tipos y nombres ofrece la API GraphQL permite introspección y con únicamente el endpoint se puede averiguar esta información.

Por ejemplo, con la siguiente consulta se puede conocer qué tipos contiene el esquema de una API. Los que comienzan con dos barras bajas o __ son tipos parte del sistema de introspección. Entre los que están el que representa un libro y autor pero también está Query que es un punto de acceso a la API.

1
2
3
4
5
6
7
{
__schema {
types {
name
}
}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
{"data":{"__schema":{"types":[{"name":"Author"},{"name":"Book"},{"name":"BookFilter"},{"name":"Boolean"},{"name":"Comment"},{"name":"CommentEdge"},{"name":"CommentsConnection"},{"name":"LocalDate"},{"name":"Long"},{"name":"Magazine"},{"name":"Mutation"},{"name":"PageInfo"},{"name":"Publication"},{"name":"Query"},{"name":"String"},{"name":"__Directive"},{"name":"__DirectiveLocation"},{"name":"__EnumValue"},{"name":"__Field"},{"name":"__InputValue"},{"name":"__Schema"},{"name":"__Type"},{"name":"__TypeKind"}]}}}

Conocer el tipo de las consultas de lectura y que consultas se pueden realizar inspeccionando el tipo Query.

1
2
3
4
5
6
7
{
__schema {
queryType {
name
}
}
}
1
2
3
4
5
6
7
8
{
__type(name: "Query") {
name
fields {
name
}
}
}
1
2
3
4
5
6
7
8
9
{"data":{"__schema":{"queryType":{"name":"Query"}}}}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{"data":{"__type":{"name":"Query","fields":[{"name":"author"},{"name":"authors"},{"name":"book"},{"name":"books"},{"name":"publications"}]}}}

Por la propiedad de GraphQL de que se pueden realizar varias consultas en una única petición se pueden obtener ambos resultados a la vez.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
__schema {
queryType {
name
}
}
__type(name: "Query") {
name
fields {
name
}
}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{"data":{"__schema":{"queryType":{"name":"Query"}},"__type":{"name":"Query","fields":[{"name":"author"},{"name":"authors"},{"name":"book"},{"name":"books"},{"name":"publications"}]}}}

Se puede obtener más en detalle los campos que contiene un tipo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
book: __type(name: "Book") {
name
fields {
name
type {
name
kind
}
}
}
author: __type(name: "Author") {
name
fields {
name
type {
name
kind
}
}
}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
{"data":{"book":{"name":"Book","fields":[{"name":"author","type":{"name":"Author","kind":"OBJECT"}},{"name":"batchedComments","type":{"name":"CommentsConnection","kind":"OBJECT"}},{"name":"batchedIsbn","type":{"name":"String","kind":"SCALAR"}},{"name":"comments","type":{"name":"CommentsConnection","kind":"OBJECT"}},{"name":"date","type":{"name":"LocalDate","kind":"SCALAR"}},{"name":"id","type":{"name":"Long","kind":"SCALAR"}},{"name":"isbn","type":{"name":"String","kind":"SCALAR"}},{"name":"title","type":{"name":"String","kind":"SCALAR"}}]},"author":{"name":"Author","fields":[{"name":"id","type":{"name":"Long","kind":"SCALAR"}},{"name":"name","type":{"name":"String","kind":"SCALAR"}}]}}}

Incluso se puede inspeccionar los tipos del sistema de instrospección. Con las descripciones de los campos o parámetros de entrada si los tuviese.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
__type(name: "__Type") {
name
fields {
name
type {
name
kind
}
}
}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
{"data":{"__type":{"name":"__Type","fields":[{"name":"description","type":{"name":"String","kind":"SCALAR"}},{"name":"enumValues","type":{"name":null,"kind":"LIST"}},{"name":"fields","type":{"name":null,"kind":"LIST"}},{"name":"inputFields","type":{"name":null,"kind":"LIST"}},{"name":"interfaces","type":{"name":null,"kind":"LIST"}},{"name":"kind","type":{"name":null,"kind":"NON_NULL"}},{"name":"name","type":{"name":"String","kind":"SCALAR"}},{"name":"ofType","type":{"name":"__Type","kind":"OBJECT"}},{"name":"possibleTypes","type":{"name":null,"kind":"LIST"}}]}}}

Conocer cuales son los campos de un tipo puede utilizarse para validar una API, comprobando que no se han eliminado campos necesarios. Es útil en el caso de querer automatizar esta validación de una API de GraphQL que se consuma ayudando a detectar de forma temprana problemas de compatibilidad al publicarse una nueva versión que no está bajo propiedad del que la usa.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.

Israel Perales: Nexus Repository

$
0
0
Nexus Repository

Don't repeat yourself

Un principio del desarrollo del software muy simple, "no repitas código".

Gracias a este principio creo que muchos desarrolladores dieron forma a las librerias, prefiriendo encapsular un comportamiento deseado en un solo lugar.

Esto hace necesario administrar las librerias de una forma eficiente y fácil de utilizar en el equipo de trabajo.

Aunque podemos expresarlo en una frase tiene una complejidad muy grande al llevarlo a la practica.

Debemos ser capaces de soportar los diferentes formatos de los componentes con los que trabajamos, en mi caso utilizo Maven, NPM/Yarn, Bower y Docker.

Al buscar una solución para estos componentes llegué a la questión de ¿que será mas facil de manejar?, ¿una plataforma por cada formato o uno que englobe a todos?.

Fue así que llegue a Nexus Repository OSS.

The free artifact repository with universal support for popular formats.

Todo en uno, gratis y con soporte para mis componentes de trabajo y algunos extras , aquí una lista de los formatos soportados:

  • Bower
  • Docker
  • Git LFS
  • Maven
  • npm
  • NuGet
  • PyPI
  • Ruby Gems
  • Yum
  • Apt
  • Conan
  • R
  • CPAN
  • Raw (Universal)
  • P2
  • Helm
  • ELPA

Instalación

Como ya es costumbre usaremos Docker para su instalación, podemos encontrar la imagen oficial de Nexus en Docker Hub.

Vamos a correr los siguientes comandos:

mkdir nexus && cd nexus

mkdir nexus-data

sudo chown -R 200 nexus-data

docker run -d -p 8081:8081 --name nexus -v nexus-data:/nexus-data sonatype/nexus3

Y ahora solo debemos entrar a la liga http://localhost:8081

Nexus Repository

Para iniciar sesión usaremos las credenciales por defecto que son admin y admin123.

Para utilizar Nexus cada formato requiere su propia configuración de los repositorios privados, en este caso, configuraremos Maven como ejemplo.

Configuración Maven

Crearemos un archivo llamado settings.xml en el directorio .m2 que se encuentra en nuestro home como se muestra en el siguiente ejemplo.

<settings>
  <mirrors>
    <mirror>
      <id>nexus</id>
      <mirrorOf>*</mirrorOf>
      <url>http://localhost:8081/repository/maven-public/</url>
    </mirror>
  </mirrors>
  <profiles>
    <profile>
      <id>nexus</id>
      <repositories>
        <repository>
          <id>central</id>
          <url>http://central</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>true</enabled></snapshots>
        </repository>
      </repositories>
     <pluginRepositories>
        <pluginRepository>
          <id>central</id>
          <url>http://central</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>true</enabled></snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>
  <activeProfiles>
    <activeProfile>nexus</activeProfile>
  </activeProfiles>
  <servers>
    <server>
      <id>nexus</id>
      <username>admin</username>
      <password>admin123</password>
    </server>
  </servers>
</settings>

Probaremos que funciona con un proyecto real:


git clone https://github.com/ripper2hl/dockerejemplos.git

cd dockerejemplos/java

mvn clean install

Si todo esta bien deberíamos algo así en la terminal:

[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------< javadocker:javadocker >------------------------
[INFO] Building javadocker 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
Downloading from nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-compiler-plugin/3.1/maven-compiler-plugin-3.1.pom
Downloaded from nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-compiler-plugin/3.1/maven-compiler-plugin-3.1.pom (0 B at 0 B/s)
Downloading from nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-compiler-plugin/3.1/maven-compiler-plugin-3.1.jar
Downloaded from nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-compiler-plugin/3.1/maven-compiler-plugin-3.1.jar (0 B at 0 B/s)
Downloading from nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-assembly-plugin/2.2-beta-5/maven-assembly-plugin-2.2-beta-5.pom
Downloaded from nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-assembly-plugin/2.2-beta-5/maven-assembly-plugin-2.2-beta-5.pom (0 B at 0 B/s)
Downloading from nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-plugins/16/maven-plugins-16.pom
Downloaded from nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-plugins/16/maven-plugins-16.pom (0 B at 0 B/s)
Downloading from nexus: http://localhost:8081/repository/maven-public/org/apache/maven/plugins/maven-assembly-plugin/2.2-beta-5/maven-assembly-plugin-2.2-beta-5.jar
.
.
.

En Nexus vemos que se crea un cache de los paquetes que descargamos y así también ayudamos a ahorrar ancho de banda.

Nexus Repository

Este ejemplo es especificamente del formato de maven, para configurar otros formatos, podemos seguir la guiá del blog oficial.

https://blog.sonatype.com/using-nexus-3-as-your-repository-part-1-maven-artifacts

Mantener el orden y tener nuestros componentes a la mano, nos dará el impulso de llevar el flujo de trabajo a otro nivel.

Tal vez existan mejores alternativas a Nexus pero me ha funcionado y aun no busco un reemplazo a esta herramienta.

Koalite: Sobre checked exceptions y manejo de excepciones

$
0
0

Hace unos días me «retaba» Iván en Twitter ha escribir un post sobre las checked exceptions de Java, y lo cierto es que me parece un tema entretenido para escribir algo más que un par de tweets, así que aquí va mi opinión.

Checked exceptions en Java

Desde la perspectiva de un sistema de tipos estático esto de las checked exceptions parece una buena idea: hace más expresiva la declaración del método y permite hacer más validaciones en tiempo de compilación.

Todo acorde con lo que uno esperaría de un sistema de tipos así. Si quieres flexibilidad vete a JavaScript y disfruta de su anarquía libertad, ¿no?

Sin embargo, para mi, que no soy ningún experto en Java, resultan incómodas. Quizá sea la sintaxis de Java, quizá sea el abuso de excepciones para situaciones que no son nada excepcionales, como que falle una conversión de string a int.

Si a eso le unes que existe un tipo mágico de excepciones que no se chequean (las que derivan de RuntimeException), pues te queda una mezcla un poco rara: por una parte me obligas a declarar y capturar excepciones con una sintaxis poco amigable, y por otra dejas una la puerta abierta a lanzar excepciones no chequeadas que hacen que nunca pueda estar seguro de si un método va a lanzar o no una excepción, por lo que esa presunta seguridad de tipos de queda en eso: presunta.

Excepciones como gestión de errores

En mi opinión, si una función puede no completar la operación que se supone que debe hacer es mejor codificarlo en el propio tipo devuelto por la función. Siguiendo con el ejemplo de convertir un string en un int, dado que es algo que puede fallar, me parece más razonable tener una función cuyo resultado indique si la conversión se pudo realizar o no y, en caso de que se realizase, el entero obtenido, en lugar de lanzar una excepción si el string no tiene un formato válido.

Si asumimos que la función puede fallar, podemos codificar el fallo en el tipo de retorno y convertir lo que sería una función parcial en una función total. En muchos lenguajes (como muchos funcionales) esto se representaría con un tipo Either o Maybe (si te da igual el motivo del fallo) y sería lo más normal del mundo.

Cuando unes ese diseño con un lenguaje que permite utilizar pattern matching para el análisis de resultados, o incluso algo como el do notation de Haskell, que suena muy exótico en pero en C# puedes simular con el select/from y seguro que en Java tienes alguna alternativa para hacer algo similar, la cosa se vuelve bastante cómoda y gestionar los errores de forma normal en lugar de como algo excepcional se convierte en rutinario.

Subiendo el nivel semántico de la excepción

Volviendo al hilo de Iván, él plantea:

Los argumentos que he escuchado en su contra son principalmente dos, el primero es que exponen detalles de implementación en la interfaz (la firma del método).

El segundo motivo en su contra es que si se modifica ese método y cambia su implementación de forma que pueda lanzar nuevas excepciones, es necesario actualizar todos sus usos añadiendo los correspondientes try.

Ciertamente son argumentos habituales en contra de las checked exceptions, y la respuesta de Iván a esos argumentos es más que razonable:

Tras darle vueltas y pensar en ello, para mi ninguno de los dos argumentos son válidos. Imagina una interfaz llamada Mailer que pueda tener diferentes implementaciones según como se quiera enviar un mensaje. Típico servicio registrado en un contenedor.

El método sería Future SendEmail(EmailAddress address, EmailContent content) throws EmailException

Bajo mi punto de vista, la interfaz debe de exponer esta excepción, y si ocurre algún tipo de excepción en alguna de sus implementaciones, relanzarla como EmailException.

De esta forma, me aseguro que la excepción siempre será EmailException y no otra. Imagina que estoy escribiendo una implementación que hace una llamada HTTP. Si HttpClient tiene HttpBadCodeResponseException como checked, me obligo a capturarla y relanzarla como EmailException de forma que no se me olvide hacer ningún catch y SendEmail lance un IOException o HttpBadResponseException, que SÍ que expondrían detalles de implementación.

A la hora de utilizar el servicio, sólo tendría que capturar EmailException en vez de Exception por si en alguna implementación se me ha olvidado capturar la excepción que produce y me encuentro con un FileNotFoundException o algo similar.

Básicamente la idea es aumentar el nivel semántico del error. Si tienes un método/función que envía un email, el resultado puede ser que lo ha enviado con éxito o que ha fallado, y si es así, el motivo real (fallo en la respuesta HTTP, fallo en el formato de la dirección del destinatario, etc.) puede considerarse algo secundario que quedará encapsulado en un EmailException.

Visto así tiene mucho sentido y es mucho más informativo encontrarte con un EmailException que con un HttpBadResponseException, pero lo cierto es que a efectos prácticos soluciona el problema a medias.

Es cierto que evita el carácter «vírico» de las checked excepctions, y si una nueva implementación del servicio puede encontrarse con otro tipo de problema los consumidores del servicio Mailer no tienen que preocuparse por ella puesto que quedará encapsulada en una EmailException. Esto funciona muy bien si desde el principio ya hemos decicido que el método SendEmail puede lanzar una excepción.

Pero, ¿qué ocurre cuando al diseñar nuestro interfaz decidimos no incluir ninguna excepción porque en las implementaciones iniciales no vemos ningún caso problemático? Básicamente, hemos vuelto al punto de partida. Cuando encontramos la primera implementación que puede lanzar excepciones, debemos encapsularlas en una excepción (con mayor valor semático, eso sí), y eso nos obliga a cambiar todas las implementaciones el interfaces Mailer y todos los consumidores del interfaces.

Una opción sería hacer que, especulativamente, todos y cada uno de los métodos de nuestros interfaces lanzasen una excepción con valor semántico asociado al interfaz; pero, sinceramente, empezar a añadir posible excepciones por si acaso en el futuro alguna implementación del interfaz la lanza no me parece muy práctico.

Y, ojo, esto no es algo que se solucione con la alternativa más «funcional» que comentaba antes de utilizar un tipo Either o similar para representar el resultado de la operación. Estás en las mismas, o bien introduces desde el principio el tipo Either como valor de retorno de todas tus funciones «por si acaso» en un futuro alguna puede fallar, o en el momento en que lo introduzcas te va a tocar modificar el código que ya existe.

Conclusión

Admito que aquí hay la cosa va por barrios.

En cierto modo, me recuerda a la típica discusión de lenguajes dinámicos y estáticos. Yo me siento más cómodo con lenguajes estáticos y nunca me ha supueto un freno tener que lidiar con tipos, más bien al contrario, pero es cierto que la excepciones chequeadas, que podrían verse como un paso más hacia la comprobación estática de errores, me han supuesto fricción adicional a la hora de desarrollar.

En realidad, ni siquiera estoy convencido de que las excepciones sean una buena idea como mecanismo de gestión de errores frente al uso de valores de retorno al estilo go, pero sin entrar a debatir eso, sí tengo claro que deberían representar cosas excepciones y que, en general, se tienden a usar en situaciones que tienen poco de excepcional.

Habitualmente intento no gestionar excepciones en el lugar en que se producen a menos que esté tratando con una librería que las lance por casi cualquier motivo y pueda hacer algo para recuperarme del error o al menos convertirlas a algo con mayor valor semántico (cosa que, sinceramente, ocurre menos veces de las que me gustaría).

Desde mi punto de vista, una excepción debería representar algo excepcional y, por tanto, algo que de lo que la aplicación no tiene muchas formas de recuperarse. Por ello, tiendo a gestionar las excepciones en la «frontera» de las aplicaciones (controladores de un API Web, manejadores globales de excepciones), y muchas veces me limito a dejar que muera el proceso (ya sea la petición concreta a un API o incluso la aplicación entera) y logear la información para evitar en problemas futuros.

No hay posts relacionados.

Variable not found: Enlaces interesantes 366

$
0
0
Enlaces interesantes Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET / .NET Core

ASP.NET / ASP.NET Core

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

Picando Código: [Libro] THEM: Adventures with extremists por Ron Jonson

$
0
0
Libro: Jon Ronson, Them

Jon Ronsom: Them – Adventures with extremists

Me encontré con este título de casualidad hace por lo menos un año. Estaba mirando libros en una tienda, en esos momentos en los que no buscamos nada en particular, pero paseamos por las estanterías levantando y ojeando libros al azar.

Me llamó la atención la tapa (que en ese momento era la de esta edición), y después de leer la descripción, me quedó guardado en la memoria:

THEM comenzó como un libro sobre distintos tipos de extremistas, pero cuando Jon pudo conocer a varios de ellos -Fundamentalistas islámicos, neo-Nazis, miembros del Ku Klux Klan- encontró que todos tenían una creencia similar: que una pequeña, misteriosa elite gobierna el mundo desde un cuarto secreto.

En THEM, Jon se pone en camino, con la ayuda de los extremistas, a ubicar ese cuarto. El viaje es tan horripilante como cómico, y por el camino Jon es perseguido por hombres con lentes oscuros, desenmascarado como judío en medio de un campo de entrenamiento Yihad, y presencia a CEOs internacionales y políticos participando en un ritual pagano estrafalario en los bosques del norte de California.

THEM es una exploración fascinante y entretenida del extremismo, en el cual Jon aprende algunas cosas alarmantes sobre el mundo al otro lado del espejo de «ellos» (them) y «nosotros». ¿Están en algo los extremistas? ¿O se ha convertido Jon en uno de ellos?

La semana pasada lo adquirí y empecé a leerlo (a pesar de tener ya una pila de libros sin leer o medio empezados). Me resultó tremendamente entretenido, al punto que lo leí en 2 días. Hacía años que no leía un libro en tan poco tiempo. Creo que ayudó haber empezado el viernes de tarde. Para el sábado de noche ya lo había terminado. Me atrapaba la intriga de un capítulo a otro, «a ver en qué se mete ahora», y me llamaba a volver al libro cada vez que tenía tiempo ocioso.

THEM no analiza las razones que llevan a la gente a ser extremistas o el por qué del odio hacia otros. Pero con esa idea en común del grupo que domina el mundo desde un cuarto secreto, relata las aventuras del autor pasando tiempo con distintos extremistas. Es bastante divertido, a la vez que enseña de personajes y eventos relacionados a grupos extremistas en la historia. También baja un poco a tierra la imagen de estos hombres en el sentido de que más allá de todo, siguen siendo seres humanos de carne y hueso (teóricamente).

Cuando algún hecho despertaba mi curiosidad y me sentía en la necesidad de aprender un poco más, siempre usé Tor para buscar más información. No quiero que el gobierno que espía mi tráfico en internet me agregue a alguna lista rara por estar buscando información sobre extremistas pensando que estoy en el equipo de alguno de ellos. Hasta ahí llega mi paranoia, que es un tema común en el libro, relatando teorías conspiratorias de un Nuevo Orden Mundial involucrando tanto a multimillonarios y políticos como a razas extraterrestres reptilianas. ¿Demasiado alocado o una conspiración de los miembros del grupo mismo para ridiculizar toda la teoría? Son el tipo de cosas se plantean en THEM.

El libro está disponible en Amazon.es y Amazon.com. Fue el primer libro que leí del autor, ni siquiera vi la película basada en su obra The Men Who Stare at Goats. Después de esto, la agrego a mi lista de películas para ver y también agrego para leer a futuro The Psychopath Test: A Journey Through the Madness Industry, lo que podría alimentar mi teoría de que la mayoría de los CEOs, políticos y empresarios son psicópatas.

Variable not found: Etiquetado de consultas en Entity Framework Core

$
0
0
Entity Framework CoreComo sabemos, las consultas que definimos mediante LINQ contra conjuntos de datos de Entity Framework son traducidas automáticamente a queries SQL, que es lo que finalmente ejecuta el servidor de base de datos.

Muchas veces estas sentencias SQL generadas de forma automática y ejecutadas al servidor son fáciles de leer y entender, pero hay veces que EF traduce el LINQ a consultas SQL enormes, complejas, con escasa legibilidad y difícilmente reconocibles.

Seguro que alguna vez habéis tenido por delante una de estas complejas sentencias SQL generada por Entity Framework y os hubiera gustado saber en qué punto del código fue lanzada. Esto es muy frecuente, por ejemplo, cuando estamos monitorizando las consultas en ejecución con SQL Profiler, o al examinar las queries que consumen mayor número de recursos desde los paneles de Azure SQL.

En versiones "clásicas" de Entity Framework había que ingeniárselas para conseguirlo, pero, como podréis comprobar a continuación, en EF Core la cosa se ha simplificado bastante :)

Etiquetando consultas

Cuando creamos consultas usando SQL a pelo, es bastante sencillo incluirles una marca que, a posteriori, nos ayude a identificar su origen o finalidad. Basta con insertar un comentario como en el siguiente ejemplo:
var sql = @"
-- Get top 10 older friends with country

SELECT TOP 10 [friend].[Name] AS [FriendName], [friend].[Age],
[friend.Country].[Name] AS [CountryName]
FROM [Friends] AS [friend]
LEFT JOIN [Countries] AS [friend.Country] ON [friend].[CountryId] = [friend.Country].[Id]
ORDER BY [friend].[Age] DESC";

context.Database.ExecuteSqlCommand(sql);
De esta forma, cuando veamos aparecer dicha consulta en los logs del servidor, podremos identificar rápidamente de qué se trata.

Pues bien, la solución planteada por Entity Framework Core 2.2 es igualmente sencilla, o incluso más ;) Basta con introducir una llamada a TagWith() en la especificación de la consulta LINQ, suministrándole la etiqueta que deseamos añadir a la misma, como se muestra a continuación:
var query = context.Friends
.OrderByDescending(friend => friend.Age)
.Take(10)
.Select(friend =>
new { FriendName = friend.Name, friend.Age, CountryName = friend.Country.Name })
.TagWith("Get top 10 older friends with country");
Y la consulta que enviaremos a la base de datos será la siguiente:
-- Get top 10 older friends with country

SELECT TOP(@__p_0) [friend].[Name] AS [FriendName], [friend].[Age],
[friend.Country].[Name] AS [CountryName]
FROM [Friends] AS [friend]
LEFT JOIN [Countries] AS [friend.Country] ON [friend].[CountryId] = [friend.Country].[Id]
ORDER BY [friend].[Age] DESC
Mola, ¿eh?

Publicado en Variable not found.

Picando Código: PyCon Latam 2019 – La conferencia de Python en América Latina

$
0
0

PyCon Latam es una versión de la conferencia PyCon que tiene como objetivo reunir a los desarrolladores de Python de todos los países latinoamericanos, y servir como una plataforma para que interactúen con la comunidad de Python en general. Esta conferencia de 3 días comienza el 29 de Agosto y termina el 31 en Puerto Vallarta, México.

PyCon Latam 2019

Agenda

Está enfocada en que los conferencistas principales representen las diferentes áreas de la industria, así como diferentes partes de la sociedad. Desde nacionalidad y género hasta experiencia en la industria, esperan que al compartir su experiencia partícular concienticen, generen empatía y provean una base que resulte familiar al contexto.

Por ahora hay 3 oradores anunciados:

Lorena Mesa– Politóloga convertida en programadora, Lorena Mesa es ingeniera de datos en el equipo de sistemas de inteligencia de software de GitHub, Directora en la Python Software Foundation, y co-organizadora de PyLadies Chicago.

Manuel Kaufmann– En estos años, Manuel contribuyó a la traducción de la Guía Oficial del Libro de Django y los tutoriales de Django Girls, al proyecto de One Laptop Per Child, entre otros. Actualmente, Manuel trabaja en Read the Docs como desarrollador de software.

Tania Allard– developer advocate en Microsoft con un enfoque en la ciencia de datos y todo lo relacionado con la informática científica de código abierto. También es miembro de la RSE del Reino Unido y de la asociación Python del Reino Unido y fundadora y organizadora de PyLadies NorthWest UK.

Becas

Como parte de su compromiso con la comunidad de Python, la organización ofrece becas especiales para las personas que necesitan ayuda financiera para asistir a PyCon Latam. Pueden ver más información en este enlace, y empresas que quieran patrocinar las becas también contactarse para apoyar la iniciativa.

Lugar y entradas

La conferencia se va a realizar en el centro de convenciones del Hotel Friendly Vallarta. Están a la venta las entradas con un precio promedio todo incluido de menos de $300 USD por persona para toda la estadía: Sala, boleto de conferencia, comida, café, bebidas y botín de PyLatam, y se pueden elegir habitaciones singles, dobles, triples y cuádruples.

Con un enfoque todo incluido, no tendrá que preocuparse por pagar más por la comida o las bebidas. Sin embargo, se suspenderá el consumo de alcohol durante la conferencia (por obvias razones), pero la fiesta se reanuda al final de cada día! 🍹

Se ubica tan solo a:

  • 10 minutos del Aeropuerto Internacional.
  • 15 minutos del Centro Internacional de Convenciones.
  • 5 minutos del Centro de Puerto Vallarta y el malecón.

Por más información pueden visitar el sitio web de PyCon Latam o seguirlos en Twitter: @PyLatam.

Picando Código: Tourmaline – Framework para bots de Telegram en Crystal

$
0
0

Tourmaline es un framework desarrollado en el lenguaje de programación Crystal. Con la reciente versión 0.70, alcanzó soporte completo para la API de Bots de Telegram:

Framwork para la API (y ojalá pronto Cliente) de Bots de Telegram en Crystal. Basado fuertemente en Telegraf, esta implementación en Crystal permite que tu bot de Telegram sea escrito en un lenguaje tanto hermoso como rápido. Benchmarks vendrán pronto.

¡Ya podemos escribir nuestro bot de Telegram en Crystal!

Tourmaline – Framework para bots de Telegram en Crystal

Para empezar a usar Tourmaline, tenemos que agregarlo a los shards de nuestra aplicación en el archivo shard.yml.


dependencies:
tourmaline:
github: watzon/tourmaline
version: ~> 0.7.0

Para experimentar, creé un proyecto Crystal nuevo con crystal init app milton_bot, agregué Tourmaline en shard.yml y ejecuté shards install. Después creé un bot en Telegram para poder probarlo. De Actualizar un canal de Telegram automáticamente con WordPress:

Para crear un bot, existe un bot… En Telegram mismo debemos conversar con BotFather, quien nos provee instrucciones para crear un nuevo bot. Los comandos a ejecutar son: /start, /newbot, nombre para el bot, nombre de usuario para el bot (debe terminar en «bot») y listo. BotFather nos va a avisar que el bot ha sido creado y nos va a dar un token para acceder a la Bot API.

Para este experimento le di vida a milton_bot. Ya creado, obvuve el API token pidiéndoselo a BotFather desde /mybots (o con /token). Para poder enviarme un mensaje por Telegram, tuve que averiguar mi id de usuario hablándole a MyIdBot.

Con unas pocas líneas de códigoya podemos mandarnos mensajes:

require "tourmaline/bot"
class MiltonBot
  VERSION = "0.1.0"
  def initialize(api_token)
    @bot = Tourmaline::Bot::Client.new(api_token)
  end
  def hola
    @bot.send_message("MI_ID_DE_USUARIO", "Hola Fernando, soy milton")
  end
end
milton = MiltonBot.new("API_TOKEN")
milton.hola

MiltonBot

😱🤖

También podemos hacer que envíe mensajes a un canal o grupo. Para poder mandar mensajes directos a otros usuarios, necesitamos su ID y que el usuario haya ejecutado /start en una conversación con nuestro bot.

Como ya tengo un canal de pruebas, agregué a milton_bot como administrador y con un par de líneas de código más puedo mandar mensajes al canal:

@bot.send_message("@picandocodigo_test", "Hello World, I'm milton")
@bot.send_message("@picandocodigo_test", "https://i.giphy.com/media/d3Kq5w84bzlBLVDO/giphy.gif")

Y el resultado:

Se pueden hacer varias cosas más con Tourmaline, pueden ver el código fuente y aprender más en watzon/tourmaline en GitHub. Tengo una idea específica con MiltonBot, espero en algún momento tener tiempo para darle más vida y publicar mi primer proyecto en Crystal.

Blog Bitix: Formatear un dispositivo de almacenamiento compatible con Windows, macOS y Smart TV en GNU/Linux

$
0
0

Los dispositivos de almacenamiento se han de formatear con un sistema de archivos. Algunos de los sistemas de archivos están mejor soportados y son compatibles con una mayor número de sistemas y dispositivos, por tanto al formatear un dispositivo de almacenamiento ha de elegirse como sistema de archivos uno compatible, dependiendo del uso es más adecuado uno u otro. Para los dispositivos extraíbles la opción recomendable es exFAT o en su defecto NTFS o FAT.

GNU
GNOME

Cada sistema operativo posee uno o varios formatos de sistemas de archivos que soporta de forma nativa. Así por ejemplo Windows como sistema de archivos para el sistema se utiliza NTFS y FAT, FAT32 o exFAT para los medios extraíbles. En GNU/Linux para el sistema se suele utilizar ext4. Y en macOS se utiliza HFS+ o APFS. Cada unos posee unas propiedades y los más antiguos para evitar sus limitaciones han sido sustituidos por unos sistemas de archivos más modernos.

Los sistemas de archivos más compatibles son los que tradicionalmente se han utilizado por Microsoft dada su amplia cuota de mercado en los sistemas de escritorio, estos son FAT y FAT32. Sin embargo, estos poseen unas limitaciones que no los hacen adecuados si el tamaño de los archivos superan los 4 GiB o la capacidad del sistemas de almacenamiento supera los 2 TiB, que son precisamente los límites máximos de FAT32. Para superar estas limitaciones Microsoft ha desarrollado exFAT como nuevo sistema de archivos para los medios extraíbles con unos límites de 16 EiB (16 x 1024, 16384 TiB) para los tamaños de archivo y 64 ZiB (64 x 1024, 65536 EiB) para el sistema de alamcenamiento son unos límites varios órdenes de magnitud más grandes (y considerarse infinitos) que las capacidades de la tecnología actual (aunque al ritmo del avance de la tecnología puede que se llegue a ellos dentro de unas décadas).

En GNU/Linux puede utilizarse FAT32, NTFS y exFAT tanto en modo lectura como escritura, pero Windows solo permite sus propios formatos nativos y ha de utilizarse alguno de los anteriores, macOS soporta FAT en modo lectura y escritura, NTFS en modo lectura y para exFAT soporta también lectura y escritura. Otros dispositivos como Smart TV suelen soportar alguno de los sistemas de archivos de Microsoft ya sea FAT32, NTFS y exFAT. Salvo que se quiera la máxima compatibilidad con FAT32 para con versiones antiguas de Windows o dispositivos con algunos años la opción más recomendable a usar es exFAT.

En GNU/Linux para formatear y utilizar particiones en NTFS hay que instalar el paquete ntfs-3g y para exFAT el paquete exfat-utils, estos son los paquetes para Arch Linux otras distribuciones tienen un paquete equivalente.

Para formatear una unidad ya sea una memoria USB o disco duro externo con formato exFAT en GNU/Linux con el entorno de escritorio GNOME se realiza con el programa Discos, aunque también es posible realizarlo desde la linea de comandos.

En la parte izquierda se encuentra los dispositivos conectados y reconocidos por el sistema. En mi caso el disco del sistema, un Samsung 970 EVO de 500 GB, un disco duro externo USB de 500 GB y una memoria USB de 16 GB sin ningún formato.

Unidades del sistema

Primero es importante identificar correctamente la unidad que se quiere formatear para no perder los datos al elegir por error otra. Se introduce el nombre del volumen que identifica al dispositivo y se elige el sistema de archivos, como opciones más comunes se ofrece ext4, NTFS y FAT pero pulsando en Otro aparecen más, entre ellos exFAT. Pulsando el botón Siguiente al cabo de unos segundos la partición queda formateada con exFAT y lista para usarse tanto en GNU/Linux como en Windows, macOS o un Smart TV.

Formatear dispositivo de almacenamiento

No está de más recordar que en el caso de desechar un dispositivo de almacenamiento es recomendable hacerle un formateo completo para que los datos que contenga no sean accedidos por la persona a la que se le entregue el dispositivo ya que incluso se pueden recuperar datos previamente eliminados incluso en una unidad corrupta. Por otro lado en GNU/Linux si se desea mayor seguridad se puede cifrar la partición con la opción LUKS.

Blog Bitix: Comprobar la seguridad de un sitio web que use SSL/TLS

$
0
0

Aunque un sitio web no trate datos sensibles como tarjetas de crédito o datos personales es muy recomendable que use el protocolo seguro HTTPS para proporcionar cifrado entre el servidor y el navegador del usuario para dotar de confidencialidad a las comunicaciones a la vez que evitar modificaciones por terceras personas de los datos transmitidos. Además, el buscador Google lo tiene en cuenta para el SEO o posicionamiento en su buscador.

Para usar HTTPS lo difícil era conseguir un certificado firmado por una autoridad de confianza que los navegadores tengan instalada, la obtención y renovación de un certificado tenía un coste. Desde hace un tiempo la autoridad Let’s encrypt emite certificados digitales gratuitamente que proporciona uno en pocos minutos y de forma automatizada incluida la renovación para usar un protocolo seguro. Usar un certificado de Let’s encrypt en el servidor web nginx no es complicado.

Sin embargo, usar HTTPS simplemente no es suficiente y ha de configurarse el servidor web para que utilice algoritmos de cifrado fuertes y que no tengan problemas seguridad conocidos o hoy estén ya considerados débiles. Para analizar el nivel de seguridad proporcionado en las conexiones HTTPS de un servidor web se puede utilizar la herramienta Qualys SSL Labs. Por ejemplo, analizando la seguridad del protocolo HTTPS ofrecido por GitHub Pages basta con introducir el dominio a analizar.

El informe que proporciona incluye información sobre el certificado del servidor entre ella su tiempo de validadez y fecha de expiración, y si es de confianza para los navegadores y plataformas como Mozilla, Apple, Android, Java o Windows. Los datos de configuración como protocolos soportados, cipher suites y una simulación de handshake con una gran variedad de versiones de navegadores en diferentes plataformas y versiones incluyendo dispositivos móviles y de escritorio que permite conocer si algún dipositivo pudiera tener algún problema con la configuración de TLS en la conexión, también otros detalle del protocolo.

Informe de seguridad TLS

La herramienta proporciona una nota entre A y F siendo la A la mejor calificación posible. Como se observa en la captura para GitHub Pages la herramienta proporciona una calificación de A.

Hay múltiples combinaciones de algoritmos de cifrado o cipher suites usados en una conexión SSL/TLS. La primera parte de los siguientes se refieren a TLS, está el tamaño de la clave y el modo y el algoritmo de autenticación del mensaje. Algunas recomendaciones de uso es usar tamaños de clave de más de 128 bits, evitar usar RC4, DES y 3DES, preferir ECDHE y DHE ya que ofrecen forward secrecy que protege las comunicaciones pasadas aún habiéndose comprometida la clave privada del servidor.

  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • TLS_RSA_WITH_AES_256_CBC_SHA256
  • TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
  • TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
  • TLS_RSA_WITH_AES_256_CBC_SHA
  • TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
  • TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA
  • TLS_DHE_DSS_WITH_AES_256_CBC_SHA
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256

Y algunas propiedades de los servidores web Apache HTTP y nginx que afectan a los algoritmos de cifrado soportados son las siguientes. Algunos navegadores antiguos puede que no soporten los últimos algoritmos de cifrado por lo que hay que permitir en el servidor web unos que sean considerados como seguros pero que también soporten los navegadores de los usuarios del sitio web.

Uan vez configurada la seguridad con TLS/SSL es recomendable redirigir el tráfico del protocolo HTTP no seguro al protocolo HTTPS seguro.

Variable not found: Enlaces interesantes 367

$
0
0
Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET / .NET Core

ASP.NET / ASP.NET Core

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin / Cross-platform

Otros

Publicado en Variable not found.
Viewing all 2715 articles
Browse latest View live