Weblogs Código

Blog Bitix

Generar credenciales de conexión a base de datos bajo demanda con Vault

agosto 15, 2019 07:00

Una de las funcionalidades proporcionada por Vault es generar credenciales dinámicas para la conexión a bases de datos. Generar las credenciales de forma dinámica proporciona varios beneficios: no hay unas credenciales que usen las aplicaciones que tengan un tiempo de vida indefinido, las aplicaciones no necesitan guardar en su configuración las credenciales, las credenciales se rotan de forma automática y los permisos para obtenerlas se pueden revocar de forma centralizada con Vault para cuales quiera bases de datos que se utilicen. Soporta las bases de datos más populares entre ellas postgres.

Vault
PostgreSQL

Las base de datos para proteger los datos realizan autenticación del usuario que se conecta. Normalmente utilizando un usuario y contraseña, una vez autenticado el usuario mediante permisos se realiza la autorización de las operaciones que puede realizar, a que bases de datos se puede conectar, que tablas puede acceder y que operaciones puede realizar.

Este modelo de autenticación tiene algunos inconvenientes. Uno de los inconvenientes es que los usuarios y contraseñas para mayor seguridad han de cambiarse con cierta frecuencia para evitar que si las credenciales quedan comprometidas no puedan utilizarse indefinidamente. Otro problema es que cada aplicación ha de conocer las credenciales de la base de datos, esto hace que haya múltiples posibilidades de que las credenciales queden comprometidas. Por otro lado el uso de las credenciales no queda registrado de forma centralizada que es necesario para saber ante una brecha de seguridad qué datos han sido accedidos y por quien.

La herramienta Vault de HashiCorp da solución a estos problemas generando credenciales de acceso a las bases de datos de forma dinámica, bajo demanda y con un tiempo de concesión limitado. Las credenciales tiene un tiempo de vida limitado si no se renueva su concesión y la generación de las credenciales queda registrado. La forma que tiene Vault de generar credenciales de forma dinámica en una base de datos relacional como postgres es conectarse a la base de datos con un usuario con permisos para generarlas y ejecutar una sentencia SQL que crea las credenciales.

Para permitir a Vault generar credenciales de conexión hay que activar el backend de bases de datos, configurarlo con la sentencia SQL que se utilizará para generar las credenciales y crear el rol de Vault que genera las credenciales cuando se le solicite. En este ejemplo se muestra para la base de datos postgres pero Vault también soporta otras bases de datos como MySQL. En el ejemplo la base de datos postgres se ejecuta en un contenedor de Docker en el que se asignan el usuario y contraseña del usuario root que utiliza Vault para generar las credenciales de forma dinámica.

Con las siguientes comandos se inicia Consul y Vault.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ consul agent -dev
==> Starting Consul agent...
==> Consul agent running!
Version: 'v1.5.0'
Node ID: '38d4f541-0958-6d7d-d49e-a31a15987286'
Node name: 'archlinux'
Datacenter: 'dc1' (Segment: '<all>')
Server: true (Bootstrap: false)
Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, DNS: 8600)
Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false
 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
$ vault server -dev -config vault.hcl
==> Vault server configuration:
Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: info
Mlock: supported: true, enabled: false
Storage: consul (HA available)
Version: Vault v1.1.1
Version Sha: a3dcd63451cf6da1d04928b601bbe9748d53842e
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.
You may need to set the following environment variable:
$ export VAULT_ADDR='http://127.0.0.1:8200'
The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.
Unseal Key: jeW10eak6TxJzH2qFnwk7bWk7HcpDXd3KQOobi1rZTQ=
Root Token: s.0YRcRzojVcPG8LbbzyUd1MEA
Development mode should NOT be used in production installations!
1
2
3
4
5
6
ui = true
storage "consul" {
address = "127.0.0.1:8500"
path = "vault"
}

La base de datos se inicia en un contenedor de Docker, se crea una base de datos y una tabla.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ docker run -it -p "5432:5432" -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres postgres:alpine
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2792b13c36c1 postgres:alpine "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 0.0.0.0:5432->5432/tcp distracted_keldysh
$ docker exec -it 2792b13c36c1 bash
bash-5.0# psql -U postgres
psql (11.4)
Type "help" for help.
postgres=# CREATE DATABASE app;
postgres=# \connect app
You are now connected to database "app" as user "postgres".
app=# CREATE TABLE product (
id bigint PRIMARY KEY,
name varchar(256) NOT NULL
);
app=# \dt
List of relations
Schema | Name | Type | Owner
--------+---------+-------+----------
public | product | table | postgres
(1 row)
$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 2792b13c36c1
172.17.0.2

En Vault hay que crear la configuración para conectarse a la base de datos y un rol que contiene la configuración para generar las credenciales y permitir obtenerlas, básicamente es un sentencia SQL con el nombre del usuario y contraseña, los permisos que se le asignan y el tiempo de concesión.

1
2
3
$ export VAULT_ADDR=http://127.0.0.1:8200
$ vault login s.0YRcRzojVcPG8LbbzyUd1MEA
$ vault secrets enable database
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ vault write database/config/app \
 plugin_name=postgresql-database-plugin \
 allowed_roles="app" \
 connection_url="postgresql://{{username}}:{{password}}@localhost:5432/?sslmode=disable" \
 username="postgres" \
 password="postgres"
$ vault write database/roles/app \
 db_name=app \
 creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
 default_ttl="1h" \
 max_ttl="24h"

Las credenciales se generan en el momento de leer una propiedad de Vault.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$ vault read database/roles/app
Key Value
--- -----
creation_statements [CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO "{{name}}";]
db_name app
default_ttl 1h
max_ttl 24h
renew_statements []
revocation_statements []
rollback_statements []
$ vault read database/creds/app
Key Value
--- -----
lease_id database/creds/app/rFFlNmpNoxezccTVh3WufZOT
lease_duration 1h
lease_renewable true
password A1a-6hRTGNaShFIEGLvp
username v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370

En postgres la conexión desde la máquina local se permiten sin necesidad de credenciales, para simular realizar la conexión desde otra máquina hay que iniciar otro contenedor. En la conexión se utilizan las credenciales que ha proporcionado Vault. Dado que se realiza una operación de red hay que desactivar el firewall del sistema o permitir la conexión al puerto de la base de datos que en postgres es el 5432 si fuera necesario. Listando los usuarios de la base de datos con el comando \du se muestra el creado por Vault y si tiempo de validez.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$ docker run -it postgres:alpine bash
bash-5.0# PGPASSWORD=A1a-6hRTGNaShFIEGLvp psql -U v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370 -h 172.17.0.2 -d app
psql (11.4)
Type "help" for help.
app=> \dt
List of relations
Schema | Name | Type | Owner
--------+---------+-------+----------
public | product | table | postgres
(1 row)
app=# \du
List of roles
Role name | Attributes | Member of
--------------------------------------------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370 | Password valid until 2019-08-15 09:22:55+00 | {}
app=> quit

Si el usuario y contraseña no es correcto no se permite la conexión a la base de datos.

1
2
bash-5.0# PGPASSWORD=tampered psql -U v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370 -h 172.17.0.2 -d app
psql: FATAL: password authentication failed for user "v-root-app-ydbbHqVq1gYQqsUxMuIc-1565857370"

En las aplicaciones Java que utilizan Spring el proyecto Spring Cloud Vault proporciona las utilidades para simplificar en gran medida la obtención de las credenciales a la base de datos utilizando Vault.

Esto permite que únicamente Vault conozca la cuenta root de la base de datos o una con suficientes permisos para crear credenciales, las aplicaciones no almacenan en su configuración las credenciales para conectarse la base de datos solo las de Vault que le permiten obtener unas credenciales para la base de datos con un tiempo de vida limitado y que pueden revocarse desde Vault en caso de un problema de seguridad para cuales quiera bases de datos que se utilicen.

» Leer más, comentarios, etc...

Picando Código

[Libro] Norse Mythology – Neil Gaiman

agosto 13, 2019 12:00

Cuando era chico me interesaba mucho la mitología nórdica. Creo que mi primer acercamiento fue gracias a un libro de historia en inglés que tenía en la época de la escuela que hablaba sobre vikingos, anglosajones, galos y demás. También me interesaba mucho la mitología griega y romana, y siempre estuve en contacto con ellas habiendo crecido leyendo Astérix.

Pero ya de más grande descubrí otra fuente de aventuras mitológicas con la interpretación de Marvel en los cómics de Thor: el Dios del Trueno. Y fue gracias a la versión de Jack Kirby y Stan Lee también que Neil Gaiman – famoso escritor inglés autor de The Sandman, American Gods, y más – descubrió Asgard y sus habitantes.

Norse Mythologies es una novela en la que Gaiman cuenta varios de los mitos conocidos de los dioses de Asgard. Surgieron en Alemania y se expandieron por Escandinavia y mediante los Vikingos a Orkey, Escocia, Irlanda y el norte de Inglaterra. Como comenta en la introducción, todavía quedan rastros de esto en el idioma Inglés, como por ejemplo en los días de la semana: Tuesday (Tyr), Wednesday (Odin), Thursday (Thor) y Friday (Frigg).

Neil Gaiman - Norse Mythology

Muchos mitos se transmitieron por cuentos populares, historias pasadas de generación en generación, poemas, y a veces por escrito. Pero varios se perdieron en la historia, por lo que parte del objetivo de la publicación es la preservación y reinterpretación.

El primer capítulo es una introducción a los protagonistas, seguido de dos capítulos donde se explica el comienzo de todo según lo define la mitología nórdica. Vamos a conocer a Odín, Thor, Loki, Mjolnir (y su origen), Yggdrasil -el árbol de la vida que conecta y une a los nueve mundos- y cómo se formó y compone ese universo. La mayoría de los nombres van a resultar familiares si han estado expuestos a mitología nórdica antes, aunque sea sólo por los cómics o películas de Thor.

Los siguientes capítulos son cuentos individuales. Son muy entretenidos y si bien tienen un orden cronológico que hace que el libro se lea mejor en orden, también se pueden leer los cuentos independientemente. Es más, es un buen libro para tener y cada tanto releer alguno de los cuentos que más nos gustaron. El último capítulo nos cuenta sobre la batalla final, el fin y el principio: Ragnarok.

Hay historias crueles, de aventuras, engaños y fantasía. Son extremadamente entretenidas y el autor logra definir bien la personalidad de los distintos personajes. Me enganchó tanto que leí el libro entero en un día. Con Them me sorprendí al descubrir que todavía tenía la capacidad de leer un libro en 2 días, con éste fue mejor. Es sumamente atrapante y no muy largo, capaz por eso me quedé como con gusto a poco. Al terminarlo pensaba ¿ésos son todos los cuentos que se conocen de la mitología nórdica? Como con ganas de leer más. Pero de repente esa era la idea, escribir un libro más accesible que un libro de historia, para conocer los mitos y despertar la curiosidad por saber más.

Así que por mi parte es un libro muy recomendable si les interesa la mitología nórdica. Probablemente busque algún otro título relacionado en breve porque es un tema que me atrae mucho y me gustaría leer más. Norse Mythologies se puede conseguir en Amazon ES y Amazon US.

Como anécdota, les cuento cómo lo obtuve. Lo tenía agregado a mi wishlist de Amazon desde que se anunció. Para mi sorpresa, un día me llegó de regalo al trabajo. Una usuaria muy conforme de mi plugin List Category Posts me lo envió como regalo. No creo que lea ésto, pero ante la mínima posibilidad de que sí, muchas gracias Margaret por el libro, ¡lo disfruté mucho!

Regalo: Norse Mythology - Neil Gaiman

» Leer más, comentarios, etc...

Picando Código

198X – The Game

agosto 12, 2019 12:00

198X

Gracias a la revista Retro Gamer me enteré de la existencia de 198X leyendo una entrevista al escritor y director: Tobias Bjarneby. 198X fue diseñado como un homenaje a los 80’s y el placer de visitar la sala de maquinitas (arcades, fichines, y demás nombres):

Bienvenido a Suburbia, justo en las afueras de City, en algún momento de 198X. Este es el viaje de Kid, un adolescente estancado entre las limitaciones de la inocente juventud y las obligaciones de la inevitable adultez. La historia se desarrolla cuando Kid descubre el local de arcades – encontrando nuevos mundos, y nuevo sentido, en los video juegos. Por cada visita al arcade – cada juego descubierto, cada movimiento dominado, cada demonio vencido – Kid se hace más fuerte. Y las líneas entre el juego y la realidad se empiezan a difuminar…

Lo interesante del juego es que no se trata simplemente de una historia con la que varios podrían sentirse identificados. Es la excusa para incluir 5 juegos del estilo de arcades de la época:

Beat ‘em up – Inspirado en títulos como Streets of Rage, Final Fight, Double Dragon, y demás.

Shoot ‘em up – En el estilo de R-Type, Gradius y otros juegos del género.

Carreras – Con una evidente influencia directa de Out Run.

Ninja – Con toques de Ninja Gaiden, Shinobi y más juegos del estilo.

RPG – Juego de rol que no me acuerdo los nombres de ninguno de los títulos que conozco de este estilo específico de RPG.

YouTube Video

Es un proyecto bastante ambicioso, pero la verdad que se ve excelente, muy fiel a los distintos estilos que quisieron reproducir. Los reviews en Steam vienen siendo generalmente positivos. Conceptualmente me encanta la idea de contar una historia a través de un juego mediante otros juegos.

Durante la campaña en Kickstarter que financió su desarrollo y publicación, decidieron dividir el juego en dos partes. La primera parte -que está disponible ahora- es aparentemente bastante corta y puede terminarse en poco más de una hora. Si al proyecto le va bien, con suerte tendremos una segunda parte todavía más grande.

Se puede encontrar en Steam y GOG para Windows. No hay versión para Linux, y según los reportes en ProtonDB, no funciona tan bien con Proton (la herramienta de Steam que permite jugar juegos de Windows en Linux con Wine). También está disponible en PlayStation 4, y más adelante este año va a salir en XBox y Nintendo Switch. Así que en mi caso toca esperar que esté disponible en Switch para probarlo.

Es un juego con terrible potencial y espero con ansias poder probarlo.

» Leer más, comentarios, etc...

Blog Bitix

Smartcards en vez de discos para una futura generación de consolas

agosto 11, 2019 01:00

Todo indica que el formato físico de los juegos está a punto de desaparecer en una futura generación de consolas no muy lejana como ya ha ocurrido en gran medida con la música o los libros. Pero los juegos digitales crean otros problemas que los juegos físicos no tienen y es el motivo por el que algunos usuarios son contrarios a solo los digitales, ¿sería posible solución a los problemas de los juegos físicos y de los digitales? Aquí teorizo sobre este tema y planteo una solución, las smartcards.

Play Station
Xbox

Hasta recientemente la forma de distribuir los juegos en las consolas y PC ha sido a través de cartuchos y discos CD, DVD, y Blu-Ray, si embargo con la masificación de internet y con anchos de banda asequibles para las conexiones residenciales de los usuarios de entre 30 Mbps, 600 Mbps y en un futuro aún más parece que es el momento de que los fabricantes y algunos usuarios estén prefiriendo un modelo de distribución basado en la descarga digital por internet. De hecho Microsoft con la Xbox One All-Digital ya ni siquiera posee lector de discos y todos los juegos ha de ser adquiridos a través de su tienda, la Play Station de Sony también posee su modelo de distribución digital.

El lector de discos junto con el posible sobrecalentamiento es uno los causantes de el mayor número de averías. Tarde o temprano el lector falla al ser algo mecánico, más temprano cuanto más uso se le da. Es uno de los motivos por los que si yo tuviese una consola me platearía adquirir los juegos digitales en vez de físicos estando a un precio similar o incluso un poco mayor, esto no quiere decir que considere que los digitales deberían ser mas baratos porque la distribución de los mismos es más sencilla y barata. En la actualidad de momento no hay interés en mantener una competencia de precios entre la tienda digital y la física, salvo ofertas puntuales aunque los físicos de segunda mano se suelen encontrar a precios menores que en las ediciones digitales. Otro motivo por el prefiero los juegos digitales es porque me ocupan espacio y en mi caso no estoy apegado a tener las cosas tangibles para adorarlas como si fuesen totems de dioses, vamos que no necesito verlas colocadas en una balda cogiendo polvo. Los discos pueden estropearse con rayadoras y necesitan de todas formas descargar actualizaciones con contenido mejorado o adicional.

Sin embargo, algunos usuarios prefieren los discos por el apego sentimental que pueden tenerle al objeto por los buenos momentos de diversión que les ha proporcionado. Otros quizá por coleccionismo. Algunos prefieren poseer algo tangible de lo que compran y en algún caso porque con razón consideran que en el caso de los digitales es la empresa la que realmente posee el juego y no quieren que sea la empresa la que tenga ese poder, si la empresa desaparece todo los bienes digitales que adquirieron ¿que pasaría con ellos? ¿también desaparecerían? Si Microsoft decide cerrar la división de juegos porque no está obteniendo el rendimiento esperado todas las personas podrían perder sus posesiones digitales.

Las smartcards como hipotética solución

De esto que das un paseo andando o estás cansado a punto de dormir y después de haber un par de vídeos anteriormente o hablado con alguien sobre el tema le das una vuelta y se te ocurre una forma de como solucionar un problema, en este caso el de la posesión física y compatibilizarlo con las descargas digitales. He estado viendo dos vídeos en dos canales de YouTube que hablan precisamente de este tema, uno de tonondor y otro de Vídeo Blog (seguro que hay más de otros usuarios de YouTube), y como solución a los problemas anteriores de fiabilidad del lector de discos y la posesión física frente a la digital se me ha ocurrido que una solución podría ser el reemplazo de los discos por una smartcard.

El concepto de una smartcard es un objeto tangible como una tarjeta de crédito que correspondería a la posesión física de un disco al que reemplazaría, al contrario de los discos no tendría almacenamiento sino que simplemente sería algún tipo de credencial de que su poseedor concede el derecho a usar un juego. Lógicamente esta smartcard debería estar dotada de suficientes medidas de seguridad para que no pueda ser suplantada. El lector de disco con partes mecánicas sería reemplazado por un lector de tarjetas inteligentes por contacto o contacless como ya funciona numerosas tarjetas de crédito y bonos de medios de transporte.

Quedada resuelta la posesión física de los juegos con la smarcard, queda como descargarlos y en este modelo que planteo la descarga se realizaría a través de internet tal como ocurre en los juegos digitales. Una vez descargado el juego ya no sería necesaria la conexión a internet y solo introducir la smartcard en cada inicio del juego, en cada 3 inicios o cada 3 días para evitar la incomodidad de tener que usar la smartcard en cada inicio.

Resuelta la posesión física y la descarga queda como poseer la imagen de juego como si de un disco físico se tratase y podría ser dando la posibilidad de guardar la imagen instalable de juego en un disco duro externo ya sea en una imagen ISO u otro formato de imagen. Nuevamente tanto la smartcard como la imagen de disco debería estar dotada de suficientes medidas de seguridad para que estos no puedan ser alterados, suplantados o usados de forma ilegítima pero si lo han hecho con los discos blu-ray no veo por que no puedan hacerlo con el sistema de smartcard.

Queda resolver como poder descargar las imágenes de los juegos en una fecha tan posterior del lanzamiento de la consola como 20 años después pero mientras la seguridad esté en la posesión de la smartcard como forma de poder jugar al juego en la consola incluso no tendría por que ser Sony, Microsoft o Steam las que distribuyan las imágenes de los juegos y podría ser cualquier otra entidad o usuario incluso mediante torrent.

Con las smartcards el mercado de segunda mano del que se nutren algunas tiendas como forma alternativa de negocio a la venta de juegos nuevos precintados podría seguir funcionando exactamente igual cosa que con los digitales es susceptible de desaparecer. Por supuesto, las smartcards serían algo más pequeñas que los discos, posiblemente tan fáciles de crear y con un coste no muy diferente.

Eliminar el lector de discos tiene la ventaja adicional de que seguramente el lector de smartcards sería mucho más pequeño con el consiguiente ahorro en tamaño de la PS4 y también peso.

» Leer más, comentarios, etc...

Blog Bitix

Iniciar una aplicación de Spring Boot en un puerto aleatorio

agosto 09, 2019 04:00

En una arquitectura basada en microservicios es normal iniciar varias instancias de un mismo servicio, si están en la misma máquina ha de asignarse a cada instancia un puerto diferente. Asignar los puertos manualmente no es recomendable cuando se quieren varias instancias, Spring Boot ofrece la funcionalidad de iniciar la aplicación en un puerto aleatorio.

Spring
Java

Mediante configuración se puede especificar el puerto en el que se desea iniciar una aplicación de Spring Boot que ofrece un servicio de red. El puerto por convención suele ser el 8080 y la propiedad de configuración de Spring Boot para modificarlo es server.port.

1
2
server:
 port: ${port:8080}
1
2
3
4
$ ./gradlew service:run
...
2019-08-09 17:02:40,417 INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer Tomcat started on port(s): 8080 (http) with context path ''
...

Cuando se tiene únicamente una aplicación este puerto por defecto es suficiente pero si se desean iniciar varias instancias de una aplicación o microservicio en una misma máquina es necesario asignar a cada una de ellas un puerto diferente para que no haya conflictos a usar el mismo puerto de red. Se puede hacer manualmente aunque con muchas instancias también se puede dejar a Spring Boot elegir un puerto aleatorio.

Para dejar a Spring Boot elegir el puerto de forma aleatoria basta con especificar el puerto con valor 0 en la propiedad de configuración server.port.

1
2
server:
 port: ${port:0}
1
2
3
4
$ ./gradlew service:run --args="--port=0"
...
2019-08-09 17:02:40,417 INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer Tomcat started on port(s): 45871 (http) with context path ''
...

Usando un servicio de registro y descubrimiento como Eureka el servicio registra su ubicación y los servicios que quieran acceder a él obtendrán del mismo servicio de registro y descubrimiento su ubicación, de forma que para los clientes es transparente en qué puerto se inicie.

Sin embargo, por algún motivo con Eureka los servicios no se registran en el puerto aleatorio en el que realmente se inician sino que se registran incorrectamente en el puerto 0, quizá utilizando Consul el servicio de Spring Boot si se inicie en un puerto aleatorio.

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 ./gradle-run.sh.

» Leer más, comentarios, etc...

Picando Código

Versión 0.3 de Gleam ✨ – el lenguaje de programación funcional estáticamente tipado en BEAM

agosto 09, 2019 12:00

En abril se publicó la primera versión pública de Gleam. Esta semana se publicó la versión 0.3 que trae varios cambios desde entonces.

Gleam

Namespaces de módulos

Los módulos se pueden contener en espacios de nombres permitiendo el uso de nombres de módulos cortos y convenientes sin riesgo de colisiones con otros módulos de Gleam o Erlang. Para usar espacios de nombre creamos un directorio con el nombre de namespace en el directorio src/ y ponemos el módulo ahí. Como ejemplo:

src/
└── vgclub
    ├── persona.gleam
    └── consolas
        ├── nintendo.gleam
        ├── sega.gleam
        └── atari.gleam

Una vez creados, los módulos se pueden traer al scope con la sentencia import:

import vgclub/persona
import vgclub/consolas/nintendo
fn jugar_consola(alicia) {
  persona:jugar(alicia, nintendo:new())
}

Ahora es posible usar varios módulos con el mismo nombre, y para más conveniencia se les puede dar un nombre a los módulos al importarlos.


import space/rocket as spaceship
import salad/rocket as leafy_green

Anotaciones de tipo

La inferencia de tipos de Gleam no requiere anotaciones para entender los tipos de todo tu código y provee seguridad de tipo completa, pero podemos querer agregar anotaciones para documentación, o para especificar tipos más restrictivos que Gleam puede inferir de otra forma.

Se ven algo así:

fn is_empty(list: List(a)) -> Bool {
  list == []
}

Instalación más sencilla

Ahora podemos descargar binarios precompilados para Linux y OSX de Glean desde la página de releases de GitHub, en vez de tener que tener instalado Rust y compilar el compilador desde el código fuente.

Victor Borja creó un plugin de Gleam para el gestor de versiones asdf, así que para los usuarios de asdf instalar Gleam es tan fácil como asdf install gleam v0.3.0.

Para los fans de Docker el compilador de Gleam ha sido empaquetado como imagen Docker con el tag lpil/gleam.

Creación más sencilla de proyectos

Anteriormente los proyectos de Gleam se creaban usando un plugin de rebar3. Esto funcionaba, pero era una cosa más a instalar, y no había forma de asegurarse que tuvieras una versión al día del plugin que coincidiera con tu instalación de Gleam.

Ahora, la creación de proyectos se maneja con el binario de gleam mismo, así que para empezar con Gleam ejecuta gleam new mi_nuevo_proyecto y generará todo lo que se necesita.

Si tienes rebar_gleam instalado, es seguro eliminarlo de tu ~/.config/rebar3/rebar.config ya que no se usa más.

El resto

Además de estas características, ha habido varias mejoras a la calidad de mensajes de error, el código generado, y varios bugs corregidos.

Para probar la nueva versión de Gleam, ve a la página de instalación. Su autor está buscando feedback sobre cómo usamos Gleam para seguir mejorándolo.

Code BEAM lite Berlin

El 11 de octubre Louis Pilfold, el autor de Gleam, va a estar dando una charla sobre el lenguaje de programación en Code BEAM lite Berlin.

Sitio web de Gleam

» Leer más, comentarios, etc...

Coding Potions

Cómo gestionar una página web. Claves para el éxito

agosto 08, 2019 12:00

Introducción

Hoy en día es muy común que cualquier empresa tenga su propia web corporativa, con la que incluso llegan a dar servicios, pero lo cierto es que no todas triunfan debido a una mala gestión de la web. En el artículo de hoy te voy a enseñar algunas claves para una correcta gestión de tus páginas web.

Lo más recomendable es que todo lo gestiones tu mismo para un mayor control sobre tu producto, pero, para una óptima gestión de insfraestructuras tecnológicas es indispensable una buena administración de sistemas IT lo que te ahorrará tiempo y esfuerzo.

Lo que voy a contar a continuación son una serie de consejos, ideas y cosas a tener en cuenta para que no tengas ningún problema a la hora de gestionar una página web.

Bases de datos y backups

Administración de bases de datos

Una de las partes cruciales de tu página web son los datos. Los datos pueden ir desde los usuarios registrados en tu web, tus productos disponibles si se trata de un e-commerce, posts, etc.

Imagina que por un fallo inexperado se vacía la base de datos. Si esto ocurre lo más probable es que lo pierdas todo y te quedes sin nada. Dependiendo de tu sector, lo más normal es que tengas automatizada la creación de backups cada cierto tiempo (dependiendo del sector de tu negocio puede ser más tiempo o menos tiempo pero mínimo un backup al día).

Los backups no son más que copias en disco de tu base de datos para que en caso de error la puedas recuperar con facilidad. Hay sectores con datos muy delicado que hacen backups en distintos servidores y discos para asegurar que no se pierde, incluso algunos hacen copias en cintas físicas para evitar errores.

En gitlab, por ejemplo, un día tuvieron muchos problemas porque uno de sus trabajadores borró bases de datos con código y recursos de producción. Mucho lo lograron recuperar pero hubo parte que perdieron: https://about.gitlab.com/2017/02/01/gitlab-dot-com-database-incident/

Seguridad

Administración de la seguridad de una web

Otro factor clave para la gestión de páginas web es la seguridad. Dependiendo del sistema que tengas montado tienes que testear posibles bugs y fallos que se puedan producir en tu página web. Un fallo de seguridad sería fatal para tu página web.

Los fallos pueden ir desde usuarios que pueden acceder a partes de tu web que no deberían (al panel de control por ejemplo), accesos directamente al servidor y su sistema de carpetas, ataques DDoS, etc.

Toda medida de seguridad es poca, y dependerá del sistema y cómo tengas montada tu infraestructura, aunque hay ciertas pruebas que se pueden hacer a todas las páginas web.

Lo que es indispensable es que conozcas a la perfección tu infraestructura. Si tienes un hosting contratado, debes ponerte en contacto con la empresa para saber con exactitud cómo tienen montados los sistemas y qué medidas de seguridad tienen. Si tu mismo controlas la infraestructura tienes que mirar cada punto de acceso y posibles fallos en el sistema.

Lo más normal en empresas grandes es que la propia empresa tenga un departamento de sistemas y seguridad. Si no cuentas con uno, lo que se suele hacer es contratar servicios de auditoría de sistemas y páginas web.

Backend y APIS

Administración de servidores y backend

Si has montado un sistema propio, lo que tienes que comprobar y monitorear es posibles caídas del servicio. Si un página web es dependiente del backend o servidor y éste falla tu aplicación o página web no va a funcionar.

Un aspecto a tener en cuenta es la protección de la API. Si la API se va a encargar de servir datos a páginas solo visibles para ciertos usuarios, tenemos que encargarnos de asegurar que esas llamadas están protegidas mediante autorización. Si la API es abierta tenemos que tener cuidado por si alguien decide explotarla y saturarla.

Otro apartado clave son los logs. Deberías tener montado un sistema de logs para tenerlos todos controlados y accesibles en un solo lugar. Tu backend debería ser capaz de almacenar en esos logs los errores producidos cuando se usa la web.

Una forma efectiva de evitar fallos es tener una buena suite de tests en el código para que cada vez que se suba a producción una nueva versión se pasen todos los tests en busca de fallos en el código.

Lo que se suele hacer con las APIS es un versionado adecuado para que los endpoints no fallen debido a la subida de nuevas versiones. Por ejemplo si el frontend está usando una versión 2 de la API, no debería cambiar de versión hasta que no se a adaptado a las nuevas funcionalidades de la versión 3.

Frontend

Administración de proyectos frontend

Como no podía ser de otra forma, en el frontend también se pueden producir errores que pueden resultar desagradables a tus usuarios. Desde pequeños errores en estilos, pasando por páginas que no se ven bien, hasta páginas que si siquiera funcionan como debería.

Al frontend se añade otros problemas, los problemas causados por los estilos responsive. Ésto hay que tenerlo en cuenta y estar pendiente de cuando se suben cosas nuevas a producción para revisarlo y evitar problemas relacionados con esto,

Como pasa en el lado del servidor, también es importante cada cierto tiempo mirar y actualizar las posibles versiones de las librerías que se estén usando en ese momento para mitigar posibles errores. Recomiendo el uso de un gestor de librerías javascript como npm o yarn.

Otro punto importante son las llamadas HTTP, tanto en backend como en front se tienen que controlar bien para gestionar posibles fallos. Una práctica recomendada consiste en proteger todas las llamadas a servidor con token o autorización. También es importante limitar las APIS para que un usuario no pueda desarrollar un bot o script que explote la API.

Contenidos

Administración de contenidos online

Si tu modelo de negocio es una aplicación web este apartado no te será de mucha ayuda, pero si tienes montado una web tipo blog o una web más enfocada a los contenidos, vas a necesitar una forma de gestionarlos sin tener que andar tocando código.

Hoy en día existen muchos CMS que te facilitan la vida a la hora de gestionar el código para las páginas web, e incluso se encargan de gestionar la base de datos como por ejemplo, Wordpress del que hablaremos más adelante.

Si tu web es muy grande y tienes un backend propio lo mejor es que te montes tu propio sistema de gestión de contenidos, es decir, páginas internas en las que la gente pueda añadir, editar y borrar contenido para tu página web.

Para Google y los usuarios lo mejor es que cada poco tiempo actualices los contenidos ta creados, los amplíes si hace falta y arregles sus posibles errores.

Wordpress, todo en uno. No todo es perfecto.

Administración de contenidos online

Muchas veces se recomienda Wordpress para administrar páginas web y contenidos ya que ofrece un “todo en uno” y en eso estoy de acuerdo. Con wordpress te vas a evitar muchos dolores de cabeza y no vas a tener que mirar tantas cosas por eso es ideal para páginas no muy grandes.

Para páginas más grandes la cosa -se queda algo corta. Aunque es cierto que todavía hay grandes medios que lo utilizan, a la hora de la verdad lo mejor, como he dicho antes es montar tu propio sistema a tu gusto, aunque te cueste esfuerzo y tiempo.

Por experiencia se que con Wordpress, va a haber ocasiones en las que se te quede algo corto o que necesites funcionalidad especifica para crear ciertas cosas. Aunque es cierto que puedes desarrollar plugins y puedes meter código, lo cierto es que vas acabas perdiendo también mucho tiempo.

Otro problema de Wordpress es que lleva mucho tiempo y es muy popular. Que sea tan popular está bien porque hace que haya mucha comunidad y si tienes un problema alguien te lo sepa resolver, pero, al usarse mucho, hace que algunos quieran hackearlo.

Y es que para evitar hackeos otra cosa que tienes que gestionar es los plugins y los temas de Wodpress, porque está visto que con temas y plugins antiguos te expones a mucho riesgo de ser hackeado.

Conclusiones

No se ha comentado, pero también hay que tener en cuenta el escalado de la web. No es lo mismo una web para 10 usuarios que para 10.000 usuarios concurrentemente.

Las empresas grandes tienen sistemas de autoescalado automático para que en caso de afluencia de gente, se repliquen las bases de datos y los servidores para ser capaces de gestionar tanto volumen de gente.

La gestión de las páginas web ya creadas es una tarea que no se puede subestimar, es casi tan importante o más que la creación de la página web.

» Leer más, comentarios, etc...

Picando Código

GNOME y KDE co-organizan el Linux App Summit en Noviembre

agosto 06, 2019 12:00

La fundación GNOME y KDE e.V se enorgullecen en anunciar Linux App Summit 2019. El Linux App Summit (LAS) se llevará a cabo en Barcelona desde el 12 al 15 de Noviembre de 2019.

Linux App Summit

LAS es el primer evento colaborativo co-organizado por las dos organizaciones desde el Desktop Summit en 2009. Ambas organizaciones están ansiosas por juntar a sus comunidades en construir un ecosistema de aplicaciones que trascienda las distribuciones individuales y amplíe el mercado para todos los involucrados.

KDE y GNOME dejarán de tener un rol pasivo en el sector del escritorio libre. Con la influencia conjunta de ambos proyectos de escritorio, LAS guiará el crecimiento del escritorio Software Libre y de Código Abierto (FOSS) alentando la creación de aplicaciones de calidad, buscando oportunidades de compensación para desarrolladores FOSS, y generando un mercado vibrante para el sistema operativo Linux.

El director ejecutivo de GNOME, Neil McGovern dice, «LAS representa uno de varios pasos hacia un ecosistema de escritorio próspero. Al asociarnos con KDE mostramos el deseo de construir el tipo de ecosistema de aplicaciones que demuestra que el Software Libre y de Código Abierto son importantes; la tecnología y organización que construyamos para alcanzar esto es valiosa y necesaria.«, LAS será la intersección donde desarrolladores de aplicaciones, diseñadores, ingenieros del espacio de usuario y kernel trabajen juntos construyendo un ambiente que apunta a crear un nuevo mercado para aplicaciones en Linux.

«A través de los años hemos construido soluciones geniales que usan millones de personas en el mundo. Ha sido cuando hemos trabajados juntos que hemos logrado ser más grandes que la suma de las partes. En conjunto con NOME, contando con la colaboración de muchas distribuciones y desarrolladores de aplicaciones, tendremos la oportunidad de trabajar lado a lado, compartir nuestras perspectivas y ofrecer la plataforma sobre la que será construida la próxima generación de soluciones.«, Aleix Pol Gonzalez, Vice-Presidente de KDE e.V sobre el esfuerzo inaugural de LAS.

Como la primera conferencia de su tipo, los temas en los que se centrará LAS serán crecer el ecosistema de aplicaciones para Linux así como proveer una plataforma para que otros compartan ideas y tecnología. Con eso en mente, los temas en los que estamos interesados son:

* Crear, empaquetar y distribuir aplicaciones
* Diseño y usabilidad
* Comercialización
* Comunidad / Legal
* Plataforma
* Ecosistema de aplicaciones Linux

El CFP está abiero y cierra el 31 de Agosto. Se pueden enviar ideas de charlas en éste enlace.

«Estoy emocionado de ver a GNOME y KDE trabajando juntos en LAS, y creo que el evento ayudará a sentar bases sólidas para desarrollo colaborativo a través de proyectos que beneficiaría a los usuarios de Linux de todas las distribuciones y en cualquier dispositivo compatible. Espero ver amplio soporte de la comunidad por el evento y, como usuario, ansío cosechar los beneficios de las semillas que se han sembrado.» – Christel Dahlskjaer, líder de proyecto de Private Internet Access y freenode.

Esperamos verlos a todos en Barcelona y construir el ecosistema de aplicaciones juntos.
Para más información sobre LAS, por favor visita el sitio web del evento.

» Leer más, comentarios, etc...

Fixed Buffer

Descanso (Mode: ON)

agosto 06, 2019 08:00

La imagen muestra un terreno en mi pueblo y se ve una casita de paja que estoy haciendo.

Después de casi un año, ya tocan unas merecidas vacaciones, así que he pensado en dedicar la entrada de esta semana para avisaros de que me voy a tomar unas pequeñas vacaciones para descansar, estar con la familia, (y terminar la casita de paja de la foto xD).

Después de cojer fuerzas, volveremos en septiembre con varias cosillas interesantes que estoy preparando.

¡Os deseo unas buenas vacaciones a todos, y nos vemos en unas semanas!

**La entrada Descanso (Mode: ON) se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Picando Código

Agenda NotPinkCon 2019 – la conferencia de seguridad informática en Buenos Aires, Argentina

agosto 05, 2019 02:30

Ya está publicada la lista de oradoras y agenda de NotPinkCon, la conferencia de seguridad informática a realizarse el 30 de agosto en Buenos Aires, Argentina.
NotPinkCon

El evento posee un enfoque técnico y la entrada es libre y gratuita para todas las personas que deseen formar parte. Va a haber charlas en español e inglés sobre varios temas como: ¿qué tan seguro es el código abierto?, herramientas de código abierto para la investigación de amenazas, seguridad en la nube, seguridad móvil, Raspberry Pi, ciberespionaje e Internet Of Things.

Visiten la agenda completa y regístrense por acá. Pueden seguir a @NotPinkCon en Twitter para estar al tanto de todas las novedades.

» Leer más, comentarios, etc...

Blog Bitix

Implementar tolerancia a fallos con Resilience4j

agosto 02, 2019 03:00

Resilience4j
Java

Hystrix ha sido una de las primeras librerías en Java disponibles para implementar varios patrones de tolerancia a fallos en los microservicios. Desde hace un tiempo ha pasado a modo mantenimiento en el que ya no se incluyen nuevas características, una de las librerías recomendadas como sustituta es Resilience4j. Resilience4j proporciona las características similares con algunas ventajas adicionales.

Los patrones útiles para aumentar la tolerancia a fallos debido a problemas de red o fallo de alguno de los múltiples servicios son:

  • Circuit breaker: para dejar de hacer peticiones cuando un servicio invocado está fallando.
  • Retry: realiza reintentos cuando un servicio ha fallado de forma temporal.
  • Bulkhead: limita el número de peticiones concurrentes salientes a un servicio para no sobrecargarlo.
  • Rate limit: limita el número de llamadas que recibe un servicio en un periodo de tiempo.
  • Cache: intenta obtener un valor de la cache y si no está presente de la función de la que lo recupera.
  • Time limiter: limita el tiempo de ejecución de una función para no esperar indifinidamente a una respuesta.
  • Además de la funcionalidad de métricas.

La ventaja de Resilience4j es que todos estos patrones para los microservicios se ejecutan en el mismo hilo que el principal y no en un aparte como en Hystrix. Su uso además no requiere de crear clases específicas para hacer uso de los patrones y pueden emplearse las funciones lambda incorporadas en Java 8.

Este artículo actualiza el ejemplo que usaba Spring Boot y Spring Cloud que implementé en su momento para la serie de artículos sobre Spring Cloud añadiendo una implementación del cliente de un microservicio con Resilience4j.

La configuración de Resilience4j se puede proporcionar mediante código Java, con anotaciones y con la integración para Spring Boot con parámetros en el archivo de configuración de la aplicación. La aplicación además de varias cosas de Spring Cloud para otros artículos de la serie consiste para el de este artículo en un servicio cliente y un servicio servidor que para ser tolerantes a fallos hacen uso de los patrones circuit breaker y time limiter para demostrar su uso.

Resilience4j para implementar los patrones lo que hace es decorar la función objetivo que hace la invocación del servicio. Si se quieren aplicar varios patrones hay que encadenar las decoraciones, por ejemplo, si se quiere limitar el número de llamadas salientes con bulkhead y el patrón circuit breaker hay que aplicar una decoración sobre la otra. En este ejemplo se aplica un time limiter y un circuit breaker usando código Java. La variable get es la que realmente contiene la llamada al servicio.

 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
package io.github.picodotdev.blogbitix.springcloud.client;
...
@Component
public class Resilience4jProxyService {
@Autowired
private LoadBalancerClient loadBalancer;
@Autowired
private Tracing tracing;
@Autowired
private Tracer tracer;
private CircuitBreakerConfig circuitBreakerConfiguration;
private TimeLimiterConfig timeLimiterConfiguration;
public Resilience4jProxyService() {
circuitBreakerConfiguration = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.recordExceptions(IOException.class, TimeoutException.class)
.build();
timeLimiterConfiguration = TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofMillis(2500))
.cancelRunningFuture(true)
.build();
}
public String get() {
ServiceInstance instance = loadBalancer.choose("proxy");
URI uri = instance.getUri();
String resource = String.format("%s%s", uri.toString(), "/service");
Invocation.Builder builder = ClientBuilder.newClient().target(resource).request();
...
CircuitBreaker circuitBreaker = CircuitBreaker.of("resilience4jCircuitBreakerProxyService", circuitBreakerConfiguration);
TimeLimiter timeLimiter = TimeLimiter.of(timeLimiterConfiguration);
Supplier<CompletableFuture<String>> get = () -> {
return CompletableFuture.supplyAsync(() -> {
return builder.get().readEntity(String.class);
});
};
Callable<String> getLimiter = TimeLimiter.decorateFutureSupplier(timeLimiter, get);
Callable<String> getCircuitBreaker = CircuitBreaker.decorateCallable(circuitBreaker, getLimiter);
return Try.of(getCircuitBreaker::call).recover((throwable) -> getFallback()).get();
}
private String getFallback() {
return "Fallback";
}
}

Las dependencias que hay que añadir en el proyecto son:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
plugins {
id 'application'
id 'org.springframework.boot' version '2.1.6.RELEASE'
}
mainClassName = 'io.github.picodotdev.blogbitix.springcloud.client.Main'
dependencies {
implementation platform("org.springframework.boot:spring-boot-dependencies:2.1.6.RELEASE")
implementation platform("org.springframework.cloud:spring-cloud-dependencies:Greenwich.SR1")
// Spring
 def excludeSpringBootStarterLogging = { exclude(group: 'org.springframework.boot', module: 'spring-boot-starter-logging') }
compile('org.springframework.boot:spring-boot-starter', excludeSpringBootStarterLogging)
compile('org.springframework.boot:spring-boot-starter-web', excludeSpringBootStarterLogging)
...
compile('org.springframework.cloud:spring-cloud-starter-config', excludeSpringBootStarterLogging)
...
compile('io.github.resilience4j:resilience4j-spring-boot2:0.17.0', excludeSpringBootStarterLogging)
compile('io.micrometer:micrometer-registry-prometheus:1.1.5')
...
}

Resilience4j proporciona añadidos de integración con Spring Boot y exportación de métricas para Prometheus.

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 ./gradle-run.sh.

» Leer más, comentarios, etc...

Navegapolis

Los mejores productos se obtienen cuestionando las ideas, no las personas.

agosto 01, 2019 01:53

thumb reuniones agilesEn algunas empresas es arriesgado expresar abiertamente opiniones y críticas. En ellas la agilidad no fluye, porque la falta de seguridad para manifestar las ideas propias y cuestionar las de otros produce pensamiento de grupo: organizaciones con personas que se acostumbran a modelar su opinión según lo que consideran que es el consenso del grupo, y a apoyar decisiones que individualmente considerarían desaconsejables.

Son empresas que pueden generar trabajo, pero no talento, porque como decía Steve Jobs en "The Lost Interview" los grandes productos surgen en equipos en los que se cuestionan y critican abiertamente las ideas.

 

Pero hay que tener cuidado, porque la crítica sin una cultura basada en la honestidad, el respeto y la confianza, acaba enfrentando a las personas, no a las ideas, y sólo produce tensión y desgaste.

Las siguientes citas de Ed Catmull, fundador y presidente de PixarAnimation y Disney Animation, extraídas del capítulo 5 (Sinceridad y franqueza) de su libro "CREATIVIDAD, S.A." describen muy bien el ecosistema de comunicación con la cultura necesaria para producir ideas y productos brillantes.

 

» Leer más, comentarios, etc...

Navegapolis

El talento se da mejor si no se confrontan los egos, sino las ideas.

agosto 01, 2019 01:53

thumb reuniones agilesEn algunas empresas es arriesgado expresar abiertamente opiniones y críticas. En ellas la creatividad ágil no fluye, porque la falta de seguridad para manifestar las ideas propias y cuestionar las de otros produce pensamiento de grupo: organizaciones con personas que se acostumbran a modelar su opinión según lo que consideran que es el consenso del grupo, y a apoyar decisiones que individualmente considerarían desaconsejables.

Son empresas que pueden producir trabajo, pero no innovación, porque como decía Steve Jobs en "The Lost Interview" los grandes productos surgen en equipos en los que se cuestionan y critican abiertamente las ideas.

 

Pero hay que tener cuidado, porque la crítica sin una cultura basada en la honestidad, el respeto y la confianza, acaba enfrentando a las personas, no a las ideas, y sólo produce tensión y desgaste.

Las siguientes citas de Ed Catmull, fundador y presidente de PixarAnimation y Disney Animation, extraídas del capítulo 5 (Sinceridad y franqueza) de su libro "CREATIVIDAD, S.A." describen muy bien el ecosistema de comunicación y la cultura necesaria para producir ideas y productos brillantes.

 

» Leer más, comentarios, etc...

Navegapolis

El talento se da mejor si no se confrontan los personas, sino las ideas.

agosto 01, 2019 01:53

thumb reuniones agilesEn algunas empresas es arriesgado expresar abiertamente opiniones y críticas. En ellas la creatividad ágil no fluye, porque la falta de seguridad para manifestar las ideas propias y cuestionar las de otros produce pensamiento de grupo: organizaciones con personas que se acostumbran a modelar su opinión según lo que consideran que es el consenso del grupo, y a apoyar decisiones que individualmente considerarían desaconsejables.

Son empresas que pueden producir trabajo, pero no innovación, porque como decía Steve Jobs en "The Lost Interview" los grandes productos surgen en equipos en los que se cuestionan y critican abiertamente las ideas.

 

Pero hay que tener cuidado, porque la crítica sin una cultura basada en la honestidad, el respeto y la confianza, acaba enfrentando a las personas, no a las ideas, y sólo produce tensión y desgaste.

Las siguientes citas de Ed Catmull, fundador y presidente de PixarAnimation y Disney Animation, extraídas del capítulo 5 (Sinceridad y franqueza) de su libro "CREATIVIDAD, S.A." describen muy bien el ecosistema de comunicación y la cultura necesaria para producir ideas y productos brillantes.

 

» Leer más, comentarios, etc...

Navegapolis

El talento se da mejor en las empresas en las que no se confrontan egos, sino ideas.

agosto 01, 2019 01:53

thumb reuniones agilesEn algunas empresas es arriesgado expresar abiertamente opiniones y críticas. En ellas la creatividad ágil no fluye, porque la falta de seguridad para manifestar las ideas propias y cuestionar las de otros produce pensamiento de grupo: organizaciones con personas que se acostumbran a modelar su opinión según lo que consideran que es el consenso del grupo, y a apoyar decisiones que individualmente considerarían desaconsejables.

Son empresas que pueden producir trabajo, pero no innovación, porque como decía Steve Jobs en "The Lost Interview" los grandes productos surgen en equipos que cuestionan y critican abiertamente las ideas.

 

Pero hay que tener cuidado, porque la crítica sin una cultura basada en la honestidad, el respeto y la confianza, acaba enfrentando a las personas, no a las ideas, y sólo produce tensión y desgaste.

Las siguientes citas de Ed Catmull, fundador y presidente de PixarAnimation y Disney Animation, extraídas del capítulo 5 (Sinceridad y franqueza) de su libro "CREATIVIDAD, S.A." describen muy bien el ecosistema de comunicación y la cultura necesaria para producir ideas y productos brillantes.

 

» Leer más, comentarios, etc...

Picando Código

The Trials of Shazam!

agosto 01, 2019 01:00

The Trials of Shazam!Hace mucho tiempo que tenía pendiente leer The Trials of Shazam!, cómic de uno de mis superhéroes favoritos: Shazam. Era medio difícil conseguir la serie entera, pero este mes DC publicó una colección nueva que reúne los 12 números: The Trials of Shazam: The Complete Series (en Amazon.es y en Amazon.com). Estaba a un precio bastante conveniente así que aproveché para comprarla y leerla.

Fue escrito por Judd Winick y el arte estuvo a cargo de Howard Porter y Mauro Cascioli. El arte está bien los primeros números por Howard Porter, a veces un poco irregular. Pero los últimos números con arte por Cascioli están excelentes. Aparentemente el cómic tuvo la maldición de atrasos que ataca a los cómics de Shazam. Howard Porter estaba a cargo del dibujo, entintado y color, y dada la presión es entendible que haya tenido algunos atrasos. Supongo que las partes irregulares se pueden atribuir a ésto. Más adelante Porter sufrió una lesión en el pulgar de la mano con la que dibuja y tuvo que obtener ayuda para terminar el trabajo. (La serie actual viene sufriendo atrasos también, va por el número 6 y el número 7 va a estar disponible 11 semanas más tarde de lo definido inicialmente).

En la época de publicación de esta serie (2006-2008), el Gran Queso Rojo todavía se llamaba Capitán Marvel y Shazam era el Mago que le había brindado los poderes. La historia se sitúa después de Infinite Crisis y Superman/Shazam: First Thunder. En Day of Vengeance, la serie limitada que condujo a Infinite Crisis, el mago Shazam es asesinado por El Espectro y el Capitán Marvel asume su lugar en la Roca de la Eternidad.

La historia en general está bastante entretenida. Al haber muerto Shazam, el mundo de la magia pierde el balance. Empiezan a aparecer Monstruos y criaturas místicas por todos lados, y el Capitán Marvel empieza a notar cambios en sus poderes. Los integrantes de la Familia Marvel, Mary Marvel y Captain Marvel Jr. pierden sus poderes mientras que Billy Batson sufre una transformación y tiene que ocupar el lugar del mago Shazam vigilando la Roca de la Eternidad. Por lo tanto, la tierra pierde a su defensor contra estos cambios y desequilibrios en el mundo de la magia.

Captain Marvel

Freddie Freeman, Captain Marvel Jr. y amigo de Billy, es elegido para ocupar el lugar del protector de la Tierra. Pero para llegar a ser el nuevo Captain Marvel, tiene que pasar por una serie de pruebas para obtener los poderes de cada uno de los dioses que dan nombre a Shazam: Salomón, Hércules, Atlas, Zeus, Aquiles y Mercurio (no en ese orden). Billy le presenta a Freddie un guía que lo va a ayudar a pasar por las pruebas y lo acompaña en esta odisea. Los dioses adquirieron forma humana en la Tierra, y Freddie tiene que ir uno por uno superando pruebas para obtener cada poder.

La aventura es bastante divertida, me leí los 12 números en dos tandas. A lo largo del camino se encuentran con varios desafíos y un grupo villanoso con la misma misión de obtener los poderes de Shazam ahora que están disponibles. Cuando parece que la historia se va a volver repetitiva, las pruebas se vuelven más diversas y vemos varios otros personajes del universo mágico de Shazam y DC. En los últimos números la acción sube varios niveles, acompañada por el excelente arte de Mauro Cascioli que comentaba antes, y termina muy arriba en cuanto a acción y desenlace.

Captain Marvel y Shazam (Bill y Freddie)

Fue un intento de tantos de presentar al Capitán Marvel a nuevas audiencias, pero fracasó. La serie deja el status quo cambiado, y podría haber dado lugar a aventuras muy interesantes en el contexto de Shazam y el mundo mágico, pero con condiciones distintas a lo que estamos acostumbrados. Había planes de mantener una serie mensual de haber sido exitosa. Pero parece que no vendió tan bien. Lo que pasó en esta historia fue revertido poco después, pero bien se podría haber continuado una saga de historias de Shazam en un universo alternativo al «principal».

Como conclusión, es una historia entretenida y recomendable. Es distinta, divertida y tiene mucha magia y acción. Otro buen cómic de Shazam para la colección.

 

» Leer más, comentarios, etc...

Blog Bitix

Administrar secretos y proteger datos sensibles con Vault

julio 27, 2019 09:00

Herramientas de aprovisionamiento como Chef, Puppet y Ansible solucionan el problema de la seguridad de los secretos de forma similar, utilizando una única clave de cifrado. Los datos cifrados están siempre a un secreto (contraseña, clave, …) de ser descifrados y generalmente no está bien protegidos dado que en un entorno elástico cada servidor necesita disponer de este secreto para descifrar los datos. Adicionalmente el acceso a los datos cifrados no está registrado de modo que si hay una intrusión no está claro que dato ha sido accedido y por quien. Utilizar variables de entorno para proporcionar secretos tampoco es seguro, y en entornos Docker suele usarse.

Vault
HashiCorp

La seguridad es un aspecto muy importante de los sistemas informáticos, no darle la consideración necesaria puede dar lugar a caídas de servicio y robo de datos potencialmente ocasionando importantes pérdidas de dinero, sanciones y pérdida de confianza de los clientes y proveedores de una organización.

La seguridad se mantiene mediante mecanismos de autenticación identifican al solicitante solicitante, de autorización permitiendo realiza únicamente las acciones para las que se tienen permisos y mediante firma y cifrado para impedir la modificación de los datos y el acceso a la información sin las credenciales y autorización requerida.

La infraestructura informática de los sistemas actuales es cada vez más compleja por el número y tipo de las distintas de piezas que emplean como bases de datos, sistemas de mensajes u otros servicios, también por el aspecto efímero en la tendencia actual de microservicios como por la utilización de entornos en la nube con una infraestructura no confiable al estar fuera del control de una organización y estar compartida con otras organizaciones.

No es seguro utilizar archivos sin cifrar aún utilizando los permisos del sistema de archivos dado que una intrusión en el sistema posibilita el acceso al secreto. Cifrarlos los archivos es el mismo caso de herramientas como Chef, Puppet y Ansible. Utilizar variables de entorno para proporcionar secretos tampoco es seguro ya que aunque los secretos no están en el sistema de archivos se pueden inspeccionar las variables de entorno de un proceso.

1
2
3
$ env | grep SECRET
$ docker inspect
$ sudo cat /proc/$pid/environ

Por otra parte las contraseñas y claves han de rotarse regularmente para limitar en el tiempo el acceso ante el filtrado de las credenciales en un sistema o para denegar el acceso a una persona que en algún momento haya tenido credenciales de acceso como un empleado que ya no pertenece a la compañía.

Vault

Vault es una herramienta para acceder de forma segura a secretos. Un secreto es cualquier cosa a la que se quiera tener severamente controlado como claves de API, contraseñas y certificados. Vault proporciona una interfaz para cualquier secreto a la vez que mantiene un control de acceso y un log de acceso detallado.

Las características principales de Vault se engloban en tres aspectos de la seguridad: cifrado, control de acceso y ciclo de vida.

  • Almacenamiento seguro de secretos: se pueden almacenar secretos arbitrarios clave/valor. Los secretos son cifrados previamente a ser almacenados en el almacenamiento persistente de modo que obtener acceso al almacenamiento persistente no es suficiente para acceder a los secretos. Vault puede almacenar los secretos en disco, Consul y más.
  • Secretos dinámicos: puede generar secretos bajo demanda para bases de datos o algunos sistemas como AWS. Por ejemplo, cuando una aplicación necesita acceso a una base de datos SQL solicita a Vault unas credenciales, Vault genera unas credenciales con los permisos adecuados. Después de crear estos secretos dinámicos también los revoca automáticamente una vez pasado su tiempo de concesión.
  • Cifrado de datos: puede cifrar y descifrar datos sin almacenarlos. Esto permite definir parámetros de seguridad y los desarrolladores almacenar los datos cifrados en localizaciones como bases de datos sin tener que diseñar sus propios métodos de cifrado.
  • Concesión y renovación: todos los secretos en Vault tienen un tiempo de concesión asociado. Al finalizar la concesión Vault los revoca automáticamente, los clientes pueden solicitar renovar las concesiones mediante las API disponibles de Vault.
  • Revocación: integra la funcionalidad de revocación, no solo secretos individuales sino jerarquías de secretos. La revocación asiste en la rotación de las claves así como cerrar el sistema en caso de intrusión.

Conceptos

Los motores de secretos son uno de los conceptos en el ámbito de Vault. Son componentes que permite almacenar, generar o cifrar datos. Algunos motores de secretos simplemente almacenan y leen datos, otros se conectan a otros servicios y generan credenciales dinámicamente bajo demanda. Otros motores de secretos proporcionan el cifrado como servicio, tokens de un solo uso, certificados y mucho más.

Otro concepto es la autenticación. Permiten realizar la autenticación y son responsables de asignar una identidad y un conjunto de policies a un usuario. Por ejemplo, para los desarrolladores el método de autenticación de GitHub es fácil de usar pero para servidores el método AppRole es el recomendado

Los secretos necesitan almacenamiento. Algunos tipos de almacenamiento son mejores para la alta disponibilidad y otros facilitan la copia de seguridad y la restauración. Puede ser en memoria, sistema de archivos, una herramienta como Consul o varias bases de datos entre ellas bases de datos relacionales.

La auditoria permite obtener una trazabilidad de las operaciones que se han realizado, dado que todas las operaciones se realizan mediante una API el log de auditoría es simplemente cada interacción autenticada con Vault, incluidas los errores. Puede ser un archivo o un socket.

Todo en Vault está basado en paths. Las policies permiten o deniegan el acceso a ciertos paths. Poseen la siguiente sintaxis, donde las capabilities son las operaciones CRUD permitidas.

1
2
3
path "secret/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}

Instalación y un caso de uso

La instalación de Vault es muy sencilla ya que es un único binario sin más dependencias. En una distribución GNU/Linux estará en los repositorios oficiales. En Arch Linux se instala con el comando.

1
$ sudo pacman -S vault

En el siguiente ejemplo en modo desarrollo de uso de Vault se inicia, se realiza la autenticación con el token root de superusuario y se crea un secreto. Aquí solo se muestra el caso de uso de guardar y recuperar secretos, otros son generar credenciales para conectarse a una base de datos y proporcionar cifrado y descifrado como servicio.

 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
$ vault server -dev
==> Vault server configuration:
Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: info
Mlock: supported: true, enabled: false
Storage: inmem
Version: Vault v1.1.1
Version Sha: a3dcd63451cf6da1d04928b601bbe9748d53842e
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.
You may need to set the following environment variable:
$ export VAULT_ADDR='http://127.0.0.1:8200'
The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.
Unseal Key: R6MKrMxcJtTTUuIjeQjwDxnv4sHbKtjmuRn0Fok98zk=
Root Token: s.hQoeIivTHHgl1AtsoVz1UF1G
Development mode should NOT be used in production installations!
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ export VAULT_ADDR='http://127.0.0.1:8200'
$ vault kv put secret/key key=s3cr3t
Key Value
--- -----
created_time 2019-07-27T17:30:29.559274833Z
deletion_time n/a
destroyed false
version 1
$ vault kv get secret/key
====== Metadata ======
Key Value
--- -----
created_time 2019-07-27T17:30:29.559274833Z
deletion_time n/a
destroyed false
version 1
=== Data ===
Key Value
--- -----
key s3cr3t

Vault al igual que otras de las herramientas de HashiCorp como Consul y Nomad posee una interfaz gráfica accesible mediante el navegador que permite realizar las mismas operaciones que a través de la API o desde la linea de comandos.

Interfaz gráfica de Vault

Vault a igual que otras de las herramientas de HashiCorp tiene una muy buena documentación en formato de guía y en formato de documentación. En una aplicación Java el proyecto Spring facilita su uso con Spring Vault y Spring Cloud Vault.

Referencia:

» Leer más, comentarios, etc...

Arragonán

Sobre el rediseño

julio 26, 2019 12:00

Hace un par de meses publiqué el rediseño de la home de mi web personal y de paso de este blog.

Versión 2013

El anterior diseño, de José Luis Lizano y maquetado por Guillermo Latorre, databa de inicios de 2013 y estaba enfocado a ser un portfolio de algunos de mis trabajos como desarrollador freelance hasta ese momento. Tenía el objetivo de dar a conocer el tipo de trabajos para el que se me podía contratar, objetivo que había perdido sentido hacía tiempo.

A su vez el blog lo maqueté yo basándome en el trabajo que hicieron ellos en la home, aún siendo un resultado medianamente digno, se evidenciaban mis limitaciones.

Pantallazo el diseño previo del blog

Originalmente, tanto la web como el blog estaban sobre Wordpress en un hosting compartido, así que tocaba ir haciendo actualizaciones y mantenimiento de vez en cuando… Normalmente tarde y mal. Así que a mediados de 2017 lo migré a Jekyll en Github Pages, integrando Disqus para los comentarios y así poder olvidarme de eso. En ese momento me tocó andar revisando la parte responsive para que no se viera el diseño totalmente roto accediendo desde móviles, algo que hasta entonces no le había dedicado atención.

Versión 2019

Tras mucho tiempo con ello en la cabeza, finalmente nos pusimos a darle una vuelta con Vanessa Rubio al rediseño. Sin tener objetivos en sí mismos, las ideas principales eran:

  • Cambio en el enfoque de comunicación, quería que la home fuera algo más parecido a una carta de presentación. Romper con el enfoque de portfolio para pasar a contar qué cosas hago, qué he hecho, mis intereses, etc.
  • Ganar en legibilidad, ya que el anterior diseño de la home estaba planteado para textos cortos y la adaptación que hice para el blog arrastraba por ello algunos problemas. Quería volver a darle protagonismo a este blog escribiendo más en él y dejando de publicar en Medium.
  • Tener un diseño pensado para consumir contenido desde dispositivos móviles, por razones evidentes.

Boceto inicial del diseño del blog tanto versión escritorio como móvil

Para ponerlo en común trabajamos sobre bocetos en papel iterando rápido hasta llegar a la imagen de este post, que usó Vanessa como base para diseñar ya la parte visual entrando a detalle junto a contenido que fui evolucionando.

Una vez diseñada la parte visual, empezó a trabajar en la maquetación responsive sobre un fork del repositorio de git. Incorporando los cambios directamente en el Jekyll existente, con el contenido real y sincronizando alguno de mis cambios en cuanto a copys. Además, aprovechando que Jekyll lo soporta de serie, en el camino migró los estilos de Less a Sass.

Para finalizar, estas son algunas explicaciones de decisiones sobre el rediseño de Vanessa:

La idea era rediseñar sin perder la identidad actual. Para eso mantuve los principales elementos identificativos, como el logo, los colores y la tipografía.

Como queríamos facilitar la lectura de textos largos, le di más peso al blanco (sustituyéndolo como color de fondo) y dejé el negro principalmente para las zonas de navegación y la intro de la home. Para hacerla también más cómoda, especialmente en dispositivos móviles, aumenté el tamaño de fuente y del interlineado; añadiendo además espacios entre apartados para facilitar la lectura en diagonal.

Quería que fuera un espacio limpio, sin elementos que pudieran distraer la lectura. Para eso eliminé la barra derecha del blog ampliando así el espacio del cuerpo del post y dejé bastante aire alrededor para relajar la vista y centrar la atención en el contenido.

Por último, también quería destacar los CTAs más importantes del blog (como el de enviar comentarios o navegar entre páginas) convirtiéndolos en botones y unificando al mismo tiempo esos mismos estilos con los de la home para mantener la coherencia entre elementos similares.

Personalmente estoy muy contento con el resultado :)

» Leer más, comentarios, etc...

Blog Bitix

Obtener los primeros, los últimos o los caracteres anteriores y posteriores de un archivo y el número de ocurrencias con head, tail y grep

julio 25, 2019 06:00

GNU
Linux

Algunos archivos de texto tienen un tamaño de cientos de megas, a veces incluso sin ningún salto de línea. Visualizar el contenido de estos archivos en una aplicación con interfaz gráfica no suele ser posible porque la aplicación se queda bloqueada al intentar cargar tan enormes archivos. Incluso tampoco puede ser posible con un editor mucho más ligero como vim. Hacer un cat del archivo tampoco es útil.

Sin embargo, sigue siendo necesario ver parte del contenido de estos archivos de texto grande para validar que el contenido de los mismos es el correcto. La opción que se puede utilizar es ver los primeros o últimos caracteres o lineas con los comandos head o tail usándolos de la siguiente forma.

1
2
3
4
5
6
$ # Primeros o últimos 100 caracteres de un archivo
$ head -c 100 archivo.txt
Lorem ipsum dolor sit amet consectetur adipiscing elit pulvinar et praesent, egestas fermentum mauri
$ tail -c 100 archivo.txt
ultricies, a dictumst velit dapibus leo pellentesque dictum dui ligula aliquam eu dignissim rhoncus.
1
2
3
4
5
6
7
$ # Primeras o últimas 2 lineas de un archivo
$ head -n 2 archivo.txt
Lorem ipsum dolor sit amet consectetur adipiscing elit pulvinar et praesent, egestas fermentum mauris phasellus non nec rutrum nibh accumsan, placerat natoque interdum dui duis viverra molestie id parturient. Imperdiet commodo viverra arcu ridiculus blandit interdum litora bibendum felis ac purus, eu facilisi habitasse ultrices nisl magnis lobortis phasellus turpis velit vestibulum faucibus, auctor sagittis consequat quis cubilia inceptos donec enim gravida mus. Lacinia felis cras leo porta imperdiet tellus ridiculus convallis praesent ante, dapibus laoreet nibh dictumst penatibus a euismod nisi nulla, luctus lacus porttitor neque magnis sed molestie curae quisque. Hac volutpat curabitur laoreet ultrices est nibh parturient quam libero, faucibus ac metus gravida quis venenatis aliquam placerat cubilia, vel ligula litora dapibus dignissim auctor rhoncus at.
$ tail -n 2 archivo.txt
Bibendum hendrerit sociosqu id libero neque, ad mollis donec consequat sagittis, tempus litora morbi nisi. Augue gravida aliquet rhoncus porta odio dui auctor velit erat lectus magna phasellus fringilla, quam praesent class cursus blandit nulla curabitur nostra feugiat consequat egestas cubilia, tortor magnis senectus volutpat ad urna semper himenaeos nascetur luctus posuere interdum. Nam quisque aliquet convallis taciti maecenas euismod vulputate mauris commodo et eleifend vel duis ultricies, a dictumst velit dapibus leo pellentesque dictum dui ligula aliquam eu dignissim rhoncus.
1
2
3
4
5
6
7
Lorem ipsum dolor sit amet consectetur adipiscing elit pulvinar et praesent, egestas fermentum mauris phasellus non nec rutrum nibh accumsan, placerat natoque interdum dui duis viverra molestie id parturient. Imperdiet commodo viverra arcu ridiculus blandit interdum litora bibendum felis ac purus, eu facilisi habitasse ultrices nisl magnis lobortis phasellus turpis velit vestibulum faucibus, auctor sagittis consequat quis cubilia inceptos donec enim gravida mus. Lacinia felis cras leo porta imperdiet tellus ridiculus convallis praesent ante, dapibus laoreet nibh dictumst penatibus a euismod nisi nulla, luctus lacus porttitor neque magnis sed molestie curae quisque. Hac volutpat curabitur laoreet ultrices est nibh parturient quam libero, faucibus ac metus gravida quis venenatis aliquam placerat cubilia, vel ligula litora dapibus dignissim auctor rhoncus at.
Proin sapien viverra nisl posuere dapibus commodo senectus aptent dui nam est tempor primis, dignissim vehicula pharetra et augue hendrerit tincidunt metus mauris curae mus eu. Quam habitasse natoque gravida cras class porttitor fringilla facilisi, phasellus mauris hendrerit et montes enim libero, suspendisse id fermentum lacus molestie purus blandit. Vivamus interdum nisi eleifend suscipit vulputate faucibus suspendisse felis curae, sodales pharetra cubilia vehicula proin velit turpis sapien ad, cursus molestie erat aliquam ridiculus rhoncus duis eu.
Mollis venenatis felis suscipit mauris fusce at massa sociosqu conubia, hac sociis aptent ut netus vestibulum nostra sed dictumst, nec non eget magna vulputate cum pellentesque arcu. Congue pharetra luctus justo curabitur turpis mi semper nibh laoreet fames, vehicula quam maecenas dui magna scelerisque dictum diam tortor, sociis massa facilisi cum viverra duis erat urna fusce. Urna interdum nisl class fames quam cum suscipit ultrices hendrerit ullamcorper, sagittis nullam aliquam porta tellus aptent fringilla iaculis vitae, vivamus vestibulum conubia elementum semper id himenaeos nunc convallis.
Bibendum hendrerit sociosqu id libero neque, ad mollis donec consequat sagittis, tempus litora morbi nisi. Augue gravida aliquet rhoncus porta odio dui auctor velit erat lectus magna phasellus fringilla, quam praesent class cursus blandit nulla curabitur nostra feugiat consequat egestas cubilia, tortor magnis senectus volutpat ad urna semper himenaeos nascetur luctus posuere interdum. Nam quisque aliquet convallis taciti maecenas euismod vulputate mauris commodo et eleifend vel duis ultricies, a dictumst velit dapibus leo pellentesque dictum dui ligula aliquam eu dignissim rhoncus.

Como programador no es raro trabajar con archivos de más de 100 MiB en los que el texto no contiene saltos de línea y el contenido es una sola línea como es el caso de un archivo en formato XML utilizado para intercambiar información entre dos aplicaciones. Estos archivos por su tamaño y sin saltos de línea se les atragantan a los editores de texto gráficos como Visual Studio Code e incluso a la opción más ligera basada en texto como vim.

En ete caso también es necesaria una forma de comprobar el contenido del archivo o contar el número de ocurrencias de un determinado patrón. La herramienta de línea de comandos grep es una gran ayuda en estos dos casos. Suponiendo un archivo XML que contiene elementos con un tag de precio se desea comprobar que estos elementos tienen un valor válido. Utilizando grep y una expresión regular se obtienen las etiquetas price, una en cada línea. El parámetro -E indica que se utilizan una expresión regular y el parámetro -o indica que cada coincidencia se emita en una línea nueva.

1
2
3
4
$ grep -E -o "<price>[^<]*</price>" archivo.xml
<price>1.0</price>
<price>2.0</price>
<price>3.0</price>
1
2
<?xml version="1.0" encoding="UTF-8"?>
<products><product><name>A</name><price>1.0</price></product><product><name>B</name><price>2.0</price></product><product><name>C</name><price>3.0</price></product></products>

En caso de no ser un archivo estructurado como XML o querer obtener los 15 caracteres anteriores o posteriores de una coincidencia se utiliza un comando grep similar cambiando la expresión regular.

1
2
3
4
$ grep -E -o ".{0,15}price.{0,15}" archivo.xml
<name>A</name><price>1.0</price></p
<name>B</name><price>2.0</price></p
<name>C</name><price>3.0</price></p

Para contar el número de coincidencias en el archivo se puede combinar el comando grep utilizando la opción -o para que emita cada coincidencia en cada línea y el comando wc con la opción -l para que cuente el número de líneas de entrada. Utilizando una tubería entre ambos comandos es posible contar el número de coincidencias en un archivo.

1
2
$ grep -E -o "<product>" archivo.xml | wc -l
3

En este caso el XML es muy pequeño y un editor de texto es capaz de abrirlo perfectamente pero un archivo de texto a partir unas cuantas decenas de MiB se le atraganta a los editores incluso a los basados en texto y en el caso querer hacer comprobaciones una buena alternativa o la única es recurrir a los comandos head, tail, grep y wc.

» Leer más, comentarios, etc...

Fixed Buffer

La potencia de la Reflexión en C# (Parte 4: Métodos)

julio 23, 2019 08:00

Imagen con el logo de C# para la entrada de reflexión para métodos

Aquí estamos una semana más hablando de la reflexión, y hoy les toca el turno a los métodos. Echando la vista atrás, hemos hablado sobre la reflexión en general y las propiedades, sobre como trabajar con ensamblados, y en la última semana hablamos sobre cómo utilizar los constructores mediante reflexión.

Hoy es el turno de trabajar con reflexión en métodos. A estas alturas, seguramente puedas imaginar cómo los vamos a obtener, puesto que es muy parecido a obtener los constructores. Salvo que esta vez, en vez de obtener un ConstructorInfo, vamos a tener un MethodInfo. (Aunque las dos clases en profundidad tienen sus diferencias, ambas heredan de MemberInfo). Además, lo hemos utilizado para probar el código en las entradas anteriores.

Obteniendo un método por reflexión

Como en todos los casos anteriores, lo que vamos a partir es del tipo (Type), pero esta vez vamos a llamar al método GetMethod() indicándole el nombre del método que queremos buscar. Adicionalmente, le podemos indicar también los modificadores y los parámetros, en caso de que tengamos varios métodos que se llaman igual, pero cambia la firma. Por ejemplo:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Obtenemos un método público
var publicMethod = type.GetMethod("Multiplicar");
//Obtenemos un método privado
var privateMethod = type.GetMethod("ResetValor", BindingFlags.Instance | BindingFlags.NonPublic);
//Obtenemos un método estático
var staticMethod = type.GetMethod("Sumar", BindingFlags.Static | BindingFlags.NonPublic);


public class ClaseEjemplo
{
    private int _valor;
    public ClaseEjemplo(int valor)
    {
        _valor = valor;
    }

    public int Multiplicar(int por)
    {
        return _valor * por;
    }

    private void ResetValor()
    {
        _valor = 0;
    }

    static int Sumar(int a, int b)
    {
        return a + b;
    }
}

Invocando nuestro método

Una vez que tenemos nuestro MethodInfo, al igual que veíamos con los constructores, basta que llamemos a Invoke pasándole los parámetros, y ya hemos conseguido ejecutar nuestro código:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Obtenemos los constructores
var constructorConParametros = type.GetConstructor(new[] { typeof(int) }); //Contructor con parametro int
var constructorSinParametros = type.GetConstructor(Type.EmptyTypes); //Constructor genérico

//Creamos el objeto de manera dinámica
var objetoConParametros = constructorConParametros.Invoke(new object[] { 2 });

// Creamos una referencia al método   
var m = assembly.GetType(className).GetMethod("Multiplicar");

//Llamamos al método pasandole el objeto creado dinámicamente y los argumentos dentro de un object[]
var retConstructorParamatrizado = m.Invoke(objetoConParametros, new object[] { 3 });

Con esto tan sencillo, ya hemos conseguido ejecutar métodos por reflexión en C#. ¡Y esto es todo! ¿O no…?

El coste de la reflexión

Estamos ya por la cuarta entrada, y siempre diciendo que la reflexión es cara, pero…. ¿Cuánto más cuesta procesar nuestro código por reflexión?,¿es mucho…? ¿poco…? La respuesta es: muchísimo, vamos a poner unos números:

La imagen muestra un benchmark comparando la llamada normal al método y la llamada por reflexión, viendo que esta última es más de 3500 veces más lenta

Vaya… con estos números, parece que la reflexión no sirve, es demasiado lenta, no podemos meter reflexión en nuestro código más allá de para facilitarnos las pruebas unitarias.

La reflexión es muy útil para testing, hoy sin ir más lejos la he utilizado para poder testear cierta parte del código de un proyecto que es privada porque así debe serlo, y he podido saltarme las restricciones de acceso y he podido añadir tests para ese código que prueba solo lo que tiene que probar.

Muy acertadamente en los comentarios de una entrada anterior, planteaban una alternativa para mejorar el rendimiento, que consiste crear el objeto mediante el constructor por reflexión, y a partir de ahí utilizar dynamic. Para quién no lo conozca, dynamic es un tipo especial de objeto que evita la comprobación de tipos en compilación utilizando Dynamic Language Runtime, delegando al runtime ese trabajo, lo que nos permite hacer algo como esto:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Obtenemos el constructor
var constructorConParametros = type.GetConstructor(new[] { typeof(int) }); 

//Creamos el objeto de manera dinámica y de tipo "dynamic"
dynamic objetoDinamicoConParametros = constructorConParametros.Invoke(new object[] { 2 });

//Llamamos al método como si fuese un objeto tipado
var retConstructorParamatrizado = objetoDinamicoConParametros.Multiplicar(3);

Con este pequeño cambio, hemos conseguido mejorar los tiempos:

La imagen muestra como utilizar "dynamic" es cerca de 23 veces más rápido que utilizar reflexión, aunque sigue siendo 150 veces más lento que una llamada normal

Los dos principales problemas de esto, son que hemos perdido la flexibilidad que teníamos para buscar los métodos, ya que ahora el nombre tiene que coincidir, no tenemos ese margen para buscar (además de que volvemos a regirnos por los modificadores de acceso), y sobre todo, sigue siendo 150 más lento que hacer una llamada convencional (aunque hemos mejorado mucho respecto a la llamada por reflexión). De todos modos, si queremos utilizar la reflexión para cargar código que puede cambiar, sigue siendo demasiado lento. Llegados a este punto, ¿tenemos que tirar la toalla con la reflexión?

Creando delegados de métodos obtenido por reflexión

Un delegado, no es más que la referencia a un método desde la cual vamos a poder llamar a ese método sin necesidad de tener acceso al objeto que lo contiene, ya que este va implícito en la referencia a donde apunta el delegado:

// Declaramos la firma del delegado
delegate void MyDelegado(string str);

// Declaramos un método con la misma firma del delegado
static void Notify(string message)
{
    Console.WriteLine(message);
}

// Creamos una instancia del delegado.
MyDelegado del1 = new MyDelegado(Notify);

// Llamamos al método a través del delegado.
del1("Llamada desde un delegado");

Ahora, si unimos esto con la reflexión, lo que podemos hacer es crear un delegado que apunte hacia nuestro método por reflexión. Para ello, siguiendo con nuestro ejemplo, vamos a utilizar el delegado «Func<int,int>» (recordemos que nuestro método recibía un entero como parámetro y devolvía otro entero), pero si fuese necesario, podemos definir el delegado que nos haga falta.

Para construirlo, vamos a aprovecharnos de Delegate.CreateDelegate, y le vamos a indicar el tipo, el objeto al que hacemos referencia, y el nombre del método al que queremos hacer el delegado:

Func<int, int> delegateMethod = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>), target, "Multiplicar");

Delegate.CreateDelegate tiene diferentes parámetros en función de lo que queramos hacer, por ejemplo, si queremos crear un delegado a un método estático, tendríamos que utilizar el objeto MethodInfo directamente, te recomiendo que le eches un ojo a sus posibilidades.

Además, como conocemos el tipo del delegado a la perfección (sabemos que esperar, o podemos consultarlo sobre el MethodInfo para saber que delegado aplicarle), podemos hacer un cast al tipo de delegado concreto, por ejemplo, el código completo sería algo así:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Obtenemos el constructor
var constructorConParametros = type.GetConstructor(new[] { typeof(int) }); 

//Creamos el objeto de manera dinámica            
object objetoDinamicoConParametros = constructorConParametros.Invoke(new object[] { 2 });
            
//Creamos el delegado pasandole el tipo, una referencia al objeto sobre el que va a trabajar, y el nombre del metodo
//Delegate.CreateDelegate tiene diferentes parámetros en función de lo que queramos hacer
Func<int, int> delegateMethod = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>), objetoDinamicoConParametros, "Multiplicar");

//Llamamos al método 
var retDelegado = delegateMethod(3);

Si ejecutas este código, veras que funciona perfectamente (Como siempre, he dejado actualizado el repositorio en GitHub para poder descargárselo y tocarlo). Además, este modo si nos permite saltarnos los limitadores de acceso, en caso de que estemos haciendo pruebas al código.

Vale, es todo muy bonito, pero a simple vista, solo supone más trabajo porque tenemos que gestionar un delegado también, ¿esto aporta algo?, vamos a ver los números:

La imagen muestra el resultado del benchmark de los 4 métodos, viendose: Llamada convencional 0.02 ns, llamada por reflexión 213.90 ns, llamada con dynamic 9.89 ns y llamada con delegado 1.74 ns

Como se puede comprobar, después de hacer una llamada convencional, utilizar delegados es lo siguiente más rápido, siendo 5,7 veces más rápido que utilizar «dynamic».

Los tiempos son solo orientativos (de hecho, han ido variando ligeramente durante los diferentes benchmark)

Conclusiones

Si bien es cierto que no podemos conseguir los tiempos que conseguiríamos con una llamada convencional. Cuando se recurre a la reflexión es precisamente cuando las llamadas convencionales no están disponibles por una razón u otra. Como se puede comprobar de los números, la reflexión es cara, pero existen maneras de hacerla más liviana.

Como decíamos en la entrada de los constructores, un gran poder conlleva una gran responsabilidad. La reflexión es algo que debemos utilizar con cabeza y criterio, pero no es algo prohibido que no hay que tocar. Como he dicho varias veces, es una herramienta especialmente útil para hacer testing por ejemplo, cuando hay cosas donde necesitamos acceder y no podemos.

**La entrada La potencia de la Reflexión en C# (Parte 4: Métodos) se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Mascando Bits

Aprende a programar en Python – Introducción – 0

julio 19, 2019 06:05

Llevaba tiempo mascando esta serie de entradas para aprender a programar en Python, para las cuales no quise quedarme en algo del tipo mira, aprende y copia. El curso tiene un enfoque práctico con su parte de teoría y ejercicios donde corresponda. Atendiendo a las actuales necesidades formativas he decidido que el curso y su material podrá ser trabajado de manera online utilizando únicamente un navegador web.

Para ello he creado un repositorio en GitHub con dos herramientas que podréis elegir usar de manera online:

Ambos proyectos usan como base el intérprete de Brython, un proyecto que intenta emular el interprete de Python que puedes instalarte en tu equipo. Este proyecto permite saltarse el problema de no poder instalar el interprete de Python debido a restricciones en el equipo que uses, por ejemplo si dependes del departamento de Sistemas para instalarlo, o simplemente si quieres retomar el curso en cualquier instante sin necesidad de instalar nada.

El proyecto de la Consola Python Online es una consola que se comporta de manera similar a la que puedes tener cuando lanzas Python desde una consola de comandos. El proyecto IDE Python Online es un entorno de desarrollo integrado donde podrás en su parte izquierda realizar la programación con realce de sintaxis y ayuda de autocompletado predictivo de código; y en su parte derecha podrás ver el resultado del código escrito a la izquierda tras darle al botón «▶ Run» de la parte superior. Con estas dos herramientas tendrás lo que te hace falta para seguir el curso.

Este proyecto es de carácter Open Source, siendo posible contribuir en el propio repositorio a la mejora de los fragmentos de código, ejercicios y herramientas.

Antes de empezar quisiera explicarte qué es Python y ofrecerte una pequeña aproximación de su historia. Python es un lenguaje de programación interpretado, lo que significa que no necesita compilarse y generar un binario para funcionar, se interpreta el código y el encargado de hacerlo (el intérprete), lo traducen a lenguaje máquina. Esto quiere decir también que con vuestro código en Python sólo necesitáis que un intérprete de Python esté instalado en la máquina para ejecutar el código, o usar las herramientas que anteriormente presentaba 😉 .

Python es un excelente lenguaje de programación si quieres aprender una herramienta que potencie o complemente tu trabajo, como es el caso del clásico Excel. O simplemente como tu primer lenguaje de programación, debido a que su curva de aprendizaje es mucho más baja a diferencia de otros lenguajes, haciendo hincapié en una sintaxis que favorece la legibilidad del código. Además Python es multiparadigma, lo que significa que puede acomodarse a distintos enfoques y necesidades de programación, incluyendo el buen diseño por defecto en la propia sintaxis y evolución del lenguaje.

Actualmente Python se encuentra en un proceso de migración de Python 2 a Python 3, debido a que el soporte de Python 2 acaba el 1 de enero de 2020, terminando con un estado de segmentación del lenguaje que llevaba varios años produciéndose. El salto de Python 2 a Python 3 supone el cambio del diseño de cierta parte de la sintaxis que rompe la compatibilidad y evitaba a Python avanzar hacia el Python que hoy conocemos y que tanta penetración tiene en los sectores técnicos y no tan técnicos. No obstante existen herramientas como 2to3 que realizan la adaptación automática de la sintaxis de Python 2 a Python3. Obviamente no es perfecto y queda en manos del programador el terminar de pulir la migración. La versión del lenguaje que aprenderás aquí, por supuesto es Python 3 😉 .

Para ir abriendo boca voy a mostrarte el clásico programa de inicio «Hello World!» o «Hola Mundo!» en español:

Si le das al botón «▶ Run» leerás en la derecha «Hello World» seguido del tiempo que ha tardado en ejecutarse nuestro programa (lo que hay en el panel izquierdo).

Ahora te propongo un simple ejercicio hasta la próxima entrada. Partiendo del siguiente código:

Intenta que imprima en el lado derecho «Hello World«. Es fácil y seguro que lo consigues 😉 .

Con esto cerramos el capítulo de introducción donde hemos conocido las herramientas que vamos a usar para el curso, hemos presentado Python y hemos ejecutado nuestro primer programa.

» Leer más, comentarios, etc...

Variable not found

await Task.WhenAll(family, relax, sleep, beach)

julio 16, 2019 06:15

Siempre llego a estas fechas hecho fosfatina, con la sensación de que las últimas semanas antes de las vacaciones son como una cuesta arriba que parece no acabar nunca. Pero afortunadamente no es así, y al final acaba llegando el ansiado momento de colgar los hábitos durante una pequeña temporada :)

Así pues, me complace anunciaros que voy a dedicar algunas semanas a tomar aire fresco y formatear un poco la mente. Mis planes son muy simples: al principio un par de semanas de familia, playita y descanso, y el resto a seguir trabajando, pero a un ritmo más tranquilo y dejándome libres los fines de semana, que es cuando suelo aprovechar para escribir en el blog.

¡Nos vemos a la vuelta, ya en septiembre!

Playa
Playa de Costa Ballena, Rota (Cádiz). Imagen: Hotel Elba

Publicado en Variable not found.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 370

julio 15, 2019 06:05

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

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

» Leer más, comentarios, etc...

Variable not found

Tipos referencia anulables en C# 8

julio 09, 2019 08:43

.NET CoreCuando, en 1965, el bueno de Tony Hoare introdujo las referencias nulas en el lenguaje ALGOL simplemente "porque era fácil de implementar", no era consciente de que se trataba de un error que a la postre él mismo definiría como su "error del billón de dólares".

De hecho, en el top ten de errores de ejecución de aplicaciones creadas con casi cualquier lenguaje y plataforma, las excepciones o crashes debidos a las referencias nulas son, con diferencia, el tipo de error más frecuente que solemos encontrar.

Pues en este repaso que vamos dando a las novedades principales de C# 8, hemos llegado la que probablemente podría ser la característica más destacada en este entrega, cuyo objetivo es precisamente establecer las bases para que podamos olvidarnos de las referencias no controladas a nulos.
No olvidéis que hasta que sea lanzado oficialmente C# 8, para poder probar sus características hay que hacer algunas cosillas.

¿Permitir valores nulos en tipos referencia?

Ya, pensaréis que todos los tipos referencia son implícitamente anulables en .NET, y de hecho es así.
A diferencia de los tipos valor (int, char, double...), las variables o miembros que contienen tipos referencia no guardan sus valores, sino punteros a los mismos.

Y como punteros que son, pueden contener un valor nulo, razón por la cual el siguiente código es válido:
var s = "Hello, world!"; // La variable "s" apunta a la posición en memoria de la cadena
s = null; // Ahora, "s" no apunta a ningún sitio
El problema es que en tiempo de ejecución nunca sabemos si una determinada variable contiene un nulo, por lo que, si queremos tener una aplicación realmente robusta, deberíamos comprobar continuamente si es así antes de utilizarla:
var s = GetSomeString(); // ¿Retornará null? ¿O tal vez no?
if(s != null)
{
Console.WriteLine(s.Length);
}
Y claro, los disgustos llegan cuando olvidamos introducir dicha comprobación o cuando, por su contexto, intuimos que el valor nunca será nulo, ignorando esa famosa ley que afirma que "si un valor puede ser nulo, el algún momento será nulo" ;)

Para evitar esto, en C# 8 podemos indicar expresamente en qué variables consideramos que null puede ser un valor válido y en cuáles, aun siendo tipos referencia, no vamos a permitir este valor.

De esta forma, conseguimos desplazar al compilador la responsabilidad de realizar dichas comprobaciones, y llevándonos a tiempo de desarrollo la detección de errores debido a este asunto.

Tipos referencia anulables

A partir de C# 8, para indicar que podemos utilizar null en un tipo referencia, debemos indicarlo expresamente añadiendo una interrogación al mismo, de la misma forma que hacíamos con los tipos valor anulables como int? o DateTime?.

La idea es que el siguiente código nos lance errores (o como mínimo warnings) en tiempo de compilación, en lugar de explotar en runtime cuando se intente establecer usar la referencia incorrecta:
string? nullableString = "Nulls are welcome!";
string notNullableString = "Nulls are not welcome!";
nullableString = null; // Allowed
notNullableString = null; // Compilation warning!
Console.WriteLine(nullableString.Length + notNullableString.Length); // Compilation warning!
Así de sencillo :)

Pero cada cosa en su contexto, y dándole la importancia apropiada

Fijaos que el hecho de marcar con la interrogación los tipos referencia anulables implicaría que gran parte de nuestro código actual sería incorrecto, por lo que el uso de esta característica se convertiría en un breaking change de los gordos en los proyectos escritos con versiones anteriores a C# 8.

Por esta razón, se trata de una característica que podemos activar o desactivar a nivel de proyecto y de bloque de código.

Por ejemplo, para indicar que el compilador debe realizar estos chequeos en el proyecto completo, basta con añadir el elemento <NullableContextOptions> al archivo .csproj como sigue:
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NullableContextOptions>enable</NullableContextOptions>
...
</Project>
Los proyectos que no incluyan este elemento, o bien lo establezcan como disable no relizarán ningún tipo de comprobación, por lo que todo funcionará como en versiones anteriores del compilador.
Otra posibilidad es establecer este valor a nivel de bloque de código, para lo cual podemos utilizar la directiva #nullable, como en el siguiente ejemplo:
13: // Activamos el chequeo de nulos...
14: #nullable enable
15: string? nullableString = "Nulls are welcome!";
16: string notNullableString = "Nulls are not welcome!";
17: nullableString = null; // Ok, we allow nulls
18: notNullableString = null; // Warning!
19: Console.WriteLine(
20: nullableString.Length + notNullableString.Length); // Warning!

21: // Ahora volvemos a aplicar la configuración a nivel de proyecto
22: #nullable restore
23: ...
Al compilar un proyecto con este código desde la CLI, el resultado obtenido por consola sería el siguiente:
D:\Test>dotnet build
Microsoft (R) Build Engine versión 16.0.443 para .NET Core
Copyright (C) Microsoft Corporation.
...

Program.cs(18,33): warning CS8600: Converting null literal or possible null value to non-nullable type.
[D:\Test\ConsoleCore2.csproj]
Program.cs(20,17): warning CS8602: Possible dereference of a null reference. [D:\Test\ConsoleCore2.csproj]
Program.cs(20,41): warning CS8602: Possible dereference of a null reference. [D:\Test\ConsoleCore2.csproj]
3 Advertencia(s)
0 Errores

Tiempo transcurrido 00:00:00.76
D:\Test>_
Por defecto, podemos ver que el compilador nos avisará de los problemas encontrados mediante warnings y ya es decisión nuestra si queremos dejarlo así, o si preferimos "ascenderlos" a errores para bloquear la generación de binarios, por ejemplo añadiendo al .csproj el elemento <TreatWarningsAsErrors>true</TreatWarningsAsErrors>, o bien indicando expresamente qué warnings queremos que sean tratados como errores:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors>
...
</Project>
En cualquier caso, los avisos nos están indicando de que:
  • Hemos establecido a nulo una variable que no lo admite (línea 18).
  • Estamos accediendo a propiedades de una referencia que podría ser nula (línea 20, dos veces).

Uso de tipos referencia anulables

En la práctica, el uso de esta característica nos permitirá crear código muy robusto, pues la comprobación de nulos no se dejará al azar o al criterio del desarrollador: será el compilador el que vele por nuestra seguridad.

Por ejemplo, en el siguiente código, vemos que el método GetPerson() está declarando explícitamente que retornará objetos Person que nunca van a ser nulos. Sin embargo, dado que en uno de los caminos de ejecución es posible que se retorne dicho valor, el compilador lanzará un warning indicándolo:
Person GetPerson(int id)
{
var person = DateTime.Now.Second % 2 == 0? _database.People.Find(id): null;
return person; // Warning CS8603: possible null reference return.
}
En cambio, si gestionamos este valor nulo internamente, el compilador ya no emitirá warnings porque detectará que el método nunca va a devolver null y, por tanto, podemos usar su retorno con total seguridad:
Person GetPerson(int id)
{
var person = DateTime.Now.Second % 2 == 0
? _database.People.Find(id)
: null;
if(person == null)
person = Person.Anonymous;
return person;
}

// Usage:
var person = GetPerson(1);
Console.WriteLine(person.Age); // It's ok, Person is always a valid instance
El compilador también estará atento al caso contrario. Si, por ejemplo, en un método indicamos que retorna un tipo anulable, null será considerado válido y no se generará ningún warning:
Person? GetPerson(int id)
{
var person = DateTime.Now.Second % 2 == 0? _database.People.Find(id): null;
return person; // Ok, null is a valid return value
}
Ahora bien, si un tipo lo hemos marcado como anulable e intentamos acceder a sus miembros sin haber asegurado previamente que no contiene nulos, nos avisará de que hay algo raro:
Person? person = GetPerson(1);
Console.WriteLine(person.Age); // CS8602: Possible dereference of a null reference
La forma de solucionarlo es bien sencilla. Podemos simplemente chequear el valor nulo antes de acceder a sus propiedades con alguna de las construcciones existentes. El siguiente bloque de código no generará ningún tipo de warning o error:
if(person != null)
{
Console.WriteLine(person.Age); // Ok, person is not null
}
Console.WriteLine(person?.Age); // If person is null, "0" will be shown

Null-forgiving operator (!)

Para aquellos casos en los que estamos absolutamente seguros de que un objeto no es nulo y queremos acceder a sus miembros sin necesidad de realizar un chequeo explícito como los vistos anteriormente, podemos usar el operador exclamación "!", aka "olvida los nulos", de la siguiente forma:
Person? person = GetPerson(1);
Console.WriteLine(person!.Age); // Ok, but it could crash in runtime
Básicamente, lo que hacemos con este operador es desactivar justo en ese punto la comprobación de nulos del compilador. O en otras palabras: estamos asegurando al compilador que ahí nunca habrá un nulo (¡y si lo hay, es responsabilidad nuestra!)

Reflexiones finales

Probablemente estemos ante una de las novedades más revulsivas introducidas al lenguaje en los últimos tiempos (bueno, exceptuando quizás el famoso operador virgulilla ;D).

Aunque su impacto ha sido bastante suavizado al permitir su opcionalidad e incluso su adopción progresiva, probablemente a la larga acabará calando en nuestras aplicaciones y evitará gran parte de los frecuentes null reference exception que sufrimos a día de hoy. El "a la larga" se debe a que, por las implicaciones que tendría introducir esta característica en código existente, en la mayoría de ocasiones lo más práctico será usarla en proyectos nuevos.

Iremos viendo...

Publicado en Variable not found.

» Leer más, comentarios, etc...

Fixed Buffer

La potencia de la Reflexión en C# (Parte 3: Constructores)

julio 09, 2019 08:00

La imagen muestra el logo de C#

Volvemos otra semana más hablando de le reflexión en C#, y hoy toca hablar de los constructores. Como recordatorio, las últimas semanas hemos dado unas pinceladas sobre la reflexión y también hemos visto cómo podemos aprovecharla en los ensamblados.

Hoy vamos a seguir buceando un poco en la potencia que nos aporta la reflexión, en este caso para los constructores. Como vimos, es posible crear instancias de clases mediante reflexión utilizando:

var assembly = Assembly.GetAssembly(typeof(Program));

//Creamos el objeto de manera dinámica
var objetoDinamico = assembly.CreateInstance("PostReflexion.ClaseEjemplo",
                                   false,
                                   BindingFlags.ExactBinding,
                                   null,
                                   new object[] { 2 }, /*Argumentos del constructor*/
                                   null,
                                   null);

Pero esto tiene un mayor coste si vamos a utilizar varias veces el mismo constructor. Esto es porque la reflexión, pese a ser un proceso potente, es caro. En la siguiente tabla se puede comparar los resultados entre instanciar el mismo objeto con el código anterior, o buscando su ConstructorInfo, almacenándolo en memoria y llamando solo a este (no te preocupes, ahora vamos a ver que es el ConstructorInfo).

La imagen muestra la comparativa en benchmark de utilizar el constructor de la clase, Assembly.CreateInstance y ConstructorInfo.Invoke, donde se puede ver que Assembly.CreateInstance tarda de media 1362 ns , ConstructorInfo.Invoke tarda de media 218 ns y el constructor de la clase 3 ns

De los datos de la imagen anterior, se puede ver claramente que el proceso de creación de un objeto es hasta 376 veces más lento usando Assembly.CreateInstance, mientras que usando un ConstructorInfo.Invoke solo lo es 60 veces. esto es porque obligamos a ejecutar todo el proceso de búsqueda del constructor de la clase cada vez que queremos crear un objeto (y recordemos la que reflexión es cara, por eso llamar al constructor de la clase siempre es más rápido).

Una vez vistos los datos, está claro que siempre que podamos, lo mejor es no utilizar reflexión, pero si vamos a usarla y encima de manera repetida, es mejor almacenar las partes que necesitemos y no tener que buscarlas cada vez.

Obteniendo los constructores por reflexión

Vale, llegados a este punto, tenemos una cosa clara:

«Un gran poder conlleva una gran responsabilidad»

Tío Ben – Spiderman

Dentro de Assembly, también podemos obtener las declaraciones de tipos («Type«), donde se encuentra toda la información de la definición:

className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

Y es aquí donde empieza «la magia»… Este objeto «Type» nos permite bucear en todos los recovecos que contiene y obtener entre otras cosas un ContructorInfo por cada constructor que se haya definido en el código (en las siguientes entradas iremos viendo el resto de sus posibilidades).

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var constructors = assembly.GetType(className).GetConstructors();

O incluso, nos permite acceder al que coincida con el tipo de argumentos (y el orden) que le pedimos:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Contructor con parametro int          
var constructorConParametros = type.GetConstructor(new[] { typeof(int) }); 
//Constructor genérico
var constructorSinParametros = type.GetConstructor(Type.EmptyTypes); 

Y sin darnos cuenta, ¡ya tenemos nuestro ConstructorInfo listo! Ahora solo nos queda llamar a su método Invoke pasándole como parámetro un array de objetos que cumpla con la firma, es decir, si el constructor espera un «int», le pasaremos un new object[] {int}, si espera un int y un string, new object[] {int,string} ,etc:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Contructor con parametro int
var constructorConParametros = type.GetConstructor(new[] { typeof(int) }); 
//Creamos el objeto de manera dinámica
var objetoDinamicoConParametros = constructorConParametros.Invoke(new object[] { 2 });

Lo que sí es un poco más «raro», es cuando queremos buscar los constructores por reflexión para conseguir el genérico, que hay que utilizar «Type.EmptyTypes» a la hora de buscarlo (y no pasarle nada en el Invoke)

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Constructor genérico           
var constructorSinParametros = type.GetConstructor(Type.EmptyTypes); 

//Creamos el objeto de manera dinámica
var objetoDinamicoSinParametros = constructorSinParametros.Invoke(new object[] { });

¡Vamos a probarlo!

Para probar que funciona, yo he definido una clase con dos constructores así:

public class ClaseEjemplo
{
    private int _valor;
    public ClaseEjemplo(int valor)
    {
        _valor = valor;
    }

    public ClaseEjemplo()
    {
        _valor = 0;
    }

    public int Multiplicar(int por)
    {
        Console.WriteLine($"Llamada a {nameof(Multiplicar)} con parámetro {por}");
        return _valor * por;
    }
}

Y con este código, voy a llamar a sus dos constructores y y a su método Multiplicar (en las próximas entradas veremos en detalle cómo). Según el código, cuando cree la instancia con el constructor genérico, el resultado de llamar a Multiplicar siempre será 0, ya que cualquier número por 0 es 0:

var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);

//Obtenemos los constructores
//Contructor con parametro int
var constructorConParametros = type.GetConstructor(new[] { typeof(int) }); 
//Constructor genérico
var constructorSinParametros = type.GetConstructor(Type.EmptyTypes); 

//Creamos el objeto de manera dinámica
var objetoDinamicoConParametros = constructorConParametros.Invoke(new object[] { 2 });
var objetoDinamicoSinParametros = constructorSinParametros.Invoke(new object[] { });

// Creamos una referencia al método   
var m = assembly.GetType(className).GetMethod("Multiplicar");

//Llamamos al método pasandole el objeto creado dinámicamente y los argumentos dentro de un object[]
var retConstructorParamatrizado = m.Invoke(objetoDinamicoConParametros, new object[] { 3 });
var retConstructorGenerico = m.Invoke(objetoDinamicoSinParametros, new object[] { 3 });
Console.WriteLine($"El retorno de la función con constructor parametrizado es: {retConstructorParamatrizado}");
Console.WriteLine($"El retorno de la función con constructor genérico es: {retConstructorGenerico}");

Tras ejecutar el programa, efectivamente podemos comprobar que el resultado es el esperado:

La imagen muestra el resultado de hacer llamadas a los constructores mediante reflexión

Con esto hemos visto una manera de crear objetos de manera dinámica «eficientemente» gracias a la reflexión en constructores. En las siguientes entradas, seguiremos desgranando como funciona esta maravillosa herramienta que es la reflexión.

He actualizado el repositorio de GitHub con el código para añadir el ejemplo de reflexión en constructores.

**La entrada La potencia de la Reflexión en C# (Parte 3: Constructores) se publicó primero en Fixed Buffer.**

» Leer más, comentarios, etc...

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin