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

Fixed Buffer: Cómo medir tiempos en .Net (con precisión)

$
0
0
Cómo medir tiempos en .Net  (con precisión)

Hace unos días mientras comíamos los compañeros de trabajo, salió el tema sobre lo preciso o impreciso que puede ser medir tiempos desde el sistema operativo. Mis compañeros (programadores C/C++ en su mayoría), tenían dudas sobre lo preciso que puede ser medir tiempos desde un entorno administrado. Nunca he necesitado tales precisiones, así que era totalmente novato en ese tema, pero hoy que he tenido un momento, he investigado un poco sobre cómo medir tiempos en .Net (con precisión):

La clase Stopwatch

El ecosistema .Net nos provee de una herramienta ya lista para utilizar con una precisión de microsegundo (si el hardware lo permite) dentro del namespace “System.Diagnostics“. Está herramienta es la clase Stopwatch . Esta disponible en todos los entornos a partir de .Net Framework 2.0 (incluyendo .Net Core y .Net Standard), así que si no la conocías, es una buena idea añadirla al cinturón.

Para usarla, simplemente es necesario instanciarla y llamar a sus métodos Start y Stop, después nos devuelve un TimeSpan con el tiempo transcurrido:

Stopwatch timeMeasure = new Stopwatch();
timeMeasure.Start();
int operacion = 10 / 4;
timeMeasure.Stop();
Console.WriteLine($"Tiempo: {timeMeasure.Elapsed.TotalMilliseconds} ms");

Pero no se queda ahí, la clase también tiene dos propiedades estáticas (ReadOnly) que nos pueden dar mucha información sobre la medida:

  • IsHighResolution (bool): Nos va a indicar si el hardware permite mediciones de alta precisión.
  • Frequency (long): Nos va a dar el valor de ticks (mediciones) por segundo que soporta nuestro hardware.

Con estos dos datos extra, podemos saber si nuestra medida es de alta precisión, e incluso la resolución de la medida:

using System.Diagnostics;
//------
Stopwatch timeMeasure = new Stopwatch();
timeMeasure.Start();
int operacion = 10 / 4;
timeMeasure.Stop();
Console.WriteLine($"Tiempo: {timeMeasure.Elapsed.TotalMilliseconds} ms");
Console.WriteLine($"Precision: {(1.0 / Stopwatch.Frequency).ToString("E")} segundos");
if (Stopwatch.IsHighResolution)
    Console.WriteLine("Alta precisión");
else
    Console.WriteLine("Baja precisión");

Después de probarlo, ya puedo decirles a mis compañeros cómo medir tiempos en .Net (con precisión) y sin nada que envidiar a otros lenguajes de más bajo nivel como C/C++.

**La entrada Cómo medir tiempos en .Net (con precisión) se publicó primero en Fixed Buffer.**


Picando Código: Nuevo servicio gratuito para compartir archivos online de forma segura – Firefox Send

$
0
0

Este nuevo servicio de Mozilla se llama Firefox Send. Mediante cualquier navegador web, nos permite subir archivos de manera gratuita y compartirlos con otros usuarios. Tenemos bastante control de seguridad sobre los archivos que compartimos. Podemos limitar la cantidad de veces que puede ser descargado, y cuánto tiempo va a durar (para un máximo de 7 días). El archivo no va a quedar guardado indefinidamente en algún servidor en la nube. También podemos asignarle un password, para asegurarnos que solamente quienes sepan el password puedan descargarlo.

Firefox Send

La interfaz es bastante simple, podemos arrastrar archivos hacia la página o elegirlos desde un navegador de archivos, elegimos las opciones y lo(s) subimos. El servicio cuenta con encriptado de punta a punta, y podemos compartir archivos de hasta 1GB. Si queremos enviar hasta 2.5GB, podemos crear una cuenta gratuita Firefox.

Una vez subido, podemos enviar un enlace de descarga a otro usuario. Para la descarga no es necesario loguearse ni tener ningún tipo de cuenta. Tan simple y rápido como enviar un mail. Próximamente estará disponible como aplicación Android también.

Send fue diseñado por Mozilla con la privacidad como principio fundamental. Los archivos están protegidos y nuestra información es manejada de manera privada y segura. Mozilla es una fundación sin fines de lucro cuyo objetivo es que internet sea abierta y accesible para todos. No lucran con nuestros datos, así que de mi parte, son de las pocas marcas en las que confío por ahora.

El servicio empezó como un experimento de Test Pilot, y fue mejorando hasta que Mozilla decidió que era tiempo de promoverlo a un proyecto independiente. El código fuente está disponible en GitHub bajo la licencia libre Mozilla Public License Version 2.0.

Visita Firefox Send

 

Picando Código: Crystal: Lenguaje de programación inspirado en Ruby

$
0
0

Lenguaje de programación Crystal

Crystal es un lenguaje de programación de propósito general orientado a objetos. Su sintaxis está inspirada en Ruby pero no busca ser compatible. Surgió del amor a la eficiencia para escribir código de Ruby, y el amor a la eficiencia para ejecutar código C. Busca ser lo mejor de ambos mundos.

Entre las diferencias fundamentales con Ruby se encuentran:

  • Es un lenguaje compilado, el código es convertido a código de máquina nativo a través de LLVM. Ruby, por otro lado, es un lenguaje interpretado.
  • Tiene un sistema de tipado estático, por lo que la comprobación de tipos se realiza durante la compilación. Esto agrega una capa más de seguridad al código, evitando errors de tipos. Ruby es dinámicamente tipado, por lo que los tipos se revisan en ejecución. Sin embargo, el compilador de Crystal cuenta con un sistema de inferencia de tipos, por lo que no es necesario declarar los tipos de todos los valores y ejecuciones ya que el compilador los puede detectar. De esta manera, el código se mantiene limpio, y esto es parte de la filosofía del lenguaje.

El siguiente código nos muestra la inferencia de tipos en acción:

puts typeof("Fernando") #=> String
puts typeof(12) #=> Int32
puts typeof(42.0) #=> Float64

También podemos definir el tipo con anotaciones:

@nombre : String
@edad : Int32

Todo es un objeto: Al igual que en Ruby, en Crystal todo es un objeto (tiene un tipo, responde a algunos métodos).

Recién va por la versión 0.27.2, así que está creciendo y cambiando rápidamente todavía. De todas formas hay algunos valientes que se han animado a usarlo en producción. El proyecto cuenta con un Roadmap que define las cosas que quieren tener en el lenguaje, así como preguntas frecuentes y una excelente documentación.

Otras cosas interesantes de Crystal sobre las que me gustaría escribir más adelante: union types (tipos de datos especiales que pueden poseer varias representaciones), Macros (sistema para meta programación), Modelo de concurrencia e integración con librerías C (tiene una sintaxis dedicada para llamar a bibliotecas nativas de forma sencilla).

Instalar Crystal

Crystal puede ser instalado en Debian, Ubuntu, RedHat, CentOS, Arch Linux, Gentoo, Alpine, FreeBSD, y demás sistemas, desde un tar.gz o compilado desde el código fuente. Si usan el gestor de versiones asdf, hay un plugin para eso. Podemos ver las distintas instrucciones de instalación en la documentación.

El comando crystal

Una vez instalado, deberíamos tener el comando crystal disponible en nuestra terminal. Los archivos de código fuente Crystal tienen la extensión .cr. Para ejecutar un archivo de código fuente Crystal, escribimos:

$ crystal run archivo.cr

El comando `run` compila el código a un binario ejecutable en una ubicación temporal y lo ejecuta. Con el comando crystal build, podemos crear un binario ejecutable:

Crystal build

También existe crystal eval para pasarle código Crystal a crystal run desde la línea de comando o a través de un pipe por la entrada estándar. La lista completa de opciones está en la documentación usando el compilador.

Creando proyectos Crystal

El comando crystal también incluye el parámetro init, que inicializa un directorio con un proyecto. El primer parámetro de init es el tipo de proyecto. Las dos opciones son lib, una biblioteca reutilizable y app, una aplicación sin el objetivo de ser usada como dependencia:


$ crystal init app prueba
create prueba/.gitignore
create prueba/.editorconfig
create prueba/LICENSE
create prueba/README.md
create prueba/.travis.yml
create prueba/shard.yml
create prueba/src/prueba.cr
create prueba/spec/spec_helper.cr
create prueba/spec/prueba_spec.cr
Initialised empty Git repository in /home/fernando/workspace/crystal/prueba/.git/

Shards: Manejo de dependencias

Shards es a Crystal lo que las gemas son a Ruby. Las aplicaciones y bibliotecas Crystal cuentan con un archivo shard.yml que declara las dependencias del proyecto. Shards se distribuye con Crystal, así que lo tenemos disponible en nuestra terminal. Con shard init, creamos un archivo shard.yml de ejemplo, seguido de shard install para instalar las dependencias y especificarlas en un archivo shard.lock.

Por ejemplo en el proyecto recién creado, agrego las siguientes líneas al archivo shard.yml:

dependencies:
  cossack:
    github: crystal-community/cossack
    version: ~> 0.1
  

Cossack es un cliente HTTP bastante simple para Crystal. Se instala al ejecutar shards install y ya lo puedo usar en el código fuente. Dentro del archivo src/prueba.cr del mismo proyecto escribo:

require "cossack"

module Prueba
  VERSION = "0.1.0"

  def self.hola
    response = Cossack.get("https://picandocodigo.net/api")
    puts response.body
  end
end

Prueba.hola

Y podemos ejecutarlo con crystal run para ver los resultados:
crystal run src/prueba.cr

Testeando Código Crystal

Crystal viene equipado con una biblioteca de testing en el módulo Spec. Incluye un DSL (lenguaje de dominio específico) inspirado en RSpec, por lo que resulta súper familiar para programadores Ruby. Cuando inicié mi proyecto más arriba,ya se creó un directorio /spec con un archivo de ejemplo. Modificando un poco el archivo prueba.cr para que retorne el valor de lo que obtiene Cossack en vez de imprimirlo en pantalla con puts, podemos escribir un test bastante sencillo:

describe Prueba do
  it "calls Picando Código's API" do
    Prueba.hola.should eq "¡Chau!"
  end
end

Y si corremos los tests, tenemos una falla! (TDDeando, por supuesto):

$ crystal spec
F

Failures:

1) Prueba calls Picando Código's API
Failure/Error: Prueba.hola.should eq "¡Chau!"

Expected: "¡Chau!"
got: "¡Hola!"

# spec/prueba_spec.cr:5

Finished in 744.67 milliseconds
1 examples, 1 failures, 0 errors, 0 pending

Failed examples:

crystal spec spec/prueba_spec.cr:4 # Prueba calls Picando Código's API

Cambiando la expectativa del test a “¡Hola!” hacemos que pase:

describe Prueba do
  it "calls Picando Código's API" do
    Prueba.hola.should eq "¡Hola!"
  end
end
$ crystal spec
.

Finished in 861.99 milliseconds
1 examples, 0 failures, 0 errors, 0 pending

Como ven, es bastante sencillo empezar a usar Crystal. Espero con este post lograr despertar el interés por el lenguaje, y con suerte tener algún intercambio al respecto. Los comentarios están abiertos si quieren dejar su opinión, ¿conocían Crystal? ¿Le ven futuro?

Por mi parte voy a seguir investigando el lenguaje e intentar escribir algunos proyectitos, así como analizar las herramientas ya disponibles, e iré compartiéndolo por acá.

Más información sobre Crystal:

Coding Potions: NPM - Todo lo que necesitas saber

$
0
0
Introducción ¿Qúe es NPM? Si eres desarrollador web, sobre todo en la parte del frontend, seguramente ya conozcas NPM. NPM es un gestor de paquetes para Javascript. Es una especie de Maven (si usas Java te sonará) para paquetes Javascript, es decir, sirve para instalar y gestionar versiones de paquetes y librerías js. NPM lleva mucho tiempo siendo el referente en cuanto a gestores de paquetes javascript, pero desde hace un tiempo le ha salido un competidor: Yarn.

Picando Código: Cómics Marvel – Leyendo a los Inhumanos: Black Bolt

$
0
0

Escrito por Saladin Ahmed y con arte de Christian Ward, Black Bolt fue la primera serie mensual del rey de los Inhumanos de Marvel Cómics. Se publicó originalmente en Mayo de 2017, y terminó en el #12 en Abril de 2018. Fue compilada en dos tomos: Hard Time y Home Free. A continuación les cuento de uno de mis cómics preferidos de Inhumans y que recomiendo ampliamente:

Tomo 1: Hard Time

Black BoltEsta historia se desarrolla entre Inhumans Vs X-Men y Royals. Pero puede ser leída sin tener contexto de lo que pasó antes (o lo que pasa después). Lo que tenemos que saber es que Black Bolt despierta en una prisión, todo lo demás nos iremos enterando más adelante. La narrativa se inclina hacia la ciencia ficción, donde el escritor Saladin Ahmed tiene bastante experiencia.

En un principio resulta de esos cómics que se apartan un poco de la continuidad, pudiendo tener más soltura a la hora de contar cosas. Pero eventualmente empiezan a aparecer referencias y conexiones de las que no se puede escapar del todo en un universo compartido. Por ese lado disfruté mucho que la historia fuera bastante independiente más allá del contexto, pero que lentamente empezara a conectarse con el universo Marvel con el que uno está familiarizado. Como dije antes, no se necesita de haber leído historias de Black Bolt que vinieron antes para disfrutarlo.

Esto no quiere decir que esté completamente despegado de la mitología Inhumana. Pero me da la impresión que no conocer mucho los personajes antes de leer este título no le quita disfrute. Aunque si son seguidores de Inhumans, seguro van a disfrutarlo más todavía.

Black BoltSi bien Black Bolt es el protagonista y centro de la trama, van apareciendo personajes de la prisión que generan dinámicas muy interesantes y entretenidas. Esto aporta mucho, algunos son viejos conocidos y otros nuevos, pero se ganan la empatía del lector más allá de las razones por las cuales se encuentran en la prisión.

La alianza de Black Bolt con sus compañeros cae en el recurso narrativo de la “banda de inadaptados que se une con un fin común”. Pero el libro tiene un muy buen balance entre “una historia sobre Black Bolt” y “una aventura de Black Bolt en un grupo”, más a lo Inhumans clásico. A través del desarrollo de los personajes, entre otras cosas se analiza el tema del bien y del mal y la redención. Algo que corre peligro de caer en clichés o historias simplistas. Pero cuando está bien escrito como en este caso, es un éxito.

Viendo la tapa del primer número y ojeando las primeras hojas, podemos notar que el arte es otro punto alto de la serie. Las primeras páginas del primer número son un deleite visual con poco texto que de a poco nos lleva de paseo a este mundo donde se desenvuelve la trama. Christian Ward se encarga de todo el arte, y lo hace de manera espectacular. La prisión juega un poco con la mente de sus prisioneros, y el estilo del artista es ideal para representar ciencia ficción medio psicodélica que en lo personal disfruto mucho.

Hace un buen uso dinámico de las viñetas y “splash pages” (las viñetas que ocupan todo un par de páginas abiertas, pero no sé la traducción). Es así que la historia y el arte se complementan perfectamente. Vale la pena tener en cuenta otros trabajos de Christian Ward, y si quieren tener una idea de qué va la cosa, visiten su sitio web.

Hard Time colecciona los números 1 al 6 de Black Bolt y pueden encontrarlo en Amazon. Es un excelente cómic y lo recomiendo mucho, más allá que conozcan a Black Bolt o los Inhumans.

Próximamente les cuento sobre el desenlace y segundo tomo: Home Free.

Coding Potions: Posts

Blog Bitix: Varias consideraciones importantes para trabajar con importes correctamente (tipo de datos, precisión y guardado)

$
0
0
Java

Entre las cosas básicas a tener en cuenta en una aplicación que maneja fechas está en guardarlas en la zona horaria UTC que no sufre de cambios por zona horaria de verano o invierno, cambian más habitualmente de lo que parece e incluso por temas políticos.

Otra consideración distinta en aplicaciones que manejan importes es usar la clase BigDecimal en vez de los tipos de datos de coma flotante float o double ya que los datos de coma flotante no son capaces de representar adecuadamente algunos valores numéricos en base 10. El asunto de este artículo es por que además de usar BigDecimal es aconsejable guardar los importes con al menos un dígito decimal más de la precisión necesaria para evitar problemas en los redondeos al aplicar operaciones matemáticas como multiplicación, división o porcentajes para algunos impuestos como el IVA, comisiones, descuentos o cambios de divisa.

Sin utilizar una mayor precisión de 2 decimales puede ocurrir que algunos importes tengan una diferencia de céntimos. Por ejemplo, los precios se pueden introducir o bien el precio del producto antes de aplicar el IVA, comisiones o descuentos o puede introducirse en el precio que paga el usuario después de aplicar el IVA y en ambos casos al realizar el cálculo del precio con IVA y el cálculo del precio base ha de coincidir. Por ello la recomendación es utilizar al menos un decimal más de la precisión necesaria.

Otras pautas importantes son guardar los importes redondeados que el usuario ve en la factura para evitar discrepancias hacia arriba de algún céntimo en la suma de los importes y aplicar el IVA, comisión o descuento no a cada producto individual sino a la suma de los importes de todos ellos.

Este artículo sobre Cómo hacer una aplicación que soporte precios con decimales sin errores están muy bien explicadas con ejemplos varios de todos estos puntos imprescindibles al manejar importes, recomendable leerlo.

Pero el tipo de datos BigDecimal tampoco es el mas apropiado con el que trabajar si la aplicación maneja múltiples divisas, en este caso es recomendable utilizar la librería Java Money que además ofrece soporte para ratios de conversión los cuales pueden obtenerse de proveedores externos que los proporcionan actualizados a lo largo del tiempo.

Bitácora de Javier Gutiérrez Chamorro (Guti): Entrevista a Pedro Francisco Hernández Mayor de Kronos

$
0
0

Recientemente pudisteis leer el artículo sobre el juego C.R.B. (Cuerpo Rompe Bolas), desarrollado por KRONOS en 1993. KRONOS, sin embargo, no eran más que tres jóvenes aficionados afincados en Murcia (Pedro Francisco Hernández Mayor, Gregorio Ortiz Fernández y Antonio José Ortiz Fernández), que a base de pasión, lograron desarrollar un título que acabaría traspasando nuestras […]

La entrada Entrevista a Pedro Francisco Hernández Mayor de Kronos aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).


Blog Bitix: Ejemplo de Reactive Streams en Java

$
0
0
Java

Los streams representan un flujo de elementos producidos por un productor y consumidos por uno o más consumidores. Para procesar los elementos del stream se pueden emplear dos modelos, el modelo push donde el productor produce elementos para el consumidor que es avisado cuando hay un nuevo elemento disponible y el modelo pull en el que es el consumidor el que solicita al productor nuevos elementos que los genera bajo demanda. Ambos modelos presentan problemas cuando el productor y el consumidor no funcionan a la misma velocidad de elementos producidos o procesados. La solución es proporcionar un stream que se adapta a la velocidad de ambos. Los reactive streams son empleados cuando los elementos son producidos y consumidos en tiempo real como en sistemas de mensajes o peticiones HTTP en vez de un flujo constante como un dispositivo de almacenamiento.

Una estrategia es conocida como backpressure que consiste en que el suscriptor notifica al productor cuántos elementos puede procesar de modo que el productor solo envía el número de elementos solicitados. La implementación de la solución son los reactive stream que proporcionan un mecanismo estándar asíncrono para el stream con backpressure. Estos evitan que el productor se bloquee por no poder entregarlos al ser rápido produciendo elementos o el suscriptor tenga un buffer grande o descarte algunos elementos por ser lento al consumirlos o se bloquee esperando nuevos elementos si es rápido consumiéndolos.

En la API entre otras novedades de la versión 9 de Java se han añadido las siguientes clases para soportar reactive streams embebidas en la clase Flow, Flow.Publisher, Flow.Subscriber, Flow.Subscription, Flow.Processor y SubmissionPublisher en el paquete java.util.concurrent incluido en el módulo java.base.

Un Publisher publica elementos para los Subscriber basándose en sus demandas recibidas. Un suscriptor se subscribe a un productor. El productor proporciona un token de suscripción con el que el suscriptor puede solicitar N elementos al productor. Cuando los elementos están disponibles el productor envía N o menos elementos al suscriptor. Posteriormente el suscriptor puede solicitar más elementos.

En el ejemplo de código un productor produce y los consumidores procesan elementos a cierto ritmo, dependiendo de la velocidad relativa de cada uno se usará un modelo push o pull. La clase Flow.Processor permite procesar los elementos del productor para aplicarles alguna transformación antes de que sean entregados a los consumidores, actual como consumidor y productor. En este stream de números enteros se aplica la función elevarlos al cuadrado.

 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
85
86
87
88
89
90
91
packageio.github.picodotdev.blogbitix.reactivestreams;importjava.util.concurrent.Flow;importjava.util.concurrent.SubmissionPublisher;importjava.util.stream.IntStream;publicclassMain{privatestaticclassPrintSubscriberimplementsFlow.Subscriber<Integer>{privateFlow.Subscriptionsubscription;@OverridepublicvoidonSubscribe(Flow.Subscriptionsubscription){this.subscription=subscription;subscription.request(1);}@OverridepublicvoidonNext(Integeritem){System.out.println("Received item: "+item);subscription.request(1);Sleeper.sleep(1000);}@OverridepublicvoidonError(Throwableerror){error.printStackTrace();}@OverridepublicvoidonComplete(){System.out.println("PrintSubscriber completed");}}publicstaticclassPowProcessorextendsSubmissionPublisher<Integer>implementsFlow.Processor<Integer,Integer>{privateFlow.Subscriptionsubscription;@OverridepublicvoidonSubscribe(Flow.Subscriptionsubscription){this.subscription=subscription;subscription.request(1);}@OverridepublicvoidonNext(Integeritem){submit(item*item);subscription.request(1);}@OverridepublicvoidonError(Throwableerror){error.printStackTrace();}@OverridepublicvoidonComplete(){System.out.println("PowProcessor completed");close();}}privatestaticclassSleeper{privatestaticvoidsleep(inttime){try{Thread.sleep(time);}catch(Exceptione){e.printStackTrace();}}}publicstaticvoidmain(String[]args)throwsException{SubmissionPublisher<Integer>publisher=newSubmissionPublisher<>();Flow.Processor<Integer,Integer>processor=newPowProcessor();Flow.Subscriber<Integer>subscriber=newPrintSubscriber();publisher.subscribe(processor);processor.subscribe(subscriber);IntStream.range(0,10).forEach(it->{publisher.submit(it);Sleeper.sleep(2000);});publisher.close();}}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Received item: 0
Received item: 1
Received item: 4
Received item: 9
Received item: 16
Received item: 25
Received item: 36
Received item: 49
Received item: 64
Received item: 81
PowProcessor completed
PrintSubscriber completed

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.

Variable not found: Enlaces interesantes 354

$
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

Otros

Publicado en: www.variablenotfound.com.

Koalite: Y tú, ¿qué haces los fines de semana?

$
0
0

Últimamente he llegado a varios hilos en twitter sobre la conveniencia o no de que los desarrolladores dediquemos nuestro tiempo libre a actividades relacionadas con el desarrollo de software.

Vaya por delante que, como muy bien decía Modesto San Juan:

Creo que lo de decirle a la gente lo que tiene que hacer o no hacer no tiene mucho sentido.

Pero también me parece interesante esta puntualización de Rafael Casuso:

Creo que tampoco son conscientes de la presión que este bombardeo de actividad frenética IT causa en muchos compañeros. Si en algo podemos ayudar las voces conocidas a quitar esa presión creo que es positivo.

No sé si cuento como voz conocida, pero ya que tengo un blog y escribo cosas en él, me uno al debate.

Llevo 18 años dedicado al desarrollo de software profesionalmente. Siempre me ha gustado y, durante casi todo ese tiempo, he dedicado más o menos parte de mi tiempo libre a aprender sobre cosas relacionadas con el desarrollo.

Durante los últimos 7 años y medio además he estado escribiendo este blog, he sido razonablemente activo en redes sociales, e incluso he asistido a algunos eventos (tampoco muchos). Todo eso me da cierta experiencia en primera persona de lo que supone pertenecer a “la comunidad” del desarrollo.

Sin embargo, como comentaba hace unos días con Miguel Ángel Pastor, desde hace dos años le dedico mucho menos tiempo. Ahora mismo prefiero dedicar más parte de mi tiempo libre a estar con mi familia y disfrutar de mi hija que a ir a un evento de fin de semana.

Eso cuadra con lo que contaba Rafael en este hilo sobre dedicar el fin de semana a desconectar y estar con los tuyos.

Podría venderlo como un (mal) ejemplo de conciliación familiar o de lo que implica ser padre. Nada más lejos de mi intención. Si hago esto, más allá de la responsabilidad que crea que tengo con mi familia, es porque es lo que más me apetece hacer. Al menos ahora. Es lo que más disfruto.

Y eso es importante. Disfrutar.

Cuando dedicaba muchas horas de mi tiempo libre a jugar con lenguajes de programación o con nuevos frameworks o a leer sobre desarrollo de software, lo hacía porque disfrutaba. Disfrutaba por el mero hecho de aprender sin necesidad de buscar una utilidad a lo que estaba aprendiendo y sin más objetivo que pasármelo bien.

Por eso no veo ningún problema en que alguien quiera dedicar su tiempo libre a aprender (sobre software, sobre historia antigua o sobre repostería) si disfruta con ese aprendizaje.

Comprendo que esto se puede volver en nuestra contra, como explica Diana Aceves:

Pero, lo más importante, normalmente menciono que el principal problema es que las empresas den por normalizado el que tengas que tener side projects para mostrar en los procesos de selección, porque entonces ya no es tan “voluntario” lo de currar fuera de horas de trabajo.

Sin duda esto es un problema, pero no ya porque dediques el tiempo libre al desarrollo de software o al cultivo de tulipanes, sino porque no tiene mucho sentido hablar de tiempo libre cuando necesariamente tienes que dedicarlo a algo concreto. ¿Qué clase de libertad es esa?

También es cierto que en esta profesión (¿y en todas?) es necesario mantenerse actualizado (aunque no haga falta aprender cosas nuevas tan rápido como pueda parecer), y de una forma u otra eso requiere tiempo. En un mundo ideal es tu empresa la que te permite destinar tiempo durante la jornada laboral para ello, pero todos sabemos que no siempre vivimos en un mundo ideal.

Que puntualmente necesites sacrificar (y ojo, que esa es la palabra: sacrificar) parte de tu tiempo libre para obtener algo a cambio es perfectamente razonable. Para mi es equivalente al que compagina los estudios con un trabajo. ¿Lo tiene más complicado que el que puede estudiar mientras le mantienen sus padres? Por supuesto. Pero a veces no hay otra alternativa.

Esto que ocurre desde un punto de vista laboral, también se manifiesta desde un punto de vista de “comunidad”, postureo o como quieras llamarlo. Lo plantea Rafael en el tweet que citaba al principio.

Es fácil sentirse abrumado al ver que las figuras más reconocidas reconocibles del mundillo del desarrollo no paran de hacer cosas. Dar charlas. Asistir a eventos. Publicar posts. Compartir enlaces en twitter. Contribuir en proyectos open source.

Hacer todo esto está muy bien, pero vuelvo al punto anterior: está muy bien si lo disfrutas. Si hacer este tipo de cosas se convierte en algo necesario para sentirte alguien guay como tus ídolos y te acaba generando ansiedad, es el momento de replantearse tus prioridades.

En resumen, ya lo decía Modesto en su tweet: no tiene mucho sentido decirle a nadie lo que debe hacer con su tiempo.

En mi opinión, es fundamental ser capaz de diferenciar las cosas que haces porque necesitas y las cosas que haces para disfrutar y tener muy claro hasta dónde puedes llegar con cada una.

Si disfrutas dedicando tiempo libre a cosas relacionadas con el desarrollo, estupendo. Si prefieres dedicar tu tiempo libre a otras actividades, perfecto. Si no te queda más remedio que sacrificar tu tiempo libre para conseguir algo…, bueno, a veces es inevitable, pero trata de estar seguro de que lo que quieres conseguir realmente merece la pena.

No hay posts relacionados.

Variable not found: Si las shadow properties no existen como propiedades en la entidad, ¿cómo podemos inicializarlas en el seed de Entity Framework Core?

$
0
0
Entity Framework Core Vamos con un post rapidito, al hilo de una pregunta que planteaba el amigo Javier  R. vía el formulario de contacto del blog, sobre el artículo donde veíamos las shadow properties de Entity Framework Core, cuya respuesta creo que puede ser interesante para alguien más.

En concreto, la duda le surgía al combinar las capacidades de data seeding de EF con las propiedades ocultas, y básicamente era:
Dado que las shadow properties no existen en la entidad, ¿cómo podemos establecerlas en el momento del seeding de datos?
Bien, aunque no es fácil de descubrir de forma intuitiva, la solución es bastante sencilla. Si nos fijamos en el intellisense del método que utilizamos para el poblado de datos, HasData(), podemos observar varias sobrecargas; por ejemplo, en la siguiente captura se puede ver la información mostrada al invocar este método para la entidad Friend:

Intellisense en HasData()


Fijaos que, aunque estemos hablando de la entidad Friend, HasData() admite la posibilidad de enviarle cualquier tipo de objeto, y ahí es donde está la clave. Podemos enviarle simples objetos anónimos, de los que extraerá el valor para sus propiedades; dado que no existe un tipado específico, podemos introducir en ellos todas las propiedades que nos interesen poblar, incluidas las shadow properties de la entidad:
// Entidad:
public class Friend
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthdate { get; set; }
}

// Contexto de datos:
public class FriendsContext : DbContext
{
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Friend>()
.Property<DateTime>("UpdatedAt");
builder.Entity<Friend>()
.Property<string>("UpdatedBy")
.HasMaxLength(20);

// Seeding con objetos anónimos:
builder.Entity<Friend>().HasData(
new { Id = 1, Name = "Lisa Smith", Birthdate = new DateTime(1984, 3, 22),
UpdatedAt = DateTime.Now, UpdatedBy = "jmaguilar"
},
new { Id = 2, Name = "Malcolm Wesser", Birthdate = new DateTime(1970, 9, 1),
UpdatedAt = DateTime.Now, UpdatedBy = "jmaguilar"
}
);
}
...
}
Fácil, ¿eh?

Hey, pero... ¿y si no me gustan los objetos anónimos?

Si eres de los que prefieren hacer funambulismo sobre la red de protección que nos proporciona el tipado fuerte con chequeo en compilación, también hay una solución para ti ;)

En este caso, bastaría con crear una clase con los campos que queramos, y enviar instancias a HasData() como si se tratara de objetos anónimos.
public class FriendsContext : DbContext
{
private class SeedFriend
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthdate { get; set; }

public DateTime UpdatedAt { get; set; }
public string UpdatedBy { get; set; }
}

protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Friend>()
.Property<DateTime>("UpdatedAt");
builder.Entity<Friend>()
.Property<string>("UpdatedBy")
.HasMaxLength(20);

// Seeding con objetos de tipos arbitrarios:
builder.Entity<Friend>().HasData(
new SeedFriend { Id = 1, Name = "Lisa Smith", Birthdate = new DateTime(1984, 3, 22),
UpdatedAt = DateTime.Now, UpdatedBy = "jmaguilar"
},
new SeedFriend { Id = 2, Name = "Malcolm Wesser", Birthdate = new DateTime(1970, 9, 1),
UpdatedAt = DateTime.Now, UpdatedBy = "jmaguilar"
}
);
}
}
Espero que os sea de utilidad :)

Publicado en: www.variablenotfound.com.

xailer.info: Lanzamiento de Xailer 6.1.0

$
0
0

Estimados usuarios de Xailer,

Hoy publicamos una nueva versión de Xailer, la versión 6.1.0.

En esta nueva versión hemos actualizado la herramienta a las últimas versiones de todas las herramientas externas que usamos como pueden ser compiladores, editores de código o bases de datos. Se ha adaptado Xailer a las las últimas versiones de:

  • Harbour
  • MinGW
  • SQLite
  • Scintilla
  • MariaDB

Y se han añadido grandes mejoras, como son:

  • Soporte de eventos en controles ActiveX
  • Soporte completo de procedimientos almacenados para MariaDB y MySQL. Incluye la creación de clases que incorporan de forma automática todos los procedimientos almacenados existentes en un catálogo de bases de datos.
  • Nuevo control TGroupboxMod que es el clásico control TGroupbox pero vitaminado.
  • Increibles mejoras en el control TRichEdit que ahora incluye múltiples formatos de importación y exportación si necesidad de tener instalado Microsoft Office. Además de soportar transparencia.
  • Nueva propiedad de opacidad en gran cantidad de controles. Ya no sólo existe la posibilidad de poner transparencia si o no. Con Xailer 6 es posible establecer un nivel de opacidad por porcentaje.
  • Nuevo método ToExcel() que permite enviar desde cualquier control tipo TBrowse, su contenido a Excel (Debe de estar instalado Excel).

Para una lista completa de todas las mejoras puede consultar el siguiente enlace:
https://www.xailer.com/?lonuevo

Esta nueva versión de Xailer arranca directamente desde la versión 6.1 debido a que la versión 6.0 sólo ha estado disponible para beta-testers y durante un tiempo considerable. Posiblemente, esta nueva versión de Xailer es la que más haya sido probada antes de su publicación definitiva debido a la actualización realizada en todos las herramientas en las que se apoya nuestro producto. Esperamos que los posibles errores que se puedan encontrar sean mínimos. Y en cualquier caso serán corregidos rápidamente.

La nueva versión de Xailer y Harbour las puede encontrar en los siguientes enlaces:

http://www2.xailer.com/download/?es&file=1
http://www2.xailer.com/download/?es&file=2

Es necesario que reconstruya completamente todos sus proyectos, incluido cualquier librería estática o dinámica que esté utilizando.

Un cordial saludo,
[El equipo de Xailer]

Blog Bitix: Novedades de Java 12

$
0
0
Java

El 19 de marzo del 2019 se publicaba la versión Java 12 siguiendo el calendario de lanzar una nueva versión cada seis meses incorporando nuevas funcionalidades de forma incremental. La versión 12 no es una versión con soporte extendido y dejará de tener actualizaciones cuando se publique la siguiente versión. La primera versión LTS con la funcionalidad de módulos es la 11 y la recomendada para proyectos de larga duración o bajo mantenimiento, la siguiente LTS será la versión 17 que según lo planificado se publicará en septiembre de 2021 después de tres años.

Las características destacadas de Java 12 son la incorporación de forma experimental las expresiones switch y mejoras en el recolector de basura para mayor rendimiento.

Las mejoras incluídas en esta versión son:

Expresiones switch

Las expresiones switch permiten quitar varias sentencias if else encadenadas. Cada rama de la sentencia siwtch devuelve un valor y no hace falta usar la sentencia break, se pueden utilizar varios casos para cada rama.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
switch(day){caseMONDAY,FRIDAY,SUNDAY->System.out.println(6);caseTUESDAY->System.out.println(7);caseTHURSDAY,SATURDAY->System.out.println(8);caseWEDNESDAY->System.out.println(9);}StringnumericString=switch(integer){case0->"zero";case1,3,5,7,9->"odd";case2,4,6,8,10->"even";default->"N/A";};

Teeing Collectors

Los stream proporcionan un flujo de elementos a procesar. En el caso de querer recolectar dos valores de ese flujo requiere usar un reduce que complica el código. Se ha añadido un nuevo colector Collectors.teeing() para enviar un elemento de un stream a dos streams, de forma similar a lo que hace el comando tee en Unix.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Range<String>range=Stream.of(1,8,2,5).collect(Collectors.teeing(// the collectors produce Optional<Integer>
Collectors.minBy(Integer::compareTo),Collectors.maxBy(Integer::compareTo),// I wrote a static factory method that creates
// a range from two Optional<Integer>
Range::ofOptional)).orElseThrow(()->newIllegalStateException("Non-empty stream was empty."));

Formato de número compacto

Ahr se puede expresar un número de forma compacta con la clase CompactNumberFormat o el método NumberFormat.getCompactNumberInstance().

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
NumberFormatfollowers=NumberFormat.getCompactNumberInstance(Locale.US,NumberFormat.Style.SHORT);followers.setMaximumFractionDigits(1);System.out.println(followers.format(5412)+" followers");// Resultado: 5.4K followers
NumberFormatnumber=NumberFormat.getCompactNumberInstance(Locale.US,NumberFormat.Style.SHORT);System.out.println(number.format(1000));// Resultado: 1K

Recolector de basura Shenandoah

Una de la áreas que más atención reciben para mejorar el rendimiento de las aplicaciones es el recolector de basura. Shenandoah es uno nuevo que independiente del tamaño de la memoria, ya sea de 200 MiB o 200 GiB, el tiempo de las pausas es el mismo. También se han implementado mejoras en el recolector de basura G1 actual.

Otras

Algunos métodos han sido eliminados varios relacionados con el método finalize cuyo uso está desaconsejado desde hace mucho tiempo por no se una forma segura de liberar recursos. Algunos algoritmos de cifrado inseguros han sido deshabilitados. Se ha añadido soporte para Unicode 11.0.0 con nuevos caracteres, bloques y scripts.

Picando Código: Firefox Send (Beta) disponible en Android

$
0
0

Firefox Send, nuevo servicio gratuito para compartir archivos online de forma segura, ya tiene su aplicación beta para Android. La aplicación no está listada en Google Play, pero la pueden encontrar en el siguiente enlace:

https://play.google.com/store/apps/details?id=org.mozilla.firefoxsend

La interfaz es básicamente la misma que el sitio web. Al ser una versión Beta, todavía puede tener algún que otro detalle. Pero por ahora anda todo muy bien.

Firefox Send Android

Firefox Send Android

En lo personal vengo usando Firefox Send con éxito, es súper práctico para compartir archivos online.

Podemos usar la aplicación web desde cualquier dispositivo entrando en Firefox Send.


Blog Bitix: Codificar los datos para evitar ataques XSS en una página web

$
0
0
HTML
Java

Validar los datos es importante para una aplicación pero no es suficiente para crear una aplicación, es más, para crear una aplicación segura es más importante codificar correctamente los datos emitidos por la aplicación. Los ataques XSS se producen precisamente por no codificar correctamente los datos emitidos provenientes de una fuente no confiable. Una fuente no confiable puede ser un parámetro en una aplicación web pero también puede ser cualquier otro dato que incluya una petición HTTP como una cabecera.

El siguiente código de un archivo JSP que obtiene un parámetro de la petición y lo emite en la salida permite a un usuario malicioso insertar código en la página web, si el dato que se envía es el contenido de xss.data y las cookies no se crearon con las cabeceras httponly el usuario malicioso puede obtener acceso a la sesión del usuario en el sitio web y es un grave fallo de seguridad. En este caso solo se emplea un alert pero el código podría ser más elaborado y realizar una petición a una URL en la que el usuario malicioso reciba los datos de las cookies de sesión.

1
2
3
4
5
6
7
8
<html>
<head>
<title>Página</title>
</head>
<body>
Hola <%= request.getParameter("user"); %>!
</body>
</html>
1
2
Hacker <script type="text/javascript">alert("Hacked!"); alert(document.cookie);</script>

El contenido HTML generado por la aplicación y enviado al navegador sería el siguiente:

1
2
3
4
5
6
7
8
<html><head><title>Página</title></head><body>
Hola Hacker <scripttype="text/javascript">alert("Hacked!");alert(document.cookie);</script>!
</body></html>

En este caso al cargar la página en el navegador se muestra un mensaje alert con una ventana emergente pero si el usuario malicioso enviase los datos de las cookies a una URL suya el usuario ni siquiera sería consciente de que le han robado la sesión. Y este fallo de seguridad se produce simplemente por cargar una página de una aplicación insegura por XSS.

XSS

Pero ¿como consigue el usuario malicioso inyectar su código mediante parámetros u otros datos emitidos por la página insegura? Una opción sería enviar al usuario un enlace especialmente construido para que se aproveche del fallo de seguridad, el medio de hacerlo llegar puede ser un correo electrónico o un enlace en las redes sociales o páginas de gran tráfico como Facebook. Para que el enlace no sea tan evidente se puede utilizar un acortador de enlaces. Los comentarios son otro vector con el que el usuario malicioso puede insertar enlaces o el propio contenido si no son tratados adecuadamente.

Para evitar los ataques XSS la regla básica es codificar correctamente cualquier dato que se emita como resultado. En el caso de una aplicación web codificar correctamente el dato a emitir depende del contexto donde se incluya el dato para escapar correctamente los caracteres especiales de ese contexto. Los contextos puede ser como HTML, como un atributo de una etiqueta, como contenido HTML, como un bloque de JavaScript o como una variable de JavaScript.

Si el framework web que usamos no proporciona facilidades para evitar ataques XSS al emitir contenido en el resultado en Java se puede usar la librería OWASP Java Encoder Project siendo su uso el siguiente. OWASP Java Encoder Project es una librería que no tiene dependencias adicionales por lo que es sencillo incorporarla en la aplicación.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<%@ page import="org.owasp.encoder.Encoder" %>
<%-- HTML Content context --%>
<body>
<%= Encode.forHtml(text) %>
</body>
<%-- HTML Attribute context --%>
<input type="text" name="address" value="<%= Encode.forHtmlAttribute(address) %>" />
<%-- HTML Textarea context --%>
<textarea name="text"><%= Encode.forHtmlContent(textAreaContent %></textarea>
<%-- Javascript Block context --%>
<script type="text/javascript">
var msg = "<%= Encode.forJavaScriptBlock(message) %>";
alert(msg);
</script>
<%-- Javascript Variable context --%>
<button onclick="alert('<%= Encode.forJavaScriptAttribute(alertMsg) %>');">Action</button>

Para los frameworks web populares ya tienen en cuenta el XSS en el comportamiento por defecto al emitir datos.

No siempre se desea codificar un dato simple según el contexto, a veces se quiere permitir insertar código HTML. La alternativa a la codificación para estos casos es el saneado permitiendo únicamente los elementos que se consideren seguros definiendo una política, por ejemplo, permitiendo etiquetas HTML de enlaces y ciertas etiquetas como em, ul, li. El saneado también se puede hacer con jsoup pero esta incluye otras funcionalidades que si no son necesarias con WASP Saniticer es suficiente.

Un ataque de XSS también puede producirse en contenidos distintos al HTML como pueden ser documentos JSON o XML en los que también hay que escapar los datos según su contexto para evitar por ejemplo que alguien cambien la estructura del XML o JSON previsto por la aplicación. El XSS es similar al problema de inyección de SQL si al construir las sentencias se insertan en ella datos en vez de usar en el caso de Java la clase PreparedStatement con parámetros.

Variable not found: Enlaces interesantes 355

$
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

Otros

Publicado en Variable not found.

Variable not found: Publicando nuestra web sobre Azure Web Apps

$
0
0

Blogger invitado

Blogger invitado

Jorge Turrado

Apasionado de la programación, siempre buscando la manera de mejorar el día a día con el desarrollo de tecnologías .NET. Apasionado de este momento tan cambiante y fabuloso para ser desarrollador C#.
Blog: Fixed Buffer
Mi tercera entrada en Variable Not Found, ¡esto se va a convertir casi en tradición ya! Hoy vengo a hablaros sobre cómo hacer aprovisionamiento de recursos en Azure para publicar nuestra aplicación web en Azure Web App.

Para hacer esto tenemos varios caminos posibles, unos más automatizables que otros, y cuál elegiremos dependerá de nuestras necesidades:
  • A través de la interfaz web de Azure
  • Desde Visual Studio
  • Usando Azure Resource Manager (ARM).
En este artículo detallaremos, paso a paso, cómo utilizar cada una de estas opciones.

Crear la Web App a través de la interfaz web de Azure

En primer lugar está la opción más obvia, que es ir al portal de Azure y crearla desde allí, para eso, nos tenemos que identificar en Azure, y dentro del “dashboard”, pulsamos sobre “Crear un recurso”:

Crear recurso

Dentro del menú, vamos a Web App:

Opción Web App

Esto nos llevará a un nuevo menú, donde vamos a dar un nombre a nuestra aplicación, elegiremos si es Windows o Linux, así como el plan de precios:

Settings de la aplicación

Al seleccionar sobre el plan de precios, nos va a abrir un nuevo menú donde seleccionaremos algún plan ya creado, o uno nuevo, en caso de no existir ninguno, se creará uno por defecto:

Plan de precios

Al pulsar sobre “Crear nuevo”, nos lanza un último menú, donde elegir la región donde queremos que este el plan, así como el tipo de equipo donde queremos que funcione nuestra Web App:

Nuevo plan de precios
Una vez que tengamos todo seleccionado, al pulsar crear, se ejecutará la implementación de los recursos:

Implementando recursos
Una vez que termine, se puede consultar desde el panel “Todos los recursos”:

Vista de todos los recursos

Crear la Web App desde Visual Studio

Una segunda opción es utilizar la propia interfaz de publicación de Visual Studio para aprovisionar los recursos. Para ello, dentro de nuestro proyecto, vamos a publicar desde el menú contextual:

Menú contextual de publicación

Y desde ahí, en la ventana, seleccionamos “App Service” y “Crear nuevo”:



Al pulsar sobre “Publicar”, se inicia el asistente donde nos vuelve a pedir los datos de nuestro App Service:

Settings del app service

En él, podemos elegir el nombre, el grupo de recursos y el plan de hospedaje para nuestra web. Una vez que lo hayamos elegido, basta con pulsar sobre el botón “Crear” para lanzar el aprovisionamiento.

Una vez haya terminado, se lanzará la publicación, consiguiendo que nuestra web esté online. Si volvemos a comprobar en el portal, podremos ver que el Web App esta creado correctamente:

Web App creada correctamente

Crear la Web App usando ARM (Azure Resource Manager)

Una tercera opción, que además es la que usan las otras 2 por detrás, es utilizar el Azure Resource Manager (ARM). Con ARM, podemos crear mediante código plantillas de implementación de recursos, que además pueden ser versionadas junto al resto del proyecto. Mediante estas plantillas, podemos conseguir configuraciones complejas tal cual lo haríamos en la interfaz web, uniendo por ejemplo nuestra Web App con un Storage y una base de datos, consiguiendo así que las siguientes implementaciones no impliquen un montón de trabajo de creación y configuración.

Otro escenario en el que puede ser muy interesante utilizar estas implementaciones es en equipos de trabajo donde queremos que los recursos sean los mismos para todo el equipo, sin tener que preocuparnos de generar “n” espacios de trabajo iguales y asignarlos, ya que, muy cómodamente, cada persona puede generar su entorno de trabajo igual a los demás.

Para poder utilizar ARM desde Visual Studio, es necesario añadirle la carga de trabajo “Desarrollo de Azure”:

Workload Desarrollo de Azure

Una vez que lo tenemos, basta con que añadamos un nuevo proyecto a nuestra solución de tipo “Grupo de recursos de Azure”, dentro del menú “Cloud”:

Nuevo grupo de recursos

Al crearlo, nos lanzará un pequeño asistente que nos permitirá seleccionar templates predefinidas que nos puedan resultar interesantes. Estas templates se pueden modificar, añadiendo o quitando lo que nos interese, pero son una buena base desde la que partir. En nuestro caso, la plantilla es suficiente para hacer un aprovisionamiento básico para una Web App sobre Windows sin ningún añadido, ni bases de datos ni storages.

Para eso, seleccionamos las plantillas de Azure QuickStart, buscamos “101-webapp-basic-windows” y pulsamos sobre “Aceptar”:

Selección de templates

Esto nos ha creado un proyecto listo en nuestra solución con los ficheros necesarios para hacer la implementación de recursos en Azure:

Proyecto de implementación

Para lanzar el aprovisionamiento, basta con hacer clic derecho sobre el proyecto, y sobre el menú contextual, seleccionamos “Implementar -> Nuevo…”:

Nueva implementación

Esto nos lanza un último menú, donde tenemos que seleccionar el grupo de recursos donde queremos hacer el aprovisionamiento y sus parámetros. Dentro de estos parámetros, están cosas como el nombre de nuestra Web App y el tipo de máquina donde tiene que correr:

Opciones de implementación
Editar parámetros

Una vez hecho esto, pulsamos sobre “Implementar” y después de esperar a que termine, ya tendremos nuestros recursos aprovisionados.

Despliegue realizado

Publicando sobre Azure App Service

Una vez que el recurso está creado mediante cualquiera de los tres métodos, ya sólo falta poner nuestra web en ese recurso. Para ello, desde el menú de publicación de Visual Studio, seleccionamos “App Service”, y esta vez, marcamos “Seleccionar existente”:

Publicar aplicación

Al pulsar “Publicar”, se nos despliegan todos los recursos disponibles en nuestra cuenta de Azure:

Recursos disponibles

Al elegir nuestra Web App y pulsar en “Aceptar”, se creará el perfil de publicación y nuestra web será desplegada sobre el recurso que hemos seleccionado. De aquí en adelante, basta con que volvamos a publicar sobre ese perfil cada vez que necesitemos modificar nuestra web.

Es importante añadir que, con lo que hemos hecho, sólo hemos creado una web en producción, y que, si volvemos a publicar y cometemos errores, nuestra web puede quedar inaccesible o accesible con errores. Además, el tiempo que dure la publicación nuestra web estará inaccesible, por no hablar de que no es obligatorio pasar las pruebas unitarias para publicar, basta con que compile…

Si nuestra web esta en producción y queremos evitar estos posibles fallos, la mejor idea puede ser utilizar webs con diferentes Slots (Ranuras) donde la publicación se haga automáticamente después de pasar por un sistema de CI. Precisamente de esto hablo en mi entrada:
Con esto me despido, ha sido un placer volver a publicar en Variable Not Found, donde espero volver (después de un tiempo, eso sí), con alguna nueva e interesante idea.
José M. Aguilar > Como siempre, es un placer tenerte por aquí, Jorge. Ya sabes que las puertas están abiertas para cuando te apetezca de nuevo. Mientras tanto, continuaremos siguiéndote de cerca en Fixed Buffer ;)
Publicado en Variable not found.

Fixed Buffer: Herramientas de desarrollo: Azure Pipelines (CD)

$
0
0
La imagen muestra el logo de Azure Pipelines

Todo lo que empieza tiene un final, y hoy es el final de la serie sobre “Integración Continua y Despliegue Continuo” (CI/CD). Hoy vamos a hablar sobre cómo hacer una integración y despliegue completos sobe Azure Web Apps de un proyecto ASP NET Core con Azure Pipelines.

Para poder hacerlo, lo primero que necesitamos es aprovisionar los recursos en Azure, y hay varias maneras de hacerlo. Hablo de ellas en Variable Not Found:

En este caso, vamos a utilizar el sistema de aprovisionamiento desde AzureRM para crear el plan, la webapp y una segunda ranura que será donde hagamos el deploy de nuestro proyecto para cambiarlo después a producción. Utilizando este sistema vamos a conseguir que nuestro proyecto esté siempre online incluso mientras se hace la publicación, ya que vamos a publicar sobre una segunda ranura y solo después de que nuestro proyecto este publicado y online, haremos el cambio entre ranuras (internamente hace un cambio de DNS, por lo que el cambio es instantáneo). Una vez dicho esto, ¡vamos a meternos en faena!

Creando la integración continua

Dentro de esta serie, publique como hacer la integración de nuestro proyectos en Azure Pieplines, así que nos vamos a saltar esa parte. El fichero .yml podría ser algo como esto:

# Configuramos el pool con la imagen
pool:
  vmImage: 'ubuntu-16.04'

# Variables de trabajo
variables:
  buildConfiguration : 'Release'
  project : '**/*.csproj'
 
# Pasos
steps:
# Restore Nuget
- task: DotNetCoreCLI@2
  displayName: Restore
  inputs:
    command: restore
    projects: '$(project)'
# Compilamos el proyecto
- task: DotNetCoreCLI@2
  displayName: Build
  inputs:
    projects: '$(project)'
    arguments: '--configuration $(buildConfiguration)'

# Aquí van las pruebas unitarias
# ------

# Publicamos la solución indicándole que queremos zipearla
- task: DotNetCoreCLI@2
  displayName: Publish
  inputs:
    command: publish
    publishWebProjects: True
    arguments: '--configuration $(buildConfiguration) --output $(build.artifactstagingdirectory)'
    zipAfterPublish: True

# Subimos los artefactos
- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'

Creando el despliegue continuo en Azure Pipelines

Con esto, ya tenemos nuestra integración funcionando y subiendo los artefactos, ahora solo falta el despliegue. La manera más sencilla quizás sea desde la propia ventana de resultados de la integración, pulsando sobre el botón Release:

La imagen muestra el botón "Release" dentro de la ventana de resultados de la integración de Azure Pipelines

Eso nos va a lanzar a una nueva página donde vamos a crear el pipeline. Por defecto nos va a dar muchas opciones, pero vamos a hacerlo desde 0, así que elegimos “empty job”:

La imagen indica "empty job" en el asistente de Azure Pipelines

Esto va a crear un job vacío, en el cual vamos a añadir todos los pasos que necesitamos. En nuestro caso son 3:

  1. Aprovisionar los recursos.
  2. Desplegar nuestro proyecto a una ranura de staging
  3. Cambiar las ranuras de staging y producción.

Para eso, vamos a pulsar sobre el Stage 1, para añadir tareas al job:

La imagen muestra el enlace que hay que pulsar para abrir la configuración

Esto nos lleva a las tareas que tiene el job, y ahí vamos a pulsar en “+” para añadir las nuestras:

La imagen señala el botón "+" para añadir tareas al job

Aquí vamos a tener que añadir 3 tareas, una por cada una de las 3 acciones que queremos hacer. La primera, será una tarea de aprovisionamiento, así que vamos a la pestaña “Deploy” y seleccionamos “Azure Resurce Group Deployment”:

La imagen muestra el recurso Azure Resurce Group Deployment

El siguiente que vamos a introducir, es “Azure App Service Deploy”:

La imagen muestra el recurso Azure App Service Deploy

Y por último, vamos a añadir “Azure App Service Manage”:

La imagen muestra el recurso Azure App Service Manage

Una vez añadidos los 3 recursos, nos quedará algo como esto:

La imagen muestra el resultado de añadir las 3 tareas al job de Azure Pipelines

Ahora vamos a configurarlos, para ello, vamos al primero y al pulsar sobre él, nos aparecen sus opciones:

La imagen enseña el asistente de aprovisionamiento de Azure Pipelines

Simplemente, tenemos que seleccionar nuestra suscripción y grupo de recursos donde queremos que se añadan, así como la zona para el despliegue. Después le indicamos que el template va a estar en una url y le pasamos las direcciones “raw” de los ficheros. Por ejemplo, en GitHub existe un botón para ir al fichero raw y luego basta con copiar la url:

La imagen señala el botón raw de github

Como se puede intuir, estos ficheros los genera el proyecto de “Grupo de Recursos de Azure” que hemos creado en Visual Studio, y los parámetros que hayamos puesto al validar nuestro script de aprovisionamiento:

La imagen señala los valores indicados en Visual Studio para el aprovisionamiento

Con esto, ya tenemos listo el aprovisionamiento de recursos. Ahora, vamos a configurar el despliegue de nuestro proyecto. Azure Pipelines nos da un asistente como este:

La imagen señala los campos del asistente de publicación

Aquí tenemos que tener especial cuidado, ya que vamos a “ciegas”. Me explico, como los recursos aún no están creados en Azure, vamos a tener que introducir los datos a mano porque los desplegables van a estar vacíos. Para eso, vamos a escribir los datos que hemos puesto al validar nuestro script de despliegue. También hay que tener cuidado con cuál es el nombre real que aplica nuestro despliegue, por ejemplo, la plantilla que hemos seleccionado para el aprovisionamiento añade “Portal” al nombre que hallamos elegido:

"webAppPortalName": "[concat(parameters('baseResourceName'), 'Portal')]"

Lo mismo pasa con la ranura (Slot) al que vamos a desplegar, realmente no existe mientras estamos configurando el despliegue, así que la escribimos a mano.

Este “problema” se puede solucionar si hacemos el aprovisionamiento de recursos antes de configurar esta parte. Si los recursos ya están creados, aparecerán todos correctamente en los desplegables.

Una vez que lo hemos terminado de configurar, lo último que nos falta es cambiar la ranura de “Staging” por la de “Produccion”, de manera que se haga un despliegue completo, y nuestro proyecto este accesible en producción. Para eso, configuramos el último apartado:

La imagen señala los campos del asistente de swap de ranuras

Igual que en el caso anterior, vamos a “ciegas” porque los recursos aun no existen. Sabiendo esto, escribimos manualmente el nombre del servicio que estamos operando, el grupo de recursos al que pertenece, y la ranura que queremos poner en producción. Puede que no queramos poner en producción la ranura y solo cambiarla por otra, esto lo podríamos conseguir si desmarcamos la casilla “Swap whit Production”, lo cual nos hace aparecer un segundo campo para rellenar con la ranura por la que queremos cambiar.

Una vez que hemos configurado las 3 tareas, pulsamos sobre el botón “Save” para guardar nuestro job:

La imagen muestra el botón de guardar el job

Ya tenemos nuestro despliegue listo. Ahora cada vez que hagamos un cambio en el repositorio, automáticamente se publicará. Antes de hacer cambios, podemos comprobar que nuestro pipeline funciona pulsando sobre el botón “Create a release”:

El la imagen señala el botón para lanzar un ciclo de release

Esto lanzará un ciclo de despliegue como podemos ver en la pestaña “Releases”:

La imagen muestra la nueva release en marcha

Una vez termine, si vamos a https://{nombre de nuestro servicio}.azurewebsites.net debería estar disponible nuestro proyecto. Si añadimos algún cambio y lo subimos a github, de que acabe la integración y el despliegue deberíamos poder ver en la url el cambio que hemos hecho. Por ejemplo:

La imagen muestra el resultado de hacer un cambio en el repositorio

Como es habitual en este tipo de entradas, el código esta disponible en GitHub para poder consultarlo.

Aviso a navegantes

No es oro todo lo que reluce, poner webs en producción de manera automática puede ser peligroso ya que puede haber errores de interfaz gráfica (o cualquier otro tipo) que no se hayan testeado mediante pruebas automáticas. Una mejor practica puede ser hacer despliegue sobre una ranura de “develop” donde poder comprobar la funcionalidad completa de la web, y una vez que estamos seguros de que todo esta bien, hacer el swap desde la ranura que hemos testeado de manera que los posibles errores estén comprobados ya.

Si por el contrario, lo único que estamos publicando es una API RESTful que hemos desarrollado con buenas prácticas y que no tiene estado (no hay datos que son necesarios mantener en memoria entre peticiones), no debería ser un problema hacer despliegue continuo automáticamente, ya que las peticiones de aquello que consuma nuestro servicio se lanzaran contra la versión establecida, y solo cuando cambiemos los clientes a la nueva versión se aplicará el cambio.

Conclusión sobre CI/CD

Aunque quizás el despliegue continuo a producción es algo idílico y difícil de alcanzar por la cantidad de posibles problemas y errores que podemos introducir, este solo es el paso final de una serie de buenas prácticas y metodologías de trabajo. Quedarse en cualquiera de los puntos anteriores al despliegue en producción sigue siendo algo muy válido, ya que estamos haciendo que no exista una dependencia tan fuerte entre código y programador, lo cual siempre facilita el trabajo y la mantenibilidad de los proyectos. Esto añadido a una buena política de pruebas unitarias,
evita los problemas asociados a realizar proyectos en equipos de trabajo, donde cada persona no tiene por qué conocer el alcance del trabajo del resto. Con la variedad de proveedores que ofrecen estos servicios, no buscar uno que se adapte a nuestras necesidades e implementarlo puede ser una decisión que a la larga salga cara.

**La entrada Herramientas de desarrollo: Azure Pipelines (CD) se publicó primero en Fixed Buffer.**

Mascando Bits: Cómo subir un paquete a PyPI

$
0
0

Recientemente un compañero mío quería distribuir una pequeña librería en Python que había escrito. En lugar de forzar a los desarrolladores a clonar su repositorio, quería que pudieran instalarse la librería con un sólo comando “pip install“. Planteamiento muy interesante que se formaliza con el concepto de gestor de paquetes.

Un gestor permite un uso más inteligente, ágil y seguro de las dependencias y ayuda tanto al que distribuye el paquete como al que lo usa, resolviendo problemas como el versionado, la cadena de dependencias dentro del paquete, la instalación…

Quisiera a fin de fomentar el uso del gestor de paquetes de Python llamado pip, que usa como repositorio oficial PyPI (Python Package Index), generar una guía lo más completa posible. ⚠Me gustaría remarcar que con ello no quiero ni pretendo incentivar que cualquiera se dedique a subir de cualquier forma lo primero que se lo ocurra. Aludo a la responsabilidad de cada uno, para no convertir PyPI en un vertedero de paquetes de dudosa calidad.⚠

¿Qué es PyPI?

Desde la web oficial:

PyPI — Índice de Paquetes Python

El Índice de Paquetes Python es un repositorio de software para el lenguaje de programación de Python.

¿Has programado algo genial? ¿Quieres que otros puedan instalarlo con easy_install o pip? Pon tu código en PyPI. Es una gran lista de paquetes de Python donde debes enviar tu paquete para que pueda instalarse fácilmente con uno sólo comando.

La buena noticia es que enviar un paquete a PyPI en la teoría es muy simple: registrarte y cargar tu código, todo de manera gratuita. La mala noticia es que en la práctica es un poco más complicado que eso 😅. La otra buena noticia es que he escrito esta guía 😁 y que, si estás atascado, siempre puedes consultar la documentación oficial 😉.

He escrito esta guía con los siguientes supuestos:

  •      El módulo / biblioteca / paquete que está enviando se llama mypackage.
  •      mypackage está alojado en GitHub.

Crear tu cuenta

Crea una cuenta en PyPI Live y también en PyPI Test. Debes crear una cuenta para poder cargar tu código. Te recomiendo usar el mismo correo electrónico y contraseña para ambas cuentas, sólo para hacerte la vida más fácil cuando llegue el momento de subir tu código. Ambas plataformas son idénticas, siendo la de test una réplica de la oficial para que pruebes a subir tus paquetes.

Crear un archivo de configuración .pypirc

Este archivo contiene su información para la autenticación con PyPI, tanto la versión en vivo como la versión de prueba.

[distutils]
index-servers =
  pypi
  pypitest

[pypi]
repository=https://upload.pypi.org/legacy/
username=your_username
password=your_password

[pypitest]
repository=https://test.pypi.org/legacy/
username=your_username
password=your_password

Esto es sólo para hacer tu vida más fácil, para que cuando llegue el momento de subir el código de de tu paquete no tengas que recordar/escribir tu nombre de usuario y contraseña. Asegúrate de poner este archivo en tu carpeta de inicio de tu sistema GNU/Linux; tu ruta debe ser:

~/.pypirc

Debido a que este archivo contiene tu nombre de usuario y contraseña, es posible que desees cambiar sus permisos para que sólo tú puedas leerlos y escribirlos. Desde la terminal, ejecuta:

chmod 600 ~/.pypirc

Si por el contrario te encuentras en un sistema Windows genera el archivo .pypirc en la carpeta de tu usuario en C:\Users\usuario con el siguiente comando:

type nul > your_file.txt
👁 Notas sobre usernames / passwords

En Python 3, si tu contraseña incluye un % sin procesar, debes generar una secuencia de escape duplicándolo. El analizador de configuración de .pypirc interpola las cadenas de texto. Por ejemplo, si tu contraseña es hello%world:

[pypi]
repository=https://pypi.python.org/pypi
username=myusername
password=hello%%world

Nunca me he encontrado con este problema, pero si te ocurre, esto podría ayudar. 😉

Este comportamiento de escape ha sido parcheado y ya no es necesario hacerlo, pero si ves un error con un código de respuesta de:

403: Invalid or non-existent authentication information

Intenta eliminar la secuencia de escape de los signos de porcentaje en tu contraseña.

Si tu contraseña incluye espacios, asegúrese de no entrecomillarla. Por ejemplo, si tu contraseña es me encanta Mascando Bits:

[pypi]
repository=https://pypi.python.org/pypi
username=myusername
password=me encanta MascandoBits

Preparar el paquete

Cada paquete en PyPI necesita tener un archivo llamado setup.py en la raíz del directorio. Si estás utilizando un archivo README en formato markdown, también necesitará un archivo MANIFEST.in. Además, es recomendable elegir una licencia para tu paquete reflejada en un archivo LICENSE que describa lo que se puede hacer con tu código. Entonces, si por ejemplo he estado trabajando en una biblioteca llamada mypackage, la estructura de mi directorio se vería tal que así:

root-dir/   # nombre de directorio de trabajo aleatorio
  setup.py
  MANIFEST.in
  LICENSE.txt
  README.md
  mypackage/
    __init__.py
    foo.py
    bar.py
    baz.py

A continuación un desglose de lo que va en cada archivo:

setup.py

Son los metadatos de la librería necesarios para generar el paquete.

from setuptools import setup

setup(
    name='mypackage',
    packages=['mypackage'], # Mismo nombre que en la estructura de carpetas de arriba
    version='0.1',
    license='LGPL v3', # La licencia que tenga tu paqeute
    description='A random test lib',
    author='RDCH106',
    author_email='contact@rdch106.hol.es',
    url='https://github.com/RDCH106/mypackage', # Usa la URL del repositorio de GitHub
    download_url='https://github.com/RDCH106/parallel_foreach_submodule/archive/v0.1.tar.gz', # Te lo explico a continuación
    keywords='test example develop', # Palabras que definan tu paquete
    classifiers=['Programming Language :: Python',  # Clasificadores de compatibilidad con versiones de Python para tu paqeute
                 'Programming Language :: Python :: 2.7',
                 'Programming Language :: Python :: 3.3',
                 'Programming Language :: Python :: 3.4',
                 'Programming Language :: Python :: 3.5',
                 'Programming Language :: Python :: 3.6',
                 'Programming Language :: Python :: 3.7'],
)

El parámetro download_url es un enlace a un archivo alojado con el código de tu repositorio. Github alojará esto para ti, pero solo si creas una etiqueta git tag. En tu repositorio, escribe en la línea de comandos:

git tag v0.1 -m "Agrega una etiqueta para que podamos poner esto en PyPI"

Luego, escribe el siguiente comando para mostrar la lista de etiquetas:

git tag

Deberías ver v0.1 en la lista.

Por último escribe el siguiente comando para actualizar tu código en Github con la información de etiqueta más reciente:

git push --tags origin master

Github creará archivos comprimidos para descargar en https://github.com/{username}/{package_name}/archive/v{tag}.tar.gz.

MANIFEST.in

Incluye archivos que se empaquetarán en al distribución del paquete.

include LICENSE.txt README.md

LICENSE.txt será el archivo que contiene la licencia y README.md será el fichero que contenga la información básica (instalación, uso…) que quieras distribuir con tu paquete.

Subir tu paquete a PyPI Test

Ejecuta:

python setup.py sdist upload -r pypitest

No debería recibir ningún error si seguiste los pasos hasta este punto, y ahora también deberías poder ver tu paquete en el repositorio PyPI de prueba. Si hay algo que no te gusta este es el momento de hacer los cambios que quieras. Eso sí, para subir el paquete de nuevo tendrás que editar el número de versión para que sea distinto al de la anterior vez.

⚠PyPI te permite borrar las versiones del paquete y subir todos las versiones que quieras, pero no editar una versión de tu paquete subida. Esto es para mantener la estabilidad de las dependencias. Es posible retirar una versión, creando la consecuente ruptura de dependencias, pero no se deja modificar para una versión de un paquete por no desvirtuar el sentido mismo del versionado.

Es posible que en algunas guía o documentación hayas visto que también se hace previo al upload un comando register:

python setup.py register -r pypitest

Ya no es necesario y no está soportado:

https://packaging.python.org/guides/migrating-to-pypi-org/#registering-package-names-metadata


Subir tu paquete a PyPI Live

Ejecuta:

python setup.py sdist upload -r pypi

Y ya, !lo has hecho! 🎉🎉🎉 Has publicado tu primer paquete en PyPI y podrá ser instalado con el gestor de paquetes pip o cualquier otro como conda.

Viewing all 2726 articles
Browse latest View live