Weblogs Código

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...

Picando Código

Comunicación y sincronización entre tu teléfono Android y tu computadora Linux con KDEConnect

julio 14, 2019 10:00

Se viene la convergencia entre computadora de escritorio y teléfono móvil, y KDEConnect la hace sentir más cercana. KDEConnect te permite conectar tu computadora con GNU/Linux y tu teléfono o dispositivo móvil con Android. Esto nos permite tener sincronización entre ambos dispositivos y podemos hacer varias cosas: controlar la computadora desde el teléfono, compartir directorios, hacer que suene el teléfono si no lo encontramos, ver notificaciones del teléfono en nuestra computadora y más.

Connect

Es súmamente práctico y funciona muy bien. Lo conocí hace un par de años probando KDE Plasma 5, y hace poco me vino a la memoria de nuevo. Soy de los que se niega a usar servicios de streaming para escuchar música. Me gusta mucho escuchar música y tener que depender de una conexión a internet para eso me resulta absurdo. Por eso sigo comprando CD’s y pasándolos a digital o comprando música para descargar en sitios como Bandcamp. Además arrastro archivos de música desde hace años. Uso mi teléfono para escuchar música y además tengo un pendrive exclusivo para música. A veces me acuerdo de llevar el pendrive del trabajo a casa y viceversa, otras no. Por eso en general el pendrive queda en el trabajo, y en casa escucho música desde el teléfono conectado ya sea con auriculares o a través de un parlante Bluetooth.

Resulta que hace poco estaba en el trabajo y me había olvidado el pendrive con música en casa. Tenía muchas ganas de escuchar un disco en particular, que tengo en el teléfono, pero no en la computadora. Tampoco tenía el cable para transferir los archivos del teléfono a la laptop, y fue ahí que pensé «qué práctico sería mandar los archivos del teléfono a la laptop por algún medio inalámbrico». Y recordé que existía KDEConnect.

KDEConnect es parte del entorno de escritorio plasma, pero funciona en KDE, GNOME y cualquier otro ambiente de escritorio de Linux. En GNOME particularmente existe la extensión GSConnect, una implementación completa de KDEConnect que se integra con Nautilus, Firefox y Chrome. La aplicación para Android se puede descargar desde la Google Play Store y la tienda de aplicaciones libres y abiertas F-Droid.

Una vez instaladas ambas partes, podemos sincronizar desde nuestro teléfono dispositivos que se encuentren en la misma red:

KDEConnect dispositivos

Al encontrar nuestra computadora, la seleccionamos y veremos que no están sincronizadas, por lo que pedimos un «pairing»:

KDE Connect - pairing

Inmediatamente veremos una notificación en nuestro sistema avisándonos que un dispositivo móvil quiere sincronizarse con nuestra computadora. Al aceptarlo, vamos a ver el ícono de KDEConnect en la bandeja de sistema junto al ícono de Wifi y demás:

KDEConnect GNOME

Como ven, nos muestra la información de la carga de batería, y opciones de usar la mensajería del teléfono, hacerlo sonar, ver archivos, compartir cosas y demás. En la App podemos ver las distintas opciones:

KDEConnect App

Como ven en esta imagen, algunas cosas necesitan permisos específicos del teléfono, por lo que tenemos que habilitarlas individualmente. El control remoto funciona increíblemente bien. Podemos usar la pantalla táctil del teléfono como touchpad, e ingresar texto a través del teclado. También podemos usar un menú de presentaciones para pasar «diapositivas» (¿alguna palabra mejor para este término heredado de la era PowerPoint?) con unos botones enormes o si bloqueamos el teléfono con las teclas de volúmen.

Controlar la música que se reproduce en la computadora desde el teléfono tiene su gracia, y me hizo acordar a aquella vez que hice mi propio control remoto para volúmen en Ruby. Para probarlo abrí Clementine, me puse a reproducir un disco, y al ver el control multimedia en KDEConnect en mi teléfono, cargó hasta la tapa del disco que estaba escuchando:

KDEConnect - Música

La aplicación soporta más cosas de las que recuerdo en el momento que la probé por primera vez. En ese momento la desinstalé después de probarla, pero esta vez se queda en mi teléfono y computadora. Cuando la precisamos, resulta extremadamente práctica.

La lista completa de funcionalidades al momento:

  • Recibir notificaciones de tu teléfono en tu computadora y responder a mensajes
  • Controlar la música que estás reproduciendo en tu computadora desde tu teléfono
  • Usar tu teléfono como control remoto de tu computadora
  • Ejecutar comandos predefinidos en tu PC desde dispositivos conectados
  • Ver la carga de la batería de tu teléfono desde la computadora
  • Hacer que suene tu teléfono si no lo encuentras
  • Compartir archivos y enlaces entre dispositivos
  • Navegar los archivos de tu teléfono desde tu computadora
  • Controlar el volúmen de tu computadora desde el teléfono

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

Blog Bitix

Recuperar datos eficientemente en GraphQL usando batching con data loaders

julio 12, 2019 04:00

Al diferencia de una API REST donde cada recurso posee un endpoint propio en GraphQL los recursos están relacionados y forman un grafo. Por otro lado las propiedades devueltas en una consulta de GraphQL son las que se indiquen en la consulta en vez de prefijadas como en una API REST. Hay que tener en cuenta que GraphQL para recuperar las propiedades de las entidades usa un resolver y las recupera una a una, si se devuelve una lista de elementos y de cada uno de esos elementos otra propiedad para la que hay que generar una consulta adicional a la base de datos el rendimiento no será bueno. Los data loaders permiten recuperar las propiedades relacionadas de una colección de entidades eficientemente evitando el problema 1+N.

GraphQL
Java

Una de las dificultades a resolver en GraphQL es evitar los problemas de generar 1+N consultas dado que en algunas peticiones se recupera una lista de elementos para recuperar alguna otra propiedad de esos elementos para la que se realiza otra consulta. Suele ocurrir al navegar las relaciones de las entidades, por ejemplo al solicitar una lista de libros y de cada libro obtener su autor, para obtener los libros se necesita una consulta y hay que evitar que para recuperar el autor de cada libro generar otra consulta, si el número de libros recuperados es grande el número de consultas será grande y la consulta será poco eficiente, lenta y generará una carga a evitar en el servidor de base de datos.

En el artículo Recuperar datos eficientemente en GraphQL usando batching comentaba una estrategia para evitar este problema que consistía en dados una serie de elementos recuperados y si la propiedad estaba presente en la consulta se obtenían los identificativos de esos elementos y se recuperaba la propiedad para todos los elementos en una única consulta.

Sin embargo, GraphQL posee otra estrategia para resolver el problema de los 1+N, mediante Data Loaders. Para usar un data loader en una propiedad de un tipo hay que crear una clase que implemente la interfaz MappedBatchLoader o MappedBatchLoaderWithContext de java-loader. El método a implementar es load(Set<K>) que recibe un conjunto de instancias de las que se quiere recuperar la propiedad y devuelve un Map<K,V> cuya clave es la instancia de la colección y el valor de la propiedad recuperada.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package io.github.picodotdev.blogbitix.graphql.dataloader;
import io.github.picodotdev.blogbitix.graphql.type.Book;
import org.dataloader.BatchLoaderEnvironment;
import org.dataloader.MappedBatchLoaderWithContext;
import org.springframework.stereotype.Component;
...
@Component
public class IsbnDataLoader implements MappedBatchLoaderWithContext<Book, String> {
public IsbnDataLoader() {
}
@Override
public CompletionStage<Map<Book, String>> load(Set<Book> books, BatchLoaderEnvironment environment) {
Map<Book, String> isbns = books.stream().collect(Collectors.toMap(
Function.identity(),
 Book::getIsbn
));
return CompletableFuture.supplyAsync(() -> isbns);
}
}

Una vez definidos los data loaders hay que incluirlos en un registro e indicarlos en la clase del contexto de GraphQL. El método contextBuilder recibe todas las instancias de data loaders, el método dataLoaderRegistry crea el registro y finalmente se asigna el registro al contexto. Los data loaders cachean los datos de modo que si los datos no se deben compartir entre peticiones hay que construir los data loaders en cada petición.

 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
package io.github.picodotdev.blogbitix.graphql;
...
@SpringBootApplication
public class Main {
...
@Bean
public GraphQLContextBuilder contextBuilder(List<MappedBatchLoaderWithContext<?, ?>> mappedBatchLoaders) {
return new GraphQLContextBuilder() {
@Override
public GraphQLContext build(HttpServletRequest request, HttpServletResponse response) {
graphql.GraphQLContext data = graphql.GraphQLContext.newContext().build();
GraphQLContext context = new DefaultGraphQLContext(data, request, response);
context.setDataLoaderRegistry(buildDataLoaderRegistry(mappedBatchLoaders, context));
return context;
}
@Override
public GraphQLContext build(Session session, HandshakeRequest request) {
graphql.GraphQLContext data = graphql.GraphQLContext.newContext().build();
GraphQLContext context = new DefaultGraphQLContext(data, session, request);
context.setDataLoaderRegistry(buildDataLoaderRegistry(mappedBatchLoaders, context));
return context;
}
@Override
public GraphQLContext build() {
graphql.GraphQLContext data = graphql.GraphQLContext.newContext().build();
GraphQLContext context = new DefaultGraphQLContext(data);
context.setDataLoaderRegistry(buildDataLoaderRegistry(mappedBatchLoaders, context));
return context;
}
};
}
private DataLoaderRegistry buildDataLoaderRegistry(List<MappedBatchLoaderWithContext<?, ?>> mappedBatchLoaders, GraphQLContext context) {
DataLoaderRegistry registry = new DataLoaderRegistry();
for (MappedBatchLoaderWithContext<?, ?> loader : mappedBatchLoaders) {
registry.register(loader.getClass().getSimpleName(),
DataLoader.newMappedDataLoader(
loader,
DataLoaderOptions.newOptions().setBatchLoaderContextProvider(() -> context)
)
);
}
return registry;
}
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}

Una vez creados los data loaders hay que usarlos en los resolver de las propiedades de una entidad en la que se desee que se cargue de forma batched. El método de la propiedad del resolver debe devolver un CompletableFuture, el método recibe la instancia de la que se quiere recuperar una propiedad y una referencia de DataFetchingEnvironment de la librería graphql-java, se recupera el data loader de esa propiedad y se le indica que acumule el conjunto de instancias de las que se quiere recuperar. GraphQL en algún momento llamará al método load(Set) que recibe un conjunto de instancias para realizar la carga de todas en una única consulta.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package io.github.picodotdev.blogbitix.graphql.resolver;
...
public class BookResolver implements GraphQLResolver<Book> {
...
public CompletableFuture<String> getDataLoaderIsbn(Book book, DataFetchingEnvironment environment) throws InterruptedException {
DataLoader<Book, String> dataLoader = environment.getDataLoader(IsbnDataLoader.class.getSimpleName());
return dataLoader.load(book);
}
...
}

Al obtener los datos del conjunto de libros que utilizan un batch loader se produce la siguiente salida.

 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
$ curl -XPOST -H 'Content-Type: application/json' -d '{"query":"query{books{id title dataLoaderIsbn}}"}' http://localhost:8080/graphql
{
"data": {
"books": [
{
"id": 7,
"title": "Ojo en el cielo",
"dataLoaderIsbn": "3a8441b1-fd9a-40d4-8765-2ccb0900a223"
},
{
"id": 8,
"title": "Muerte de la luz",
"dataLoaderIsbn": "06f217f7-5be0-4334-b946-1b29e93387a1"
},
{
"id": 9,
"title": "El nombre de la rosa",
"dataLoaderIsbn": "ffc704a3-b34a-4a06-80e1-506e33d20aab"
},
{
"id": 10,
"title": "Los tejedores de cabellos",
"dataLoaderIsbn": "21b70880-e245-405e-bffc-ab6c5975d837"
},
{
"id": 11,
"title": "Ready Player One",
"dataLoaderIsbn": "18cd56d3-8050-4467-9fa8-fb9aeb0d1ea5"
}
]
}
}

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

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

Picando Código

Spacemacs: entorno integrado eficiente y sofisticado para Emacs

julio 12, 2019 11:00

Desde hace unos 2 años vengo usando Spacemacs como editor de texto para programar, escribir y más. Lo he mencionado varias veces en el blog particularmente en posts sobre Emacs, pero nunca escribí al respecto. Es un proyecto que me ha dado mucho y me gustaría compartir lo que he aprendido, y con suerte animar a alguien más a probar Spacemacs. Así que ¡hablemos de Spacemacs!

Spacemacs

¿Qué es Spacemacs?

Spacemacs es una «distribución» de Emacs. Emacs es un editor de texto extensible y personalizable. Cada uno puede crear su propia «distribución» agregando funciones, paquetes y distintas configuraciones en archivos Elisp (Emacs Lisp), para que Emacs se comporte o se vea como uno prefiera. En sí Spacemacs es un conjunto de archivos elisp. Si bien hay varios kits de inicio de Emacs para mejorar su funcionamiento por defecto, Spacemacs es uno de los más populares. Se caracteriza entre otras cosas por tener un desarrollo comunitario de software libre bajo licencia GPLv3.

Cuando alguien tiene un problema en Spacemacs, no lo arregla sólo para su caso particular, la solución o nueva característica es compartida con el resto en el marco en común y opinionado que es Spacemacs. Es sumamente modular, no necesitamos usar TODO lo que nos provee, de hecho su perfil altamente configurable nos deja activar y desactivar cosas a medida que las precisamos. Y es muy personalizable.

Dedicada a los usuarios de Vim

Una característica fundamental de Spacemacs es que comenzó como una distribución basada en Evil, una capa extensible de vi para Emacs. Esta herramienta emula las características principales de Vim en Emacs. Gracias a Evil, podemos aprovechar lo bueno de Vim y lo bueno de Emacs combinado en un editor que provee lo mejor de ambos mundos. Ésta fue la razón principal por la que empezamos a usar Spacemacs en mi trabajo en su momento. Había usuarios de Emacs y usuarios de Vim, y con Spacemacs podíamos hacer pair programming en la máquina de cada uno en un entorno familiar. Si bien creo que soy el único que quedó usando Spacemacs, migré mis preferencias particulares de mi configuración de Emacs a Spacemacs y nunca volví atrás. Por más que no necesite usar Vim en mi Emacs, la distribución alcanzó ser mucho más que la combinación de Emacs con Vim.

¿Y qué tiene de bueno?

Viniendo de Emacs, una cosa que me encantaba era agregar funciones que me encontraba por ahí, configuraciones, paquetes nuevos y personalizaciones. En Spacemacs me siento más seguro de hacerlo al poder trabajar dentro en un «framework». Y no es casualidad, Spacemacs se basa en varios principios:

Ergonomía – la forma de usar comandos y atajos está definida con la comodidad y salud de nuestros dedos y manos en mente. En lo personal no sé si exploto esta característica del todo porque no uso el modo Vim que tiene un modo de inserción de texto y otro de ejecución de comandos. Como uso modo Emacs, sigo apretando mucho Ctrl y Alt todo el tiempo 😛

Mnemotecnia – Los atajos de teclado están organizados con prefijos mnemónicos como b para buffer, p para proyecto, etc., por lo que son fáciles de aprender y recordar.

Visible – Visibilidad en tiempo real sobre los comandos y atajos de teclado disponible. Y teniendo una idea de cómo usarlo, es fácil encontrar y descubrir nuevas funcionalidades.

Consistencia – Dadas ciertas convenciones, funciones similares tienen los mismos atajos de teclado en todos lados. Por ejemplo el «ir a definición» de una clase o módulo sería el mismo atajo para Ruby que para Python, o algo así.

Una ventaja que ya tenía Emacs para mí, y se transporta a Spacemacs es que uso una sóla herramienta para todo. Puedo programar en Ruby, Elixir, editar archivos de configuración, ejecutar tests, compilar, usar Git, jugar Tetris, etc. Con el soporte para Language Server Protocol, se puede usar casi cualquier lenguaje de programación con las características de un IDE (auto-complete, documentación). Es un excelente punto de inicio para principiantes que quieran empezar a usar Emacs. En el fondo sigue siendo el mismo editor de texto que vengo usando hace años, y todo lo que se puede hacer en Emacs, se puede hacer en Spacemacs.

¿Cómo se usa?

Spacemacs nos permite acceder a modos comunes y herramientas disponibles en Emacs a través de unidades auto-contenidas que llama capas («layers»). Éstas capas son paquetes de archivos de código elisp que incluyen configuraciones, atajos de teclado, funciones y otros paquetes. Un ejemplo es la capa ruby que incluye un montón de paquetes como rake, bundler, chruby, rvm, y más herramientas que nos ayudan a trabajar con el lenguaje de programación Ruby, y las integra sin tener que instalar cada una o configurarlas a mano. Generalmente podemos personalizar y configurar todo más a fondo, pero las convenciones son suficientemente buenas como para empezar a trabajar con una nueva capa sin mucho esfuerzo.

Es importante recordar que tanto Emacs como Spacemacs son editores de texto. Se usan para mucho más que programación. Varios autores lo usan para escribir. Un ejemplo famoso es Neal Stephenson, autor de Snow Crash, The Diamond Age, entre otros.

Por defecto, Spacemacs usa un archivo ~/.spacemacs para controlar qué capas cargar y personalizar todo. Dentro de este archivo hay varias funciones de Spacemacs donde podemos especificar y personalizar distintos aspectos. Es el archivo que nos conviene guardar bajo control de versiones para ir modificando y mejorando con el tiempo. Pueden leer más al respecto en la guía rápida. Pero si hay algo en particular de lo que les gustaría leer en español sobre Spacemacs, no duden en pedirlo en los comentarios de este post.

En mi caso, como empezamos compartiendo una configuración de Spacemacs, teníamos un archivo .spacemacs bajo control de versiones en un repositorio de la empresa. Y para mis configuraciones personales, escribí una capa personal. Escribí más al respecto en el blog de Cultivate (en inglés), pero en algún momento voy a traducir y actualizar ese post para publicarlo acá.

Cómo aprender a usar Spacemacs

Como mencioné al principio, Spacemacs está basado en Evil, que es un modo que nos permite usar la configuración de teclas de Vim. Es así que existen dos modos principales: Evil Mode (Vim) o Holy Mode (Emacs) y un modo híbrido. Otra característica fundamental de Spacemacs es la tecla líder. En el caso de Evil Mode es SPC y en Holy Mode Alt + M. Esto nos permite ejecutar varios comandos de Spacemacs mismo. La tecla también es modificable. Pero en la documentación siempre vamos a ver SPC para referirse a la tecla líder. Por ejemplo con SPC m (Alt m m en Holy Mode), podemos encontrar todos los comandos del modo principal activado.

Y para hacer las cosas todavía más fáciles, Spacemacs incluye un tutorial propio, al que podemos acceder con SPC h Y para ingresar a un Vimtutor adaptado a Evil que también beneficiará a usuarios en modo Emacs.

Instalación de paquetes

Viniendo de Emacs, nos podemos ver tentados a instalar un paquete con package-install o desde el menú list-packages. Pero al reiniciar Spacemacs, los paquetes instalados «A la Emacs» se van a desinstalar por ser considerados «huérfanos». Para gestionar los paquetes, tenemos que agregarlos al archivo .spacemacs, ya sea agregando una capa que lo use, o agregando un paquete en particular. Al iniciar Spacemacs, se va a fijar los paquetes que tiene que instalar o desinstalar basado en nuestra configuración.

master vs develop

Recomiendo usar la rama develop del repositorio Git, porque master se actualiza muy poco y el desarrollo periódico se va haciendo en develop. El último «release estable» fue en Enero de 2018, pero la rama master se mantiene actualizada con bugs (en teoría). Vengo usando develop casi desde un principio y no he tenido problemas. Pero teóricamente puede tener regresiones.

Conclusión

Gracias por leer hasta acá, espero haber despertado su interés por Spacemacs o que al menos lo tengan más presente como opción si no lo tenían ya. Mis archivos de configuración están compartidos en GitHub, por si quieren ver más. Aunque más adelante voy a contar un poco sobre lo que hay ahí en otro post.

Me gusta mucho seguir usando una herramienta tan extensible como Emacs desde hace años, siempre se aprende algo nuevo. En base a una pregunta en Twitter, veo que no soy el único que se queda con lo mismo. Hasta encontré más gente que usa Spacemacs 🙌🏻. Me interesa saber cómo otras personas usan su editor de texto preferido y qué les lleva a cambiar de uno a otro. Así que si tienen algún comentario al respecto, les agradezco lo compartan 🙂

Entiendo que mi relación con Emacs es un poco personal. Pero también le veo ventaja a aprender una sóla herramienta muy bien que después puedo seguir usando a pesar de cambiar de tecnología o lenguaje de programación. Ni que hablar no tener que volver a aprender atajos de teclado o procesos de trabajo con otro editor de texto. Pero todos somos distintos y siempre lo mejor es tener opciones (incluso con Emacs, cada persona puede tener un entorno sumamente personalizado). Además que cambiar de un editor a otro puede ser un desafío interesante y entretenido, además de darnos la habilidad de aprender nuevas herramientas. Y uno mismo va cambiando con el tiempo, lo que me sirve hoy puede no servirme mañana.

En fin, temas interesantes para charlar.

Les invito a probar Spacemacs, y cualquier duda que tengan pueden contactarme que prometo ayudar dentro de lo que pueda.

Post escrito con Spacemacs ✌

» 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...

Variable not found

Enlaces interesantes 369

julio 08, 2019 03:37

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

Por si te lo perdiste...

.NET / .NET Core

ASP.NET / ASP.NET Core

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en: www.variablenotfound.com.

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

Blog Bitix

Los tipos de módulos de JPMS añadidos a partir de Java 9

julio 07, 2019 10:00

Los módulos de Java dotan a la plataforma de nuevas características. Para garantiza la compatibilidad con las librerías existentes y permitir una transición progresiva de una versión sin módulos a una con módulos la plataforma de módulos de Java define varios tipos de módulos.

Java

Con la publicación de Java 9 el 2017 se introdujo la importante novedad de los módulos que proporciona a la plataforma Java varias características como encapsulación fuerte, interfaces bien definidas y dependencias explícitas. Todos las clases se organizan en paquetes y en Java 9 también en módulos para lo cual fue necesario reorganizar en módulos todos los paquetes de los que se compone la API de Java.

Antes de Java 9 todas las clases se proporcionaban en una lista ordenada de archivos jar, lo que se conocía como el classpath y donde cualquier clase tenía acceso a cualquier otra que se encontrase en él respetando los ámbitos de visibilidad (public, protected, private y package). En la definición de cada módulo en su archivo module-info.java se debe especificar cuales son los módulos requeridos para su funcionamiento no permitiendo la máquina virtual de Java el acceso a ninguna otra clase de otros módulos ni a ninguna clase de los paquetes no exportados.

Para mantener la compatibilidad hacia atrás y hacer más sencillo la transición hacía los módulos, algunas librerías puede que ya no tengan mantenimiento, se pueden dar tres tipos de módulos.

  • Módulos con nombre: están compuestos por las librerías que tienen su definición de módulo en el archivo module-info.java y son colocados en el modulepath al iniciar la aplicación. Únicamente leen los módulos que explícitamente se ha indicado en la definición del módulo con la palabra requires y tiene acceso a los paquetes y sus clases exportados de los módulos requeridos.
  • Módulos automáticos: son las librerías que no tienen una definición de módulo pero que son colocadas en el modulepath. La máquina virtual de Java le asigna un nombre de módulo de forma automática según el nombre de la librería o según la propiedad Automatic-Module-Name del archivo de manifiesto. Leen todos los otros módulos del sistema, los que se encuentren en el modulepath (incluidos todos los otros automáticos) y de la imagen del JDK, y todas las clases del módulo anónimo. Los módulos automáticos son necesarios para que no requerir convertir una librería a un módulo, esto es no requerir convertir a un módulo todo el código ya existente lo cual es un problema ya que muchas librerías ya no tienen mantenimiento. Ya que no tienen una definición de módulo se exportan todos los paquetes.
  • Módulo anónimo: todas las librerías (incluso las que tienen su definición del módulo) que se colocan el classpath forman el módulo anónimo. Leen todos los módulos del sistema y tienen acceso a todos sus paquetes exportados.

Ya se han publicado varios libros que explican detalladamente la modularidad introducida en Java 9. Cualquiera de ellos es una guía completa de la modularidad de Java.

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

Blog Bitix

¿Donde comprar un ordenador sin Windows o con GNU/Linux?

julio 05, 2019 03:30

Hace no tanto tiempo era prácticamente imposible adquirir un equipo sin Windows preinstalado y salvo algunas excepciones en muchos comercios solo incluyen equipos con Windows o macOS. Pero a día hoy si alguien quiere comprar un equipo sin Windows para instalarle GNU/Linux hay varias posibilidades.

Slimbook
VANT

En todos los comercios, grandes superficies e incluso en las pequeñas tiendas especializadas en informática solo hay dos opciones para comprar un portátil o lo compras con Windows incluído o optas por los caros mac de Apple, los ordenadores de marca en formato torre o todo en uno también vienen todos con Windows. Hasta el momento no he encontrado ningún portátil con la posibilidad de adquirirlos con GNU/Linux en las tiendas en las que he estado. En el caso de los ordenadores de torre que montan las pequeñas tiendas a medida es posible adquirirlos sin sistema operativo pero para los usuarios con pocos conocimientos es un problema ya que no saben como instalárselo. Aún así tampoco he visto a ningún pequeño comercio ofrecer el servicio de instalarle alguna distribución de GNU/Linux sin coste al adquirir el equipo o con un coste mucho más reducido que la licencia de Windows.

Sin embargo, desde hace un tiempo es posible adquirir un ordenador con GNU/Linux y sin la licencia de Windows ni su coste, que no tienen nada que envidiar a cualquier otro equipo comercial de una marca más grande. En el caso de portátil están los Slimbook o de VANT que tiene unas características muy notables con el Slimbook PRO X a un precio razonable, con última generación de procesadores Intel, posibilidad de dos SSD NVMe, 32 GiB de memoria, pantalla con resolución 1920x1080 de marcos reducidos. En el caso de Slimbook ofrecen también un modelo de mini PC, el Slimbook ONE o con disipación pasiva el ZERO. En el caso de VANT sus portátiles MOOVE y de escritorio BLOCK, CELL y LIFE inluso con procesadores AMD Ryzen. En ambos casos hay posibilidad de elegir entre algunas distribuciones de GNU/Linux con las que se quiere que venga preinstalado y estos son solo algunos de los modelos que tienen disponibles, Slimbook tiene también algún modelo tipo AIO o all-in-one.

Portátiles Slimbook y VANT
Ordenadores de escritorio Slimbook y VANT

Otra alternativa son los Inte NUC como el Bean Canyon que adquirí hace unos unos meses, al ser un barebone no incluía memoria ni almacenamiento, tanto la memoria como el almacenamiento SSD los adquirí aparte y su instalación realizable en unos pocos minutos es muy sencilla ni requiere grandes conocimiento. Como no incluía almacenamiento tampoco incluía Windows, le instalé Arch Linux y todo el hardware fue reconocido sin necesidad de controladores adicionales.

Los pequeños comercios seguramente no puedan competir en precio con los grandes superficies o gigantes como Amazon o grandes superficies como El Corte Inglés o MediaMarkt pero creo que tienen una oportunidad si ofrecieran el servicio de instalar alguna distribución de GNU/Linux o en ofrecer asesoramiento personalizado.

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

Variable not found

Null coalescing assigment "??=", el nuevo operador de asignación en C# 8

julio 02, 2019 06:15

.NET CoreEn esta ocasión vamos a ver una pequeña novedad de C# 8 destinada a mejorar la codificación de un escenario muy frecuente: asignar un valor a una variable si ésta es nula.
Recordad que C#8 está aún en preview, y para usarlo hay que seguir los pasos que vimos en un post anterior.
En otras palabras, esta mejora pretende simplificar implementaciones como las siguientes, donde comprobamos si una variable contiene null y, en caso afirmativo, le asignamos un valor:
...
var defaultValue = ... // lo que sea;
var x = GetSomething();

// Usando un bloque if:
if(x == null)
{
x = defaultValue;
}

// O bien, usando el null coalescing operator:
x = x ?? defaultValue;

La solución propuesta en C# 8 ha sido la introducción del operador null coalescing assignment ??=, de forma que cualquiera de los bloques anteriores podría escribirse de la siguiente forma:
x ??= defaultValue;
Para verlo en acción sobre un ejemplo práctico, implementaremos la clásica propiedad con backing field que solemos usar para inicializar propiedades de tipo colección de forma lazy, es decir, sólo cuando vamos a utilizarlas. En versiones de C# anteriores a la 8, sería algo así:
public class Invoice
{
private ICollection<InvoiceLine> _lines;

public ICollection<InvoiceLine> Lines
{
get => _lines ?? (_lines = new HashSet<InvoiceLine>());
set => _lines = value;
}
}
Y ahora, quedará algo más compacto:
    public class Invoice
{
private ICollection<InvoiceLine> _lines;

public ICollection<InvoiceLine> Lines
{
get => _lines ??= new HashSet<InvoiceLine>(); // <- Here!
set => _lines = value;
}
}
En fin, sin ser algo revolucionario, sí es uno de esos pequeños detalles que continúan haciendo de C# un lenguaje cada vez más completo... ;)

Publicado en Variable not found.

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

Variable not found

Un año más, ¡Microsoft MVP!

julio 01, 2019 04:28

MVP Award ProgramHace un ratillo he recibido por parte de Microsoft una gran alegría, y necesito compartirla con todos vosotros porque al fin y al cabo sois una parte muy importante del asunto :)

Por noveno año consecutivo (¡nueve años ya, wow!), he sido reconocido Microsoft MVP por las contribuciones realizadas a la comunidad de desarrolladores durante el año pasado.

Es todo un lujo y un honor seguir formando parte de este grupo de locos de la tecnología y apasionados del software, entre los que me precio de contar con buenos amigos y colegas a los que admiro profundamente.

Lo primero, me gustaría volver a agradeceros a todos, amigos y amigas de Variable Not Found, vuestro incondicional apoyo a lo largo de estos años. Sin duda, es lo ha hecho posible llegar hasta este punto, y tener aún cuerda para ir mucho más lejos ;)

Gracias a mis tres niñas por permitirme tantas horas de dedicación a lo que tanto me gusta, asumiendo con deportividad mi ausencia en muchos momentos. De no contar con su comprensión e infinita generosidad, tampoco habría sido posible llegar a este momento 

Me gustaría también agradecer al equipo del programa MVP en Microsoft el trabajo que realizan, y especialmente a Cristina e Irene por su esfuerzo, cercanía y por ponerlo todo tan fácil.

Por último, aprovecho para enviar una afectuosa bienvenida a los MVP que en este momento estáis celebrando vuestro primer nombramiento y desearos que disfrutéis el momento, porque probablemente se convierta en uno de vuestros más preciados recuerdos. Y por supuesto, mi más sincera enhorabuena también a los que repetís galardón: como suele decirse, el mérito no es sólo llegar, sino también mantenerse.

Y ahora, ¡a celebrarlo!

Desarrollador tecleando como un poseso
Source: Gifmanía.

Publicado en: www.variablenotfound.com.

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

Blog Bitix

Hemeroteca #15

junio 30, 2019 08:30

Hugo

Estos seis primeros meses del 2019 han transcurrido como todos los años anteriores, sigo manteniendo la constancia de publicar dos artículos nuevos y únicos, algunas semanas sólo uno las menos tres.

En cuanto al blog durante este tiempo le he hecho un cambio de diseño para que el contenido quede centrado en la pantalla y tenga más espacio horizontal lo que creo hace más agradable la lectura del texto y los extractos de código se ven mejor con menos necesidad de hacer desplazamiento horizontal.

Para que la publicidad y los ingresos de adsense no se viesen perjudicados y para mejorarlos más aún si cabe he puesto un bloque billboard en la cabecera, he mantenido el leaderboard después del resumen del articulo en aquellos que lo tienen y la publicidad lateral he hecho que sea sticky de manera que permanece mas tiempo visible con la consiguiente mejora en el numero de clic.

Sólo han pasado dos meses con el nuevo diseño pero creo que ha sido un acierto, para la lectura del usuario como para los ingresos de adsense que apreciablemente sigue mejorado respecto al año anterior. Estos meses de verano el tráfico suele descender algo y las visitas ya no me continúan creciendo mes a mes, los mejores meses son los de octubre, noviembre y diciembre con lo que esas fechas podré comparar mejor con las del año pasado. El número de visitas se mantiene más o menos contante y no de crecimiento como semestres anteriores.

En cuanto a los artículos que he escrito han sido sobre las temáticas habituales a las que dedicó este blog. Como desde hace poco estoy pudiendo usar Java 11 (¡por fin!, algo al menos) en el trabajo espero poder escribir algunos artículos con lo que considere destacable, por el momento he actualizado el ejemplo de código de la serie de artículos de GraphQL de los que tengo pendiente publicar alguno más. Los artículos de este semestre han sido los siguientes. En total 47 nuevos.

En la categoría de Java.

En la categoría de GNU/Linux.

Unos sobre algunas de las herramientas de HashiCorp, los que me gustaría seguir ampliando en el futuro.

Varios sobre JavaScript y desarrollo web.

Sobre SQL destacando el dedicado a como hacer paginación correctamente con seek en vez de como habitualmente con ofsset.

Otros que no entran en las categorias anteriores y otro de opinión.

Los dedicados al blog.

Y finalmente uno que estuvo patrocinado.

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

Bitácora de Javier Gutiérrez Chamorro (Guti)

Sale más a cuenta escribir un libro que escribir software

junio 30, 2019 07:12

Hace casi un año desde Análisis estático de FileOptimizer, mucho tiempo sin hablar de FileOptimizer y de software. No significa que el proyecto haya sido abandonado, simplemente que no he encontrado nada interesante que decir. Desde septiembre de 2018 con la versión 13.20, he publicado 5 actualizaciones, ahora vamos ya por la 13.70. Los cambios …

Sale más a cuenta escribir un libro que escribir software Leer más »

Artículo publicado originalmente en Bitácora de Javier Gutiérrez Chamorro (Guti)

La entrada Sale más a cuenta escribir un libro que escribir software aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

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

Blog Bitix

Sobre la Play Station 4, Play Station 5 y Google Stadia

junio 29, 2019 09:00

El Intel NUC que adquirí hace unos meses no es el ideal para jugar sobre todo por su pequeño tamaño y temperaturas, en mi caso como jugador ocasional es suficiente pero unido a que soy usuario de GNU/Linux hace que deba usar Wine o Steam para los juegos con lo que hay algunos juegos que me llaman la atención que no tengo disponibles. La Play Station 4 está ya al final de su ciclo de vida, ya hay noticias de la Play Station 5 y Google Stadia ofrecerá una nueva experiencia de juego ¿comprar una Play Station 4? ¿o seguir con Diablo 3 mientras se lanzan la Play Station 5 o a Stadia?.

Play Station
Google Stadia

Desde que me compré un Intel NUC he estado jugando a Diablo 3 en GNU/Linux con Wine en la distribución Arch Linux perfectamente, al menos de forma jugable con una resolución de 1600x900 en un monitor Benq PD2700Q y con unos detalles de calidad gráfica medios. El NUC con un gráfica Intel integrada Iris 655 es notablemente mejor que la típica UHD 630 de otros modelos de procesador Intel que cumple para un jugador ocasional pero no se puede comparar con una dedicada NVIDIA o AMD de un equipo más grande. Y aunque funciona sin problemas la temperatura que alcanza llega a a entre los 75º y 80º, teniendo en cuenta que es un equipo de 10cm x 10 cm x 3.5cm es una temperatura para la que probablemente no sea recomendable mantener durante largos periodos de tiempo.

Por otro lado el hecho de usar Linux hace que no todos los juegos estén disponibles, con el gran trabajo de Steam hay mayor número de títulos disponibles pero algunos únicamente siguen estando disponibles para Windows como Watch Dogs. Probablemente la mejor alternativa para un usuario de Linux y para mi es usar una consola para tener un catálogo amplio de juegos, sin problemas de compatibilidad y con buen rendimiento. La consola candidata que evaluaría sería una Play Station.

Ya han sido publicadas noticias indicando que la Play Station 4 está al final de su ciclo de vida comercial y será sustituida previsiblemente en algún momento de 2020 o 2021 por una nueva Play Station 5. Por otro lado Google ha anunciado su plataforma de juegos Stadia con un funcionamiento vía streaming, disponible a finales del 2019 o principios del 2020. En esta situación surgen varias dudas razonables: ¿comprar una Play Station 4? ¿seguir con Diablo 3? ¿esperar a la Play Station 5? ¿que ofrece Google Stadia?

Play Station 4

La Play Station 4 fue comercializada a finales del 2013, con su actualización del modelo slim y pro en el 2016. Habiendo ya pasado varios años desde su lanzamiento posee un amplio catálogo de juegos con muy buena calidad. Su precio está entre los 350€ nueva para el modelo slim o 230€ de segunda mano o seminueva en una tienda. Al haber pasado ya unos años hace que muchos destacados juegos se encuentren en unos razonables precios de entre 10€ y 20€.

Aún habiéndose anunciado la Play Station 5 como su sucesora aún están por lanzarse varios títulos importantes, todavía ofrecerá muchas horas de juego durante varios años más aún después de lanzarse la PS5.

Algunos de los juegos más populares son los siguientes: Grand Theft Auto V, Watch Dogs y Watch Dogs 2, Last of Us, Assassins Creed, FIFA, Dirt Rally, Horizon Zero Dawn, God of War, Bloodborne, Far Cry 5, The Witcher 3, Mafia 3, Tropico 5, Fallout 4, Dark Souls, Days Gone, Uncharted, The Division, Nioh, XCOM 2, Little Big Plannet, …

Diablo 3

Como tengo el Diablo 3 al que juego de forma muy esporádica y aún no le he exprimido completamente puedo pasar un tiempo jugando a este juego. Si Diablo 3 tiene algo es que está diseñado para ser extremadamente rejugable con varios personajes, niveles de dificultad, variaciones en los escenarios y mejora de objetos y personajes aún habiendo completado la historia principal. Tambien tengo en la biblioteca de Steam el Company of Heroes 2 que ni siquiera aún he instalado.

Con lo que en mi caso podría esperar al lanzamiento de la PS5 o esperar a ver que ofrece Stadia jugando al Diablo 3.

Play Station 5

Entre las noticias que han aparecido sobre la Play Station 5 es que usará nuevamente un procesador y gráfica AMD pero actualizados para ofrecer mucha más potencia. Usará un AMD Ryzen mucho más capaces que los Jaguar de la PS4 y una gráfica Navi ofreciendo una capacidad de cómputo de entre 8 y 10 TFLOPS por los 1,8 de la PS4.

Uno de los problemas de lanzar una nueva consola es que hasta pasado una buena cantidad de tiempo no posee un amplio catálogo de juegos. En el caso de la PS5 al utilizar la misma arquitectura de procesador otra de las características destacadas es la retrocompatibilidad lo que la dotará del mismo catálogo de la PS4 desde mismo momento del lanzamiento, y todos los buenos juegos de la PS4 puedan ser jugados en la PS5.

Google Stadia

Desde hace bastante tiempo la Play Station ha sido la consola dominante sobre la Xbox y las varias de Nintendo. Google ha presentado ya su plataforma de juegos mediante streaming estando disponible a finales del 2019. La ventaja de Stadia es que al estar completamente en la nube no hace falta adquirir hardware, únicamente comprar los juegos con lo que al igual que las consolas se eliminan completamente los problemas de controladores, rendimiento y compatibilidad, dado que se basa en la nube también elimina el tener que descargar pesadas actualizaciones y reducirá sensiblemente los tiempos de carga.

Ofrecerá una modalidad de suscripción para tener acceso a 4K, 60 FPS, HDR y sonido 5.1 pero en la modalidad Básica solo es necesario adquirir los juegos. Dado que se basa en la nube y funciona con streaming requiere conexión permanente de internet y de un buen ancho de banda, un ADSL no soportará 4K y justamente la calidad 720p o 1080p con lo que sería recomendable utilizar fibra o cable de al menos 30 Mbps. Está por ver como afectará la latencia de la conexión a la experiencia de juego que es especialmente sensible a este aspecto.

Por lo demás el precio de suscripción de 10€/mes es recurrente pero teniendo en cuenta que una PS5 costará entre 400€ y 500€ en el momento de lanzamiento el precio de suscripción dan para varios años en lo que costaría comprar una PS5. Esta también por ver el precio de los juegos en Stadia si serán similares a los de las consolas tradicionales o algo superiores y el catálogo de juegos que ofrece en el momento de lanzamiento y pasados unos meses o algún año. Sin embargo, la tendencia a futuro parece indicar que el modelo de Stadia sea el que sigan las consolas o plataformas de juego más tarde o temprano.

Si Stadia ofrece un buen catalogo de juegos y la latencia no da problemas, los precios no son desorbitados y como parece se adelanta al lanzamiento de la PS5 puede suponer un cambio en las reglas del mercado de la consolas y ponerle dificultades a la hasta ahora dominante posición de Play Station.

Switcher HDMI

En el caso de utilizar un monitor que solo disponga de una entrada HDMI tanto para el PC como para una consola se necesita un conmutador o switch HDMI que permita conmutar la entrada sin tener que conectar y desconectar cables. En Amazon hay muchos modelos, uno de los que más me ha gustado ha sido este Conmutador HDMI 2.0 4K@60Hz de 5 entradas que ofrece 4K a 60 Hz con hasta cinco entradas HDMI, una salida y está alimentado por USB.

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

Blog Bitix

Orden de ejecución de las cláusulas de las sentencias SELECT de SQL

junio 28, 2019 03:00

PostgreSQL
MySQL

El lenguaje SQL es un potente lenguaje declarativo usado en las bases de datos relacionales como MySQL o PostgreSQL. En el lenguaje SQL se declara que datos se quieren recuperar, qué condiciones han de cumplir cumplir y qué funciones se aplican a los datos pero no se define como han de recuperarse los datos, es la base de datos la que decide como guardarlos e interpretando la sentencia SQL la que decide cómo recuperarlos.

El lenguaje SQL se compone de diferentes tipos de sentencias según el tipo de operación, lectura de datos con SELECT, inserción de datos con INSERT, actualización con UPDATE y eliminación con DELETE.

Las sentencias SELECT tienen la siguiente sintaxis en PostgreSQL.

 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
[ WITH [ RECURSIVE ] with_query [, ...] ]
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
[ * | expression [ [ AS ] output_name ] [, ...] ]
[ FROM from_item [, ...] ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
[ HAVING condition [, ...] ]
[ WINDOW window_name AS ( window_definition ) [, ...] ]
[ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
[ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ]
[ LIMIT { count | ALL } ]
[ OFFSET start [ ROW | ROWS ] ]
[ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ]
[ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]
where from_item can be one of:
[ ONLY ] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
[ TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ] ]
[ LATERAL ] ( select ) [ AS ] alias [ ( column_alias [, ...] ) ]
with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
[ LATERAL ] function_name ( [ argument [, ...] ] )
[ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
[ LATERAL ] function_name ( [ argument [, ...] ] ) [ AS ] alias ( column_definition [, ...] )
[ LATERAL ] function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )
[ LATERAL ] ROWS FROM( function_name ( [ argument [, ...] ] ) [ AS ( column_definition [, ...] ) ] [, ...] )
[ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]
and grouping_element can be one of:
( )
expression
( expression [, ...] )
ROLLUP ( { expression | ( expression [, ...] ) } [, ...] )
CUBE ( { expression | ( expression [, ...] ) } [, ...] )
GROUPING SETS ( grouping_element [, ...] )
and with_query is:
with_query_name [ ( column_name [, ...] ) ] AS ( select | values | insert | update | delete )
TABLE [ ONLY ] table_name [ * ]

La sentencia SELECT se compone de varias cláusulas que se interpretan siguiendo una secuencia de operaciones tal que:

  1. FROM: obtener los registros de todas las tablas fuentes de dato. Si hay subqueries en la cláusula FROM son evaluadas primero.
  2. JOIN: Realizar todas las posibles combinaciones descartando aquellas combinaciones que no cumplen las condiciones JOIN o estableciendo NULL en caso de outer joins.
  3. WHERE: Filtrar las combinaciones que cumplen las condiciones de la cláusula WHERE.
  4. GROUP BY: Construir los grupos basados en las expresiones de la lista de la cláusulas GROUP BY.
  5. HAVING: Filtrar los grupos que cumplen las condiciones de la cláusula HAVING.
  6. SELECT: Evaluar las expresiones de la lista SELECT para seleccionar los datos.
  7. DISTINCT: Eliminar filas duplicadas si se especifica DISTINCT.
  8. UNION, EXCEPT, INTERSECT: Aplicar las operaciones UNION, EXCEPT e INTERSECT.
  9. ORDER BY: Ordenar las filas de acuerdo a la cláusula ORDER BY.
  10. OFFSET, LIMIT: Descartar los registros de acuerdo OFFSET y LIMIT.

Este es el orden general pero el algoritmo del planificador puede optimizar estos pasos realizándose en diferente orden o incluso simultáneamente. Por ejemplo, si se especifica un límite de 1 no es necesario obtener todas las filas de las tablas fuente sino solo una que cumpla la condición WHERE.

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

Picando Código

Emacs Boostrap: Entornos de desarrollo para Emacs al vuelo

junio 26, 2019 10:30

Emacs Bootstrap es un sitio que te permite generar entornos de desarrollo en Emacs para distintos lenguajes de programación: Python, Ruby, Go, PHP, JavaScript, Web, Haskell, Elixir, Rust, Racket y C. Desde la página elegimos qué lenguages queremos usar con Emacs y va a generar las configuraciones necesarias para empezar a escribir código. También nos permite elegir entre 3 temas distintos: solarized-emacs, zenburn-emacs y spacemacs y qué motor de autocompletado preferimos entre ivy y helm.

Emacs Bootstrap

Esto nos genera un archivo con el directorio .emacs.d ya listo para ubicar en nuestro directorio home, ejecutar Emacs, esperar que se bajen los paquetes y empezar a programar.

El entorno es opinionado, por lo que tiene su forma de hacer las cosas. Para eso hay que aprenderse los atajos de teclado y después ir metiendo mano en el archivo init.el si queremos agregarle más cosas.

El autor está buscando extender Emacs-bootsrap para darle soporte a más lenguajes de programación. El código está disponible en GitHub, así que si crees que tenés una configuración perfecta de un lenguaje de programación no incluido, envía un Pull Request.

En lo personal vengo usando Spacemacs hace como 2 años, pero todas estas iniciativas son muy bienvenidas. Sobretodo a la hora de arrancar, para no sentirse abrumado con un archivo de configuración vacío o la configuración por defecto. Recurso agregado a Emacs.sexy 🙂

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

Picando Código

Actualización de MontevideoBicis con datos nuevos en el mapa: bicicircuitos, bicicletarios, estaciones y talleres de reparación

junio 25, 2019 08:05

Montevideo Bicis

Actualicé el sitio MontevideoBicis con datos nuevos. Los datos de accidentes de tránsito no han sido actualizados a 2018 por UNASEV todavía, pero sí los del mapa. La versión más reciente es de marzo de 2018, pero tenía una versión bastante más antigua en el sitio.

Las actualizaciones entonces:

  • Actualizados datos de bicicircuitos, bicicletarios, estaciones y talleres de reparación (fuente). Habría menos calles de 30km/h en Ciudad Vieja que en los datos anteriores, y algunas calles de 30km/h más en el este de la ciudad.
  • El mapa se ve un poco más grande, ocupando el espacio de la pantalla.
  • Actualicé la versión de Ruby a 2.6.3 y las gemas a sus respectivas versiones nuevas.

Por cierto mirando datos, aprendí que GitHub reconoce los archivos .geojson y los muestra en un mapa (Ejemplo).

Usar HAML parecía una buena idea en su momento, pero ahora lo miro y me dan muchas ganas de pasar todo a ERB… y quitar Bootstrap… y darle un diseño más decente… Pero bueno, algún día habrá tiempo.

Los datos de geolocalización son convertidos a geojson para usar en el mapa y los pueden encontrar y reutilizar desde los siguientes enlaces:

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

Fixed Buffer

La potencia de la Reflexión en C# (Parte 2: Ensamblados)

junio 25, 2019 08:00

La imagen muestra el logo de C# para Reflexión Ensamblados

En la última entrada hablábamos sobre un problema que me había encontrado en el trabajo y como la reflexión me había permitido resolverlo de una manera elegante y con poco código. Al menos, muchísimo menos código del que habría necesitado sin haberla usado.

Pensaba hacer simplemente un par de entradas hablando sobre el tema, pero creo que tiene bastante miga, así que lo mejor va a ser hacer una pequeña serie hablando de todas las posibilidades que nos ofrece esta poderosa herramienta. Así que hoy vamos a empezar con la primera de la lista y la que a su vez las contiene a todas: «Assembly».

Assembly (ensamblado): Los ensamblados son los bloques de creación de las aplicaciones .NET Framework; constituyen la unidad fundamental de implementación, control de versiones, reutilización, ámbitos de activación y permisos de seguridad. Un ensamblado es una colección de tipos y recursos compilados para funcionar en conjunto y formar una unidad lógica de funcionalidad. Los ensamblados proporcionan a Common Language Runtime la información necesaria para conocer las implementaciones de tipos. Para la ejecución, un tipo no existe fuera del contexto de un ensamblado.

Fuente: MSDN

¿Y que es un assembly? Pues dicho con palabras sencillas, es la unidad mínima que el CLR puede ejecutar. Contiene las los módulos, las clases, los tipos… y lo más importante, el manifiesto, que es donde se registran todos los metadatos. (Cuando hablemos de los módulos veremos que la principal diferencia es esta última). Cuando una aplicación arranca, el CLR consulta los metadatos del ensamblado para conocer el punto de entrada a este. Él

static void Main(string[] args)

de toda la vida. Mediante reflexión, podemos obtener esos metadatos de el/los ensamblados cargados en la aplicación, pudiendo saber que versión de fichero estamos ejecutando, obtener una lista detallada de todas las clases y métodos que están disponibles en nuestra aplicación, o incluso cargar nuevos ensamblados en nuestra aplicación y permitir que estén disponibles de manera dinámica.

Ejemplos de uso para metadatos

Por ejemplo, un código como este nos permitiría saber la versión que estamos ejecutando:

using System;
using System.Reflection;

namespace PostReflexion
{
    class Program
    {
        static void Main(string[] args)
        {
            var assembly = Assembly.GetAssembly(typeof(Program));
            Console.WriteLine($"Versión: {assembly.GetName().Version}");
        }
    }
}

U obtener todos los tipos (clases, interfaces, enumeraciones….):

using System;
using System.Reflection;

namespace PostReflexion
{
    class Program
    {
        static void Main(string[] args)
        {
            var assembly = Assembly.GetAssembly(typeof(Program));
            foreach (var type in assembly.DefinedTypes)
            {
                Console.WriteLine(type);
            }
        }
    }
}

-Vale, ¿y eso para qué vale? ¡Tampoco es una grandísima utilidad…!

En si mismo, lo visto anteriormente no es de una gran utilidad, ya que para obtener la versión podríamos utilizar «FileVersionInfo» y saber el contenido de un ensamblado en tiempo de ejecución no nos vale de mucho… ¿O sí?

Una herramienta muy potente que nos da la clase Assembly, es que nos permite crear objetos de manera dinámica, es decir, durante el la ejecución del programa, y sin estar explícitamente escrito en nuestro código.

Imagina que tienes una aplicación que sirve de punto de lanzador de otra serie de aplicaciones contenidas en librerías. A simple vista, tienes 3 opciones:

  • Distribuir la aplicación con todas su dll referenciadas, haciendo que gente que no ha pagado por todas las aplicaciones se tenga que descargar un montón de ficheros que no va a poder usar. (Mayor tamaño de archivos)
  • Generar diferentes soluciones que utilicen unas u otras librerías para generar diferentes paquetes de aplicaciones, pero esto crece de manera exponencial con el número de librerías y tipos de «paquete». (Mayor trabajo de mantenimiento)
  • Listar las librerías disponibles dentro del directorio, obtener de ahí las clases que inician las diferentes aplicaciones y ejecutarlas de manera dinámica.

Nota: Cualquiera de las 3 opciones debería contar con un sistema de autenticación que acredite que realmente tiene derecho a utilizar la aplicación.

Creando instancias de manera dinámica

Para ello, aprovechando la opción que nos da la reflexión de instanciar clases, podríamos hacer algo como esto:

var assembly = Assembly.LoadFile("ruta a la librería");
            
//Creamos el objeto de manera dinámica
var formDinamico = assembly.CreateInstance("Nombre completo de la clase") as Form;

//Si hemos podido crear la instancia, abrimos el formulario
formDinamico?.ShowDialog();

Con este código y gracias a assembly, solo cambiando las rutas de cargar la librería y el nombre de la clase, podemos abrir cualquier formulario que herede de Form (WinForms). Esto mismo se puede aplicar a WPF sin ninguna dificultad.

Además, también es posible crear instancias de clases que tienen un constructor con argumentos, pasándole esos argumentos:

//Código de la clase
//=============================================
public class ClaseEjemplo
{
    private int _valor;
    public ClaseEjemplo(int valor)
    {
        _valor = valor;
    }
    public int Multiplicar(int por)
    {
        Console.WriteLine($"Llamada a {nameof(Multiplicar)} con parámetro {por}");
        return _valor * por;
    }
}

//Código para instanciar y ejecutar sus métodos
//=============================================
var assembly = Assembly.LoadFile("ruta a la librería");
//Creamos el objeto de manera dinámica
var objetoDinamico = assembly.CreateInstance("PostReflexion.ClaseEjemplo"
                               ,false
                               ,BindingFlags.ExactBinding
                               ,null
                               ,new object[]{2} //Contructor
                               ,null  
                               ,null);

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

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

No vamos a entrar a ver como hemos llamado a su método, ya que eso lo veremos cuando lleguemos a esa parte, pero el código es funcional y podemos comprobar como hemos instanciado de manera dinámica la clase y le hemos pasado un valor a su constructor, pudiéndolo comprobar al llamar al método.

Estas son solo alguna de las muchísimas opciones que nos da la reflexión en C# a través de la clase Assembly. Combinándola con las demás que vamos a ver, nos permite ejecutar cualquier código de manera dinámica en tiempo de ejecución, lo cual es una herramienta muy potente y que abre un gran abanico de posibilidades.

He actualizado el repositorio de GitHub para añadir los ejemplos de obtención de metadatos y creación de clases de manera dinámica para poder probar esos conceptos.

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

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

Picando Código

Tourmaline – Framework para bots de Telegram en Crystal

junio 19, 2019 11:30

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

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

¡Ya podemos escribir nuestro bot de Telegram en Crystal!

Tourmaline – Framework para bots de Telegram en Crystal

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


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

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

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

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

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

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

MiltonBot

😱 🤖

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

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

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

Y el resultado:

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

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

Picando Código

PyCon Latam 2019 – La conferencia de Python en América Latina

junio 18, 2019 06:40

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

PyCon Latam 2019

Agenda

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

Por ahora hay 3 oradores anunciados:

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

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

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

Becas

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

Lugar y entradas

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

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

Se ubica tan solo a:

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

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

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

Koalite

Sobre checked exceptions y manejo de excepciones

junio 17, 2019 05:06

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

Checked exceptions en Java

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

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

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

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

Excepciones como gestión de errores

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

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

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

Subiendo el nivel semántico de la excepción

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Conclusión

Admito que aquí hay la cosa va por barrios.

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

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

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

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

No hay posts relacionados.

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

Israel Perales

Nexus Repository

junio 16, 2019 05:54

Nexus Repository

Don't repeat yourself

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

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

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

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

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

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

Fue así que llegue a Nexus Repository OSS.

The free artifact repository with universal support for popular formats.

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

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

Instalación

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

Vamos a correr los siguientes comandos:

mkdir nexus && cd nexus

mkdir nexus-data

sudo chown -R 200 nexus-data

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

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

Nexus Repository

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

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

Configuración Maven

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

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

Probaremos que funciona con un proyecto real:


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

cd dockerejemplos/java

mvn clean install

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

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

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

Nexus Repository

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

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

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

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

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

Fixed Buffer

La potencia de la Reflexión (Parte 1)

junio 11, 2019 08:00

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

Si nos fijamos en la definición:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

» 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